Merge authors:
  James Hunt (jamesodhunt)
Related merge proposals:
  
https://code.launchpad.net/~jamesodhunt/upstart/upstart-dbus-bridge/+merge/161772
  proposed by: James Hunt (jamesodhunt)
  review: Approve - Dmitrijs Ledkovs (xnox)
------------------------------------------------------------
revno: 1486 [merge]
committer: Dmitrijs Ledkovs <[email protected]>
branch nick: upstart
timestamp: Wed 2013-06-26 10:15:41 +0100
message:
  Merge dbus-bridge.
added:
  extra/conf/upstart-dbus-bridge.conf
  extra/man/dbus-event.7
  extra/man/upstart-dbus-bridge.8
  extra/upstart-dbus-bridge.c
modified:
  ChangeLog
  extra/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	2013-06-25 15:56:00 +0000
+++ ChangeLog	2013-06-26 09:15:41 +0000
@@ -1,3 +1,16 @@
+2013-06-26  James Hunt  <[email protected]>
+
+	* extra/Makefile.am: Add man pages and conf file.
+	* extra/upstart-dbus-bridge.c: Only emit events if any jobs care
+	  about them.
+	* extra/conf/upstart-dbus-bridge.conf: New configuration file.
+	* extra/man/dbus-event.7: New man page.
+	* extra/man/upstart-dbus-bridge.8: New man page.
+	* extra/upstart-dbus-bridge.c:
+	  - Comments and formatting.
+	  - main(): Default to an appropriate bus.
+	  - signal_filter(): Display signal details when run with --debug.
+
 2013-06-24  James Hunt  <[email protected]>
 
 	* init/Makefile.am: Added missing json file to TEST_DATA_FILES.

=== modified file 'extra/Makefile.am'
--- extra/Makefile.am	2013-03-11 20:02:18 +0000
+++ extra/Makefile.am	2013-05-01 04:33:35 +0000
@@ -19,19 +19,24 @@
 sbin_PROGRAMS = \
 	upstart-socket-bridge \
 	upstart-event-bridge \
-	upstart-file-bridge
+	upstart-file-bridge \
+	upstart-dbus-bridge
 
 dist_init_DATA = \
 	conf/upstart-socket-bridge.conf \
 	conf/upstart-event-bridge.conf \
-	conf/upstart-file-bridge.conf
+	conf/upstart-file-bridge.conf \
+	conf/upstart-dbus-bridge.conf
 
+# FIXME: add man/upstart-dbus-bridge.8
 dist_man_MANS = \
 	man/upstart-socket-bridge.8 \
 	man/upstart-event-bridge.8 \
 	man/upstart-file-bridge.8 \
+	man/upstart-dbus-bridge.8 \
 	man/socket-event.7 \
-	man/file-event.7
+	man/file-event.7 \
+	man/dbus-event.7
 
 upstart_socket_bridge_SOURCES = \
 	upstart-socket-bridge.c
@@ -66,6 +71,17 @@
 	$(NIH_DBUS_LIBS) \
 	$(DBUS_LIBS)
 
+upstart_dbus_bridge_SOURCES = \
+	upstart-dbus-bridge.c
+nodist_upstart_dbus_bridge_SOURCES = \
+	$(com_ubuntu_Upstart_OUTPUTS) \
+	$(com_ubuntu_Upstart_Job_OUTPUTS)
+upstart_dbus_bridge_LDADD = \
+	$(LTLIBINTL) \
+	$(NIH_LIBS) \
+	$(NIH_DBUS_LIBS) \
+	$(DBUS_LIBS)
+
 if HAVE_UDEV
 dist_init_DATA += \
 	conf/upstart-udev-bridge.conf

=== added file 'extra/conf/upstart-dbus-bridge.conf'
--- extra/conf/upstart-dbus-bridge.conf	1970-01-01 00:00:00 +0000
+++ extra/conf/upstart-dbus-bridge.conf	2013-05-01 04:33:35 +0000
@@ -0,0 +1,17 @@
+# upstart-dbus-bridge - Bridge D-Bus signal events into upstart
+#
+# This helper daemon receives D-Bus signal events and
+# emits equivalent Upstart events.
+
+description	"Bridge D-Bus signal events into upstart"
+
+emits dbus
+
+start on startup
+
+stop on runlevel [!2345]
+
+expect daemon
+respawn
+
+exec upstart-dbus-bridge --daemon --system

=== added file 'extra/man/dbus-event.7'
--- extra/man/dbus-event.7	1970-01-01 00:00:00 +0000
+++ extra/man/dbus-event.7	2013-05-01 04:33:35 +0000
@@ -0,0 +1,53 @@
+.TH dbus\-event 7 2013-04-25 upstart
+.\"
+.SH NAME
+dbus \- event signalling that a dbus signal has been emitted
+.\"
+.SH SYNOPSIS
+.B dbus
+.BI SIGNAL\fR= SIGNAL
+.BI INTERFACE\fR= INTERFACE
+.BI PATH\fR= PATH
+.BI SENDER\fR= SENDER
+.BI DESTINATION\fR= DESTINATION
+.\"
+.SH DESCRIPTION
+
+The
+.B dbus
+event is generated by the
+.BR upstart\-dbus\-bridge (8)
+daemon when a D-Bus signal is emitted whose details match the
+.I dbus
+event condition and environment specified in a job's
+.B start on
+or
+.B stop on
+stanza is modified.
+
+.\"
+.SH EXAMPLES
+.\"
+.IP "start on dbus SIGNAL=NameAcquired INTERFACE=org.freedesktop.DBus PATH=/org/freedesktop/DBus SENDER=org.freedesktop.DBus"
+Start job when a particular
+.I NameAcquired
+D-Bus signal is received.
+.\"
+.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 init (5)
+.BR init (8)
+.BR upstart\-dbus\-bridge (8)

=== added file 'extra/man/upstart-dbus-bridge.8'
--- extra/man/upstart-dbus-bridge.8	1970-01-01 00:00:00 +0000
+++ extra/man/upstart-dbus-bridge.8	2013-05-01 04:57:37 +0000
@@ -0,0 +1,84 @@
+.TH upstart\-dbus\-bridge 8 2013-04-25 upstart
+.\"
+.SH NAME
+upstart\-dbus\-bridge \- Bridge between Upstart and D-Bus
+.\"
+.SH SYNOPSIS
+.B upstart\-dbus\-bridge
+.RI [ OPTIONS ]...
+.\"
+.SH DESCRIPTION
+.B upstart\-dbus\-bridge
+receives information about D-Bus signals
+and creates
+.BR init (8)
+events for them.
+
+With no options, monitors signals on the D-Bus system bus and emits
+an Upstart event called
+.I dbus
+via a D-Bus system bus connection to Upstart.
+
+When run with \fB\-\-user\fP, monitors signals on the users D-Bus session bus
+and emits Upstart events via the private D-Bus connection to the users Session Init.
+
+See \fBdbus\-daemon\fP(1) and for further details.
+
+.\"
+.SH OPTIONS
+.\"
+.TP
+.B \-\-always
+Always emit events on receipt of D-Bus signal 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 \-\-session
+Monitor signals on the D-Bus session bus.
+.\"
+.TP
+.B \-\-system
+Monitor signals on the D-Bus system bus.
+.\"
+.TP
+.B \-\-user
+User-session mode: connect to Upstart via the user session rather than
+over the D\-Bus system bus.
+.\"
+.TP
+.B \-\-verbose
+Enable verbose output.
+.\"
+.SH RESTRICTIONS
+D-Bus signals emitted by Upstart itself are ignored.
+
+.\"
+.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 dbus\-daemon (1)
+.BR dbus\-event (7)
+.BR init (5)
+.BR init (8)

=== added file 'extra/upstart-dbus-bridge.c'
--- extra/upstart-dbus-bridge.c	1970-01-01 00:00:00 +0000
+++ extra/upstart-dbus-bridge.c	2013-06-26 09:15:41 +0000
@@ -0,0 +1,640 @@
+/* upstart
+ *
+ * Copyright © 2013 Canonical Ltd.
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.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"
+
+/**
+ * DBUS_EVENT:
+ *
+ * Name of event this program handles.
+ **/
+#define DBUS_EVENT "dbus"
+
+/* Prototypes for static functions */
+static int               dbus_bus_setter      (NihOption *option, const char *arg);
+static void              dbus_disconnected    (DBusConnection *connection);
+static void              upstart_disconnected (DBusConnection *connection);
+static DBusHandlerResult signal_filter        (DBusConnection *connection,
+					       DBusMessage *message, void *user_data); 
+static void              emit_event_error     (void *data, NihDBusMessage *message);
+static void              upstart_job_added    (void *data, NihDBusMessage *message,
+					       const char *job);
+static void              upstart_job_removed  (void *data, NihDBusMessage *message,
+					       const char *job);
+
+/**
+ * daemonise:
+ *
+ * Set to TRUE if we should become a daemon, rather than just running
+ * in the foreground.
+ **/
+static int daemonise = FALSE;
+
+/**
+ * upstart:
+ *
+ * Proxy to Upstart daemon.
+ **/
+static NihDBusProxy *upstart = NULL;
+
+/**
+ * user_mode:
+ *
+ * If TRUE, connect to Session Init rather than PID 1.
+ **/
+static int user_mode = FALSE;
+
+/**
+ * dbus_bus:
+ *
+ * type of D-Bus bus to connect to.
+ **/
+DBusBusType dbus_bus = (DBusBusType)-1;
+
+/**
+ * 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;
+
+/**
+ * jobs:
+ *
+ * Jobs that we're monitoring.
+ **/
+static NihHash *jobs = NULL;
+
+/**
+ * always:
+ *
+ * If TRUE, always emit Upstart events, regardless of whether
+ * existing jobs care about DBUS_EVENT.
+ */
+static int always = FALSE;
+
+/**
+ * options:
+ *
+ * Command-line options accepted by this program.
+ **/
+static NihOption options[] = {
+	{ 0, "always", N_("Always emit an event on receipt of D-Bus signal"),
+	  NULL, NULL, &always, NULL },
+	{ 0, "daemon", N_("Detach and run in the background"),
+	  NULL, NULL, &daemonise, NULL },
+	{ 0, "user", N_("Connect to user session"),
+	  NULL, NULL, &user_mode, NULL },
+	{ 0, "session", N_("Use D-Bus session bus"),
+		NULL, NULL, NULL, dbus_bus_setter },
+	{ 0, "system", N_("Use D-Bus system bus"),
+		NULL, NULL, NULL, dbus_bus_setter },
+
+	NIH_OPTION_LAST
+};
+
+
+int
+main (int   argc,
+      char *argv[])
+{
+	char               **args;
+	DBusConnection      *dbus_connection;
+	DBusConnection      *connection;
+	int                  ret;
+	char                *pidfile_path = NULL;
+	char                *pidfile = NULL;
+	char                *user_session_addr = NULL;
+	nih_local char     **user_session_path = NULL;
+	char                *path_element = NULL;
+	DBusError            error;
+	char               **job_class_paths;
+
+	nih_main_init (argv[0]);
+
+	nih_option_set_synopsis (_("Bridge D-Bus signals into upstart"));
+	nih_option_set_help (
+		_("By default, upstart-event-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 (EXIT_FAILURE);
+
+	dbus_error_init (&error);
+
+	/* Default to an appropriate bus */
+	if (dbus_bus == (DBusBusType)-1)
+		dbus_bus = user_mode ? DBUS_BUS_SESSION : DBUS_BUS_SYSTEM;
+
+	/* Connect to the chosen D-Bus bus */
+	dbus_connection = NIH_SHOULD (nih_dbus_bus (dbus_bus, dbus_disconnected));
+
+	if (! dbus_connection) {
+		NihError *err;
+
+		err = nih_error_get ();
+		nih_fatal ("%s: %s", _("Could not connect to D-Bus"),
+			   err->message);
+		nih_free (err);
+
+		exit (EXIT_FAILURE);
+	}
+
+	dbus_bus_add_match (dbus_connection, "type='signal'", &error);
+
+	if (dbus_error_is_set (&error)) {
+		nih_fatal ("%s: %s %s", _("Could not add D-Bus signal match"),
+			   error.name, error.message);
+		dbus_error_free (&error);
+
+		exit (EXIT_FAILURE);
+	}
+
+	dbus_connection_add_filter (dbus_connection, signal_filter, NULL, NULL);
+
+	dbus_error_free (&error);
+
+	if (user_mode) {
+		user_session_addr = getenv ("UPSTART_SESSION");
+		if (! user_session_addr) {
+			nih_fatal (_("UPSTART_SESSION is not set in environment"));
+			exit (EXIT_FAILURE);
+		}
+	}
+
+	connection = NIH_SHOULD (nih_dbus_connect (user_mode
+				? user_session_addr
+				: DBUS_ADDRESS_UPSTART,
+				upstart_disconnected));
+
+	if (! connection) {
+		NihError *err;
+
+		err = nih_error_get ();
+		nih_fatal ("%s: %s", _("Could not connect to Upstart"),
+			   err->message);
+		nih_free (err);
+
+		exit (EXIT_FAILURE);
+	}
+
+	/* Allocate jobs hash table */
+	jobs = NIH_MUST (nih_hash_string_new (NULL, 0));
+
+	upstart = NIH_SHOULD (nih_dbus_proxy_new (NULL, connection,
+				NULL, DBUS_PATH_UPSTART,
+				NULL, NULL));
+
+	if (! upstart) {
+		NihError *err;
+
+		err = nih_error_get ();
+		nih_fatal ("%s: %s", _("Could not create Upstart proxy"),
+			   err->message);
+		nih_free (err);
+
+		exit (EXIT_FAILURE);
+	}
+
+	/* Connect signals to be notified when jobs come and go */
+	if (! nih_dbus_proxy_connect (upstart, &upstart_com_ubuntu_Upstart0_6, "JobAdded",
+				      (NihDBusSignalHandler)upstart_job_added, NULL)) {
+		NihError *err;
+
+		err = nih_error_get ();
+		nih_fatal ("%s: %s", _("Could not create JobAdded signal connection"),
+			   err->message);
+		nih_free (err);
+
+		exit (EXIT_FAILURE);
+	}
+
+	if (! nih_dbus_proxy_connect (upstart, &upstart_com_ubuntu_Upstart0_6, "JobRemoved",
+				      (NihDBusSignalHandler)upstart_job_removed, NULL)) {
+		NihError *err;
+
+		err = nih_error_get ();
+		nih_fatal ("%s: %s", _("Could not create JobRemoved signal connection"),
+			   err->message);
+		nih_free (err);
+
+		exit (EXIT_FAILURE);
+	}
+
+	/* Request a list of all current jobs */
+	if (upstart_get_all_jobs_sync (NULL, upstart, &job_class_paths) < 0) {
+		NihError *err;
+
+		err = nih_error_get ();
+		nih_fatal ("%s: %s", _("Could not obtain job list"),
+			   err->message);
+		nih_free (err);
+
+		exit (EXIT_FAILURE);
+	}
+
+	for (char **job_class_path = job_class_paths;
+	     job_class_path && *job_class_path; job_class_path++)
+		upstart_job_added (NULL, NULL, *job_class_path);
+
+	nih_free (job_class_paths);
+
+	/* Become daemon */
+	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.
+		 */
+
+		if (user_mode) {
+			/* Extract PID from UPSTART_SESSION */
+			user_session_path = nih_str_split (NULL, user_session_addr, "/", TRUE);
+			for (int i = 0; user_session_path[i] != NULL; i++)
+				path_element = user_session_path[i];
+
+			if (! path_element) {
+				nih_fatal (_("Invalid value for UPSTART_SESSION"));
+				exit (EXIT_FAILURE);
+			}
+
+			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-dbus-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 (EXIT_FAILURE);
+		}
+	}
+
+	/* 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));
+
+	if (! daemonise) {
+		nih_signal_set_handler (SIGINT, nih_signal_handler);
+		NIH_MUST (nih_signal_add_handler (NULL, SIGINT, nih_main_term_signal, NULL));
+	}
+
+	ret = nih_main_loop ();
+
+	/* Destroy any PID file we may have created */
+	if (daemonise) {
+		nih_main_unlink_pidfile();
+	}
+
+	return ret;
+}
+
+/**
+ * dbus_disconnected:
+ *
+ * @connection: connection to a D-Bus bus.
+ *
+ * Handler called when bridge disconnected from D-Bus.
+ **/
+static void
+dbus_disconnected (DBusConnection *connection)
+{
+	nih_fatal (_("Disconnected from D-Bus"));
+	nih_main_loop_exit (EXIT_FAILURE);
+}
+
+/**
+ * upstart_disconnected:
+ *
+ * @connection: connection to Upstart.
+ *
+ * Handler called when bridge disconnected from Upstart.
+ **/
+static void
+upstart_disconnected (DBusConnection *connection)
+{
+	nih_fatal (_("Disconnected from Upstart"));
+	nih_main_loop_exit (EXIT_FAILURE);
+}
+
+/**  
+ * NihOption setter function to handle selection of D-Bus bus type.
+ *
+ * Returns: 0 on success, -1 on invalid console type.
+ **/
+static int
+dbus_bus_setter (NihOption *option, const char *arg)
+{
+	nih_assert (option);
+	nih_assert (option->long_option);
+
+	if (! strcmp (option->long_option, "session")) {
+		dbus_bus = DBUS_BUS_SESSION;
+	} else {
+		dbus_bus = DBUS_BUS_SYSTEM;
+	}
+
+	return 0;
+}
+
+/**
+ * signal_filter:
+ * @connection: D-Bus connection,
+ * @message: D-Bus message,
+ * @user_data: unused.
+ *
+ * Handle D-Bus signal message by emitting an Upstart event
+ * containing pertinent details from the original message.
+ *
+ * Returns: DBUS_HANDLER_RESULT_HANDLED always.
+ **/
+static DBusHandlerResult
+signal_filter (DBusConnection  *connection,
+	       DBusMessage     *message,
+	       void            *user_data)
+{
+	int                 emit = FALSE;
+	DBusPendingCall    *pending_call;
+	DBusError           error;
+	nih_local char    **env = NULL;
+	const char         *sender;
+	const char         *destination;
+	const char         *interface;
+	const char         *signal;
+	const char         *path;
+	size_t              env_len = 0;
+
+	nih_assert (connection);
+	nih_assert (message);
+
+	if (! always) {
+		NIH_HASH_FOREACH (jobs, iter) {
+			emit = TRUE;
+			break;
+		}
+
+		/* No jobs care about DBUS_EVENT, so ignore it */
+		if (! emit)
+			goto out;
+	}
+
+	dbus_error_init (&error);
+
+	sender = dbus_message_get_sender (message);
+	signal = dbus_message_get_member (message);
+	interface = dbus_message_get_interface (message);
+	path = dbus_message_get_path (message);
+	destination = dbus_message_get_destination (message);
+
+	/* Don't react to D-Bus signals generated by Upstart
+	 * to avoid a possible feedback loop: for example, imagine a job
+	 * that emits an event when it detects (via this bridge) that
+	 * Upstart has emitted an event by considering Upstarts
+	 * "EventEmitted" D-Bus signal interface...
+	 */
+	if ((sender && ! strcmp (sender, DBUS_SERVICE_UPSTART)) ||
+	    (interface && ! strcmp (interface, DBUS_INTERFACE_UPSTART))) {
+		nih_debug ("ignoring signal originating from upstart itself");
+		goto out;
+	}
+
+	env = NIH_MUST (nih_str_array_new (NULL));
+
+	if (signal) {
+		nih_local char *var = NULL;
+		var = NIH_MUST (nih_sprintf (NULL, "SIGNAL=%s", signal));
+		NIH_MUST (nih_str_array_addp (&env, NULL, &env_len, var));
+	} else {
+		/* We need something to work with */
+		nih_debug ("Ignoring message with no signal name");
+		goto out;
+	}
+
+	if (interface) {
+		nih_local char *var = NULL;
+		var = NIH_MUST (nih_sprintf (NULL, "INTERFACE=%s", interface));
+		NIH_MUST (nih_str_array_addp (&env, NULL, &env_len, var));
+	}
+
+	if (path) {
+		nih_local char *var = NULL;
+		var = NIH_MUST (nih_sprintf (NULL, "PATH=%s", path));
+		NIH_MUST (nih_str_array_addp (&env, NULL, &env_len, var));
+	}
+
+	if (sender) {
+		nih_local char *var = NULL;
+		var = NIH_MUST (nih_sprintf (NULL, "SENDER=%s", sender));
+		NIH_MUST (nih_str_array_addp (&env, NULL, &env_len, var));
+	}
+
+	if (destination) {
+		nih_local char *var = NULL;
+		var = NIH_MUST (nih_sprintf (NULL, "DESTINATION=%s", destination));
+		NIH_MUST (nih_str_array_addp (&env, NULL, &env_len, var));
+	}
+
+	nih_debug ("Received D-Bus signal: %s "
+		   "(sender=%s, destination=%s, interface=%s, path=%s)",
+		   signal ? signal : "",
+		   sender ? sender : "",
+		   destination ? destination : "",
+		   interface ? interface : "",
+		   path ? path : "");
+
+	pending_call = upstart_emit_event (upstart,
+			DBUS_EVENT, env, FALSE,
+			NULL, emit_event_error, NULL,
+			NIH_DBUS_TIMEOUT_NEVER);
+
+	if (! pending_call) {
+		NihError *err;
+		err = nih_error_get ();
+		nih_warn ("%s", err->message);
+		nih_free (err);
+	}
+
+	dbus_pending_call_unref (pending_call);
+
+out:
+	return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static void
+emit_event_error (void            *data,
+		  NihDBusMessage  *message)
+{
+	NihError *err;
+
+	err = nih_error_get ();
+	nih_warn ("%s", err->message);
+	nih_free (err);
+}
+
+static void
+upstart_job_added (void            *data,
+		   NihDBusMessage  *message,
+		   const char      *job_class_path)
+{
+	/* set to TRUE if jobs start/stop conditions specify
+	 * DBUS_EVENT. Used to restrict emission of events
+	 * unnecessarily. Note that event environment matching
+	 * though is handled by Upstart.
+	 */
+	int                       add = FALSE;
+
+	Job                      *job;
+	nih_local NihDBusProxy   *job_class = NULL;
+	nih_local char         ***start_on = NULL;
+	nih_local char         ***stop_on = NULL;
+
+	nih_assert (job_class_path != NULL);
+
+	/* Obtain a proxy to the job */
+	job_class = nih_dbus_proxy_new (NULL, upstart->connection,
+					upstart->name, job_class_path,
+					NULL, NULL);
+	if (! job_class) {
+		NihError *err;
+
+		err = nih_error_get ();
+		nih_error ("Could not create proxy for job %s: %s",
+			   job_class_path, err->message);
+		nih_free (err);
+
+		return;
+	}
+
+	job_class->auto_start = FALSE;
+
+	/* Obtain the start_on and stop_on properties of the job */
+	if (job_class_get_start_on_sync (NULL, job_class, &start_on) < 0) {
+		NihError *err;
+
+		err = nih_error_get ();
+		nih_error ("Could not obtain job start condition %s: %s",
+			   job_class_path, err->message);
+		nih_free (err);
+
+		return;
+	}
+
+	if (job_class_get_stop_on_sync (NULL, job_class, &stop_on) < 0) {
+		NihError *err;
+
+		err = nih_error_get ();
+		nih_error ("Could not obtain job stop condition %s: %s",
+			   job_class_path, err->message);
+		nih_free (err);
+
+		return;
+	}
+
+	/* Find out whether this job listens for any DBUS events */
+	for (char ***event = start_on; event && *event && **event; event++)
+		if (! strcmp (**event, DBUS_EVENT)) {
+			add = TRUE;
+			break;
+		}
+
+	for (char ***event = stop_on; ! add && event && *event && **event; event++)
+		if (! strcmp (**event, DBUS_EVENT)) {
+			add = TRUE;
+			break;
+		}
+
+	if (! add)
+		return;
+
+	nih_debug ("Job got added %s for event %s", job_class_path, DBUS_EVENT);
+
+	/* Free any existing record for the job (should never happen,
+	 * but worth being safe).
+	 */
+	job = (Job *)nih_hash_lookup (jobs, job_class_path);
+	if (job)
+		nih_free (job);
+
+	/* 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);
+}
+
+static void
+upstart_job_removed (void            *data,
+		     NihDBusMessage  *message,
+		     const char      *job_path)
+{
+	Job *job;
+
+	nih_assert (job_path != NULL);
+
+	job = (Job *)nih_hash_lookup (jobs, job_path);
+	if (job) {
+		nih_debug ("Job went away %s", job_path);
+		nih_free (job);
+	}
+}
+

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

Reply via email to