James Hunt has proposed merging lp:~jamesodhunt/upstart/upstart-dconf-bridge 
into lp:upstart.

Requested reviews:
  Upstart Reviewers (upstart-reviewers)

For more details, see:
https://code.launchpad.net/~jamesodhunt/upstart/upstart-dconf-bridge/+merge/177650

New user bridge that emits Upstart events on dconf key changes.
-- 
https://code.launchpad.net/~jamesodhunt/upstart/upstart-dconf-bridge/+merge/177650
Your team Upstart Reviewers is requested to review the proposed merge of 
lp:~jamesodhunt/upstart/upstart-dconf-bridge into lp:upstart.
=== modified file 'ChangeLog'
--- ChangeLog	2013-07-25 19:44:38 +0000
+++ ChangeLog	2013-07-30 17:01:26 +0000
@@ -1,3 +1,15 @@
+2013-07-30  James Hunt  <[email protected]>
+
+	* extra/man/dconf-event.7: New man page.
+	* extra/man/upstart-dconf-bridge.8: New man page.
+	* extra/upstart-dconf-bridge.c: Bridge will now only emit
+	  events on dconf changes if any jobs care about them
+	  (unless --always is specified).
+	* extra/conf-session/upstart-dconf-bridge.conf: Sample conf
+	  file for dconf bridge.
+	* extra/Makefile.am: Added dconf bridge man pages and sample
+	  conf to distribution.
+
 2013-07-25  James Hunt  <[email protected]>
 
 	* extra/Makefile.am: Renamed to upstart-local-bridge.
@@ -110,6 +122,32 @@
 	  part of the earlier Session deserialisation. (LP: #1199778)
 	* init/state.c: Formatting.
 
+2013-07-09  James Hunt  <[email protected]>
+
+	* {configure.ac,Makefile.am}: Allow upstart-dconf-bridge to be
+	  disabled even if dependencies are available (--disable-dconf-bridge).
+	* extra/upstart-dconf-bridge.c: Changed event name to simply 'dconf'
+	  with fixed first argument of 'TYPE=changed' for consistency with
+	  other bridge events and to accommodate future dconf API changes.
+
+2013-07-08  James Hunt  <[email protected]>
+
+	* extra/upstart-dconf-bridge.c: dconf_changed():
+	  - Simplified logic after desrt clarified 'changed' signal
+	  behaviour.
+
+2013-07-05  James Hunt  <[email protected]>
+
+	* extra/upstart-dconf-bridge.c:
+	  - Added DCONF_EVENT.
+	  - Reformatted to be more consistent with other bridges.
+	  - main():
+	    - Connect to UPSTART_SESSION rather than D-Bus session bus.
+	    - Handle generation of pidfile name.
+	  - dconf_changed():
+	    - Correct path logic and ensure that if the changes array contains
+	      values that they are separated correctly from the prefix.
+
 2013-07-04  James Hunt  <[email protected]>
 
 	* NEWS: Release 1.9.1

=== modified file 'configure.ac'
--- configure.ac	2013-07-16 08:45:58 +0000
+++ configure.ac	2013-07-30 17:01:26 +0000
@@ -30,9 +30,20 @@
 PKG_CHECK_MODULES([NIH], [libnih >= 1.0.2])
 PKG_CHECK_MODULES([NIH_DBUS], [libnih-dbus >= 1.0.0])
 PKG_CHECK_MODULES([DBUS], [dbus-1 >= 1.2.16])
+PKG_CHECK_MODULES([GIO], [gio-2.0 >= 2.36], [have_gio=yes], [have_gio=no])
 PKG_CHECK_MODULES([UDEV], [libudev >= 146], [have_udev=yes], [have_udev=no])
+PKG_CHECK_MODULES([DCONF], [dconf >= 0.14], [have_dconf=yes], [have_dconf=no])
 AM_CONDITIONAL([HAVE_UDEV], [test "$have_udev" = yes])
 
+AC_ARG_ENABLE([dconf-bridge],
+	AS_HELP_STRING([--disable-dconf-bridge],
+		[Disable building of upstart-dconf-bridge even if required dependencies available]),
+		[dconf_bridge=no], [dconf_bridge=yes])
+
+AM_CONDITIONAL([ENABLE_DCONF_BRIDGE], [test "$have_dconf" = yes &&
+                                test "$have_gio" = yes &&
+				test "$dconf_bridge" = yes])
+
 # Reasons for requiring this library version:
 #
 # 1) RFC 4627, the JSON "memo" (it is *NOT* a standard!) helpfully fails

=== modified file 'extra/Makefile.am'
--- extra/Makefile.am	2013-07-25 19:44:38 +0000
+++ extra/Makefile.am	2013-07-30 17:01:26 +0000
@@ -102,6 +102,30 @@
 	$(NIH_DBUS_LIBS) \
 	$(DBUS_LIBS)
 
+if ENABLE_DCONF_BRIDGE
+dist_sessions_DATA += \
+	conf-session/upstart-dconf-bridge.conf
+
+dist_man_MANS += \
+	man/upstart-dconf-bridge.8 \
+	man/dconf-event.7
+
+sbin_PROGRAMS += \
+	upstart-dconf-bridge
+
+upstart_dconf_bridge_SOURCES = \
+	upstart-dconf-bridge.c
+nodist_upstart_dconf_bridge_SOURCES = \
+	$(com_ubuntu_Upstart_OUTPUTS)
+upstart_dconf_bridge_LDADD = \
+	$(LTLIBINTL) \
+	$(NIH_LIBS) \
+	$(NIH_DBUS_LIBS) \
+	$(DBUS_LIBS) \
+	$(GIO_LIBS) \
+	$(DCONF_LIBS)
+endif
+
 if HAVE_UDEV
 dist_init_DATA += \
 	conf/upstart-udev-bridge.conf

=== added file 'extra/conf-session/upstart-dconf-bridge.conf'
--- extra/conf-session/upstart-dconf-bridge.conf	1970-01-01 00:00:00 +0000
+++ extra/conf-session/upstart-dconf-bridge.conf	2013-07-30 17:01:26 +0000
@@ -0,0 +1,10 @@
+description	"Bridge dconf events into session upstart"
+
+emits dconf
+
+start on started dbus
+stop on stopped dbus
+
+respawn
+
+exec upstart-dconf-bridge

=== added file 'extra/man/dconf-event.7'
--- extra/man/dconf-event.7	1970-01-01 00:00:00 +0000
+++ extra/man/dconf-event.7	2013-07-30 17:01:26 +0000
@@ -0,0 +1,52 @@
+.TH dconf\-event 7 2013-07-09 upstart
+.\"
+.SH NAME
+dconf \- event signalling that a dconf key has been changed
+.\"
+.SH SYNOPSIS
+.B dconf
+.BI TYPE\fR= changed
+.BI KEY\fR= KEY
+.BI VALUE\fR= VALUE
+.\"
+.SH DESCRIPTION
+
+The
+.B dconf
+event is generated by the
+.BR upstart\-dconf\-bridge (8)
+daemon when a dconf key changes whose details match the
+.I dconf
+event condition and environment specified in a job's
+.B start on
+or
+.B stop on
+stanza.
+
+.\"
+.SH EXAMPLES
+.\"
+.IP "start on dconf TYPE=changed KEY=/desktop/gnome/remote-access/notify-on-connect VALUE=true"
+
+Start job when the user allows remote access to their desktop.
+.\"
+.SH AUTHOR
+Written by James Hunt
+.RB < [email protected] >
+.\"
+.SH BUGS
+Report bugs at 
+.RB < https://launchpad.net/upstart/+bugs >
+.\"
+.SH COPYRIGHT
+Copyright \(co 2013 Canonical Ltd.
+.PP
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.SH SEE ALSO
+.BR dconf (7)
+.BR gsettings (1)
+.BR init (5)
+.BR init (8)
+.BR upstart\-dconf\-bridge (8)

=== added file 'extra/man/upstart-dconf-bridge.8'
--- extra/man/upstart-dconf-bridge.8	1970-01-01 00:00:00 +0000
+++ extra/man/upstart-dconf-bridge.8	2013-07-30 17:01:26 +0000
@@ -0,0 +1,66 @@
+.TH upstart\-dconf\-bridge 8 2013-07-09 upstart
+.\"
+.SH NAME
+upstart\-dconf\-bridge \- Bridge between Upstart and dconf/gsettings
+.\"
+.SH SYNOPSIS
+.B upstart\-dconf\-bridge
+.RI [ OPTIONS ]...
+.\"
+.SH DESCRIPTION
+.B upstart\-dconf\-bridge
+receives information about dconf/gsettings changes
+and creates
+.BR init (8)
+events for them.
+
+With no options (and if there are jobs which have registered an interest
+in the event), monitors dconf changes and emits
+an Upstart event called
+.I dconf
+with details of the dconf change.
+
+See \fBdconf\fP(7) and for further details.
+
+.\"
+.SH OPTIONS
+.\"
+.TP
+.B \-\-always
+Always emit events on receipt of dconf changes regardless of whether jobs
+care about them.
+.TP
+.B \-\-daemon
+Detach and run in the background.
+.\"
+.TP
+.B \-\-debug
+Enable debugging output.
+.\"
+.TP
+.B \-\-help
+Show brief usage summary.
+.\"
+.TP
+.B \-\-verbose
+Enable verbose output.
+.\"
+.SH AUTHOR
+Written by James Hunt
+.RB < [email protected] >
+.\"
+.SH BUGS
+Report bugs at 
+.RB < https://launchpad.net/ubuntu/+source/upstart/+bugs >
+.\"
+.SH COPYRIGHT
+Copyright \(co 2013 Canonical Ltd.
+.PP
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+.SH SEE ALSO
+.BR dconf (7)
+.BR dconf\-event (7)
+.BR gsettings (1)
+.BR init (5)
+.BR init (8)

=== added file 'extra/upstart-dconf-bridge.c'
--- extra/upstart-dconf-bridge.c	1970-01-01 00:00:00 +0000
+++ extra/upstart-dconf-bridge.c	2013-07-30 17:01:26 +0000
@@ -0,0 +1,608 @@
+/* upstart-dconf-bridge
+ *
+ * Copyright © 2012-2013 Canonical Ltd.
+ * Author: Stéphane Graber <[email protected]>.
+ * Author: Thomas Bechtold <[email protected]>.
+ * Author: James Hunt <[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 <dconf.h>
+#include <gio/gio.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <ctype.h>
+
+#include <nih/macros.h>
+#include <nih/alloc.h>
+#include <nih/string.h>
+#include <nih/hash.h>
+#include <nih/io.h>
+#include <nih/option.h>
+#include <nih/main.h>
+#include <nih/logging.h>
+#include <nih/error.h>
+
+#include <nih-dbus/dbus_connection.h>
+#include <nih-dbus/dbus_proxy.h>
+
+#include "dbus/upstart.h"
+#include "com.ubuntu.Upstart.h"
+#include "com.ubuntu.Upstart.Job.h"
+
+/**
+ * DCONF_EVENT:
+ *
+ * Name of event this program emits.
+ **/
+#define DCONF_EVENT "dconf"
+
+/* Prototypes for static functions */
+static void dconf_changed (DConfClient *client, const gchar *prefix,
+			   const gchar * const *changes, const gchar *tag,
+			   GDBusProxy *upstart);
+
+static void handle_upstart_job (GDBusProxy *proxy, gchar *sender_name,
+			 gchar *signal_name, GVariant *parameters,
+			 gpointer user_data);
+
+static int handle_existing_jobs (GDBusProxy *upstart_proxy)
+	__attribute__ ((warn_unused_result));
+
+static int job_needs_event (const char *object_path)
+	__attribute__ ((warn_unused_result));
+
+static int jobs_need_event (void)
+	__attribute__ ((warn_unused_result));
+
+/**
+ * Structure we use for tracking jobs
+ *
+ * @entry: list header, 
+ * @path: D-Bus path of job being tracked.
+ **/
+typedef struct job {
+	NihList entry;
+	char *path;
+} Job;
+
+/**
+ * daemonise:
+ *
+ * Set to TRUE if we should become a daemon, rather than just running
+ * in the foreground.
+ **/
+static int daemonise = FALSE;
+
+/**
+ * always:
+ *
+ * If TRUE, always emit Upstart events, regardless of whether
+ * existing jobs care about DBUS_EVENT.
+ */
+static int always = FALSE;
+
+/**
+ * jobs:
+ *
+ * Jobs that we're monitoring.
+ **/
+static NihHash *jobs = NULL;
+
+/**
+ * connection:
+ *
+ * D-Bus connection to Upstart.
+ **/
+GDBusConnection *connection = NULL;
+
+/**
+ * options:
+ *
+ * Command-line options accepted by this program.
+ **/
+static NihOption options[] = {
+	{ 0, "always", N_("Always emit an event on a dconf change"),
+	  NULL, NULL, &always, NULL },
+	{ 0, "daemon", N_("Detach and run in the background"),
+	  NULL, NULL, &daemonise, NULL },
+	NIH_OPTION_LAST
+};
+
+int
+main (int   argc,
+      char *argv[])
+{
+	char             **args;
+	DConfClient       *client;
+	GMainLoop         *mainloop;
+	GDBusProxy        *upstart_proxy;
+	GError            *error = NULL;
+	char              *user_session_addr = NULL;
+	nih_local char   **user_session_path = NULL;
+	char              *path_element = NULL;
+	char              *pidfile_path = NULL;
+	char              *pidfile = NULL;
+
+	client = dconf_client_new ();
+	mainloop = g_main_loop_new (NULL, FALSE);
+
+	/* Use NIH to parse the arguments */
+	nih_main_init (argv[0]);
+
+	nih_option_set_synopsis (_("Bridge dconf events into upstart"));
+	nih_option_set_help (
+		_("By default, upstart-dconf-bridge does not detach from the "
+		  "console and remains in the foreground.  Use the --daemon "
+		  "option to have it detach."));
+
+	args = nih_option_parser (NULL, argc, argv, options, FALSE);
+	if (! args)
+		exit (1);
+
+	user_session_addr = getenv ("UPSTART_SESSION");
+	if (! user_session_addr) {
+		nih_fatal (_("UPSTART_SESSION isn't set in environment"));
+		exit (1);
+	}
+
+	/* Connect to the Upstart session */
+	connection = g_dbus_connection_new_for_address_sync (user_session_addr,
+			G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
+			NULL, /* GDBusAuthObserver*/
+			NULL, /* GCancellable */
+			&error);
+
+	if (! connection) {
+		g_error ("D-BUS Upstart session init error: %s",
+			 (error && error->message) ? error->message : "Unknown error");
+		g_clear_error (&error);
+		exit (1);
+	}
+
+	/* Allocate jobs hash table */
+	jobs = NIH_MUST (nih_hash_string_new (NULL, 0));
+
+	/* Get an Upstart proxy object */
+	upstart_proxy = g_dbus_proxy_new_sync (connection,
+					       G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
+					       NULL, /* GDBusInterfaceInfo */
+					       NULL, /* name */
+					       "/com/ubuntu/Upstart",
+					       "com.ubuntu.Upstart0_6",
+					       NULL, /* GCancellable */
+					       &error);
+
+	if (! upstart_proxy) {
+		g_error ("D-BUS Upstart proxy error: %s",
+			 (error && error->message) ? error->message : "Unknown error");
+		g_clear_error (&error);
+		exit (1);
+	}
+
+	/* Connect signal to be notified when jobs come and go */
+	g_signal_connect (upstart_proxy, "g-signal", (GCallback) handle_upstart_job, NULL);
+
+	if (! handle_existing_jobs (upstart_proxy))
+		exit (1);
+	
+	if (daemonise) {
+		/* Deal with the pidfile location when becoming a daemon.
+		 * We need to be able to run one bridge per upstart daemon.
+		 * Store the PID file in XDG_RUNTIME_DIR or HOME and include the pid of
+		 * the Upstart instance (last part of the DBus path) in the filename.
+		 */
+
+		/* Extract PID from UPSTART_SESSION */
+		user_session_path = nih_str_split (NULL, user_session_addr, "/", TRUE);
+
+		for (int i = 0; user_session_path && user_session_path[i]; i++)
+			path_element = user_session_path[i];
+
+		if (! path_element) {
+			nih_fatal (_("Invalid value for UPSTART_SESSION"));
+			exit (1);
+		}
+
+		pidfile_path = getenv ("XDG_RUNTIME_DIR");
+		if (!pidfile_path)
+			pidfile_path = getenv ("HOME");
+
+		if (pidfile_path) {
+			NIH_MUST (nih_strcat_sprintf (&pidfile, NULL,
+						"%s/upstart-dconf-bridge.%s.pid",
+						pidfile_path, path_element));
+			nih_main_set_pidfile (pidfile);
+		}
+
+		if (nih_main_daemonise () < 0) {
+			NihError *err;
+
+			err = nih_error_get ();
+			nih_fatal ("%s: %s", _("Unable to become daemon"),
+				   err->message);
+			nih_free (err);
+
+			exit (1);
+		}
+	}
+
+	/* Handle TERM and INT signals gracefully */
+	nih_signal_set_handler (SIGTERM, nih_signal_handler);
+	NIH_MUST (nih_signal_add_handler (NULL, SIGTERM, nih_main_term_signal, NULL));
+
+	/* Listen for any dconf change */
+	g_signal_connect (client, "changed", (GCallback) dconf_changed, upstart_proxy);
+	dconf_client_watch_sync (client, "/");
+
+	/* Start the glib mainloop */
+	g_main_loop_run (mainloop);
+
+	g_object_unref (client);
+	g_object_unref (upstart_proxy);
+	g_object_unref (connection);
+	g_main_loop_unref (mainloop);
+
+	exit (0);
+}
+
+/**
+ * handle_upstart_job:
+ *
+ * Called when an Upstart D-Bus signal is emitted.
+ **/
+static void
+handle_upstart_job (GDBusProxy *proxy,
+		    gchar      *sender_name,
+		    gchar      *signal_name,
+		    GVariant   *parameters,
+		    gpointer    user_data)
+{
+	GVariantIter   iter;
+	GVariant      *child;
+	const gchar   *job_class_path;
+	Job           *job;
+	int            add;
+
+	nih_assert (signal_name);
+	nih_assert (parameters);
+	nih_assert (jobs);
+
+	if (! strcmp (signal_name, "JobAdded")) {
+		add = 1;
+	} else if (! strcmp (signal_name, "JobRemoved")) {
+		add = 0;
+	} else {
+		return;
+	}
+
+	nih_assert (g_variant_is_of_type (parameters, G_VARIANT_TYPE_TUPLE));
+
+	g_variant_iter_init (&iter, parameters);
+
+	nih_assert (g_variant_iter_n_children (&iter) == 1);
+
+	child = g_variant_iter_next_value (&iter);
+
+	job_class_path = g_variant_get_string (child, NULL);
+	nih_assert (g_variant_is_object_path (job_class_path));
+
+	/* Free any existing record for the job if we are adding
+	 * (should never happen, but worth being safe).
+	 */
+	job = (Job *)nih_hash_lookup (jobs, job_class_path);
+	if (job)
+		nih_free (job);
+
+	/* Job isn't interested in DCONF_EVENT */
+	if (add && ! job_needs_event (job_class_path))
+		goto out;
+
+	if (add)
+		nih_debug ("Job got added %s for event %s", job_class_path, DCONF_EVENT);
+	else
+		nih_debug ("Job went away %s", job_class_path);
+
+	/* We're removing, so job done */
+	if (! add)
+		goto out;
+
+	/* Create new record for the job */
+	job = NIH_MUST (nih_new (NULL, Job));
+	job->path = NIH_MUST (nih_strdup (job, job_class_path));
+
+	nih_list_init (&job->entry);
+	nih_alloc_set_destructor (job, nih_list_destroy);
+	nih_hash_add (jobs, &job->entry);
+
+out:
+	g_variant_unref (child);
+}
+
+/**
+ * dconf_changed:
+ *
+ * Emit an Upstart event corresponding to a dconf key change.
+ **/
+static void
+dconf_changed (DConfClient         *client,
+	       const gchar         *prefix,
+	       const gchar * const *changes,
+	       const gchar         *tag,
+	       GDBusProxy          *upstart)
+{
+	GVariant         *value;
+	gchar            *value_str = NULL;
+	gchar            *path = NULL;
+	gchar            *env_key = NULL;
+	gchar            *env_value = NULL;
+	GVariant         *event;
+	GVariantBuilder   builder;
+	int               i = 0;
+
+	/* dconf currently only currently supports the changed signal,
+	 * but parameterise to allow for a future API change.
+	 */
+	const gchar      *event_type = "TYPE=changed";
+
+	if (! jobs_need_event () && ! always)
+		return;
+
+	/* Iterate through the various changes */
+	while (changes[i] != NULL) {
+		path = g_strconcat (prefix, changes[i], NULL);
+
+		value = dconf_client_read (client, path);
+		value_str = g_variant_print (value, FALSE);
+
+		env_key = g_strconcat ("KEY=", path, NULL);
+		env_value = g_strconcat ("VALUE=", value_str, NULL);
+
+		/* Build event environment as GVariant */
+		g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
+
+		g_variant_builder_add (&builder, "s", DCONF_EVENT);
+
+		g_variant_builder_open (&builder, G_VARIANT_TYPE_ARRAY);
+		g_variant_builder_add (&builder, "s", event_type);
+		g_variant_builder_add (&builder, "s", env_key);
+		g_variant_builder_add (&builder, "s", env_value);
+		g_variant_builder_close (&builder);
+
+		g_variant_builder_add (&builder, "b", FALSE);
+		event = g_variant_builder_end (&builder);
+
+		/* Send the event */
+		g_dbus_proxy_call (upstart,
+				"EmitEvent",
+				event,
+				G_DBUS_CALL_FLAGS_NONE,
+				-1,
+				NULL,
+				NULL, /* GAsyncReadyCallback
+					 we don't care about the answer */
+				NULL);
+
+		g_variant_builder_clear (&builder);
+		g_variant_unref (value);
+		g_free (path);
+		g_free (value_str);
+		g_free (env_key);
+		g_free (env_value);
+
+		i += 1;
+	}
+}
+
+/**
+ * jobs_need_event:
+ *
+ * Returns: TRUE if any jobs need DCONF_EVENT, else FALSE.
+ **/
+static int
+jobs_need_event (void)
+{
+	NIH_HASH_FOREACH (jobs, iter) {
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+/**
+ * job_needs_event:
+ * @object_path: Full D-Bus object path for job.
+ *
+ * Returns: TRUE if job specified by @object_path specifies DCONF_EVENT
+ * in its 'start on' or 'stop on' stanza, else FALSE.
+ **/
+static int
+job_needs_event (const char *class_path)
+{
+	GDBusProxy    *job_proxy;
+	GError        *error = NULL;
+	GVariantIter   iter;
+	const gchar   *event_name;
+	int            ret = FALSE;
+
+	/* Arrays of arrays of strings (aas) */
+	GVariant      *start_on = NULL;
+	GVariant      *stop_on = NULL;
+
+	/* Array containing event name and optional environment
+	 * variable elements.
+	 */
+	GVariant      *event_element;
+
+	/* Either an event name or "/AND" or "/OR" */
+	GVariant      *event;
+
+	nih_assert (class_path);
+
+	job_proxy = g_dbus_proxy_new_sync (connection,
+			G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
+			NULL, /* GDBusInterfaceInfo */
+			NULL, /* name */
+			class_path,
+			"com.ubuntu.Upstart0_6.Job",
+			NULL, /* GCancellable */
+			&error);
+
+	start_on = g_dbus_proxy_get_cached_property (job_proxy, "start_on");
+	nih_assert (g_variant_is_of_type (start_on, G_VARIANT_TYPE_ARRAY));
+
+	g_variant_iter_init (&iter, start_on);
+
+	while ((event_element = g_variant_iter_next_value (&iter))) {
+		nih_assert (g_variant_is_of_type (event_element, G_VARIANT_TYPE_ARRAY));
+
+		/* First element is always the event name */
+		event = g_variant_get_child_value (event_element, 0);
+		nih_assert (g_variant_is_of_type (event, G_VARIANT_TYPE_STRING));
+
+		event_name = g_variant_get_string (event, NULL);
+
+		if (! strcmp (event_name, DCONF_EVENT))
+			ret = TRUE;
+
+		g_variant_unref (event_element);
+		g_variant_unref (event);
+
+		if (ret)
+			goto out;
+	}
+
+	/* Now handle stop on */
+	stop_on = g_dbus_proxy_get_cached_property (job_proxy, "stop_on");
+	nih_assert (g_variant_is_of_type (stop_on, G_VARIANT_TYPE_ARRAY));
+
+	g_variant_iter_init (&iter, stop_on);
+
+	while ((event_element = g_variant_iter_next_value (&iter))) {
+		nih_assert (g_variant_is_of_type (event_element, G_VARIANT_TYPE_ARRAY));
+
+		/* First element is always the event name */
+		event = g_variant_get_child_value (event_element, 0);
+		nih_assert (g_variant_is_of_type (event, G_VARIANT_TYPE_STRING));
+
+		event_name = g_variant_get_string (event, NULL);
+
+		if (! strcmp (event_name, DCONF_EVENT))
+			ret = TRUE;
+
+		g_variant_unref (event_element);
+		g_variant_unref (event);
+
+		if (ret)
+			goto out;
+	}
+
+out:
+	if (start_on)
+		g_variant_unref (start_on);
+
+	if (stop_on)
+		g_variant_unref (stop_on);
+
+	g_object_unref (job_proxy);
+
+	return ret;
+}
+
+/**
+ * handle_existing_jobs:
+ *
+ * @upstart_proxy: Upstart proxy.
+ *
+ * Add all existing jobs which specify DCONF_EVENT to the list
+ * of tracked jobs.
+ *
+ * Returns: TRUE or FALSE on error.
+ **/
+static int
+handle_existing_jobs (GDBusProxy *upstart_proxy)
+{
+	GVariant      *result;
+	GVariant      *child;
+	GVariant      *proxy_job;
+	const gchar   *job_class_path;
+	GError        *error = NULL;
+	GVariantIter   iter;
+	Job           *job;
+
+	nih_assert (upstart_proxy);
+
+	result = g_dbus_proxy_call_sync (upstart_proxy,
+			"GetAllJobs",
+			NULL,
+			G_DBUS_CALL_FLAGS_NO_AUTO_START,
+			-1,
+			NULL,
+			&error);
+
+	if (! result) {
+		g_error ("D-BUS Upstart proxy error: %s",
+				(error && error->message)
+				? error->message
+				: "Unknown error");
+		g_clear_error (&error);
+		return FALSE;
+	}
+
+	nih_assert (g_variant_is_of_type (result, G_VARIANT_TYPE_TUPLE));
+	nih_assert (g_variant_n_children (result) == 1);
+
+	child = g_variant_get_child_value (result, 0);
+
+	nih_assert (g_variant_is_of_type (child, G_VARIANT_TYPE_OBJECT_PATH_ARRAY));
+
+	g_variant_iter_init (&iter, child);
+
+	while ((proxy_job = g_variant_iter_next_value (&iter))) {
+		job_class_path = g_variant_get_string (proxy_job, NULL);
+
+		/* Free any existing record for the job if we are adding
+		 * (should never happen, but worth being safe).
+		 */
+		job = (Job *)nih_hash_lookup (jobs, job_class_path);
+		if (job)
+			nih_free (job);
+
+		if (job_needs_event (job_class_path)) {
+			/* Create new record for the job */
+			job = NIH_MUST (nih_new (NULL, Job));
+			job->path = NIH_MUST (nih_strdup (job, job_class_path));
+
+			nih_list_init (&job->entry);
+			nih_alloc_set_destructor (job, nih_list_destroy);
+			nih_hash_add (jobs, &job->entry);
+
+			nih_debug ("Job added %s for event %s", job_class_path, DCONF_EVENT);
+		}
+
+		g_variant_unref (proxy_job);
+	}
+
+	g_variant_unref (child);
+	g_variant_unref (result);
+
+	return TRUE;
+}

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

Reply via email to