James Hunt has proposed merging lp:~jamesodhunt/upstart/initctl-list-sessions into lp:upstart.
Requested reviews: Upstart Reviewers (upstart-reviewers) For more details, see: https://code.launchpad.net/~jamesodhunt/upstart/initctl-list-sessions/+merge/144958 Implementation of the 'initctl list-sessions' command. -- https://code.launchpad.net/~jamesodhunt/upstart/initctl-list-sessions/+merge/144958 Your team Upstart Reviewers is requested to review the proposed merge of lp:~jamesodhunt/upstart/initctl-list-sessions into lp:upstart.
=== modified file 'ChangeLog' --- ChangeLog 2013-01-24 08:37:53 +0000 +++ ChangeLog 2013-01-25 15:38:24 +0000 @@ -1,3 +1,49 @@ +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(). + * init/xdg.c: get_home_subdir(): Handle unset 'HOME' immediately. + * init/control.c: Make use of SESSION_EXT. + * init/man/init.5: Added session files. + * init/paths.h: + - Comments. + - Added SESSION_EXT. + +2013-01-24 James Hunt <[email protected]> + + * init/control.c: + - control_init(): Create session file in user mode. + - control_cleanup(): New function for cleanup activities. + - control_session_file_create(): Create session file containing + UPSTART_SESSION details. + - control_session_file_remove(): Delete the session file. + * init/main.c: Call control_cleanup() to remove session file. + * init/paths.h: Added INIT_XDG_SESSION_SUBDIR and SESSION_ENV. + * init/xdg.c: + - get_subdir(): Refactor of get_home_subdir(). + - get_home_subdir(): Now calls get_subdir(). + - Replaced mkdir mode values with INIT_XDG_PATH_MODE. + - xdg_get_runtime_dir(): Obtain XDG_RUNTIME_DIR value. + - get_session_dir(): Obtain path to session directory. + * init/xdg.h: Added INIT_XDG_PATH_MODE. + 2013-01-21 Dmitrijs Ledkovs <[email protected]> * init/xdg.[ch]: add xdg_get_cache_home and get_user_log_dir === modified file 'init/control.c' --- init/control.c 2013-01-23 12:56:00 +0000 +++ init/control.c 2013-01-25 15:38:24 +0000 @@ -56,15 +56,19 @@ #include "errors.h" #include "state.h" #include "event.h" +#include "paths.h" +#include "xdg.h" #include "com.ubuntu.Upstart.h" /* Prototypes for static functions */ -static int control_server_connect (DBusServer *server, DBusConnection *conn); -static void control_disconnected (DBusConnection *conn); -static void control_register_all (DBusConnection *conn); +static int control_server_connect (DBusServer *server, DBusConnection *conn); +static void control_disconnected (DBusConnection *conn); +static void control_register_all (DBusConnection *conn); -static void control_bus_flush (void); +static void control_bus_flush (void); +static void control_session_file_create (void); +static void control_session_file_remove (void); /** * use_session_bus: @@ -108,6 +112,8 @@ /* External definitions */ extern int user_mode; +extern char *session_file; + /** * control_init: * @@ -120,14 +126,27 @@ control_conns = NIH_MUST (nih_list_new (NULL)); if (! control_server_address) { - if (user_mode) + if (user_mode) { NIH_MUST (nih_strcat_sprintf (&control_server_address, NULL, "%s-session/%d/%d", DBUS_ADDRESS_UPSTART, getuid (), getpid ())); - else - control_server_address = nih_strdup (NULL, DBUS_ADDRESS_UPSTART); + + control_session_file_create (); + } else { + control_server_address = NIH_MUST (nih_strdup (NULL, DBUS_ADDRESS_UPSTART)); + } } } +/** + * control_cleanup: + * + * Perform cleanup operations. + **/ +void +control_cleanup (void) +{ + control_session_file_remove (); +} /** * control_server_open: @@ -1117,3 +1136,55 @@ NIH_ZERO (control_emit_restarted (conn, DBUS_PATH_UPSTART)); } } + +/** + * control_session_file_create: + * + * Create session file if possible. + * + * Errors are not fatal - the file is just not created. + **/ +static void +control_session_file_create (void) +{ + nih_local char *session_dir = NULL; + FILE *f; + int ret; + + nih_assert (control_server_address); + + session_dir = get_session_dir (); + + if (! session_dir) + return; + + NIH_MUST (nih_strcat_sprintf (&session_file, NULL, "%s/%d%s", + session_dir, (int)getpid (), SESSION_EXT)); + + f = fopen (session_file, "w"); + if (! f) { + nih_error ("%s: %s", _("unable to create session file"), session_file); + return; + } + + 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); +} + +/** + * control_session_file_remove: + * + * Delete session file. + * + * Errors are not fatal. + **/ +static void +control_session_file_remove (void) +{ + if (session_file) + (void)unlink (session_file); +} === modified file 'init/control.h' --- init/control.h 2012-12-14 23:43:15 +0000 +++ init/control.h 2013-01-25 15:38:24 +0000 @@ -54,6 +54,7 @@ void control_init (void); +void control_cleanup (void); int control_server_open (void) __attribute__ ((warn_unused_result)); === modified file 'init/main.c' --- init/main.c 2013-01-23 12:40:36 +0000 +++ init/main.c 2013-01-25 15:38:24 +0000 @@ -651,6 +651,8 @@ nih_main_loop_interrupt (); ret = nih_main_loop (); + control_cleanup (); + return ret; } === modified file 'init/man/init.5' --- init/man/init.5 2013-01-23 12:40:36 +0000 +++ init/man/init.5 2013-01-25 15:38:24 +0000 @@ -1050,6 +1050,9 @@ .TP .I $XDG_CACHE_HOME/upstart/*.log Default location of user session job output logs. +.TP +.I $XDG_RUNTIME_DIR/upstart/sessions/*.session +Location of session files created when running in User Session mode. .RE .\" .SH AUTHOR === modified file 'init/paths.h' --- init/paths.h 2012-12-17 15:46:35 +0000 +++ init/paths.h 2013-01-25 15:38:24 +0000 @@ -116,6 +116,16 @@ #endif /** + * INIT_XDG_SESSION_SUBDIR: + * + * Directory below XDG_RUNTIME_DIR/INIT_XDG_SUBDIR used to + * store session details. + **/ +#ifndef INIT_XDG_SESSION_SUBDIR +#define INIT_XDG_SESSION_SUBDIR "sessions" +#endif + +/** * SHELL: * * This is the shell binary used whenever we need special processing for @@ -166,13 +176,25 @@ #define LOGDIR_ENV "UPSTART_LOGDIR" #endif +/** + * SESSION_ENV: + * + * Environment variable that is set when running as a Session Init. + **/ +#ifndef SESSION_ENV +#define SESSION_ENV "UPSTART_SESSION" +#endif /** + * CONF_EXT_STD: + * * File extension for standard configuration files. **/ #define CONF_EXT_STD ".conf" /** + * CONF_EXT_OVERRIDE: + * * File extension for override files. * * Note that override files are not stored in the ConfSource 'files' hash: @@ -182,6 +204,15 @@ #define CONF_EXT_OVERRIDE ".override" /** + * SESSION_EXT: + * + * File extension for session files. + **/ +#ifndef SESSION_EXT +#define SESSION_EXT ".session" +#endif + +/** * Determine if specified path extension representes a standard * configuration file. * === modified file 'init/tests/test_xdg.c' --- init/tests/test_xdg.c 2013-01-22 12:01:56 +0000 +++ init/tests/test_xdg.c 2013-01-25 15:38:24 +0000 @@ -435,6 +435,49 @@ rmdir (dirname); } +void +test_get_session_dir (void) +{ + char dirname[PATH_MAX]; + char *expected; + char *path; + + TEST_FUNCTION ("get_session_dir"); + + TEST_FEATURE ("with XDG_RUNTIME_DIR set"); + + TEST_FILENAME (dirname); + assert0 (setenv ("XDG_RUNTIME_DIR", dirname, 1)); + TEST_EQ (mkdir (dirname, 0755), 0); + + expected = nih_sprintf (NULL, "%s/upstart/sessions", dirname); + + TEST_ALLOC_FAIL { + path = get_session_dir (); + if (test_alloc_failed) { + TEST_EQ_P (path, NULL); + } else { + TEST_EQ_STR (path, expected); + _test_dir_created (expected); + nih_free (path); + } + } + + TEST_FEATURE ("with XDG_RUNTIME_DIR unset"); + assert0 (unsetenv ("XDG_RUNTIME_DIR")); + + /* no fallback */ + path = get_session_dir (); + TEST_EQ_P (path, NULL); + + rmdir (expected); + nih_free (expected); + path = nih_sprintf (NULL, "%s/upstart", dirname); + rmdir (path); + nih_free (path); + rmdir (dirname); +} + int main (int argc, char *argv[]) @@ -445,6 +488,7 @@ test_get_user_upstart_dirs (); test_get_cache_home (); test_get_user_log_dir (); + test_get_session_dir (); return 0; } === modified file 'init/xdg.c' --- init/xdg.c 2013-01-22 12:01:56 +0000 +++ init/xdg.c 2013-01-25 15:38:24 +0000 @@ -34,6 +34,8 @@ #include "paths.h" #include "xdg.h" +#ifndef INITCTL_BUILD + /** * user_mode: * @@ -42,37 +44,76 @@ int user_mode = FALSE; /** - * get_home_subdir: - * @suffix: sub-directory name - * @create: flag to create sub-directory - * - * Construct path to @suffix directory in user's HOME dir. If @create - * flag is TRUE, also attempt to create that directory. Errors upon - * directory creation are ignored. - * - * Returns: newly-allocated path, or NULL on error. + * session_file: + * + * Full path to file containing UPSTART_SESSION details (only set when + * user_mode in operation). + * + * File is created on startup and removed on clean shutdown. + **/ +const char *session_file = NULL; + +#endif /* INITCTL_BUILD */ + +/** + * get_subdir: + * @dir: initial directory, + * @suffix: sub-directory of @dir, + * @create: flag to create sub-directory. + * + * Construct path by appending @suffix to @dir. If @create + * flag is TRUE, also attempt to create that directory. + * + * Errors upon directory creation are ignored. + * + * Returns: Newly-allocated path, or NULL on error. **/ char * -get_home_subdir (const char * suffix, int create) +get_subdir (const char *dir, const char *suffix, int create) { - char *dir; + char *newdir; + nih_assert (dir != NULL); nih_assert (suffix != NULL); nih_assert (suffix[0]); - dir = getenv ("HOME"); if (dir && dir[0] == '/') { - dir = nih_sprintf (NULL, "%s/%s", dir, suffix); - if (! dir) + newdir = nih_sprintf (NULL, "%s/%s", dir, suffix); + if (! newdir) return NULL; if (create) - mkdir (dir, 0700); - return dir; + mkdir (newdir, INIT_XDG_PATH_MODE); + return newdir; } return NULL; } /** + * get_home_subdir: + * + * @suffix: sub-directory name, + * @create: flag to create sub-directory. + * + * Construct path to @suffix directory in user's HOME directory. + * If @create is TRUE, also attempt to create that directory. + * + * Errors upon directory creation are ignored. + * + * Returns: Newly-allocated path, or NULL on error. + **/ +char * +get_home_subdir (const char *suffix, int create) +{ + char *env; + + env = getenv ("HOME"); + if (! env) + return NULL; + + return get_subdir (env, suffix, create); +} + +/** * xdg_get_cache_home: * * Determine an XDG compliant XDG_CACHE_HOME @@ -82,13 +123,12 @@ char * xdg_get_cache_home (void) { - nih_local char **env = NULL; char *dir; dir = getenv ("XDG_CACHE_HOME"); if (dir && dir[0] == '/') { - mkdir (dir, 0700); + mkdir (dir, INIT_XDG_PATH_MODE); dir = nih_strdup (NULL, dir); return dir; } @@ -115,13 +155,12 @@ char * xdg_get_config_home (void) { - nih_local char **env = NULL; - char *dir; + char *dir; dir = getenv ("XDG_CONFIG_HOME"); if (dir && dir[0] == '/') { - mkdir (dir, 0700); + mkdir (dir, INIT_XDG_PATH_MODE); dir = nih_strdup (NULL, dir); return dir; } @@ -136,6 +175,60 @@ } /** + * xdg_get_runtime_dir: + * + * Determine an XDG compliant XDG_RUNTIME_DIR. + * + * Returns: newly-allocated path, or NULL on error. + **/ +char * +xdg_get_runtime_dir (void) +{ + char *dir; + + dir = getenv ("XDG_RUNTIME_DIR"); + + if (dir && dir[0] == '/') { + mkdir (dir, INIT_XDG_PATH_MODE); + dir = nih_strdup (NULL, dir); + return dir; + } + + return dir; +} + +/** + * get_session_dir: + * + * Determine full path to XDG-compliant session directory used to store + * session files. + * + * Returns: Newly-allocated path, or NULL on error. + **/ +char * +get_session_dir (void) +{ + nih_local char *runtime_dir = NULL; + nih_local char *dir = NULL; + char *session_dir; + + runtime_dir = xdg_get_runtime_dir (); + + if (runtime_dir && runtime_dir[0] == '/') { + dir = get_subdir (runtime_dir, INIT_XDG_SUBDIR, TRUE); + if (! dir) + return NULL; + + session_dir = get_subdir (dir, INIT_XDG_SESSION_SUBDIR, + TRUE); + + return session_dir; + } + + return NULL; +} + +/** * xdg_get_config_dirs: * * Determine a list of XDG compliant XDG_CONFIG_DIRS @@ -189,7 +282,7 @@ if (path && path[0]) { if (! nih_strcat_sprintf (&path, NULL, "/%s", INIT_XDG_SUBDIR)) goto error; - mkdir (path, 0700); + mkdir (path, INIT_XDG_PATH_MODE); if (! nih_str_array_add (&all_dirs, NULL, NULL, path)) goto error; nih_free (path); @@ -261,7 +354,7 @@ dir = nih_sprintf (NULL, "%s/%s", path, INIT_XDG_SUBDIR); if (! dir) return NULL; - mkdir (dir, 0700); + mkdir (dir, INIT_XDG_PATH_MODE); return dir; } return NULL; === modified file 'init/xdg.h' --- init/xdg.h 2013-01-23 12:56:00 +0000 +++ init/xdg.h 2013-01-25 15:38:24 +0000 @@ -23,8 +23,19 @@ #include "paths.h" #include <nih/macros.h> +/** + * INIT_XDG_PATH_MODE: + * + * Absolute mode to create XDG-compliant directory elements with. + **/ +#define INIT_XDG_PATH_MODE 0700 + NIH_BEGIN_EXTERN +char * get_env_subdir (const char *envvar, const char *suffix, + int create) + __attribute__ ((malloc, warn_unused_result)); + char * get_home_subdir (const char * suffix, int create) __attribute__ ((malloc, warn_unused_result)); @@ -34,6 +45,9 @@ char * xdg_get_cache_home (void) __attribute__ ((malloc, warn_unused_result)); +char * xdg_get_runtime_dir (void) + __attribute__ ((malloc, warn_unused_result)); + char ** xdg_get_config_dirs (void) __attribute__ ((malloc, warn_unused_result)); @@ -43,6 +57,9 @@ char * get_user_log_dir (void) __attribute__ ((malloc, warn_unused_result)); +char * get_session_dir (void) + __attribute__ ((malloc, warn_unused_result)); + NIH_END_EXTERN #endif /* INIT_XDG_H */ === modified file 'util/Makefile.am' --- util/Makefile.am 2012-12-12 14:13:08 +0000 +++ util/Makefile.am 2013-01-25 15:38:24 +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-25 15:38:24 +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,123 @@ 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)); + + contents = nih_file_read (NULL, path, &len); + + if (! contents) + continue; + + if (contents[len-1] == '\n') + contents[len-1] = '\0'; + + p = strchr (contents, '='); + if (! p) + continue; + + /* Invalid contents */ + if (strncmp (contents, "UPSTART_SESSION", (p - contents))) + continue; + + session = p + 1; + + if (! session || ! *session) + continue; + + if (kill (pid, 0)) { + nih_info ("%s: %s", _("Ignoring stale session file"), path); + 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 +2783,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:38:24 +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-22 18:17:04 +0000 +++ util/tests/test_initctl.c 2013-01-25 15:38:24 +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,109 @@ } 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; + size_t len; + char *value; + + TEST_GROUP ("list-sessions"); + + /*******************************************************************/ + TEST_FEATURE ("with no instances"); + + 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"); + + TEST_FILENAME (dirname); + TEST_EQ (mkdir (dirname, 0755), 0); + + TEST_FILENAME (confdir); + TEST_EQ (mkdir (confdir, 0755), 0); + + /* 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); + + /*******************************************************************/ + + TEST_EQ (unsetenv ("UPSTART_CONFDIR"), 0); + + TEST_EQ (rmdir (dirname), 0); + TEST_EQ (rmdir (confdir), 0); + + /*******************************************************************/ +} + +void test_show_config (void) { char dirname[PATH_MAX]; @@ -15239,6 +15386,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
