Merge authors: James Hunt (jamesodhunt) Stéphane Graber (stgraber) Thomas Bechtold (toabctl) Related merge proposals: https://code.launchpad.net/~jamesodhunt/upstart/upstart-dconf-bridge/+merge/177650 proposed by: James Hunt (jamesodhunt) ------------------------------------------------------------ revno: 1519 [merge] committer: Dmitrijs Ledkovs <[email protected]> branch nick: upstart timestamp: Wed 2013-08-21 14:40:13 +0100 message: Merge lp:~jamesodhunt/upstart/upstart-dconf-bridge added: extra/conf-session/upstart-dconf-bridge.conf extra/man/dconf-event.7 extra/man/upstart-dconf-bridge.8 extra/upstart-dconf-bridge.c modified: ChangeLog configure.ac 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-08-21 13:27:50 +0000 +++ ChangeLog 2013-08-21 13:40:13 +0000 @@ -2,9 +2,14 @@ * configure.ac: - Allow udev bridge to be disabled. - * extra/Makefile.am: Ensure source for upstart-udev-bridge is - distributed, regardless of whether the local system is able to build - it, or has disabled building it. + * extra/Makefile.am: + - Ensure source for upstart-udev-bridge is distributed, + regardless of whether the local system is able to build it, + or has disabled building it. + - Add missing DCONF_CFLAGS. + - Ensure upstart-dconf-bridge sources are always distributed, + regardless of whether the local system is able to build it, or has + disabled building it. 2013-08-06 James Hunt <[email protected]> @@ -39,6 +44,15 @@ * scripts/tests/test_pyupstart_session_init.py: Session tests extracted from python-upstart.py. * scripts/tests/test_pyupstart_system_init.py: New PID 1 tests. + * 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]> @@ -157,6 +171,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-08-15 09:51:55 +0000 +++ configure.ac 2013-08-15 13:37:43 +0000 @@ -30,7 +30,9 @@ 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]) AC_ARG_ENABLE([udev-bridge], AS_HELP_STRING([--disable-udev-bridge], @@ -39,6 +41,15 @@ AM_CONDITIONAL([ENABLE_UDEV_BRIDGE], [test "$have_udev" = yes && test "$udev_bridge" = 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-08-15 09:51:55 +0000 +++ extra/Makefile.am 2013-08-15 13:37:43 +0000 @@ -1,10 +1,14 @@ ## Process this file with automake to produce Makefile.in +# Required to allow conditional appends below +EXTRA_DIST = + AM_CFLAGS = \ $(NIH_CFLAGS) \ $(NIH_DBUS_CFLAGS) \ $(DBUS_CFLAGS) \ - $(UDEV_CFLAGS) + $(UDEV_CFLAGS) \ + $(DCONF_CFLAGS) AM_CPPFLAGS = \ -DLOCALEDIR="\"$(localedir)\"" \ @@ -102,6 +106,33 @@ $(NIH_DBUS_LIBS) \ $(DBUS_LIBS) +dist_sessions_DATA += \ + conf-session/upstart-dconf-bridge.conf + +dist_man_MANS += \ + man/upstart-dconf-bridge.8 \ + man/dconf-event.7 + +if ENABLE_DCONF_BRIDGE +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) +else +EXTRA_DIST += \ + upstart-dconf-bridge.c +endif + dist_init_DATA += \ conf/upstart-udev-bridge.conf @@ -136,7 +167,7 @@ done else -EXTRA_DIST = \ +EXTRA_DIST += \ upstart-udev-bridge.c \ man/upstart-udev-bridge.8 endif === 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 16:59:33 +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 16:26:44 +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 16:26:44 +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 16:26:44 +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
