Merge authors:
  Dmitrijs Ledkovs (xnox)
  Stéphane Graber (stgraber)
Related merge proposals:
  https://code.launchpad.net/~xnox/upstart/upstart-user-mode/+merge/140258
  proposed by: Dmitrijs Ledkovs (xnox)
  review: Approve - James Hunt (jamesodhunt)
------------------------------------------------------------
revno: 1414 [merge]
committer: James Hunt <[email protected]>
branch nick: upstart
timestamp: Tue 2012-12-18 16:24:31 +0000
message:
  * Merge of lp:~xnox/upstart/upstart-user-mode.
added:
  init/tests/test_xdg.c
  init/xdg.c
  init/xdg.h
modified:
  init/Makefile.am
  init/main.c
  init/man/init.5
  init/man/init.8
  init/paths.h


--
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 '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/main.c'
--- init/main.c	2012-12-17 13:47:32 +0000
+++ init/main.c	2012-12-18 14:09:55 +0000
@@ -68,6 +68,7 @@
 #include "conf.h"
 #include "control.h"
 #include "state.h"
+#include "xdg.h"
 
 
 /* Prototypes for static functions */
@@ -86,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);
 
 
@@ -119,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;
@@ -164,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 },
 
@@ -176,6 +188,7 @@
       char *argv[])
 {
 	char **args = NULL;
+	char **dirs = NULL;
 	int    ret;
 
 	args_copy = NIH_MUST (nih_str_array_copy (NULL, NULL, argv));
@@ -194,6 +207,7 @@
 
 	handle_confdir ();
 	handle_logdir ();
+	handle_usermode ();
 
 	if (disable_job_logging)
 		nih_debug ("Job logging disabled");
@@ -519,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 ();
 
@@ -903,6 +927,9 @@
 	if (conf_dir)
 		goto out;
 
+	if (user_mode)
+		return;
+
 	conf_dir = CONFDIR;
 
 	dir = getenv (CONFDIR_ENV);
@@ -943,6 +970,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-12-17 14:24:22 +0000
+++ init/man/init.5	2012-12-18 13:58:23 +0000
@@ -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:
@@ -120,6 +129,20 @@
 be used within a chroot environment.
 
 .\"
+.SS User Session Mode
+
+Upstart can manage complete User Session. In this mode upstart is
+running as a user process. It will read configuration files from
+.B $XDG_CONFIG_HOME/upstart/,
+.B $XDG_CONFIG_DIRS/upstart/,
+.B $HOME/.init/ and
+.B /usr/share/upstart/sessions/.
+
+It will then launch the user's session. It will try to parent all
+spawned process with aid from prctl. And kill everything upon logout
+or shutdown.
+
+.\"
 .SS Configuration File Format
 Each line begins with a configuration stanza and continues until either
 the end of the line or a line containing a closing stanza.  Line breaks

=== modified file 'init/man/init.8'
--- init/man/init.8	2011-12-09 14:07:11 +0000
+++ init/man/init.8	2012-12-18 13:58:23 +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,16 +113,35 @@
 .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. Unless \-\-user option is used, then it will read alternative
+configuration files and manage the individual user session in a
+similar fashion.
 .\"
 .SH FILES
 .\"
@@ -131,6 +150,8 @@
 .I /etc/init/*.conf
 
 .I $HOME/.init/
+
+.I $XDG_CONFIG_DIRS/upstart/, $XDG_CONFIG_HOME/upstart/
 .\"
 .SH AUTHOR
 Written by Scott James Remnant
@@ -141,7 +162,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:

=== 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:24:31 +0000
@@ -0,0 +1,182 @@
+/* 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 == NULL)
+		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 == NULL)
+		goto error;
+	if (path && path[0]) {
+	        if (nih_strcat_sprintf (&path, NULL, "/%s", INIT_XDG_SUBDIR) == NULL)
+			goto error;
+		if (nih_str_array_add (&all_dirs, NULL, NULL, path) == NULL)
+			goto error;
+		nih_free (path);
+		path = NULL;
+	}
+
+	/* Legacy User's: ~/.init */
+	path = get_home_subdir (USERCONFDIR);
+	if (path == NULL)
+		goto error;
+	if (path && path[0]) {
+		if (nih_str_array_add (&all_dirs, NULL, NULL, path) == NULL)
+			goto error;
+		nih_free (path);
+		path = NULL;
+	}
+
+	/* Systems': XDG_CONFIG_DIRS/upstart */
+	dirs = xdg_get_config_dirs ();
+	if (dirs == NULL)
+		goto error;
+	for (char **p = dirs; p && *p; p++) {
+		if (nih_strcat_sprintf (p, NULL, "/%s", INIT_XDG_SUBDIR) == NULL)
+			goto error;
+		if (nih_str_array_add (&all_dirs, NULL, NULL, *p) == NULL)
+			goto error;
+	}
+	nih_free (dirs);
+	dirs = NULL;
+
+	/* System's read-only location */
+	if (nih_str_array_add (&all_dirs, NULL, NULL, SYSTEM_USERCONFDIR) == NULL)
+		goto error;
+
+	return all_dirs;
+	
+error:
+	if (path != NULL)
+		nih_free (path);
+	if (dirs != NULL)
+		nih_free (dirs);
+	if (all_dirs != NULL)
+		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 */

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

Reply via email to