Merge authors:
  Dmitrijs Ledkovs (xnox)
  James Hunt (jamesodhunt)
  Steve Langasek (vorlon)
  Stéphane Graber (stgraber)
Related merge proposals:
  https://code.launchpad.net/~stgraber/upstart/upstart-tests-pty/+merge/140388
  proposed by: Stéphane Graber (stgraber)
  review: Approve - James Hunt (jamesodhunt)
  https://code.launchpad.net/~xnox/upstart/upstart-user-mode/+merge/140258
  proposed by: Dmitrijs Ledkovs (xnox)
  review: Approve - James Hunt (jamesodhunt)
  https://code.launchpad.net/~stgraber/upstart/upstart-shell-exec/+merge/140233
  proposed by: Stéphane Graber (stgraber)
  review: Approve - James Hunt (jamesodhunt)
  https://code.launchpad.net/~stgraber/upstart/upstart-shell-paths/+merge/140175
  proposed by: Stéphane Graber (stgraber)
  review: Approve - James Hunt (jamesodhunt)
  
https://code.launchpad.net/~vorlon/upstart/default-priority-not-always-zero/+merge/140025
  proposed by: Steve Langasek (vorlon)
  review: Approve - James Hunt (jamesodhunt)
  https://code.launchpad.net/~stgraber/upstart/upstart-dbus-events/+merge/139726
  proposed by: Stéphane Graber (stgraber)
  review: Needs Fixing - James Hunt (jamesodhunt)
  https://code.launchpad.net/~xnox/upstart/fix-extra-dist/+merge/139472
  proposed by: Dmitrijs Ledkovs (xnox)
  https://code.launchpad.net/~stgraber/upstart/upstart-prctl/+merge/136759
  proposed by: Stéphane Graber (stgraber)
  review: Approve - James Hunt (jamesodhunt)
------------------------------------------------------------
revno: 1407 [merge]
committer: James Hunt <[email protected]>
branch nick: upstart-setenv+getenv
timestamp: Wed 2012-12-19 09:08:57 +0000
message:
  * Resync with lp:upstart.
added:
  init/tests/test_xdg.c
  init/xdg.c
  init/xdg.h
modified:
  ChangeLog
  configure.ac
  dbus/com.ubuntu.Upstart.xml
  init/Makefile.am
  init/control.c
  init/control.h
  init/event.c
  init/job_class.c
  init/job_class.h
  init/job_process.c
  init/log.c
  init/main.c
  init/man/init.5
  init/man/init.8
  init/paths.h
  init/tests/test_event.c
  init/tests/test_job_class.c
  init/tests/test_job_process.c
  init/tests/test_log.c
  init/tests/test_state.c
  util/Makefile.am


--
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	2012-12-11 16:45:55 +0000
+++ ChangeLog	2012-12-19 09:08:57 +0000
@@ -1,3 +1,17 @@
+2012-12-17  James Hunt  <[email protected]>
+
+	* init/man/init.5: Document that User Jobs are not supported
+	  within a chroot environment.
+
+2012-12-14  Steve Langasek  <[email protected]>
+	* init/job_class.[ch]: instead of assuming a fixed value (0) as the
+	  default nice value for job processes, use whatever the nice value
+	  of the current process is.  This will be important later for user
+	  sessions where an entire session may be started with a higher nice
+	  value; and it fixes running the test suite as part of a nice'd
+	  build.
+	* init/tests/test_job_class.c: update test suite to match.
+
 2012-12-11  James Hunt  <[email protected]>
 
 	* init/Makefile.am: Add explicit -lrt for tests (LP: #1088863)

=== modified file 'configure.ac'
--- configure.ac	2012-12-07 20:33:03 +0000
+++ configure.ac	2012-12-07 21:39:17 +0000
@@ -53,7 +53,7 @@
 AM_CONDITIONAL([HAVE_UDEV], [test "$have_udev" = yes])
 
 # Checks for header files.
-AC_CHECK_HEADERS([valgrind/valgrind.h])
+AC_CHECK_HEADERS([valgrind/valgrind.h, sys/prctl.h])
 
 # Checks for typedefs, structures, and compiler characteristics.
 AC_PROG_CC_C99

=== modified file 'dbus/com.ubuntu.Upstart.xml'
--- dbus/com.ubuntu.Upstart.xml	2012-12-11 16:45:55 +0000
+++ dbus/com.ubuntu.Upstart.xml	2012-12-19 09:08:57 +0000
@@ -60,6 +60,15 @@
       <arg name="job" type="o" />
     </signal>
 
+    <!-- Signal for events being emitted -->
+    <signal name="EventEmitted">
+      <arg name="name" type="s" />
+      <arg name="env" type="as" />
+    </signal>
+
+    <!-- Signal emitted after upstart restarted and reconnected to DBUS -->
+    <signal name="Restarted" />
+
     <!-- Event emission -->
     <method name="EmitEvent">
       <annotation name="com.netsplit.Nih.Method.Async" value="true" />

=== modified file 'init/Makefile.am'
--- init/Makefile.am	2012-12-11 13:59:01 +0000
+++ init/Makefile.am	2012-12-14 15:54:35 +0000
@@ -56,6 +56,7 @@
 	parse_conf.c parse_conf.h \
 	conf.c conf.h \
 	control.c control.h \
+	xdg.c xdg.h \
 	errors.h
 nodist_init_SOURCES = \
 	$(com_ubuntu_Upstart_OUTPUTS) \
@@ -134,7 +135,6 @@
 	$(TEST_DATA_DIR)/upstart-1.6.json
 
 EXTRA_DIST = init.supp $(TEST_DATA_FILES)
-	
 
 test_util_SOURCES = \
 	tests/test_util.c tests/test_util.h
@@ -154,6 +154,7 @@
 	test_parse_job \
 	test_parse_conf \
 	test_conf \
+	test_xdg \
 	test_control
 
 check_PROGRAMS = $(TESTS)
@@ -338,6 +339,13 @@
 	$(JSON_LIBS) \
 	-lrt
 
+test_xdg_SOURCES = tests/test_xdg.c
+test_xdg_LDADD = \
+	xdg.o \
+	environ.o \
+	$(NIH_LIBS) \
+	-lrt
+
 test_control_SOURCES = tests/test_control.c
 test_control_LDADD = \
 	system.o environ.o process.o \

=== modified file 'init/control.c'
--- init/control.c	2012-12-11 16:45:55 +0000
+++ init/control.c	2012-12-19 09:08:57 +0000
@@ -55,6 +55,7 @@
 #include "control.h"
 #include "errors.h"
 #include "state.h"
+#include "event.h"
 
 #include "com.ubuntu.Upstart.h"
 
@@ -1069,6 +1070,45 @@
 }
 
 /**
+ * control_notify_event_emitted
+ *
+ * Re-emits an event over DBUS using the EventEmitted signal
+ **/
+void
+control_notify_event_emitted (Event *event)
+{
+	nih_assert (event != NULL);
+
+	control_init ();
+
+	NIH_LIST_FOREACH (control_conns, iter) {
+		NihListEntry   *entry = (NihListEntry *)iter;
+		DBusConnection *conn = (DBusConnection *)entry->data;
+
+		NIH_ZERO (control_emit_event_emitted (conn, DBUS_PATH_UPSTART,
+							    event->name, event->env));
+	}
+}
+
+/**
+ * control_notify_restarted
+ *
+ * DBUS signal sent when upstart has re-executed itself.
+ **/
+void
+control_notify_restarted (void)
+{
+	control_init ();
+
+	NIH_LIST_FOREACH (control_conns, iter) {
+		NihListEntry   *entry = (NihListEntry *)iter;
+		DBusConnection *conn = (DBusConnection *)entry->data;
+
+		NIH_ZERO (control_emit_restarted (conn, DBUS_PATH_UPSTART));
+	}
+}
+
+/**
  * control_set_env:
  *
  * @data: not used,

=== modified file 'init/control.h'
--- init/control.h	2012-12-07 18:26:43 +0000
+++ init/control.h	2012-12-14 23:43:15 +0000
@@ -30,6 +30,8 @@
 
 #include <json.h>
 
+#include "event.h"
+
 /**
  * USE_SESSION_BUS_ENV:
  *
@@ -113,6 +115,9 @@
 int  control_restart (void *data, NihDBusMessage *message)
 	__attribute__ ((warn_unused_result));
 
+void control_notify_event_emitted (Event *event);
+void control_notify_restarted (void);
+
 NIH_END_EXTERN
 
 #endif /* INIT_CONTROL_H */

=== modified file 'init/event.c'
--- init/event.c	2012-10-10 13:24:51 +0000
+++ init/event.c	2012-12-14 23:47:51 +0000
@@ -42,6 +42,7 @@
 #include "event.h"
 #include "job.h"
 #include "blocked.h"
+#include "control.h"
 #include "errors.h"
 
 #include "com.ubuntu.Upstart.h"
@@ -507,6 +508,8 @@
 		}
 	}
 
+	control_notify_event_emitted (event);
+
 	nih_free (event);
 }
 

=== modified file 'init/job_class.c'
--- init/job_class.c	2012-12-11 16:45:55 +0000
+++ init/job_class.c	2012-12-19 09:08:57 +0000
@@ -27,6 +27,8 @@
 #include <errno.h>
 #include <string.h>
 #include <signal.h>
+#include <sys/time.h>
+#include <sys/resource.h>
 
 #include <nih/macros.h>
 #include <nih/alloc.h>
@@ -243,7 +245,7 @@
 	class->console = default_console >= 0 ? default_console : CONSOLE_LOG;
 
 	class->umask = JOB_DEFAULT_UMASK;
-	class->nice = JOB_DEFAULT_NICE;
+	class->nice = JOB_NICE_INVALID;
 	class->oom_score_adj = JOB_DEFAULT_OOM_SCORE_ADJ;
 
 	for (i = 0; i < RLIMIT_NLIMITS; i++)

=== modified file 'init/job_class.h'
--- init/job_class.h	2012-12-11 16:45:55 +0000
+++ init/job_class.h	2012-12-19 09:08:57 +0000
@@ -102,11 +102,11 @@
 #define JOB_DEFAULT_UMASK 022
 
 /**
- * JOB_DEFAULT_NICE:
+ * JOB_NICE_INVALID:
  *
- * The default nice level for processes.
+ * The nice level for processes when no nice level is set.
  **/
-#define JOB_DEFAULT_NICE 0
+#define JOB_NICE_INVALID -21
 
 /**
  * JOB_DEFAULT_OOM_SCORE_ADJ:

=== modified file 'init/job_process.c'
--- init/job_process.c	2012-12-03 20:27:09 +0000
+++ init/job_process.c	2012-12-18 09:02:24 +0000
@@ -239,6 +239,12 @@
 			NIH_MUST (nih_str_array_addp (&argv, NULL,
 						      &argc, cmd));
 		}
+
+		/* At the end, always set proc->script to TRUE, even if the user didn't
+		 * explicitly set it (when using shell variables). That way tests
+		 * can reliably check for shell-specific behaviour.
+		 */
+		proc->script = TRUE;
 	} else {
 		/* Split the command on whitespace to produce a list of
 		 * arguments that we can exec directly.
@@ -780,7 +786,8 @@
 
 	/* Adjust the process priority ("nice level").
 	 */
-	if (setpriority (PRIO_PROCESS, 0, class->nice) < 0) {
+	if (class->nice != JOB_NICE_INVALID &&
+	    setpriority (PRIO_PROCESS, 0, class->nice) < 0) {
 		nih_error_raise_system ();
 		job_process_error_abort (fds[1],
 					 JOB_PROCESS_ERROR_PRIORITY, 0);

=== modified file 'init/log.c'
--- init/log.c	2012-11-23 11:36:47 +0000
+++ init/log.c	2012-12-07 21:38:17 +0000
@@ -31,7 +31,6 @@
 #include "session.h"
 #include "conf.h"
 #include "paths.h"
-#include <sys/prctl.h>
 
 static int  log_file_open   (Log *log);
 static int  log_file_write  (Log *log, const char *buf, size_t len);

=== modified file 'init/main.c'
--- init/main.c	2012-12-11 16:45:55 +0000
+++ init/main.c	2012-12-19 09:08:57 +0000
@@ -30,6 +30,13 @@
 #include <sys/resource.h>
 #include <sys/mount.h>
 
+#ifdef HAVE_SYS_PRCTL_H
+#include <sys/prctl.h>
+#ifndef PR_SET_CHILD_SUBREAPER
+#define PR_SET_CHILD_SUBREAPER 35
+#endif
+#endif
+
 #include <errno.h>
 #include <stdio.h>
 #include <limits.h>
@@ -61,6 +68,7 @@
 #include "conf.h"
 #include "control.h"
 #include "state.h"
+#include "xdg.h"
 
 
 /* Prototypes for static functions */
@@ -79,6 +87,7 @@
 
 static void handle_confdir      (void);
 static void handle_logdir       (void);
+static void handle_usermode     (void);
 static int  console_type_setter (NihOption *option, const char *arg);
 
 
@@ -112,6 +121,13 @@
  **/
 static int disable_startup_event = FALSE;
 
+/**
+ * user_mode:
+ *
+ * If TRUE, upstart runs in user session mode.
+ **/
+static int user_mode = FALSE;
+
 extern int          disable_sessions;
 extern int          disable_job_logging;
 extern int          use_session_bus;
@@ -157,6 +173,9 @@
 	{ 0, "startup-event", N_("specify an alternative initial event (for testing)"),
 		NULL, "NAME", &initial_event, NULL },
 
+	{ 0, "user", N_("start in user mode (as used for user sessions)"),
+		NULL, NULL, &user_mode, NULL },
+
 	/* Ignore invalid options */
 	{ '-', "--", NULL, NULL, NULL, NULL, NULL },
 
@@ -169,6 +188,7 @@
       char *argv[])
 {
 	char **args = NULL;
+	char **dirs = NULL;
 	int    ret;
 
 	args_copy = NIH_MUST (nih_str_array_copy (NULL, NULL, argv));
@@ -187,6 +207,7 @@
 
 	handle_confdir ();
 	handle_logdir ();
+	handle_usermode ();
 
 	if (disable_job_logging)
 		nih_debug ("Job logging disabled");
@@ -512,8 +533,18 @@
 	}
 
 	/* Read configuration */
-	NIH_MUST (conf_source_new (NULL, CONFFILE, CONF_FILE));
-	NIH_MUST (conf_source_new (NULL, conf_dir, CONF_JOB_DIR));
+	if (! user_mode)
+		NIH_MUST (conf_source_new (NULL, CONFFILE, CONF_FILE));
+
+	if (conf_dir)
+		NIH_MUST (conf_source_new (NULL, conf_dir, CONF_JOB_DIR));
+
+	if (user_mode) {
+		dirs = NIH_MUST (get_user_upstart_dirs ());
+		for (char **d = dirs; d && *d; d++)
+			NIH_MUST (conf_source_new (NULL, *d, CONF_JOB_DIR));
+		nih_free (dirs);
+	}
 
 	conf_reload ();
 
@@ -598,12 +629,29 @@
 		 * disabled by the term_handler */
 		sigemptyset (&mask);
 		sigprocmask (SIG_SETMASK, &mask, NULL);
+
+		/* Emit the Restarted signal so that any listing Instance Init
+		 * knows that it needs to restart too.
+		 */
+		control_notify_restarted();
 	}
 
 	if (disable_sessions)
 		nih_debug ("Sessions disabled");
 
 	job_class_environment_init ();
+	/* Set us as the child subreaper.
+	 * This ensures that even when init doesn't run as PID 1, it'll always be
+	 * the ultimate parent of everything it spawns. */
+
+#ifdef HAVE_SYS_PRCTL_H
+	if (getpid () > 1 && prctl (PR_SET_CHILD_SUBREAPER, 1) < 0) {
+		nih_warn ("%s: %s", _("Unable to register as subreaper"),
+				  strerror (errno));
+
+		NIH_MUST (event_new (NULL, "child-subreaper-failed", NULL));
+	}
+#endif
 
 	/* Run through the loop at least once to deal with signals that were
 	 * delivered to the previous process while the mask was set or to
@@ -880,6 +928,9 @@
 	if (conf_dir)
 		goto out;
 
+	if (user_mode)
+		return;
+
 	conf_dir = CONFDIR;
 
 	dir = getenv (CONFDIR_ENV);
@@ -920,6 +971,18 @@
 			log_dir);
 }
 
+/**
+ * handle_usermode:
+ *
+ * Setup user session mode.
+ **/
+static void
+handle_usermode (void)
+{
+	if (user_mode)
+		use_session_bus = TRUE;
+}
+
 /**  
  * NihOption setter function to handle selection of default console
  * type.

=== modified file 'init/man/init.5'
--- init/man/init.5	2012-11-19 09:48:17 +0000
+++ init/man/init.5	2012-12-18 17:40:49 +0000
@@ -1,4 +1,4 @@
-.TH init 5 2011-05-12 "Upstart"
+.TH init 5 2012-12-18 "Upstart"
 .\"
 .SH NAME
 init \- Upstart init daemon job configuration
@@ -12,6 +12,10 @@
 .B $HOME/.init/
 Default location of user job configuration files.
 .\"
+.TP
+.B $XDG_CONFIG_HOME/upstart/, $XDG_CONFIG_DIRS/upstart/
+Default locations of user session job configuration files.
+.\"
 .SH DESCRIPTION
 On startup, the Upstart
 .BR init (8)
@@ -25,6 +29,11 @@
 .B User Jobs
 for further details.
 
+If Upstart was invoked as a user process with \-\-user option, it will
+run in User Session mode. See
+.B User Session Mode
+for further details.
+
 To be considered by Upstart, files in this directory must have a
 recognized suffix and may also be present in sub\-directories.  There are
 two recognized suffixes:
@@ -115,7 +124,47 @@
 .B Process environment
 below).
 
-Note too that User Jobs can be created within a chroot environment.
+Note that User Jobs
+.B cannot
+be used within a chroot environment.
+
+.\"
+.SS User Session Mode
+
+Upstart can manage complete User Sessions. In this mode it runs with a
+process id greater than 1 and will read job configuration files from the
+following list of directories in the order shown:
+
+.IP \(bu 4
+.I $XDG_CONFIG_HOME/upstart/
+.IP \(bu 4
+.I $HOME/.init/
+.IP \(bu 4
+.I $XDG_CONFIG_DIRS/upstart/
+.IP \(bu 4
+.I /usr/share/upstart/sessions/
+.P
+
+Note that the first directory to contain a job is considered the owner
+of that job name: any subsequently searched directory that contains a
+job of the same name will be ignored. The same applies for override
+files: only the first override file found in the search order will be
+applied. Note that an override file does not have to be in the same
+directory as the job it overrides, but if not in the directory of the
+job it overrides, it must be in an
+.I earlier
+directory to that which contains the job.
+
+Jobs in these locations are expected to launch the user's session.
+Upstart will try to parent all spawned process with the aid of
+.BR prctl (2) "" .
+If successful this will ensure that even double-forking daemons will be
+reparented to the User Session process, and not to the
+.BR init (8)
+daemon running with process id 1.
+
+When running in User Session mode, Upstart will kill all job processes
+on session logout or shutdown.
 
 .\"
 .SS Configuration File Format
@@ -1000,5 +1049,6 @@
 .SH SEE ALSO
 .BR init (8)
 .BR initctl (8)
+.BR prctl (2)
+.BR pty (7)
 .BR sh (1)
-.BR pty (7)

=== modified file 'init/man/init.8'
--- init/man/init.8	2011-12-09 14:07:11 +0000
+++ init/man/init.8	2012-12-18 17:40:49 +0000
@@ -1,4 +1,4 @@
-.TH init 8 2011-04-06 "Upstart"
+.TH init 8 2012-12-18 "Upstart"
 .\"
 .SH NAME
 init \- Upstart process management daemon
@@ -113,24 +113,66 @@
 .BR startup (7) .
 .\"
 .TP
-.B \-\-verbose
+.B \-\-user
+Starts in user mode, as used for user sessions. Upstart will be run as
+an unprivileged user, reading configuration files from configuration
+locations as per roughly XDG Base Directory Specification. See 
+.BR init (5)
+for further details.
+.\"
+.TP
+.B \-q, \-\-quiet
+Reduces output messages to errors only.
+.\"
+.TP
+.B \-v, \-\-verbose
 Outputs verbose messages about job state changes and event emissions to the
 system console or log, useful for debugging boot.
 .\"
+.TP
+.B \-\-version
+Outputs version information and exits.
+.\"
 .SH NOTES
 .B init
 is not normally executed by a user process, and expects to have a process
 id of 1.  If this is not the case, it will actually execute
 .BR telinit (8)
-and pass all arguments to that.  See that manual page for further details.
+and pass all arguments to that.  See that manual page for further
+details. However, if the
+.B \-\-user
+option is specified, it will read alternative configuration files and
+manage the individual user session in a similar fashion.
+.\"
+.SH ENVIRONMENT VARIABLES
+
+When run as a user process, the following variables may be used to find
+job configuration files:
+
+.IP \(bu 4
+.I $XDG_CONFIG_HOME
+.IP \(bu 4
+.I $XDG_CONFIG_DIRS
+.P
+
+See
+.B User Session Mode
+in
+.BR init (5)
+for further details.
+
 .\"
 .SH FILES
 .\"
 .I /etc/init.conf
 
-.I /etc/init/*.conf
+.I /etc/init/
 
 .I $HOME/.init/
+
+.I $XDG_CONFIG_DIRS/upstart/
+
+.I $XDG_CONFIG_HOME/upstart/
 .\"
 .SH AUTHOR
 Written by Scott James Remnant
@@ -141,7 +183,7 @@
 .RB < https://launchpad.net/upstart/+bugs >
 .\"
 .SH COPYRIGHT
-Copyright \(co 2009\-2011 Canonical Ltd.
+Copyright \(co 2009\-2012 Canonical Ltd.
 .br
 This is free software; see the source for copying conditions.  There is NO
 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

=== modified file 'init/paths.h'
--- init/paths.h	2012-09-10 07:50:32 +0000
+++ init/paths.h	2012-12-17 15:46:35 +0000
@@ -96,6 +96,24 @@
 #define CONFDIR_ENV "UPSTART_CONFDIR"
 #endif
 
+/**
+ * INIT_XDG_SUBDIR:
+ *
+ * This is the name of the sub folder we will use when constructing
+ * config source dirs with XDG compliant folders.
+ **/
+#ifndef INIT_XDG_SUBDIR
+#define INIT_XDG_SUBDIR "upstart"
+#endif
+
+/**
+ * SYSTEM_USERCONFDIR:
+ *
+ * This is the path to system-wide user session jobs.
+ **/
+#ifndef SYSTEM_USERCONFDIR
+#define SYSTEM_USERCONFDIR "/usr/share/upstart/sessions"
+#endif
 
 /**
  * SHELL:

=== modified file 'init/tests/test_event.c'
--- init/tests/test_event.c	2011-12-09 14:07:11 +0000
+++ init/tests/test_event.c	2012-11-27 23:49:12 +0000
@@ -20,6 +20,7 @@
  */
 
 #include <nih/test.h>
+#include <nih-dbus/test_dbus.h>
 
 #include <sys/types.h>
 #include <sys/wait.h>
@@ -32,6 +33,8 @@
 #include <nih/main.h>
 #include <nih/error.h>
 
+#include "dbus/upstart.h"
+
 #include "control.h"
 #include "job.h"
 #include "event.h"
@@ -135,11 +138,39 @@
 test_poll (void)
 {
 	Event *event = NULL;
+	pid_t           dbus_pid;
+	DBusError       dbus_error;
+	DBusConnection *conn, *client_conn;
+	DBusMessage    *message;
+	NihListEntry   *entry;
 
 	TEST_FUNCTION ("event_poll");
+	nih_error_init ();
+	nih_timer_init ();
+	nih_main_loop_init ();
+	control_init ();
 	job_class_init ();
+
+	/* Check that when a D-Bus connection is open, the new instance
+	 * is registered on that connection as an object and the InstanceAdded
+	 * signal is emitted.
+	 */
+	TEST_FEATURE ("with D-Bus connection");
+	dbus_error_init (&dbus_error);
+
+	TEST_DBUS (dbus_pid);
+	TEST_DBUS_OPEN (conn);
+	TEST_DBUS_OPEN (client_conn);
+
+	dbus_bus_add_match (client_conn, "type='signal'", &dbus_error);
+	assert (! dbus_error_is_set (&dbus_error));
+
 	control_init ();
 
+	entry = nih_list_entry_new (NULL);
+	entry->data = conn;
+	nih_list_add (control_conns, &entry->entry);
+
 
 	/* Check that a pending event which does not get blocked goes
 	 * straight though and gets freed.
@@ -154,6 +185,12 @@
 
 		event_poll ();
 
+		TEST_DBUS_MESSAGE (client_conn, message);
+		TEST_TRUE (dbus_message_is_signal (message, DBUS_INTERFACE_UPSTART,
+						   "EventEmitted"));
+
+		dbus_message_unref (message);
+
 		TEST_FREE (event);
 	}
 
@@ -213,6 +250,14 @@
 
 		TEST_FREE (event);
 	}
+
+	nih_free (entry);
+
+	TEST_DBUS_CLOSE (conn);
+	TEST_DBUS_CLOSE (client_conn);
+	TEST_DBUS_END (dbus_pid);
+
+	dbus_shutdown ();
 }
 
 

=== modified file 'init/tests/test_job_class.c'
--- init/tests/test_job_class.c	2011-12-09 15:27:57 +0000
+++ init/tests/test_job_class.c	2012-12-14 20:48:51 +0000
@@ -27,6 +27,8 @@
 #include <sys/wait.h>
 #include <sys/ptrace.h>
 #include <sys/select.h>
+#include <sys/time.h>
+#include <sys/resource.h>
 
 #include <time.h>
 #include <stdio.h>
@@ -131,7 +133,7 @@
 		TEST_EQ (class->console, CONSOLE_LOG);
 
 		TEST_EQ (class->umask, 022);
-		TEST_EQ (class->nice, 0);
+		TEST_EQ (class->nice, JOB_NICE_INVALID);
 		TEST_EQ (class->oom_score_adj, 0);
 
 		for (i = 0; i < RLIMIT_NLIMITS; i++)

=== modified file 'init/tests/test_job_process.c'
--- init/tests/test_job_process.c	2012-12-07 21:52:38 +0000
+++ init/tests/test_job_process.c	2012-12-18 11:02:00 +0000
@@ -680,6 +680,8 @@
 		output = fopen (filename, "r");
 		TEST_FILE_EQ (output, "BAR=BAZ\n");
 		TEST_FILE_EQ (output, "FOO=BAR\n");
+		if (job->class->process[PROCESS_MAIN]->script)
+			TEST_FILE_EQ (output, "PWD=/\n");
 		TEST_FILE_EQ (output, "UPSTART_INSTANCE=\n");
 		TEST_FILE_EQ (output, "UPSTART_JOB=test\n");
 		TEST_FILE_EQ (output, "UPSTART_NO_SESSIONS=1\n");
@@ -734,6 +736,8 @@
 		output = fopen (filename, "r");
 		TEST_FILE_EQ (output, "BAR=BAZ\n");
 		TEST_FILE_EQ (output, "FOO=BAR\n");
+		if (job->class->process[PROCESS_MAIN]->script)
+			TEST_FILE_EQ (output, "PWD=/\n");
 		TEST_FILE_EQ (output, "UPSTART_INSTANCE=foo\n");
 		TEST_FILE_EQ (output, "UPSTART_JOB=test\n");
 		TEST_FILE_EQ (output, "UPSTART_NO_SESSIONS=1\n");
@@ -790,6 +794,8 @@
 		TEST_FILE_EQ (output, "BAR=BAZ\n");
 		TEST_FILE_EQ (output, "CRACKLE=FIZZ\n");
 		TEST_FILE_EQ (output, "FOO=SMACK\n");
+		if (job->class->process[PROCESS_PRE_STOP]->script)
+			TEST_FILE_EQ (output, "PWD=/\n");
 		TEST_FILE_EQ (output, "UPSTART_INSTANCE=\n");
 		TEST_FILE_EQ (output, "UPSTART_JOB=test\n");
 		TEST_FILE_EQ (output, "UPSTART_NO_SESSIONS=1\n");
@@ -846,6 +852,8 @@
 		TEST_FILE_EQ (output, "BAR=BAZ\n");
 		TEST_FILE_EQ (output, "CRACKLE=FIZZ\n");
 		TEST_FILE_EQ (output, "FOO=SMACK\n");
+		if (job->class->process[PROCESS_POST_STOP]->script)
+			TEST_FILE_EQ (output, "PWD=/\n");
 		TEST_FILE_EQ (output, "UPSTART_INSTANCE=\n");
 		TEST_FILE_EQ (output, "UPSTART_JOB=test\n");
 		TEST_FILE_EQ (output, "UPSTART_NO_SESSIONS=1\n");
@@ -9190,6 +9198,8 @@
 			io_error_handler, NULL);
 	TEST_NE_P (io, NULL);
 
+	ret = nih_main_loop ();
+
 	/* wait for child to finish */
 	TEST_EQ (waitpid (pid, &status, 0), pid);
 
@@ -9199,7 +9209,6 @@
 		      WIFSTOPPED (status) ?  WSTOPSIG (status) :
 		      EXIT_FAILURE;
 
-	ret = nih_main_loop ();
 	exit (exit_status ? exit_status : ret);
 }
 

=== modified file 'init/tests/test_log.c'
--- init/tests/test_log.c	2012-09-20 08:12:05 +0000
+++ init/tests/test_log.c	2012-12-07 21:38:17 +0000
@@ -26,7 +26,6 @@
 #include <libgen.h>
 #include <sys/types.h>
 #include <sys/ioctl.h>
-#include <sys/prctl.h>
 #include <nih/test.h>
 #include <nih/timer.h>
 #include <nih/child.h>

=== modified file 'init/tests/test_state.c'
--- init/tests/test_state.c	2012-12-04 16:09:18 +0000
+++ init/tests/test_state.c	2012-12-07 21:38:17 +0000
@@ -28,7 +28,6 @@
 #include <libgen.h>
 #include <sys/types.h>
 #include <sys/ioctl.h>
-#include <sys/prctl.h>
 #include <nih/test.h>
 #include <nih/timer.h>
 #include <nih/child.h>

=== added file 'init/tests/test_xdg.c'
--- init/tests/test_xdg.c	1970-01-01 00:00:00 +0000
+++ init/tests/test_xdg.c	2012-12-18 14:16:10 +0000
@@ -0,0 +1,306 @@
+/* upstart
+ *
+ * test_xdg.c - test suite for init/xdg.c
+ *
+ * Copyright © 2012 Canonical Ltd.
+ * Author: Dmitrijs Ledkovs <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <nih/string.h>
+#include <nih/test.h>
+
+#include <stdlib.h>
+#include <limits.h>
+
+#include "xdg.h"
+
+void
+test_get_home_subdir (void)
+{
+	char    dirname[PATH_MAX];
+	char       *dir;
+	char * expected=NULL;
+
+	TEST_FUNCTION ("get_home_subdir");
+
+	TEST_FEATURE ("with HOME not set");
+	TEST_EQ (unsetenv ("HOME"), 0);
+
+	TEST_ALLOC_FAIL {
+		dir = get_home_subdir ("test");
+		TEST_EQ_P (dir, NULL);
+	}
+
+	TEST_FEATURE ("with HOME set");
+	TEST_FILENAME (dirname);
+	TEST_EQ (setenv ("HOME", dirname, 1), 0);
+
+	TEST_ALLOC_FAIL {
+		TEST_ALLOC_SAFE {
+			dir = NULL;
+			expected = NIH_MUST (nih_sprintf (NULL, "%s/test", dirname));
+		}
+
+		dir = get_home_subdir ("test");
+
+		if (test_alloc_failed) {
+			TEST_EQ_P (dir, NULL);
+		} else {
+			TEST_EQ_STR (dir, expected);
+			nih_free (dir);
+		}
+
+		if (expected)
+			nih_free (expected);
+	}
+}
+
+void
+test_get_config_home (void)
+{
+	char   dirname[PATH_MAX];
+	char * outname;
+	char * expected;
+
+	TEST_FUNCTION ("xdg_get_config_home");
+
+	TEST_FEATURE ("with HOME set and without environment override");
+	TEST_FILENAME (dirname);
+	TEST_EQ (setenv ("HOME", dirname, 1), 0);
+	TEST_EQ (unsetenv ("XDG_CONFIG_HOME"), 0);
+	TEST_ALLOC_FAIL {
+		TEST_ALLOC_SAFE {
+			expected = NIH_MUST (nih_sprintf (NULL, "%s/.config", dirname));
+		}
+
+		outname = NULL;
+		outname = xdg_get_config_home ();
+
+		if (! test_alloc_failed) {
+			TEST_EQ_STR (outname, expected);
+		} else {
+			TEST_EQ_P (outname, NULL);
+		}
+
+		if (outname)
+			nih_free (outname);
+
+		nih_free(expected);
+	}
+
+	TEST_FEATURE ("with HOME set and with empty environment override");
+	TEST_EQ (setenv ("XDG_CONFIG_HOME", "", 1), 0);
+
+
+	TEST_ALLOC_FAIL {
+		TEST_ALLOC_SAFE {
+			expected = NIH_MUST (nih_sprintf (NULL, "%s/.config", dirname));
+		}
+		outname = NULL;
+		outname = xdg_get_config_home();
+
+		if (test_alloc_failed) {
+			TEST_EQ_P (outname, NULL);
+		} else {
+			TEST_EQ_STR (outname, expected);
+		}
+		if (outname)
+			nih_free (outname);
+		nih_free(expected);
+	}
+
+	TEST_FEATURE ("with HOME set and with environment override");
+	expected = NIH_MUST (nih_strdup (NULL, "/home/me/.config-test"));
+	TEST_EQ (setenv ("XDG_CONFIG_HOME", expected, 1), 0);
+
+	TEST_ALLOC_FAIL {
+		outname = NULL;
+		outname = xdg_get_config_home();
+
+		if (test_alloc_failed) {
+			TEST_EQ_P (outname, NULL);
+		} else {
+			TEST_EQ_STR (outname, expected);
+		}
+		if (outname)
+			nih_free (outname);
+	}
+
+	TEST_FEATURE ("without HOME set and with environment override");
+	TEST_EQ (unsetenv ("HOME"), 0);
+
+	TEST_ALLOC_FAIL {
+		outname = NULL;
+		outname = xdg_get_config_home();
+
+		if (test_alloc_failed) {
+			TEST_EQ_P (outname, NULL);
+		} else {
+			TEST_EQ_STR (outname, expected);
+		}
+		if (outname)
+			nih_free (outname);
+	}
+	nih_free(expected);
+
+	TEST_FEATURE ("without HOME set and with empty environment override");
+	TEST_EQ (setenv ("XDG_CONFIG_HOME", "", 1), 0);
+
+	TEST_ALLOC_FAIL {
+		outname = NULL;
+		outname = xdg_get_config_home();
+		TEST_EQ_P (outname, NULL);
+	}
+
+	TEST_FEATURE ("without HOME set and without environment override");
+	TEST_EQ (unsetenv ("XDG_CONFIG_HOME"), 0);
+	TEST_ALLOC_FAIL {
+		outname = NULL;
+		outname = xdg_get_config_home();
+		TEST_EQ_P (outname, NULL);
+	}
+}
+
+void
+test_get_config_dirs (void)
+{
+	char   **dirs = NULL;
+
+	TEST_FUNCTION ("xdg_get_config_dirs");
+	TEST_FEATURE ("without environment override set");
+	TEST_EQ (unsetenv ("XDG_CONFIG_DIRS"), 0);
+
+	TEST_ALLOC_FAIL {
+		dirs = NULL;
+		dirs = xdg_get_config_dirs();
+
+		if (test_alloc_failed) {
+			TEST_EQ_P (dirs, NULL);
+		} else {
+			TEST_EQ_STR (dirs[0], "/etc/xdg");
+			TEST_EQ (dirs[1], NULL);
+			nih_free (dirs);
+		}
+	}
+
+	TEST_FEATURE ("with empty environment override");
+	TEST_EQ (setenv ("XDG_CONFIG_DIRS", "", 1), 0);
+	TEST_ALLOC_FAIL {
+		dirs = NULL;
+		dirs = xdg_get_config_dirs();
+
+		if (test_alloc_failed) {
+			TEST_EQ_P (dirs, NULL);
+		} else {
+			TEST_EQ_STR (dirs[0], "/etc/xdg");
+			TEST_EQ (dirs[1], NULL);
+			nih_free (dirs);
+		}
+	}
+
+	TEST_FEATURE ("with environment override set to single path");
+	TEST_EQ (setenv ("XDG_CONFIG_DIRS", "/etc/xdg/xdg-test", 1), 0);
+	TEST_ALLOC_FAIL {
+		dirs = NULL;
+		dirs = xdg_get_config_dirs();
+
+		if (test_alloc_failed) {
+			TEST_EQ_P (dirs, NULL);
+		} else {
+			TEST_EQ_STR (dirs[0], "/etc/xdg/xdg-test");
+			TEST_EQ (dirs[1], NULL);
+			nih_free (dirs);
+		}
+	}
+
+	TEST_FEATURE ("with environment override set to multiple paths");
+	TEST_FEATURE ("with environment override set to single path");
+	TEST_EQ (setenv ("XDG_CONFIG_DIRS", "/etc/xdg/xdg-test:/etc/xdg/xdg-other", 1), 0);
+	TEST_ALLOC_FAIL {
+		dirs = NULL;
+		dirs = xdg_get_config_dirs();
+
+		if (test_alloc_failed) {
+			TEST_EQ_P (dirs, NULL);
+		} else {
+			TEST_EQ_STR (dirs[0], "/etc/xdg/xdg-test");
+			TEST_EQ_STR (dirs[1], "/etc/xdg/xdg-other");
+			TEST_EQ (dirs[2], NULL);
+			nih_free (dirs);
+		}
+	}
+}
+
+void
+test_get_user_upstart_dirs (void)
+{
+	char   dirname[PATH_MAX];
+	char      ** dirs = NULL;
+	char       * path = NULL;
+	char  ** expected = NULL;
+
+	/* Currently only one test for "typical" output.
+         * Not sure what else to test here.
+         */
+	TEST_FUNCTION ("get_user_upstart_dirs");
+
+	TEST_FEATURE ("with HOME set");
+	TEST_FILENAME (dirname);
+	TEST_EQ (setenv ("HOME", dirname, 1), 0);
+	TEST_EQ (unsetenv ("XDG_CONFIG_HOME"), 0);
+	TEST_EQ (unsetenv ("XDG_CONFIG_DIRS"), 0);
+
+	TEST_ALLOC_FAIL {
+		TEST_ALLOC_SAFE {
+			dirs = NULL;
+			expected = nih_str_array_new (NULL);
+			path = NIH_MUST (nih_sprintf (NULL, "%s/.config/upstart", dirname));
+			assert (nih_str_array_add (&expected, NULL, NULL, path));
+			nih_free(path);
+			path = NIH_MUST (nih_sprintf (NULL, "%s/.init", dirname));
+			assert (nih_str_array_add (&expected, NULL, NULL, path));
+			nih_free(path);
+		}
+
+		dirs = NULL;
+		dirs = get_user_upstart_dirs ();
+
+		if (test_alloc_failed) {
+			TEST_EQ_P (dirs, NULL);
+		} else {
+			TEST_EQ_STR (dirs[0], expected[0]);
+			TEST_EQ_STR (dirs[1], expected[1]);
+			TEST_EQ_STR (dirs[2], "/etc/xdg/upstart");
+			TEST_EQ_STR (dirs[3], SYSTEM_USERCONFDIR);
+			TEST_EQ (dirs[4], NULL);
+			nih_free (dirs);
+		}
+		nih_free(expected);
+	}
+
+}
+
+int
+main (int   argc,
+      char *argv[])
+{
+	test_get_home_subdir ();
+	test_get_config_home ();
+	test_get_config_dirs ();
+	test_get_user_upstart_dirs ();
+
+	return 0;
+}

=== added file 'init/xdg.c'
--- init/xdg.c	1970-01-01 00:00:00 +0000
+++ init/xdg.c	2012-12-18 16:31:55 +0000
@@ -0,0 +1,187 @@
+/* upstart
+ *
+ * xdg.c - XDG compliant path constructor
+ *
+ * Copyright © 2012 Canonical Ltd.
+ * Author: Dmitrijs Ledkovs <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+
+#include <nih/alloc.h>
+#include <nih/logging.h>
+#include <nih/string.h>
+
+#include "paths.h"
+#include "xdg.h"
+
+/**
+ * get_home_subdir:
+ *
+ * Construct path to directory in user's HOME dir.
+ * 
+ * Returns: newly-allocated path, or NULL on error.
+ */
+
+char *
+get_home_subdir (const char * suffix)
+{
+	char *dir;
+	nih_assert (suffix && suffix[0]);
+	
+	dir = getenv ("HOME");
+	if (dir && dir[0]) {
+		dir = nih_sprintf (NULL, "%s/%s", dir, suffix);
+		return dir;
+	}
+
+	return NULL;
+}
+
+/**
+ * xdg_get_config_home:
+ *
+ * Determine an XDG compliant XDG_CONFIG_HOME
+ *
+ * Returns: newly-allocated path, or NULL on error.
+ **/
+char *
+xdg_get_config_home (void)
+{
+	nih_local char  **env = NULL;
+	char             *dir;
+
+	dir = getenv ("XDG_CONFIG_HOME");
+	
+	if (dir && dir[0]) {
+		dir = nih_strdup (NULL, dir);
+		return dir;
+	}
+
+	dir = get_home_subdir (".config");
+
+	return dir;
+}
+
+/**
+ * xdg_get_config_dirs:
+ *
+ * Determine a list of XDG compliant XDG_CONFIG_DIRS
+ *
+ * Returns: newly-allocated array of paths, or NULL on error.
+ **/
+char **
+xdg_get_config_dirs (void)
+{
+	char         *env_path;
+	char        **dirs = NULL;
+
+	env_path = getenv ("XDG_CONFIG_DIRS");
+	if (! env_path || ! env_path[0])
+		env_path = "/etc/xdg";
+
+	dirs = nih_str_split (NULL, env_path, ":", TRUE);
+
+	return dirs;
+}
+
+/**
+ * get_user_upstart_dirs:
+ *
+ * Construct an array of user session config source paths to config
+ * dirs for a particular user. This array is sorted in highest
+ * priority order and therefore can be iterated to add each of these
+ * directories as config source dirs, when e.g. upstart is running as
+ * user session init.
+ *
+ * Returns: newly-allocated array of paths, or NULL or error.
+ **/
+char **
+get_user_upstart_dirs (void)
+{
+	char       *path = NULL;
+	char      **dirs = NULL;
+	char  **all_dirs = NULL;
+
+	all_dirs = nih_str_array_new (NULL);
+	if (! all_dirs)
+		goto error;
+
+	/* The current order is inline with Enhanced User Sessions Spec */
+
+	/* User's: ~/.config/upstart or XDG_CONFIG_HOME/upstart */
+	path = xdg_get_config_home ();
+	if (! path)
+		goto error;
+
+	if (path && path[0]) {
+	        if (! nih_strcat_sprintf (&path, NULL, "/%s", INIT_XDG_SUBDIR))
+			goto error;
+		if (! nih_str_array_add (&all_dirs, NULL, NULL, path))
+			goto error;
+		nih_free (path);
+		path = NULL;
+	}
+
+	/* Legacy User's: ~/.init */
+	path = get_home_subdir (USERCONFDIR);
+	if (! path)
+		goto error;
+
+	if (path && path[0]) {
+		if (! nih_str_array_add (&all_dirs, NULL, NULL, path))
+			goto error;
+		nih_free (path);
+		path = NULL;
+	}
+
+	/* Systems': XDG_CONFIG_DIRS/upstart */
+	dirs = xdg_get_config_dirs ();
+	if (! dirs)
+		goto error;
+
+	for (char **p = dirs; p && *p; p++) {
+		if (! nih_strcat_sprintf (p, NULL, "/%s", INIT_XDG_SUBDIR))
+			goto error;
+		if (! nih_str_array_add (&all_dirs, NULL, NULL, *p))
+			goto error;
+	}
+	nih_free (dirs);
+	dirs = NULL;
+
+	/* System's read-only location */
+	if (! nih_str_array_add (&all_dirs, NULL, NULL, SYSTEM_USERCONFDIR))
+		goto error;
+
+	return all_dirs;
+	
+error:
+	if (path)
+		nih_free (path);
+
+	if (dirs)
+		nih_free (dirs);
+
+	if (all_dirs)
+		nih_free (all_dirs);
+
+	return NULL;
+}
+

=== added file 'init/xdg.h'
--- init/xdg.h	1970-01-01 00:00:00 +0000
+++ init/xdg.h	2012-12-18 13:58:23 +0000
@@ -0,0 +1,42 @@
+/* upstart
+ *
+ * Copyright © 2012 Canonical Ltd.
+ * Author: Dmitrijs Ledkovs <[email protected]>.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef INIT_XDG_H
+#define INIT_XDG_H
+
+#include "paths.h"
+#include <nih/macros.h>
+
+NIH_BEGIN_EXTERN
+
+char *    get_home_subdir        (const char * suffix)
+	__attribute__ ((malloc, warn_unused_result));
+
+char *    xdg_get_config_home    (void)
+	__attribute__ ((malloc, warn_unused_result));
+
+char **   xdg_get_config_dirs    (void)
+	__attribute__ ((malloc, warn_unused_result));
+
+char **   get_user_upstart_dirs  (void)
+	__attribute__ ((malloc, warn_unused_result));
+
+NIH_END_EXTERN
+
+#endif /* INIT_XDG_H */

=== modified file 'util/Makefile.am'
--- util/Makefile.am	2012-12-08 00:00:28 +0000
+++ util/Makefile.am	2012-12-12 14:13:08 +0000
@@ -188,7 +188,7 @@
 	test_sysv \
 	test_telinit
 
-EXTRA_DIST = tests/test_user_sessions.sh
+EXTRA_DIST += tests/test_user_sessions.sh
 
 check_PROGRAMS = $(TESTS)
 

-- 
upstart-devel mailing list
[email protected]
Modify settings or unsubscribe at: 
https://lists.ubuntu.com/mailman/listinfo/upstart-devel

Reply via email to