Merge authors: James Hunt (jamesodhunt) Related merge proposals: https://code.launchpad.net/~jamesodhunt/upstart/initctl-list-sessions/+merge/145325 proposed by: Steve Langasek (vorlon) review: Needs Fixing - Steve Langasek (vorlon) ------------------------------------------------------------ revno: 1433 [merge] committer: James Hunt <[email protected]> branch nick: upstart timestamp: Wed 2013-01-30 16:39:11 +0000 message: * Merge of lp:~jamesodhunt/upstart/initctl-list-sessions. modified: ChangeLog init/control.c init/xdg.c util/Makefile.am util/initctl.c util/man/initctl.8 util/tests/test_initctl.c
-- lp:upstart https://code.launchpad.net/~upstart-devel/upstart/trunk Your team Upstart Reviewers is subscribed to branch lp:upstart. To unsubscribe from this branch go to https://code.launchpad.net/~upstart-devel/upstart/trunk/+edit-subscription
=== modified file 'ChangeLog' --- ChangeLog 2013-01-30 16:28:07 +0000 +++ ChangeLog 2013-01-30 16:39:11 +0000 @@ -24,6 +24,35 @@ doesn't already exist. - Simplify logic. +2013-01-28 James Hunt <[email protected]> + + * util/initctl.c: list_session_action(): + - Test for stale session earlier. + - Simplify checks on "UPSTART_SESSION". + * util/tests/test_initctl.c: test_list_sessions(): + - Added test with XDG_RUNTIME_DIR explicitly unset. + - Changed "with no instances" test to set XDG_RUNTIME_DIR to a + temporary value. + - Revert XDG_RUNTIME_DIR on cleanup. + +2013-01-25 James Hunt <[email protected]> + + * init/control.c: control_session_file_create(): Simplified. + * init/xdg.c: Added check for INITCTL_BUILD to hide certain symbols when + building with initctl. + * util/Makefile.am: + - Define INITCTL_BUILD. + - Make use of xdg.[ch] in build of initctl and its test. + * util/initctl.c: + - list_session_action(): Implementation of 'list-sessions' command. + * util/man/initctl.8: Updated for 'list-sessions' command. + * util/tests/test_initctl.c: + - _start_upstart(): Replacement for _START_UPSTART() macro. + - start_upstart_common(): Start an instance with common options. + - start_upstart(): Simplest way to start an instance. + - START_UPSTART(): Now calls start_upstart_common(). + - test_list_sessions(): Test 'list-sessions' command. + 2013-01-25 James Hunt <[email protected]> * init/tests/test_xdg.c: Added test_get_session_dir(). === modified file 'init/control.c' --- init/control.c 2013-01-30 16:28:07 +0000 +++ init/control.c 2013-01-30 16:39:11 +0000 @@ -1247,6 +1247,7 @@ { nih_local char *session_dir = NULL; FILE *f; + int ret; nih_assert (control_server_address); @@ -1264,9 +1265,10 @@ return; } - if (fprintf (f, SESSION_ENV "=%s\n", control_server_address) < 0) { + ret = fprintf (f, SESSION_ENV "=%s\n", control_server_address); + + if (ret < 0) nih_error ("%s: %s", _("unable to write session file"), session_file); - } fclose (f); } === modified file 'init/xdg.c' --- init/xdg.c 2013-01-29 09:29:28 +0000 +++ init/xdg.c 2013-01-30 16:39:11 +0000 @@ -34,6 +34,8 @@ #include "paths.h" #include "xdg.h" +#ifndef INITCTL_BUILD + /** * user_mode: * @@ -51,6 +53,8 @@ **/ const char *session_file = NULL; +#endif /* INITCTL_BUILD */ + /** * get_subdir: * @dir: initial directory, === modified file 'util/Makefile.am' --- util/Makefile.am 2012-12-12 14:13:08 +0000 +++ util/Makefile.am 2013-01-25 15:32:44 +0000 @@ -7,6 +7,7 @@ AM_CPPFLAGS = \ -DLOCALEDIR="\"$(localedir)\"" \ + -DINITCTL_BUILD \ -DSBINDIR="\"$(sbindir)\"" \ -I$(top_builddir) -I$(top_srcdir) -iquote$(builddir) -iquote$(srcdir) \ -I$(top_srcdir)/intl @@ -29,7 +30,8 @@ telinit initctl_SOURCES = \ - initctl.c initctl.h + initctl.c initctl.h \ + $(top_srcdir)/init/xdg.c $(top_srcdir)/init/xdg.h nodist_initctl_SOURCES = \ $(com_ubuntu_Upstart_OUTPUTS) \ $(com_ubuntu_Upstart_Job_OUTPUTS) \ @@ -192,7 +194,10 @@ check_PROGRAMS = $(TESTS) -test_initctl_SOURCES = tests/test_initctl.c initctl.c +test_initctl_SOURCES = \ + tests/test_initctl.c \ + initctl.c \ + $(top_srcdir)/init/xdg.c $(top_srcdir)/init/xdg.h test_initctl_CFLAGS = $(AM_CFLAGS) -DTEST test_initctl_LDADD = \ com.ubuntu.Upstart.o \ === modified file 'util/initctl.c' --- util/initctl.c 2013-01-22 16:50:19 +0000 +++ util/initctl.c 2013-01-29 11:08:31 +0000 @@ -30,6 +30,9 @@ #include <stdlib.h> #include <unistd.h> #include <fnmatch.h> +#include <pwd.h> +#include <dirent.h> +#include <ctype.h> #include <nih/macros.h> #include <nih/alloc.h> @@ -41,6 +44,7 @@ #include <nih/error.h> #include <nih/hash.h> #include <nih/tree.h> +#include <nih/file.h> #include <nih-dbus/dbus_error.h> #include <nih-dbus/dbus_proxy.h> @@ -53,7 +57,8 @@ #include "com.ubuntu.Upstart.Job.h" #include "com.ubuntu.Upstart.Instance.h" -#include "../init/events.h" +#include "init/events.h" +#include "init/xdg.h" #include "initctl.h" @@ -126,6 +131,7 @@ int check_config_action (NihCommand *command, char * const *args); int usage_action (NihCommand *command, char * const *args); int notify_disk_writeable_action (NihCommand *command, char * const *args); +int list_sessions_action (NihCommand *command, char * const *args); /** * use_dbus: @@ -1706,6 +1712,119 @@ return 1; } + +/** + * list_sessions_action: + * @command: NihCommand invoked, + * @args: command-line arguments. + * + * This function is called for the "list-sessions" command. + * + * Unlike other commands, this does not attempt to connect to Upstart. + * + * Returns: command exit status. + **/ +int +list_sessions_action (NihCommand *command, char * const *args) +{ + nih_local const char *session_dir = NULL; + DIR *dir; + struct dirent *ent; + + nih_assert (command); + nih_assert (args); + + session_dir = get_session_dir (); + + if (! session_dir) { + nih_error (_("Unable to query session directory")); + return 1; + } + + dir = opendir (session_dir); + if (! dir) + goto error; + + while ((ent = readdir (dir))) { + nih_local char *contents = NULL; + size_t len; + nih_local char *path = NULL; + pid_t pid; + nih_local char *name = NULL; + char *session; + char *p; + char *ext; + char *file; + int all_digits = TRUE; + + file = ent->d_name; + + if (! strcmp (file, ".") || ! strcmp (file, "..")) + continue; + + ext = p = strchr (file, '.'); + + /* No extension */ + if (! ext) + continue; + + /* Invalid extension */ + if (strcmp (ext, ".session")) + continue; + + NIH_MUST (nih_strncat (&name, NULL, file, (p - file))); + + for (p = name; p && *p; p++) { + if (! isdigit (*p)) { + all_digits = FALSE; + break; + } + } + + /* Invalid name */ + if (! all_digits) + continue; + + pid = (pid_t) atol (name); + + NIH_MUST (nih_strcat_sprintf (&path, NULL, "%s/%s", session_dir, file)); + + if (kill (pid, 0)) { + nih_info ("%s: %s", _("Ignoring stale session file"), path); + continue; + } + + contents = nih_file_read (NULL, path, &len); + + if (! contents) + continue; + + if (contents[len-1] == '\n') + contents[len-1] = '\0'; + + p = strstr (contents, "UPSTART_SESSION" "="); + if (p != contents) + continue; + + session = p + strlen ("UPSTART_SESSION") + 1; + + if (! session || ! *session) + continue; + + nih_message ("%d %s", (int)pid, session); + } + + closedir (dir); + + return 0; + +error: + nih_error ("unable to determine sessions"); + return 1; + +} + + static void start_reply_handler (char ** job_path, NihDBusMessage *message, @@ -2660,6 +2779,11 @@ "disk is writeable are flushed to disk"), NULL, NULL, notify_disk_writeable_action }, + { "list-sessions", NULL, + N_("List all sessions."), + N_("Displays list of running Session Init sessions"), + NULL, NULL, list_sessions_action }, + NIH_COMMAND_LAST }; === modified file 'util/man/initctl.8' --- util/man/initctl.8 2013-01-22 17:14:40 +0000 +++ util/man/initctl.8 2013-01-25 15:32:44 +0000 @@ -555,6 +555,16 @@ .RE .\" .TP +.B list\-sessions +List the pid of the Session Init process followed by the value of +.B UPSTART_SESSION +in use for that session separted by a space character. Session files +relating to non-longer running Session Init processes are considered +\(aqstale\(aq and are not listed (although when run using +.BR \-\-verbose "," +the full path of the stale session file is displayed). +.\" +.TP .B usage .I JOB .RI [ KEY=VALUE ]... === modified file 'util/tests/test_initctl.c' --- util/tests/test_initctl.c 2013-01-25 09:08:09 +0000 +++ util/tests/test_initctl.c 2013-01-30 16:39:11 +0000 @@ -44,6 +44,7 @@ #include <nih/main.h> #include <nih/command.h> #include <nih/error.h> +#include <nih/file.h> #include <nih/string.h> #include "dbus/upstart.h" @@ -104,61 +105,6 @@ } /** - * _START_UPSTART: - * - * @pid: pid_t that will contain pid of running instance on success, - * @confdir: full path to configuration directory, or NULL to use - * the default, - * @logdir: full path to log directory, or NULL to use the default. - * - * Start an instance of Upstart. Fork errors are fatal. Waits for a - * reasonable amount of time for Upstart to appear on D-Bus. - **/ -#define _START_UPSTART(pid, confdir, logdir) \ -{ \ - nih_local char **args = NULL; \ - nih_local char *conf_opts = NULL; \ - nih_local char *log_opts = NULL; \ - \ - TEST_TRUE (getenv ("DBUS_SESSION_BUS_ADDRESS")); \ - \ - args = NIH_MUST (nih_str_array_new (NULL)); \ - \ - NIH_MUST (nih_str_array_add (&args, NULL, NULL, \ - UPSTART_BINARY)); \ - \ - NIH_MUST (nih_str_array_add (&args, NULL, NULL, \ - "--session")); \ - \ - NIH_MUST (nih_str_array_add (&args, NULL, NULL, \ - "--no-startup-event")); \ - \ - NIH_MUST (nih_str_array_add (&args, NULL, NULL, \ - "--no-sessions")); \ - \ - if (confdir != NULL) { \ - NIH_MUST (nih_str_array_add (&args, NULL, NULL, \ - "--confdir")); \ - NIH_MUST (nih_str_array_add (&args, NULL, NULL, \ - confdir)); \ - } \ - \ - if (logdir != NULL) { \ - NIH_MUST (nih_str_array_add (&args, NULL, NULL, \ - "--logdir")); \ - NIH_MUST (nih_str_array_add (&args, NULL, NULL, \ - logdir)); \ - } \ - \ - TEST_NE (pid = fork (), -1); \ - \ - if (pid == 0) \ - execv (args[0], args); \ - \ - WAIT_FOR_UPSTART (); \ -} - -/** * START_UPSTART: * * @pid: pid_t that will contain pid of running instance on success. @@ -166,7 +112,7 @@ * Start an instance of Upstart and return PID in @pid. **/ #define START_UPSTART(pid) \ - _START_UPSTART (pid, NULL, NULL) + start_upstart_common (&(pid), NULL, NULL, NULL) /** * KILL_UPSTART: @@ -310,6 +256,104 @@ } /** + * _start_upstart: + * + * @pid: PID of running instance, + * @args: optional list of arguments to specify. + * + * Start an instance of Upstart. + * + * If the instance fails to start, abort(3) is called. + **/ +void +_start_upstart (pid_t *pid, char * const *args) +{ + nih_local char **argv = NULL; + + assert (pid); + + TEST_TRUE (getenv ("DBUS_SESSION_BUS_ADDRESS")); + + argv = NIH_MUST (nih_str_array_new (NULL)); + + NIH_MUST (nih_str_array_add (&argv, NULL, NULL, + UPSTART_BINARY)); + + if (args) + NIH_MUST (nih_str_array_append (&argv, NULL, NULL, args)); + + TEST_NE (*pid = fork (), -1); + + if (*pid == 0) + execv (argv[0], argv); + + WAIT_FOR_UPSTART (); +} + +/** + * start_upstart_common: + * + * @pid: PID of running instance, + * @confdir: full path to configuration directory, + * @logdir: full path to log directory, + * @extra: optional extra arguments. + * + * Wrapper round _start_upstart() which specifies common options. + **/ +void +start_upstart_common (pid_t *pid, const char *confdir, + const char *logdir, char * const *extra) +{ + nih_local char **args = NULL; + + assert (pid); + + args = NIH_MUST (nih_str_array_new (NULL)); + + NIH_MUST (nih_str_array_add (&args, NULL, NULL, + "--session")); + + NIH_MUST (nih_str_array_add (&args, NULL, NULL, + "--no-startup-event")); + + NIH_MUST (nih_str_array_add (&args, NULL, NULL, + "--no-sessions")); + + if (confdir) { + NIH_MUST (nih_str_array_add (&args, NULL, NULL, + "--confdir")); + NIH_MUST (nih_str_array_add (&args, NULL, NULL, + confdir)); + } + + if (logdir) { + NIH_MUST (nih_str_array_add (&args, NULL, NULL, + "--logdir")); + NIH_MUST (nih_str_array_add (&args, NULL, NULL, + logdir)); + } + + if (extra) + NIH_MUST (nih_str_array_append (&args, NULL, NULL, extra)); + + _start_upstart (pid, args); +} + +/** + * start_upstart: + * + * @pid: PID of running instance. + * + * Wrapper round _start_upstart() which just runs an instance with no + * options. + **/ +void +start_upstart (pid_t *pid) +{ + start_upstart_common (pid, NULL, NULL, NULL); +} + +/** * job_to_pid: * * @job: job name. @@ -11324,7 +11368,7 @@ /*******************************************************************/ TEST_FEATURE ("single job producing output across a re-exec"); - _START_UPSTART (upstart_pid, confdir, logdir); + start_upstart_common (&upstart_pid, confdir, logdir, NULL); contents = nih_sprintf (NULL, "pre-start exec echo pre-start\n" @@ -11481,6 +11525,137 @@ } void +test_list_sessions (void) +{ + char dirname[PATH_MAX]; + char confdir[PATH_MAX]; + nih_local char *cmd = NULL; + nih_local char **args = NULL; + pid_t upstart_pid = 0; + pid_t dbus_pid = 0; + char **output; + size_t lines; + struct stat statbuf; + nih_local char *contents = NULL; + nih_local char *session_file = NULL; + nih_local char *path = NULL; + nih_local char *expected = NULL; + nih_local char *orig_xdg_runtime_dir = NULL; + size_t len; + char *value; + + TEST_GROUP ("list-sessions"); + + TEST_FILENAME (dirname); + TEST_EQ (mkdir (dirname, 0755), 0); + + TEST_FILENAME (confdir); + TEST_EQ (mkdir (confdir, 0755), 0); + + /* Take care to avoid disrupting users environment by saving and + * restoring this variable (assuming the tests all pass...). + */ + orig_xdg_runtime_dir = getenv ("XDG_RUNTIME_DIR"); + if (orig_xdg_runtime_dir) + orig_xdg_runtime_dir = NIH_MUST (nih_strdup (NULL, orig_xdg_runtime_dir)); + + /*******************************************************************/ + TEST_FEATURE ("with no instances and XDG_RUNTIME_DIR unset"); + + assert0 (unsetenv ("XDG_RUNTIME_DIR")); + cmd = nih_sprintf (NULL, "%s list-sessions 2>&1", INITCTL_BINARY); + TEST_NE_P (cmd, NULL); + RUN_COMMAND (NULL, cmd, &output, &lines); + TEST_EQ (lines, 1); + TEST_EQ_STR (output[0], "initctl: Unable to query session directory"); + nih_free (output); + + /*******************************************************************/ + TEST_FEATURE ("with no instances and XDG_RUNTIME_DIR set"); + + TEST_EQ (setenv ("XDG_RUNTIME_DIR", dirname, 1), 0); + + cmd = nih_sprintf (NULL, "%s list-sessions 2>&1", INITCTL_BINARY); + TEST_NE_P (cmd, NULL); + RUN_COMMAND (NULL, cmd, &output, &lines); + TEST_EQ (lines, 0); + + /*******************************************************************/ + TEST_FEATURE ("with 1 running instance"); + + /* Use the "secret" interface */ + TEST_EQ (setenv ("UPSTART_CONFDIR", confdir, 1), 0); + TEST_EQ (setenv ("XDG_RUNTIME_DIR", dirname, 1), 0); + + args = NIH_MUST (nih_str_array_new (NULL)); + NIH_MUST (nih_str_array_add (&args, NULL, NULL, "--user")); + + /* Start to create session file */ + TEST_DBUS (dbus_pid); + start_upstart_common (&upstart_pid, NULL, NULL, args); + + session_file = nih_sprintf (NULL, "%s/upstart/sessions/%d.session", + dirname, (int)upstart_pid); + + /* session file should now have been created by Upstart */ + TEST_EQ (stat (session_file, &statbuf), 0); + + contents = nih_file_read (NULL, session_file, &len); + TEST_NE_P (contents, NULL); + TEST_TRUE (len); + + /* overwrite '\n' */ + contents[len-1] = '\0'; + + TEST_EQ_P (strstr (contents, "UPSTART_SESSION="), contents); + value = strchr (contents, '='); + TEST_NE_P (value, NULL); + + /* jump over '=' */ + value++; + TEST_NE_P (value, NULL); + + expected = nih_sprintf (NULL, "%d %s", (int)upstart_pid, value); + + cmd = nih_sprintf (NULL, "%s list-sessions 2>&1", INITCTL_BINARY); + TEST_NE_P (cmd, NULL); + RUN_COMMAND (NULL, cmd, &output, &lines); + TEST_EQ (lines, 1); + TEST_EQ_STR (output[0], expected); + nih_free (output); + + STOP_UPSTART (upstart_pid); + TEST_DBUS_END (dbus_pid); + + /* Upstart cannot yet be instructed to shutdown cleanly, so for + * now we have to remove the session file manually. + */ + TEST_EQ (unlink (session_file), 0); + + /* Remove the directory tree the Session Init created */ + path = NIH_MUST (nih_sprintf (NULL, "%s/upstart/sessions", dirname)); + TEST_EQ (rmdir (path), 0); + path = NIH_MUST (nih_sprintf (NULL, "%s/upstart", dirname)); + TEST_EQ (rmdir (path), 0); + + /*******************************************************************/ + + if (orig_xdg_runtime_dir) { + /* restore */ + setenv ("XDG_RUNTIME_DIR", orig_xdg_runtime_dir, 1); + } else { + assert0 (unsetenv ("XDG_RUNTIME_DIR")); + } + + assert0 (unsetenv ("UPSTART_CONFDIR")); + + TEST_EQ (rmdir (dirname), 0); + TEST_EQ (rmdir (confdir), 0); + + /*******************************************************************/ +} + +void test_show_config (void) { char dirname[PATH_MAX]; @@ -15242,6 +15417,7 @@ test_log_priority_action (); test_usage (); test_reexec (); + test_list_sessions (); if (in_chroot () && !dbus_configured ()) { fprintf(stderr, "\n\n"
-- upstart-devel mailing list [email protected] Modify settings or unsubscribe at: https://lists.ubuntu.com/mailman/listinfo/upstart-devel
