Merge lp:~jamesodhunt/upstart/upstart-dconf-bridge into lp:upstart

Proposed by James Hunt
Status: Merged
Merged at revision: 1519
Proposed branch: lp:~jamesodhunt/upstart/upstart-dconf-bridge
Merge into: lp:upstart
Diff against target: 922 lines (+826/-5)
7 files modified
ChangeLog (+46/-3)
configure.ac (+11/-0)
extra/Makefile.am (+33/-2)
extra/conf-session/upstart-dconf-bridge.conf (+10/-0)
extra/man/dconf-event.7 (+52/-0)
extra/man/upstart-dconf-bridge.8 (+66/-0)
extra/upstart-dconf-bridge.c (+608/-0)
To merge this branch: bzr merge lp:~jamesodhunt/upstart/upstart-dconf-bridge
Reviewer Review Type Date Requested Status
Upstart Reviewers Pending
Review via email: mp+177650@code.launchpad.net

Description of the change

New user bridge that emits Upstart events on dconf key changes.

To post a comment you must log in.
1472. By James Hunt

* extra/Makefile.am:
  - 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.

1473. By James Hunt

* Sync with lp:upstart.

1474. By James Hunt

* Sync with lp:upstart taking care to set extra/Makefile.am's EXTRA_DIST
  correctly.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'ChangeLog'
--- ChangeLog 2013-08-15 09:51:55 +0000
+++ ChangeLog 2013-08-15 13:38:35 +0000
@@ -2,9 +2,14 @@
22
3 * configure.ac:3 * configure.ac:
4 - Allow udev bridge to be disabled.4 - Allow udev bridge to be disabled.
5 * extra/Makefile.am: Ensure source for upstart-udev-bridge is5 * extra/Makefile.am:
6 distributed, regardless of whether the local system is able to build6 - Ensure source for upstart-udev-bridge is distributed,
7 it, or has disabled building it.7 regardless of whether the local system is able to build it,
8 or has disabled building it.
9 - Add missing DCONF_CFLAGS.
10 - Ensure upstart-dconf-bridge sources are always distributed,
11 regardless of whether the local system is able to build it, or has
12 disabled building it.
813
92013-07-31 James Hunt <james.hunt@ubuntu.com>142013-07-31 James Hunt <james.hunt@ubuntu.com>
1015
@@ -12,6 +17,18 @@
12 since the NIH main loop may be iterated once more before17 since the NIH main loop may be iterated once more before
13 shutdown.18 shutdown.
1419
202013-07-30 James Hunt <james.hunt@ubuntu.com>
21
22 * extra/man/dconf-event.7: New man page.
23 * extra/man/upstart-dconf-bridge.8: New man page.
24 * extra/upstart-dconf-bridge.c: Bridge will now only emit
25 events on dconf changes if any jobs care about them
26 (unless --always is specified).
27 * extra/conf-session/upstart-dconf-bridge.conf: Sample conf
28 file for dconf bridge.
29 * extra/Makefile.am: Added dconf bridge man pages and sample
30 conf to distribution.
31
152013-07-25 James Hunt <james.hunt@ubuntu.com>322013-07-25 James Hunt <james.hunt@ubuntu.com>
1633
17 * extra/Makefile.am: Renamed to upstart-local-bridge.34 * extra/Makefile.am: Renamed to upstart-local-bridge.
@@ -124,6 +141,32 @@
124 part of the earlier Session deserialisation. (LP: #1199778)141 part of the earlier Session deserialisation. (LP: #1199778)
125 * init/state.c: Formatting.142 * init/state.c: Formatting.
126143
1442013-07-09 James Hunt <james.hunt@ubuntu.com>
145
146 * {configure.ac,Makefile.am}: Allow upstart-dconf-bridge to be
147 disabled even if dependencies are available (--disable-dconf-bridge).
148 * extra/upstart-dconf-bridge.c: Changed event name to simply 'dconf'
149 with fixed first argument of 'TYPE=changed' for consistency with
150 other bridge events and to accommodate future dconf API changes.
151
1522013-07-08 James Hunt <james.hunt@ubuntu.com>
153
154 * extra/upstart-dconf-bridge.c: dconf_changed():
155 - Simplified logic after desrt clarified 'changed' signal
156 behaviour.
157
1582013-07-05 James Hunt <james.hunt@ubuntu.com>
159
160 * extra/upstart-dconf-bridge.c:
161 - Added DCONF_EVENT.
162 - Reformatted to be more consistent with other bridges.
163 - main():
164 - Connect to UPSTART_SESSION rather than D-Bus session bus.
165 - Handle generation of pidfile name.
166 - dconf_changed():
167 - Correct path logic and ensure that if the changes array contains
168 values that they are separated correctly from the prefix.
169
1272013-07-04 James Hunt <james.hunt@ubuntu.com>1702013-07-04 James Hunt <james.hunt@ubuntu.com>
128171
129 * NEWS: Release 1.9.1172 * NEWS: Release 1.9.1
130173
=== modified file 'configure.ac'
--- configure.ac 2013-08-15 09:51:55 +0000
+++ configure.ac 2013-08-15 13:38:35 +0000
@@ -30,7 +30,9 @@
30PKG_CHECK_MODULES([NIH], [libnih >= 1.0.2])30PKG_CHECK_MODULES([NIH], [libnih >= 1.0.2])
31PKG_CHECK_MODULES([NIH_DBUS], [libnih-dbus >= 1.0.0])31PKG_CHECK_MODULES([NIH_DBUS], [libnih-dbus >= 1.0.0])
32PKG_CHECK_MODULES([DBUS], [dbus-1 >= 1.2.16])32PKG_CHECK_MODULES([DBUS], [dbus-1 >= 1.2.16])
33PKG_CHECK_MODULES([GIO], [gio-2.0 >= 2.36], [have_gio=yes], [have_gio=no])
33PKG_CHECK_MODULES([UDEV], [libudev >= 146], [have_udev=yes], [have_udev=no])34PKG_CHECK_MODULES([UDEV], [libudev >= 146], [have_udev=yes], [have_udev=no])
35PKG_CHECK_MODULES([DCONF], [dconf >= 0.14], [have_dconf=yes], [have_dconf=no])
3436
35AC_ARG_ENABLE([udev-bridge],37AC_ARG_ENABLE([udev-bridge],
36 AS_HELP_STRING([--disable-udev-bridge],38 AS_HELP_STRING([--disable-udev-bridge],
@@ -39,6 +41,15 @@
3941
40AM_CONDITIONAL([ENABLE_UDEV_BRIDGE], [test "$have_udev" = yes && test "$udev_bridge" = yes])42AM_CONDITIONAL([ENABLE_UDEV_BRIDGE], [test "$have_udev" = yes && test "$udev_bridge" = yes])
4143
44AC_ARG_ENABLE([dconf-bridge],
45 AS_HELP_STRING([--disable-dconf-bridge],
46 [Disable building of upstart-dconf-bridge even if required dependencies available]),
47 [dconf_bridge=no], [dconf_bridge=yes])
48
49AM_CONDITIONAL([ENABLE_DCONF_BRIDGE], [test "$have_dconf" = yes &&
50 test "$have_gio" = yes &&
51 test "$dconf_bridge" = yes])
52
42# Reasons for requiring this library version:53# Reasons for requiring this library version:
43#54#
44# 1) RFC 4627, the JSON "memo" (it is *NOT* a standard!) helpfully fails55# 1) RFC 4627, the JSON "memo" (it is *NOT* a standard!) helpfully fails
4556
=== modified file 'extra/Makefile.am'
--- extra/Makefile.am 2013-08-15 09:51:55 +0000
+++ extra/Makefile.am 2013-08-15 13:38:35 +0000
@@ -1,10 +1,14 @@
1## Process this file with automake to produce Makefile.in1## Process this file with automake to produce Makefile.in
22
3# Required to allow conditional appends below
4EXTRA_DIST =
5
3AM_CFLAGS = \6AM_CFLAGS = \
4 $(NIH_CFLAGS) \7 $(NIH_CFLAGS) \
5 $(NIH_DBUS_CFLAGS) \8 $(NIH_DBUS_CFLAGS) \
6 $(DBUS_CFLAGS) \9 $(DBUS_CFLAGS) \
7 $(UDEV_CFLAGS)10 $(UDEV_CFLAGS) \
11 $(DCONF_CFLAGS)
812
9AM_CPPFLAGS = \13AM_CPPFLAGS = \
10 -DLOCALEDIR="\"$(localedir)\"" \14 -DLOCALEDIR="\"$(localedir)\"" \
@@ -102,6 +106,33 @@
102 $(NIH_DBUS_LIBS) \106 $(NIH_DBUS_LIBS) \
103 $(DBUS_LIBS)107 $(DBUS_LIBS)
104108
109dist_sessions_DATA += \
110 conf-session/upstart-dconf-bridge.conf
111
112dist_man_MANS += \
113 man/upstart-dconf-bridge.8 \
114 man/dconf-event.7
115
116if ENABLE_DCONF_BRIDGE
117sbin_PROGRAMS += \
118 upstart-dconf-bridge
119
120upstart_dconf_bridge_SOURCES = \
121 upstart-dconf-bridge.c
122nodist_upstart_dconf_bridge_SOURCES = \
123 $(com_ubuntu_Upstart_OUTPUTS)
124upstart_dconf_bridge_LDADD = \
125 $(LTLIBINTL) \
126 $(NIH_LIBS) \
127 $(NIH_DBUS_LIBS) \
128 $(DBUS_LIBS) \
129 $(GIO_LIBS) \
130 $(DCONF_LIBS)
131else
132EXTRA_DIST += \
133 upstart-dconf-bridge.c
134endif
135
105dist_init_DATA += \136dist_init_DATA += \
106 conf/upstart-udev-bridge.conf137 conf/upstart-udev-bridge.conf
107138
@@ -136,7 +167,7 @@
136 done167 done
137168
138else169else
139EXTRA_DIST = \170EXTRA_DIST += \
140 upstart-udev-bridge.c \171 upstart-udev-bridge.c \
141 man/upstart-udev-bridge.8172 man/upstart-udev-bridge.8
142endif173endif
143174
=== 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-08-15 13:38:35 +0000
@@ -0,0 +1,10 @@
1description "Bridge dconf events into session upstart"
2
3emits dconf
4
5start on started dbus
6stop on stopped dbus
7
8respawn
9
10exec upstart-dconf-bridge
011
=== 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-08-15 13:38:35 +0000
@@ -0,0 +1,52 @@
1.TH dconf\-event 7 2013-07-09 upstart
2.\"
3.SH NAME
4dconf \- event signalling that a dconf key has been changed
5.\"
6.SH SYNOPSIS
7.B dconf
8.BI TYPE\fR= changed
9.BI KEY\fR= KEY
10.BI VALUE\fR= VALUE
11.\"
12.SH DESCRIPTION
13
14The
15.B dconf
16event is generated by the
17.BR upstart\-dconf\-bridge (8)
18daemon when a dconf key changes whose details match the
19.I dconf
20event condition and environment specified in a job's
21.B start on
22or
23.B stop on
24stanza.
25
26.\"
27.SH EXAMPLES
28.\"
29.IP "start on dconf TYPE=changed KEY=/desktop/gnome/remote-access/notify-on-connect VALUE=true"
30
31Start job when the user allows remote access to their desktop.
32.\"
33.SH AUTHOR
34Written by James Hunt
35.RB < james.hunt@canonical.com >
36.\"
37.SH BUGS
38Report bugs at
39.RB < https://launchpad.net/upstart/+bugs >
40.\"
41.SH COPYRIGHT
42Copyright \(co 2013 Canonical Ltd.
43.PP
44This is free software; see the source for copying conditions. There is NO
45warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
46.\"
47.SH SEE ALSO
48.BR dconf (7)
49.BR gsettings (1)
50.BR init (5)
51.BR init (8)
52.BR upstart\-dconf\-bridge (8)
053
=== 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-08-15 13:38:35 +0000
@@ -0,0 +1,66 @@
1.TH upstart\-dconf\-bridge 8 2013-07-09 upstart
2.\"
3.SH NAME
4upstart\-dconf\-bridge \- Bridge between Upstart and dconf/gsettings
5.\"
6.SH SYNOPSIS
7.B upstart\-dconf\-bridge
8.RI [ OPTIONS ]...
9.\"
10.SH DESCRIPTION
11.B upstart\-dconf\-bridge
12receives information about dconf/gsettings changes
13and creates
14.BR init (8)
15events for them.
16
17With no options (and if there are jobs which have registered an interest
18in the event), monitors dconf changes and emits
19an Upstart event called
20.I dconf
21with details of the dconf change.
22
23See \fBdconf\fP(7) and for further details.
24
25.\"
26.SH OPTIONS
27.\"
28.TP
29.B \-\-always
30Always emit events on receipt of dconf changes regardless of whether jobs
31care about them.
32.TP
33.B \-\-daemon
34Detach and run in the background.
35.\"
36.TP
37.B \-\-debug
38Enable debugging output.
39.\"
40.TP
41.B \-\-help
42Show brief usage summary.
43.\"
44.TP
45.B \-\-verbose
46Enable verbose output.
47.\"
48.SH AUTHOR
49Written by James Hunt
50.RB < james.hunt@canonical.com >
51.\"
52.SH BUGS
53Report bugs at
54.RB < https://launchpad.net/ubuntu/+source/upstart/+bugs >
55.\"
56.SH COPYRIGHT
57Copyright \(co 2013 Canonical Ltd.
58.PP
59This is free software; see the source for copying conditions. There is NO
60warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
61.SH SEE ALSO
62.BR dconf (7)
63.BR dconf\-event (7)
64.BR gsettings (1)
65.BR init (5)
66.BR init (8)
067
=== 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-08-15 13:38:35 +0000
@@ -0,0 +1,608 @@
1/* upstart-dconf-bridge
2 *
3 * Copyright © 2012-2013 Canonical Ltd.
4 * Author: Stéphane Graber <stgraber@ubuntu.com>.
5 * Author: Thomas Bechtold <thomasbechtold@jpberlin.de>.
6 * Author: James Hunt <james.hunt@ubuntu.com>.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2, as
10 * published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 */
21
22#ifdef HAVE_CONFIG_H
23# include <config.h>
24#endif /* HAVE_CONFIG_H */
25
26#include <dconf.h>
27#include <gio/gio.h>
28
29#include <stdlib.h>
30#include <string.h>
31#include <syslog.h>
32#include <ctype.h>
33
34#include <nih/macros.h>
35#include <nih/alloc.h>
36#include <nih/string.h>
37#include <nih/hash.h>
38#include <nih/io.h>
39#include <nih/option.h>
40#include <nih/main.h>
41#include <nih/logging.h>
42#include <nih/error.h>
43
44#include <nih-dbus/dbus_connection.h>
45#include <nih-dbus/dbus_proxy.h>
46
47#include "dbus/upstart.h"
48#include "com.ubuntu.Upstart.h"
49#include "com.ubuntu.Upstart.Job.h"
50
51/**
52 * DCONF_EVENT:
53 *
54 * Name of event this program emits.
55 **/
56#define DCONF_EVENT "dconf"
57
58/* Prototypes for static functions */
59static void dconf_changed (DConfClient *client, const gchar *prefix,
60 const gchar * const *changes, const gchar *tag,
61 GDBusProxy *upstart);
62
63static void handle_upstart_job (GDBusProxy *proxy, gchar *sender_name,
64 gchar *signal_name, GVariant *parameters,
65 gpointer user_data);
66
67static int handle_existing_jobs (GDBusProxy *upstart_proxy)
68 __attribute__ ((warn_unused_result));
69
70static int job_needs_event (const char *object_path)
71 __attribute__ ((warn_unused_result));
72
73static int jobs_need_event (void)
74 __attribute__ ((warn_unused_result));
75
76/**
77 * Structure we use for tracking jobs
78 *
79 * @entry: list header,
80 * @path: D-Bus path of job being tracked.
81 **/
82typedef struct job {
83 NihList entry;
84 char *path;
85} Job;
86
87/**
88 * daemonise:
89 *
90 * Set to TRUE if we should become a daemon, rather than just running
91 * in the foreground.
92 **/
93static int daemonise = FALSE;
94
95/**
96 * always:
97 *
98 * If TRUE, always emit Upstart events, regardless of whether
99 * existing jobs care about DBUS_EVENT.
100 */
101static int always = FALSE;
102
103/**
104 * jobs:
105 *
106 * Jobs that we're monitoring.
107 **/
108static NihHash *jobs = NULL;
109
110/**
111 * connection:
112 *
113 * D-Bus connection to Upstart.
114 **/
115GDBusConnection *connection = NULL;
116
117/**
118 * options:
119 *
120 * Command-line options accepted by this program.
121 **/
122static NihOption options[] = {
123 { 0, "always", N_("Always emit an event on a dconf change"),
124 NULL, NULL, &always, NULL },
125 { 0, "daemon", N_("Detach and run in the background"),
126 NULL, NULL, &daemonise, NULL },
127 NIH_OPTION_LAST
128};
129
130int
131main (int argc,
132 char *argv[])
133{
134 char **args;
135 DConfClient *client;
136 GMainLoop *mainloop;
137 GDBusProxy *upstart_proxy;
138 GError *error = NULL;
139 char *user_session_addr = NULL;
140 nih_local char **user_session_path = NULL;
141 char *path_element = NULL;
142 char *pidfile_path = NULL;
143 char *pidfile = NULL;
144
145 client = dconf_client_new ();
146 mainloop = g_main_loop_new (NULL, FALSE);
147
148 /* Use NIH to parse the arguments */
149 nih_main_init (argv[0]);
150
151 nih_option_set_synopsis (_("Bridge dconf events into upstart"));
152 nih_option_set_help (
153 _("By default, upstart-dconf-bridge does not detach from the "
154 "console and remains in the foreground. Use the --daemon "
155 "option to have it detach."));
156
157 args = nih_option_parser (NULL, argc, argv, options, FALSE);
158 if (! args)
159 exit (1);
160
161 user_session_addr = getenv ("UPSTART_SESSION");
162 if (! user_session_addr) {
163 nih_fatal (_("UPSTART_SESSION isn't set in environment"));
164 exit (1);
165 }
166
167 /* Connect to the Upstart session */
168 connection = g_dbus_connection_new_for_address_sync (user_session_addr,
169 G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
170 NULL, /* GDBusAuthObserver*/
171 NULL, /* GCancellable */
172 &error);
173
174 if (! connection) {
175 g_error ("D-BUS Upstart session init error: %s",
176 (error && error->message) ? error->message : "Unknown error");
177 g_clear_error (&error);
178 exit (1);
179 }
180
181 /* Allocate jobs hash table */
182 jobs = NIH_MUST (nih_hash_string_new (NULL, 0));
183
184 /* Get an Upstart proxy object */
185 upstart_proxy = g_dbus_proxy_new_sync (connection,
186 G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
187 NULL, /* GDBusInterfaceInfo */
188 NULL, /* name */
189 "/com/ubuntu/Upstart",
190 "com.ubuntu.Upstart0_6",
191 NULL, /* GCancellable */
192 &error);
193
194 if (! upstart_proxy) {
195 g_error ("D-BUS Upstart proxy error: %s",
196 (error && error->message) ? error->message : "Unknown error");
197 g_clear_error (&error);
198 exit (1);
199 }
200
201 /* Connect signal to be notified when jobs come and go */
202 g_signal_connect (upstart_proxy, "g-signal", (GCallback) handle_upstart_job, NULL);
203
204 if (! handle_existing_jobs (upstart_proxy))
205 exit (1);
206
207 if (daemonise) {
208 /* Deal with the pidfile location when becoming a daemon.
209 * We need to be able to run one bridge per upstart daemon.
210 * Store the PID file in XDG_RUNTIME_DIR or HOME and include the pid of
211 * the Upstart instance (last part of the DBus path) in the filename.
212 */
213
214 /* Extract PID from UPSTART_SESSION */
215 user_session_path = nih_str_split (NULL, user_session_addr, "/", TRUE);
216
217 for (int i = 0; user_session_path && user_session_path[i]; i++)
218 path_element = user_session_path[i];
219
220 if (! path_element) {
221 nih_fatal (_("Invalid value for UPSTART_SESSION"));
222 exit (1);
223 }
224
225 pidfile_path = getenv ("XDG_RUNTIME_DIR");
226 if (!pidfile_path)
227 pidfile_path = getenv ("HOME");
228
229 if (pidfile_path) {
230 NIH_MUST (nih_strcat_sprintf (&pidfile, NULL,
231 "%s/upstart-dconf-bridge.%s.pid",
232 pidfile_path, path_element));
233 nih_main_set_pidfile (pidfile);
234 }
235
236 if (nih_main_daemonise () < 0) {
237 NihError *err;
238
239 err = nih_error_get ();
240 nih_fatal ("%s: %s", _("Unable to become daemon"),
241 err->message);
242 nih_free (err);
243
244 exit (1);
245 }
246 }
247
248 /* Handle TERM and INT signals gracefully */
249 nih_signal_set_handler (SIGTERM, nih_signal_handler);
250 NIH_MUST (nih_signal_add_handler (NULL, SIGTERM, nih_main_term_signal, NULL));
251
252 /* Listen for any dconf change */
253 g_signal_connect (client, "changed", (GCallback) dconf_changed, upstart_proxy);
254 dconf_client_watch_sync (client, "/");
255
256 /* Start the glib mainloop */
257 g_main_loop_run (mainloop);
258
259 g_object_unref (client);
260 g_object_unref (upstart_proxy);
261 g_object_unref (connection);
262 g_main_loop_unref (mainloop);
263
264 exit (0);
265}
266
267/**
268 * handle_upstart_job:
269 *
270 * Called when an Upstart D-Bus signal is emitted.
271 **/
272static void
273handle_upstart_job (GDBusProxy *proxy,
274 gchar *sender_name,
275 gchar *signal_name,
276 GVariant *parameters,
277 gpointer user_data)
278{
279 GVariantIter iter;
280 GVariant *child;
281 const gchar *job_class_path;
282 Job *job;
283 int add;
284
285 nih_assert (signal_name);
286 nih_assert (parameters);
287 nih_assert (jobs);
288
289 if (! strcmp (signal_name, "JobAdded")) {
290 add = 1;
291 } else if (! strcmp (signal_name, "JobRemoved")) {
292 add = 0;
293 } else {
294 return;
295 }
296
297 nih_assert (g_variant_is_of_type (parameters, G_VARIANT_TYPE_TUPLE));
298
299 g_variant_iter_init (&iter, parameters);
300
301 nih_assert (g_variant_iter_n_children (&iter) == 1);
302
303 child = g_variant_iter_next_value (&iter);
304
305 job_class_path = g_variant_get_string (child, NULL);
306 nih_assert (g_variant_is_object_path (job_class_path));
307
308 /* Free any existing record for the job if we are adding
309 * (should never happen, but worth being safe).
310 */
311 job = (Job *)nih_hash_lookup (jobs, job_class_path);
312 if (job)
313 nih_free (job);
314
315 /* Job isn't interested in DCONF_EVENT */
316 if (add && ! job_needs_event (job_class_path))
317 goto out;
318
319 if (add)
320 nih_debug ("Job got added %s for event %s", job_class_path, DCONF_EVENT);
321 else
322 nih_debug ("Job went away %s", job_class_path);
323
324 /* We're removing, so job done */
325 if (! add)
326 goto out;
327
328 /* Create new record for the job */
329 job = NIH_MUST (nih_new (NULL, Job));
330 job->path = NIH_MUST (nih_strdup (job, job_class_path));
331
332 nih_list_init (&job->entry);
333 nih_alloc_set_destructor (job, nih_list_destroy);
334 nih_hash_add (jobs, &job->entry);
335
336out:
337 g_variant_unref (child);
338}
339
340/**
341 * dconf_changed:
342 *
343 * Emit an Upstart event corresponding to a dconf key change.
344 **/
345static void
346dconf_changed (DConfClient *client,
347 const gchar *prefix,
348 const gchar * const *changes,
349 const gchar *tag,
350 GDBusProxy *upstart)
351{
352 GVariant *value;
353 gchar *value_str = NULL;
354 gchar *path = NULL;
355 gchar *env_key = NULL;
356 gchar *env_value = NULL;
357 GVariant *event;
358 GVariantBuilder builder;
359 int i = 0;
360
361 /* dconf currently only currently supports the changed signal,
362 * but parameterise to allow for a future API change.
363 */
364 const gchar *event_type = "TYPE=changed";
365
366 if (! jobs_need_event () && ! always)
367 return;
368
369 /* Iterate through the various changes */
370 while (changes[i] != NULL) {
371 path = g_strconcat (prefix, changes[i], NULL);
372
373 value = dconf_client_read (client, path);
374 value_str = g_variant_print (value, FALSE);
375
376 env_key = g_strconcat ("KEY=", path, NULL);
377 env_value = g_strconcat ("VALUE=", value_str, NULL);
378
379 /* Build event environment as GVariant */
380 g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
381
382 g_variant_builder_add (&builder, "s", DCONF_EVENT);
383
384 g_variant_builder_open (&builder, G_VARIANT_TYPE_ARRAY);
385 g_variant_builder_add (&builder, "s", event_type);
386 g_variant_builder_add (&builder, "s", env_key);
387 g_variant_builder_add (&builder, "s", env_value);
388 g_variant_builder_close (&builder);
389
390 g_variant_builder_add (&builder, "b", FALSE);
391 event = g_variant_builder_end (&builder);
392
393 /* Send the event */
394 g_dbus_proxy_call (upstart,
395 "EmitEvent",
396 event,
397 G_DBUS_CALL_FLAGS_NONE,
398 -1,
399 NULL,
400 NULL, /* GAsyncReadyCallback
401 we don't care about the answer */
402 NULL);
403
404 g_variant_builder_clear (&builder);
405 g_variant_unref (value);
406 g_free (path);
407 g_free (value_str);
408 g_free (env_key);
409 g_free (env_value);
410
411 i += 1;
412 }
413}
414
415/**
416 * jobs_need_event:
417 *
418 * Returns: TRUE if any jobs need DCONF_EVENT, else FALSE.
419 **/
420static int
421jobs_need_event (void)
422{
423 NIH_HASH_FOREACH (jobs, iter) {
424 return TRUE;
425 }
426
427 return FALSE;
428}
429
430/**
431 * job_needs_event:
432 * @object_path: Full D-Bus object path for job.
433 *
434 * Returns: TRUE if job specified by @object_path specifies DCONF_EVENT
435 * in its 'start on' or 'stop on' stanza, else FALSE.
436 **/
437static int
438job_needs_event (const char *class_path)
439{
440 GDBusProxy *job_proxy;
441 GError *error = NULL;
442 GVariantIter iter;
443 const gchar *event_name;
444 int ret = FALSE;
445
446 /* Arrays of arrays of strings (aas) */
447 GVariant *start_on = NULL;
448 GVariant *stop_on = NULL;
449
450 /* Array containing event name and optional environment
451 * variable elements.
452 */
453 GVariant *event_element;
454
455 /* Either an event name or "/AND" or "/OR" */
456 GVariant *event;
457
458 nih_assert (class_path);
459
460 job_proxy = g_dbus_proxy_new_sync (connection,
461 G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
462 NULL, /* GDBusInterfaceInfo */
463 NULL, /* name */
464 class_path,
465 "com.ubuntu.Upstart0_6.Job",
466 NULL, /* GCancellable */
467 &error);
468
469 start_on = g_dbus_proxy_get_cached_property (job_proxy, "start_on");
470 nih_assert (g_variant_is_of_type (start_on, G_VARIANT_TYPE_ARRAY));
471
472 g_variant_iter_init (&iter, start_on);
473
474 while ((event_element = g_variant_iter_next_value (&iter))) {
475 nih_assert (g_variant_is_of_type (event_element, G_VARIANT_TYPE_ARRAY));
476
477 /* First element is always the event name */
478 event = g_variant_get_child_value (event_element, 0);
479 nih_assert (g_variant_is_of_type (event, G_VARIANT_TYPE_STRING));
480
481 event_name = g_variant_get_string (event, NULL);
482
483 if (! strcmp (event_name, DCONF_EVENT))
484 ret = TRUE;
485
486 g_variant_unref (event_element);
487 g_variant_unref (event);
488
489 if (ret)
490 goto out;
491 }
492
493 /* Now handle stop on */
494 stop_on = g_dbus_proxy_get_cached_property (job_proxy, "stop_on");
495 nih_assert (g_variant_is_of_type (stop_on, G_VARIANT_TYPE_ARRAY));
496
497 g_variant_iter_init (&iter, stop_on);
498
499 while ((event_element = g_variant_iter_next_value (&iter))) {
500 nih_assert (g_variant_is_of_type (event_element, G_VARIANT_TYPE_ARRAY));
501
502 /* First element is always the event name */
503 event = g_variant_get_child_value (event_element, 0);
504 nih_assert (g_variant_is_of_type (event, G_VARIANT_TYPE_STRING));
505
506 event_name = g_variant_get_string (event, NULL);
507
508 if (! strcmp (event_name, DCONF_EVENT))
509 ret = TRUE;
510
511 g_variant_unref (event_element);
512 g_variant_unref (event);
513
514 if (ret)
515 goto out;
516 }
517
518out:
519 if (start_on)
520 g_variant_unref (start_on);
521
522 if (stop_on)
523 g_variant_unref (stop_on);
524
525 g_object_unref (job_proxy);
526
527 return ret;
528}
529
530/**
531 * handle_existing_jobs:
532 *
533 * @upstart_proxy: Upstart proxy.
534 *
535 * Add all existing jobs which specify DCONF_EVENT to the list
536 * of tracked jobs.
537 *
538 * Returns: TRUE or FALSE on error.
539 **/
540static int
541handle_existing_jobs (GDBusProxy *upstart_proxy)
542{
543 GVariant *result;
544 GVariant *child;
545 GVariant *proxy_job;
546 const gchar *job_class_path;
547 GError *error = NULL;
548 GVariantIter iter;
549 Job *job;
550
551 nih_assert (upstart_proxy);
552
553 result = g_dbus_proxy_call_sync (upstart_proxy,
554 "GetAllJobs",
555 NULL,
556 G_DBUS_CALL_FLAGS_NO_AUTO_START,
557 -1,
558 NULL,
559 &error);
560
561 if (! result) {
562 g_error ("D-BUS Upstart proxy error: %s",
563 (error && error->message)
564 ? error->message
565 : "Unknown error");
566 g_clear_error (&error);
567 return FALSE;
568 }
569
570 nih_assert (g_variant_is_of_type (result, G_VARIANT_TYPE_TUPLE));
571 nih_assert (g_variant_n_children (result) == 1);
572
573 child = g_variant_get_child_value (result, 0);
574
575 nih_assert (g_variant_is_of_type (child, G_VARIANT_TYPE_OBJECT_PATH_ARRAY));
576
577 g_variant_iter_init (&iter, child);
578
579 while ((proxy_job = g_variant_iter_next_value (&iter))) {
580 job_class_path = g_variant_get_string (proxy_job, NULL);
581
582 /* Free any existing record for the job if we are adding
583 * (should never happen, but worth being safe).
584 */
585 job = (Job *)nih_hash_lookup (jobs, job_class_path);
586 if (job)
587 nih_free (job);
588
589 if (job_needs_event (job_class_path)) {
590 /* Create new record for the job */
591 job = NIH_MUST (nih_new (NULL, Job));
592 job->path = NIH_MUST (nih_strdup (job, job_class_path));
593
594 nih_list_init (&job->entry);
595 nih_alloc_set_destructor (job, nih_list_destroy);
596 nih_hash_add (jobs, &job->entry);
597
598 nih_debug ("Job added %s for event %s", job_class_path, DCONF_EVENT);
599 }
600
601 g_variant_unref (proxy_job);
602 }
603
604 g_variant_unref (child);
605 g_variant_unref (result);
606
607 return TRUE;
608}

Subscribers

People subscribed via source and target branches