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

Reply via email to