Merge lp:~xnox/upstart/systemd-local-bridge into lp:ubuntu/vivid/upstart

Proposed by Dimitri John Ledkov
Status: Merged
Merged at revision: 1605
Proposed branch: lp:~xnox/upstart/systemd-local-bridge
Merge into: lp:ubuntu/vivid/upstart
Diff against target: 1265 lines (+636/-233) (has conflicts)
15 files modified
ChangeLog (+12/-0)
debian/changelog (+21/-1)
debian/control (+2/-2)
debian/rules (+0/-1)
debian/upstart-bin.install (+4/-0)
debian/upstart.install (+0/-4)
extra/Makefile.am (+40/-4)
extra/com.ubuntu.Upstart.xml (+29/-0)
extra/conf-session/upstart-udev-bridge.conf (+22/-0)
extra/conf/upstart-event-bridge.conf (+0/-15)
extra/org.freedesktop.systemd1.xml (+19/-0)
extra/upstart-event-bridge.c (+40/-4)
extra/upstart-local-bridge.c (+322/-181)
extra/upstart-udev-bridge.c (+63/-5)
util/telinit.c (+62/-16)
Text conflict in debian/changelog
To merge this branch: bzr merge lp:~xnox/upstart/systemd-local-bridge
Reviewer Review Type Date Requested Status
James Hunt Pending
Ubuntu branches Pending
Review via email: mp+246772@code.launchpad.net
To post a comment you must log in.
1599. By Dimitri John Ledkov

* debian/upstart-bin.upstart.cron.daily: Emit "rotate-logs" event direct
  into session init, by-passing system upstart & session
* extra/upstart-local-bridge: implement systemd pid1 logic.
* extra/upstart-event-bridge: make it re-emit upstart-local-bridge
  events direct.
* util/telinit: Revert to synchronous behaviour coupled with unavoidable
  poll to ensure telinit only returns once a re-exec has completed (LP:
  #901038).

1600. By Dimitri John Ledkov

Add control xml bindings.

1601. By Dimitri John Ledkov

Drop event-bridge

1602. By Dimitri John Ledkov

move udev & local bridges to upstart-bin package.

1603. By Dimitri John Ledkov

Drop local option, use systemd_booted detection instead.

1604. By Dimitri John Ledkov

releasing package upstart version 1.13.2-0ubuntu6

1605. By Dimitri John Ledkov

Correct upstart-udev-bridge session job start/stop on conditions.

Revision history for this message
Dimitri John Ledkov (xnox) wrote :

This merge proposal is in SILO 01

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'ChangeLog'
2--- ChangeLog 2014-09-04 11:29:54 +0000
3+++ ChangeLog 2015-01-17 15:39:44 +0000
4@@ -1,3 +1,15 @@
5+2014-09-08 James Hunt <james.hunt@ubuntu.com>
6+
7+ * util/telinit.c: Remove UPSTART_TELINIT_U_NO_WAIT check as it
8+ shouldn't realistically be needed.
9+
10+2014-08-21 James Hunt <james.hunt@ubuntu.com>
11+
12+ * util/telinit.c: restart_upstart():
13+ - Revert to synchronous behaviour coupled with unavoidable
14+ poll to ensure telinit only returns once a re-exec has
15+ completed (LP: #901038).
16+
17 2014-09-04 James Hunt <james.hunt@ubuntu.com>
18
19 * NEWS: Release 1.13.2
20
21=== modified file 'debian/changelog'
22--- debian/changelog 2015-01-16 19:15:46 +0000
23+++ debian/changelog 2015-01-17 15:39:44 +0000
24@@ -1,13 +1,33 @@
25+<<<<<<< TREE
26 upstart (1.13.2-0ubuntu6) UNRELEASED; urgency=medium
27
28 * debian/upstart-bin.upstart.cron.daily: Emit "rotate-logs" event direct
29 into session init, by-passing system upstart & session
30+=======
31+upstart (1.13.2-0ubuntu7) UNRELEASED; urgency=medium
32+
33+ * Correct upstart-udev-bridge session job start/stop on conditions.
34+
35+ -- Dimitri John Ledkov <dimitri.j.ledkov@linux.intel.com> Sat, 17 Jan 2015 15:38:35 +0000
36+
37+upstart (1.13.2-0ubuntu6) vivid; urgency=medium
38+
39+ * debian/upstart-bin.upstart.cron.daily: Emit "rotate-logs" event direct
40+ into session init, by-passing system upstart & session
41+>>>>>>> MERGE-SOURCE
42 event-bridge. This way session logs will be rotated, even upstart is
43 not system init.
44 * debian/control: make upstart-monitor & upstart-dconf-bridge be
45 installable with just session init, upstart-bin.
46+ * extra/upstart-local-bridge: implement systemd pid1 logic.
47+ * extra/upstart-event-bridge: make it re-emit upstart-local-bridge
48+ events direct.
49+ * util/telinit: Revert to synchronous behaviour coupled with unavoidable
50+ poll to ensure telinit only returns once a re-exec has completed (LP:
51+ #901038).
52+ * move udev & local bridges to upstart-bin package.
53
54- -- Dimitri John Ledkov <dimitri.j.ledkov@linux.intel.com> Sun, 11 Jan 2015 01:15:34 +0000
55+ -- Dimitri John Ledkov <dimitri.j.ledkov@linux.intel.com> Sat, 17 Jan 2015 01:59:42 +0000
56
57 upstart (1.13.2-0ubuntu5) vivid; urgency=medium
58
59
60=== modified file 'debian/control'
61--- debian/control 2015-01-11 01:19:24 +0000
62+++ debian/control 2015-01-17 15:39:44 +0000
63@@ -33,8 +33,8 @@
64 Architecture: any
65 Depends: ${shlibs:Depends}, ${misc:Depends}, sysvinit-utils, initscripts, libjson0 (>= 0.10-1.1ubuntu1), debianutils (>= 4)
66 Suggests: python3, graphviz, bash-completion, upstart-monitor
67-Replaces: upstart (<< 1.13.2-0ubuntu3)
68-Breaks: upstart (<< 1.13.2-0ubuntu3)
69+Replaces: upstart (<< 1.13.2-0ubuntu6)
70+Breaks: upstart (<< 1.13.2-0ubuntu6)
71 Multi-Arch: foreign
72 Description: event-based init daemon - essential binaries
73 upstart is a replacement for the /sbin/init daemon which handles
74
75=== modified file 'debian/rules'
76--- debian/rules 2014-11-19 11:52:17 +0000
77+++ debian/rules 2015-01-17 15:39:44 +0000
78@@ -52,7 +52,6 @@
79 install -m 644 debian/upstart-bin.apport \
80 debian/upstart-bin/usr/share/apport/package-hooks/source_upstart.py
81 rm debian/upstart-bin/usr/share/upstart/sessions/upstart-dconf-bridge.conf
82- rm debian/upstart/etc/init/upstart-event-bridge.conf
83 rm debian/upstart/etc/init/upstart-dbus-bridge.conf
84
85 override_dh_installcron:
86
87=== modified file 'debian/upstart-bin.install'
88--- debian/upstart-bin.install 2014-11-19 11:52:17 +0000
89+++ debian/upstart-bin.install 2015-01-17 15:39:44 +0000
90@@ -11,6 +11,8 @@
91 sbin/upstart-dbus-bridge
92 sbin/upstart-event-bridge
93 sbin/upstart-file-bridge
94+sbin/upstart-local-bridge
95+sbin/upstart-udev-bridge
96 debian/running-in-container bin/
97 debian/apparmor-profile-load lib/init/
98 usr/share/upstart/sessions/*
99@@ -31,6 +33,8 @@
100 usr/share/man/man8/upstart.8
101 usr/share/man/man8/upstart-file-bridge.8
102 usr/share/man/man8/upstart-dbus-bridge.8
103+usr/share/man/man8/upstart-local-bridge.8
104+usr/share/man/man8/upstart-udev-bridge.8
105 usr/share/man/man8/initctl2dot.8
106 usr/share/man/man8/initctl.8
107 usr/share/man/man5/upstart.5
108
109=== modified file 'debian/upstart.install'
110--- debian/upstart.install 2014-11-19 11:52:17 +0000
111+++ debian/upstart.install 2015-01-17 15:39:44 +0000
112@@ -6,9 +6,7 @@
113 sbin/reboot
114 sbin/runlevel
115 sbin/shutdown
116-sbin/upstart-local-bridge
117 sbin/upstart-socket-bridge
118-sbin/upstart-udev-bridge
119 debian/upstart-job lib/init/
120 debian/migrate-inittab.pl usr/lib/upstart/
121 usr/share/man/man7/control-alt-delete.7
122@@ -17,8 +15,6 @@
123 usr/share/man/man7/socket-event.7
124 usr/share/man/man7/power-status-changed.7
125 usr/share/man/man8/shutdown.8
126-usr/share/man/man8/upstart-local-bridge.8
127-usr/share/man/man8/upstart-udev-bridge.8
128 usr/share/man/man8/runlevel.8
129 usr/share/man/man8/reboot.8
130 usr/share/man/man8/upstart-socket-bridge.8
131
132=== modified file 'extra/Makefile.am'
133--- extra/Makefile.am 2013-11-14 17:41:01 +0000
134+++ extra/Makefile.am 2015-01-17 15:39:44 +0000
135@@ -23,6 +23,7 @@
136 conf-session/upstart-event-bridge.conf \
137 conf-session/upstart-file-bridge.conf \
138 conf-session/re-exec.conf \
139+ conf-session/upstart-udev-bridge.conf \
140 conf-session/upstart-dbus-session-bridge.conf \
141 conf-session/upstart-dbus-system-bridge.conf
142
143@@ -33,7 +34,6 @@
144
145 dist_init_DATA = \
146 conf/upstart-socket-bridge.conf \
147- conf/upstart-event-bridge.conf \
148 conf/upstart-file-bridge.conf \
149 conf/upstart-dbus-bridge.conf
150
151@@ -106,8 +106,9 @@
152 upstart_local_bridge_SOURCES = \
153 upstart-local-bridge.c
154 nodist_upstart_local_bridge_SOURCES = \
155+ $(org_freedesktop_systemd1_OUTPUTS) \
156 $(com_ubuntu_Upstart_OUTPUTS) \
157- $(com_ubuntu_Upstart_Job_OUTPUTS)
158+ $(control_com_ubuntu_Upstart_OUTPUTS)
159 upstart_local_bridge_LDADD = \
160 $(LTLIBINTL) \
161 $(NIH_LIBS) \
162@@ -224,15 +225,50 @@
163 --output=$@ $<
164
165
166+org_freedesktop_systemd1_OUTPUTS = \
167+ org.freedesktop.systemd1.c \
168+ org.freedesktop.systemd1.h
169+
170+org_freedesktop_systemd1_XML = \
171+ org.freedesktop.systemd1.xml
172+
173+$(org_freedesktop_systemd1_OUTPUTS): $(org_freedesktop_systemd1_XML)
174+ $(AM_V_GEN)$(NIH_DBUS_TOOL) \
175+ --package=$(PACKAGE) \
176+ --mode=proxy --prefix=systemd \
177+ --default-interface=org.freedesktop.systemd1.Manager \
178+ --output=$@ $<
179+
180+# Server for upstart-local-bridge
181+control_com_ubuntu_Upstart_OUTPUTS = \
182+ control_com.ubuntu.Upstart.c \
183+ control_com.ubuntu.Upstart.h
184+
185+control_com_ubuntu_Upstart_XML = \
186+ com.ubuntu.Upstart.xml
187+
188+$(control_com_ubuntu_Upstart_OUTPUTS): $(control_com_ubuntu_Upstart_XML)
189+ $(AM_V_GEN)$(NIH_DBUS_TOOL) \
190+ --package=$(PACKAGE) \
191+ --mode=object --prefix=control \
192+ --default-interface=com.ubuntu.Upstart0_6 \
193+ --output=$@ $<
194+
195+
196+
197 # These have to be built sources because we can't compile object files
198 # without the header file existing first
199 BUILT_SOURCES = \
200 $(com_ubuntu_Upstart_OUTPUTS) \
201- $(com_ubuntu_Upstart_Job_OUTPUTS)
202+ $(control_com_ubuntu_Upstart_OUTPUTS) \
203+ $(com_ubuntu_Upstart_Job_OUTPUTS) \
204+ $(org_freedesktop_systemd1_OUTPUTS)
205
206 CLEANFILES = \
207 $(com_ubuntu_Upstart_OUTPUTS) \
208- $(com_ubuntu_Upstart_Job_OUTPUTS)
209+ $(control_com_ubuntu_Upstart_OUTPUTS) \
210+ $(com_ubuntu_Upstart_Job_OUTPUTS) \
211+ $(org_freedesktop_systemd1_OUTPUTS)
212
213
214 clean-local:
215
216=== added file 'extra/com.ubuntu.Upstart.xml'
217--- extra/com.ubuntu.Upstart.xml 1970-01-01 00:00:00 +0000
218+++ extra/com.ubuntu.Upstart.xml 2015-01-17 15:39:44 +0000
219@@ -0,0 +1,29 @@
220+<?xml version="1.0" encoding="UTF-8" ?>
221+<!-- upstart
222+
223+ com.ubuntu.Upstart.xml - interface definition for manager object
224+
225+ Copyright © 2009 Canonical Ltd.
226+ Author: Scott James Remnant <scott@netsplit.com>.
227+
228+ This file is free software; Canonical Ltd gives unlimited permission
229+ to copy and/or distribute it, with or without modifications, as long
230+ as this notice is preserved.
231+
232+ Communication and interaction with Upstart through this interface is
233+ permitted without restriction.
234+ -->
235+
236+<!DOCTYPE node PUBLIC
237+ "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
238+ "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
239+
240+<node name="/com/ubuntu/Upstart">
241+ <interface name="com.ubuntu.Upstart0_6">
242+ <!-- Signal for events being emitted -->
243+ <signal name="EventEmitted">
244+ <arg name="name" type="s" />
245+ <arg name="env" type="as" />
246+ </signal>
247+ </interface>
248+</node>
249
250=== added file 'extra/conf-session/upstart-udev-bridge.conf'
251--- extra/conf-session/upstart-udev-bridge.conf 1970-01-01 00:00:00 +0000
252+++ extra/conf-session/upstart-udev-bridge.conf 2015-01-17 15:39:44 +0000
253@@ -0,0 +1,22 @@
254+# upstart-udev-bridge - Bridge udev events into session upstart
255+#
256+# This helper daemon receives udev events from the netlink socket and
257+# emits equivalent Upstart events.
258+
259+description "Bridge udev events into upstart"
260+
261+# From upstart-udev-bridge itself
262+emits *-device-added
263+emits *-device-removed
264+emits *-device-changed
265+# From http://www.kernel.org/pub/linux/utils/kernel/hotplug/libudev/libudev-udev-device.html
266+emits *-device-online
267+emits *-device-offline
268+
269+start on startup
270+stop on desktop-end
271+
272+expect daemon
273+respawn
274+
275+exec upstart-udev-bridge --daemon --user
276
277=== removed file 'extra/conf/upstart-event-bridge.conf'
278--- extra/conf/upstart-event-bridge.conf 2013-01-22 20:08:29 +0000
279+++ extra/conf/upstart-event-bridge.conf 1970-01-01 00:00:00 +0000
280@@ -1,15 +0,0 @@
281-# upstart-event-bridge - Bridge system upstarts events into session upstart
282-#
283-# This helper daemon receives system upstart events from the DBus system bus
284-# and emits equivalent events (with a :sys:) prefix to the session bus
285-
286-description "Bridge Upstart system events into session Upstart"
287-
288-emits :sys:*
289-
290-start on started dbus
291-stop on stopped dbus
292-
293-respawn
294-
295-exec upstart-event-bridge
296
297=== added file 'extra/org.freedesktop.systemd1.xml'
298--- extra/org.freedesktop.systemd1.xml 1970-01-01 00:00:00 +0000
299+++ extra/org.freedesktop.systemd1.xml 2015-01-17 15:39:44 +0000
300@@ -0,0 +1,19 @@
301+<?xml version="1.0" encoding="UTF-8" ?>
302+<!--
303+ org.freedesktop.systemd1- interface definition for systemd manager object
304+
305+ Public Domain
306+
307+ Generated file using gdbus introspect call against systemd1 instance
308+ -->
309+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
310+"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
311+<node>
312+ <interface name="org.freedesktop.systemd1.Manager">
313+ <method name="StartUnit">
314+ <arg name="name" type="s" direction="in"/>
315+ <arg name="mode" type="s" direction="in"/>
316+ <arg name="job" type="o" direction="out"/>
317+ </method>
318+ </interface>
319+</node>
320
321=== modified file 'extra/upstart-event-bridge.c'
322--- extra/upstart-event-bridge.c 2013-07-05 08:44:00 +0000
323+++ extra/upstart-event-bridge.c 2015-01-17 15:39:44 +0000
324@@ -26,6 +26,9 @@
325 #include <stdlib.h>
326 #include <string.h>
327 #include <ctype.h>
328+#include <sys/types.h>
329+#include <sys/stat.h>
330+#include <unistd.h>
331
332 #include <nih/macros.h>
333 #include <nih/alloc.h>
334@@ -42,8 +45,10 @@
335 #include "dbus/upstart.h"
336 #include "com.ubuntu.Upstart.h"
337
338+#define DBUS_ADDRESS_LOCAL "unix:abstract=/com/ubuntu/upstart/local/bridge"
339
340 /* Prototypes for static functions */
341+static int systemd_booted (void);
342 static void upstart_disconnected (DBusConnection *connection);
343 static void upstart_forward_event (void *data, NihDBusMessage *message,
344 const char *path);
345@@ -60,6 +65,14 @@
346 static int daemonise = FALSE;
347
348 /**
349+ * local:
350+ *
351+ * Set to TRUE if we should connect to upstart-local-bridge instead of
352+ * the system init.
353+ **/
354+static int local = FALSE;
355+
356+/**
357 * system_upstart:
358 *
359 * Proxy to system Upstart daemon.
360@@ -119,9 +132,14 @@
361 exit (1);
362 }
363
364+ local = systemd_booted ();
365+
366 /* Initialise the connection to system Upstart */
367- system_connection = NIH_SHOULD (nih_dbus_bus (DBUS_BUS_SYSTEM, upstart_disconnected));
368-
369+ if (local) {
370+ system_connection = NIH_SHOULD (nih_dbus_connect (DBUS_ADDRESS_LOCAL, upstart_disconnected));
371+ } else {
372+ system_connection = NIH_SHOULD (nih_dbus_bus (DBUS_BUS_SYSTEM, upstart_disconnected));
373+ }
374 if (! system_connection) {
375 NihError *err;
376
377@@ -134,7 +152,7 @@
378 }
379
380 system_upstart = NIH_SHOULD (nih_dbus_proxy_new (NULL, system_connection,
381- DBUS_SERVICE_UPSTART, DBUS_PATH_UPSTART,
382+ NULL, DBUS_PATH_UPSTART,
383 NULL, NULL));
384 if (! system_upstart) {
385 NihError *err;
386@@ -259,6 +277,20 @@
387 return ret;
388 }
389
390+static int
391+systemd_booted (void)
392+{
393+ struct stat st;
394+
395+ if (lstat ("/run/systemd/system/", &st) == 0) {
396+ if (S_ISDIR(st.st_mode)) {
397+ return TRUE;
398+ }
399+ }
400+
401+ return FALSE;
402+}
403+
404 static void
405 upstart_disconnected (DBusConnection *connection)
406 {
407@@ -293,7 +325,11 @@
408 nih_assert (event_name != NULL);
409
410 /* Build the new event name */
411- NIH_MUST (nih_strcat_sprintf (&new_event_name, NULL, ":sys:%s", event_name));
412+ if (local) {
413+ new_event_name = NIH_MUST (nih_strdup (NULL, event_name));
414+ } else {
415+ new_event_name = NIH_MUST (nih_sprintf (NULL, ":sys:%s", event_name));
416+ }
417
418 /* Re-transmit the event */
419 pending_call = upstart_emit_event (user_upstart,
420
421=== modified file 'extra/upstart-local-bridge.c'
422--- extra/upstart-local-bridge.c 2013-11-14 17:41:01 +0000
423+++ extra/upstart-local-bridge.c 2015-01-17 15:39:44 +0000
424@@ -22,10 +22,14 @@
425 #endif /* HAVE_CONFIG_H */
426
427 #include <sys/types.h>
428+#include <sys/stat.h>
429 #include <sys/socket.h>
430 #include <sys/un.h>
431+#include <sys/types.h>
432+#include <sys/wait.h>
433
434 #include <errno.h>
435+#include <stdio.h>
436 #include <stdlib.h>
437 #include <string.h>
438 #include <syslog.h>
439@@ -45,24 +49,17 @@
440
441 #include <nih-dbus/dbus_connection.h>
442 #include <nih-dbus/dbus_proxy.h>
443+#include <nih-dbus/dbus_object.h>
444
445 #include "dbus/upstart.h"
446 #include "com.ubuntu.Upstart.h"
447-#include "com.ubuntu.Upstart.Job.h"
448+#include "org.freedesktop.systemd1.h"
449+#include "control_com.ubuntu.Upstart.h"
450
451-/**
452- * Job:
453- *
454- * @entry: list header,
455- * @path: D-Bus path for a job.
456- *
457- * Representation of an Upstart Job.
458- *
459- **/
460-typedef struct job {
461- NihList entry;
462- char *path;
463-} Job;
464+#define DBUS_ADDRESS_SYSTEMD "unix:path=/run/systemd/private"
465+#define DBUS_PATH_SYSTEMD "/org/freedesktop/systemd1"
466+#define DBUS_SERVICE_SYSTEMD "org.freedesktop.systemd1"
467+#define DBUS_ADDRESS_LOCAL "unix:abstract=/com/ubuntu/upstart/local/bridge"
468
469 /**
470 * Socket:
471@@ -100,12 +97,14 @@
472 struct ucred ucred;
473 } ClientConnection;
474
475-static void upstart_job_added (void *data, NihDBusMessage *message,
476- const char *job);
477-static void upstart_job_removed (void *data, NihDBusMessage *message,
478- const char *job);
479 static void upstart_connect (void);
480-static void upstart_disconnected (DBusConnection *connection);
481+static void systemd_connect (void);
482+static int systemd_booted (void);
483+static int control_server_open (void);
484+static int control_server_connect (DBusServer *server,
485+ DBusConnection *conn);
486+static void control_disconnected (DBusConnection *conn);
487+static void init_disconnected (DBusConnection *connection);
488
489 static Socket *create_socket (void *parent);
490
491@@ -121,6 +120,8 @@
492
493 static void emit_event (ClientConnection *client, const char *pair, size_t len);
494
495+static void process_event (ClientConnection *client, const char *pair, size_t len);
496+
497 static void signal_handler (void *data, NihSignal *signal);
498
499 static void cleanup (void);
500@@ -134,13 +135,6 @@
501 static int daemonise = FALSE;
502
503 /**
504- * jobs:
505- *
506- * Jobs that we're monitoring.
507- **/
508-static NihHash *jobs = NULL;
509-
510-/**
511 * upstart:
512 *
513 * Proxy to Upstart daemon.
514@@ -148,9 +142,32 @@
515 static NihDBusProxy *upstart = NULL;
516
517 /**
518+ * systemd:
519+ *
520+ * Proxy to systemd daemon.
521+ **/
522+static NihDBusProxy *systemd = NULL;
523+
524+/**
525+ * control_server
526+ *
527+ * D-Bus server listening for new direct connections.
528+ **/
529+DBusServer *control_server = NULL;
530+
531+/**
532+ * control_conns:
533+ *
534+ * Open control connections, including the connection to a D-Bus
535+ * bus and any private client connections.
536+ **/
537+NihList *control_conns = NULL;
538+
539+/**
540 * event_name:
541 *
542- * Name of event this bridge emits.
543+ * upstart: Name of event this bridge emits.
544+ * systmed: Name of target this generator creates.
545 **/
546 static char *event_name = NULL;
547
548@@ -202,7 +219,7 @@
549 { 0, "daemon", N_("Detach and run in the background"),
550 NULL, NULL, &daemonise, NULL },
551
552- { 0, "event", N_("specify name of event to emit on receipt of name=value pair"),
553+ { 0, "event", N_("specify name of event to emit / target to generate on receipt of name=value pair"),
554 NULL, "EVENT", &event_name, NULL },
555
556 { 0, "any-user", N_("allow any user to connect"),
557@@ -258,7 +275,7 @@
558
559 nih_main_init (argv[0]);
560
561- nih_option_set_synopsis (_("Local socket Upstart Bridge"));
562+ nih_option_set_synopsis (_("Local socket Upstart Bridge & systemd generator"));
563 nih_option_set_help (
564 _("By default, this bridge does not detach from the "
565 "console and remains in the foreground. Use the --daemon "
566@@ -273,9 +290,6 @@
567 exit (1);
568 }
569
570- /* Allocate jobs hash table */
571- jobs = NIH_MUST (nih_hash_string_new (NULL, 0));
572-
573 sock = create_socket (NULL);
574 if (! sock) {
575 nih_fatal ("%s %s",
576@@ -286,7 +300,26 @@
577
578 nih_debug ("Connected to socket '%s' on fd %d", socket_name, sock->sock);
579
580- upstart_connect ();
581+ if (systemd_booted() == TRUE) {
582+ systemd_connect ();
583+ } else {
584+ upstart_connect ();
585+ }
586+
587+ control_conns = NIH_MUST (nih_list_new (NULL));
588+
589+ while ((ret = control_server_open ()) < 0) {
590+ NihError *err;
591+
592+ err = nih_error_get ();
593+ if (err->number != ENOMEM) {
594+ nih_warn ("%s: %s", _("Unable to listen for private"
595+ "connections"), err->message);
596+ nih_free (err);
597+ break;
598+ }
599+ nih_free (err);
600+ }
601
602 /* Become daemon */
603 if (daemonise) {
604@@ -326,103 +359,14 @@
605 return ret;
606 }
607
608-static void
609-upstart_job_added (void *data,
610- NihDBusMessage *message,
611- const char *job_class_path)
612-{
613- nih_local NihDBusProxy *job_class = NULL;
614- nih_local char ***start_on = NULL;
615- nih_local char ***stop_on = NULL;
616- Job *job;
617-
618- nih_assert (job_class_path != NULL);
619-
620- /* Obtain a proxy to the job */
621- job_class = nih_dbus_proxy_new (NULL, upstart->connection,
622- upstart->name, job_class_path,
623- NULL, NULL);
624- if (! job_class) {
625- NihError *err;
626-
627- err = nih_error_get ();
628- nih_error ("Could not create proxy for job %s: %s",
629- job_class_path, err->message);
630- nih_free (err);
631-
632- return;
633- }
634-
635- job_class->auto_start = FALSE;
636-
637- /* Obtain the start_on and stop_on properties of the job */
638- if (job_class_get_start_on_sync (NULL, job_class, &start_on) < 0) {
639- NihError *err;
640-
641- err = nih_error_get ();
642- nih_error ("Could not obtain job start condition %s: %s",
643- job_class_path, err->message);
644- nih_free (err);
645-
646- return;
647- }
648-
649- if (job_class_get_stop_on_sync (NULL, job_class, &stop_on) < 0) {
650- NihError *err;
651-
652- err = nih_error_get ();
653- nih_error ("Could not obtain job stop condition %s: %s",
654- job_class_path, err->message);
655- nih_free (err);
656-
657- return;
658- }
659-
660- /* Free any existing record for the job (should never happen,
661- * but worth being safe).
662- */
663- job = (Job *)nih_hash_lookup (jobs, job_class_path);
664- if (job)
665- nih_free (job);
666-
667- /* Create new record for the job */
668- job = NIH_MUST (nih_new (NULL, Job));
669- job->path = NIH_MUST (nih_strdup (job, job_class_path));
670-
671- nih_list_init (&job->entry);
672-
673- nih_debug ("Job got added %s", job_class_path);
674-
675- nih_alloc_set_destructor (job, nih_list_destroy);
676-
677- /* Add all jobs */
678- nih_hash_add (jobs, &job->entry);
679-}
680-
681-static void
682-upstart_job_removed (void *data,
683- NihDBusMessage *message,
684- const char *job_path)
685-{
686- Job *job;
687-
688- nih_assert (job_path != NULL);
689-
690- job = (Job *)nih_hash_lookup (jobs, job_path);
691- if (job) {
692- nih_debug ("Job went away %s", job_path);
693- nih_free (job);
694- }
695-}
696
697 static void
698 upstart_connect (void)
699 {
700 DBusConnection *connection;
701- char **job_class_paths;
702
703 /* Initialise the connection to Upstart */
704- connection = NIH_SHOULD (nih_dbus_connect (DBUS_ADDRESS_UPSTART, upstart_disconnected));
705+ connection = NIH_SHOULD (nih_dbus_connect (DBUS_ADDRESS_UPSTART, init_disconnected));
706 if (! connection) {
707 NihError *err;
708
709@@ -449,59 +393,169 @@
710 }
711
712 nih_debug ("Connected to Upstart");
713-
714- /* Connect signals to be notified when jobs come and go */
715- if (! nih_dbus_proxy_connect (upstart, &upstart_com_ubuntu_Upstart0_6, "JobAdded",
716- (NihDBusSignalHandler)upstart_job_added, NULL)) {
717- NihError *err;
718-
719- err = nih_error_get ();
720- nih_fatal ("%s: %s", _("Could not create JobAdded signal connection"),
721- err->message);
722- nih_free (err);
723-
724- exit (1);
725- }
726-
727- if (! nih_dbus_proxy_connect (upstart, &upstart_com_ubuntu_Upstart0_6, "JobRemoved",
728- (NihDBusSignalHandler)upstart_job_removed, NULL)) {
729- NihError *err;
730-
731- err = nih_error_get ();
732- nih_fatal ("%s: %s", _("Could not create JobRemoved signal connection"),
733- err->message);
734- nih_free (err);
735-
736- exit (1);
737- }
738-
739- /* Request a list of all current jobs */
740- if (upstart_get_all_jobs_sync (NULL, upstart, &job_class_paths) < 0) {
741- NihError *err;
742-
743- err = nih_error_get ();
744- nih_fatal ("%s: %s", _("Could not obtain job list"),
745- err->message);
746- nih_free (err);
747-
748- exit (1);
749- }
750-
751- for (char **job_class_path = job_class_paths;
752- job_class_path && *job_class_path; job_class_path++)
753- upstart_job_added (NULL, NULL, *job_class_path);
754-
755- nih_free (job_class_paths);
756-}
757-
758-static void
759-upstart_disconnected (DBusConnection *connection)
760-{
761- nih_fatal (_("Disconnected from Upstart"));
762+}
763+
764+static void
765+systemd_connect (void)
766+{
767+ DBusConnection *connection;
768+
769+ /* Initialise the connection to systemd */
770+ /* /run/systemd/private is supposedly "private" end-point
771+ * which systemctl & libsystemd use */
772+ connection = NIH_SHOULD (nih_dbus_connect (DBUS_ADDRESS_SYSTEMD, init_disconnected));
773+ if (! connection) {
774+ NihError *err;
775+
776+ err = nih_error_get ();
777+ nih_fatal ("%s: %s", _("Could not connect to systemd"),
778+ err->message);
779+ nih_free (err);
780+
781+ exit (1);
782+ }
783+
784+ systemd = NIH_SHOULD (nih_dbus_proxy_new (NULL, connection,
785+ NULL, DBUS_PATH_SYSTEMD,
786+ NULL, NULL));
787+ if (! systemd) {
788+ NihError *err;
789+
790+ err = nih_error_get ();
791+ nih_fatal ("%s: %s", _("Could not create systemd proxy"),
792+ err->message);
793+ nih_free (err);
794+
795+ exit (1);
796+ }
797+
798+ FILE *fp = NULL;
799+ nih_local char *template_name = NULL;
800+
801+ template_name = NIH_MUST (nih_sprintf (NULL, "/run/systemd/system/%s@.target", event_name));
802+
803+ fp = NIH_SHOULD (fopen(template_name, "we"));
804+ if (!fp) {
805+ nih_fatal ("%s %s", _("Failed to create target template"),
806+ strerror (errno));
807+ exit (1);
808+ }
809+ fprintf (fp,
810+ "# Automatically generated by %s\n\n"
811+ "[Unit]\n"
812+ "Description=Local bridge key value pairs\n"
813+ "Documentation=man:%s\n",
814+ program_name, program_name);
815+ fflush (fp);
816+ if (ferror (fp)) {
817+ nih_fatal ("%s %s", _("Failed to write target template"),
818+ strerror (errno));
819+ exit (1);
820+ }
821+ fclose (fp);
822+
823+ nih_debug ("Connected to systemd");
824+}
825+
826+static int
827+systemd_booted (void)
828+{
829+ struct stat st;
830+
831+ if (lstat ("/run/systemd/system/", &st) == 0) {
832+ if (S_ISDIR(st.st_mode)) {
833+ return TRUE;
834+ }
835+ }
836+
837+ return FALSE;
838+}
839+
840+static void
841+init_disconnected (DBusConnection *connection)
842+{
843+ nih_fatal (_("Disconnected from init"));
844 nih_main_loop_exit (1);
845 }
846
847 /**
848+ * control_server_open:
849+ *
850+ * Open a listening D-Bus server and store it in the control_server global.
851+ * New connections are permitted from the root user, and handled
852+ * automatically in the main loop.
853+ *
854+ * Returns: zero on success, negative value on raised error.
855+ **/
856+
857+int
858+control_server_open (void)
859+{
860+ nih_assert (control_server == NULL);
861+
862+ control_server = nih_dbus_server (DBUS_ADDRESS_LOCAL,
863+ control_server_connect,
864+ control_disconnected);
865+ if (! control_server)
866+ return -1;
867+
868+ nih_debug("D-Bus server started at address: %s", DBUS_ADDRESS_LOCAL);
869+
870+ return 0;
871+}
872+
873+/**
874+ * control_server_connect:
875+ *
876+ * Called when a new client connects to our server and is used to register
877+ * objects on the new connection.
878+ *
879+ * Returns: always TRUE.
880+ **/
881+static int
882+control_server_connect (DBusServer *server,
883+ DBusConnection *conn)
884+{
885+ nih_assert (server != NULL);
886+ nih_assert (server == control_server);
887+ nih_assert (conn != NULL);
888+ NihListEntry *entry = NULL;
889+
890+ /* Register objects on the connection. */
891+ NIH_MUST (nih_dbus_object_new (NULL, conn, DBUS_PATH_UPSTART,
892+ control_interfaces, NULL));
893+
894+
895+ entry = NIH_MUST (nih_list_entry_new (NULL));
896+ entry->data = conn;
897+ nih_list_add (control_conns, &entry->entry);
898+ nih_debug("Connection from private client");
899+
900+ return TRUE;
901+}
902+
903+/**
904+ * control_disconnected:
905+ *
906+ * This function is called when the connection to the D-Bus system bus,
907+ * or a client connection to our D-Bus server, is dropped and our reference
908+ * is about to be list. We clear the connection from our current list
909+ * and drop the control_bus global if relevant.
910+ **/
911+static void
912+control_disconnected (DBusConnection *conn)
913+{
914+ nih_assert (conn != NULL);
915+ /* Remove from the connections list */
916+ NIH_LIST_FOREACH_SAFE (control_conns, iter) {
917+ NihListEntry *entry = (NihListEntry *)iter;
918+
919+ if (entry->data == conn)
920+ nih_free (entry);
921+ }
922+}
923+
924+/**
925 * socket_watcher:
926 *
927 * @sock: Socket,
928@@ -645,7 +699,7 @@
929 if (used_len < min_len)
930 continue;
931
932- emit_event (client, pair, used_len);
933+ process_event (client, pair, used_len);
934 }
935
936 /* Consume the entire length */
937@@ -724,6 +778,8 @@
938 /* Handle abstract names */
939 if (sock->sun_addr.sun_path[0] == '@')
940 sock->sun_addr.sun_path[0] = '\0';
941+ else
942+ (void) unlink(sock->sun_addr.sun_path);
943
944 sock->sock = socket (sock->addr.sa_family, SOCK_STREAM, 0);
945 if (sock->sock < 0) {
946@@ -830,17 +886,102 @@
947 /* Add the name=value pair */
948 NIH_MUST (nih_str_array_addn (&env, NULL, NULL, pair, len));
949
950- pending_call = upstart_emit_event (upstart,
951- event_name, env, FALSE,
952- NULL, emit_event_error, NULL,
953- NIH_DBUS_TIMEOUT_NEVER);
954-
955- if (! pending_call) {
956+ if (upstart) {
957+ pending_call = upstart_emit_event (upstart,
958+ event_name, env, FALSE,
959+ NULL, emit_event_error, NULL,
960+ NIH_DBUS_TIMEOUT_NEVER);
961+
962+ if (! pending_call) {
963+ NihError *err;
964+ err = nih_error_get ();
965+ nih_warn ("%s", err->message);
966+ nih_free (err);
967+ }
968+
969+ dbus_pending_call_unref (pending_call);
970+ }
971+
972+ NIH_LIST_FOREACH (control_conns, iter) {
973+ NihListEntry *entry = (NihListEntry *)iter;
974+ DBusConnection *conn = (DBusConnection *)entry->data;
975+
976+ NIH_ZERO (control_emit_event_emitted (conn, DBUS_PATH_UPSTART,
977+ event_name, env));
978+ }
979+
980+}
981+
982+static void
983+systemd_launch_instance (ClientConnection *client,
984+ const char *pair,
985+ size_t len)
986+{
987+ nih_local char *safe_pair = NULL;
988+ nih_local char **key_value = NULL;
989+ nih_local char *group_name = NULL;
990+ nih_local char *unit_name = NULL;
991+ nih_local char *job_name = NULL;
992+
993+ nih_assert (client);
994+ nih_assert (pair);
995+ nih_assert (len);
996+
997+ /* Why is pair not null-terminated?! */
998+ safe_pair = NIH_MUST (nih_strndup (NULL, pair, len));
999+
1000+ /* Get key val from the key=val pair */
1001+ key_value = NIH_MUST (nih_str_split (NULL, safe_pair, "=", TRUE));
1002+
1003+ /* Construct systemd event@key=*.target group name */
1004+ group_name = NIH_MUST (nih_sprintf (NULL, "%s@%s=*.target",
1005+ event_name, key_value[0]));
1006+
1007+ /* Construct systemd event@key=value.target unit name */
1008+ unit_name = NIH_MUST (nih_sprintf (NULL, "%s@%s\\x3d%s.target",
1009+ event_name, key_value[0],
1010+ key_value[1]));
1011+
1012+ /* Stop group */
1013+ int pid = -1;
1014+ siginfo_t info;
1015+ do {
1016+ pid = fork ();
1017+ } while (pid < 0);
1018+
1019+ if (pid) {
1020+ info.si_code = 0;
1021+ info.si_status = 0;
1022+ if (waitid (P_PID, pid, &info, WEXITED)) {
1023+ nih_fatal ("%s %s", _("Failed to wait for systemctl"),
1024+ strerror (errno));
1025+ }
1026+ if (info.si_code != CLD_EXITED || info.si_status) {
1027+ nih_fatal ("Bad systemctl exit code %i and status %i\n", info.si_code, info.si_status);
1028+ }
1029+ } else {
1030+ /* Create and submit stop state transition, do not wait to complete */
1031+ execlp ("systemctl", "systemctl", "--no-block", "stop", group_name, (char *)NULL);
1032+ }
1033+
1034+ /* Create and submit start state transition, do not wait to complete */
1035+ if (systemd_start_unit_sync (NULL, systemd, unit_name, "replace", &job_name)) {
1036 NihError *err;
1037 err = nih_error_get ();
1038 nih_warn ("%s", err->message);
1039 nih_free (err);
1040 }
1041-
1042- dbus_pending_call_unref (pending_call);
1043+}
1044+
1045+
1046+static void
1047+process_event (ClientConnection *client,
1048+ const char *pair,
1049+ size_t len)
1050+{
1051+ emit_event (client, pair, len);
1052+
1053+ if (systemd) {
1054+ systemd_launch_instance (client, pair, len);
1055+ }
1056 }
1057
1058=== modified file 'extra/upstart-udev-bridge.c'
1059--- extra/upstart-udev-bridge.c 2013-10-18 15:02:34 +0000
1060+++ extra/upstart-udev-bridge.c 2015-01-17 15:39:44 +0000
1061@@ -69,6 +69,15 @@
1062 static NihDBusProxy *upstart = NULL;
1063
1064 /**
1065+ * user:
1066+ *
1067+ * If TRUE, run in User Session mode connecting to the Session Init
1068+ * rather than PID 1. In this mode, certain relative paths are also
1069+ * expanded.
1070+ **/
1071+static int user = FALSE;
1072+
1073+/**
1074 * no_strip_udev_data:
1075 *
1076 * If TRUE, do not modify any udev message data (old behaviour).
1077@@ -86,6 +95,8 @@
1078 NULL, NULL, &daemonise, NULL },
1079 { 0, "no-strip", N_("Do not strip non-printable bytes from udev message data"),
1080 NULL, NULL, &no_strip_udev_data, NULL },
1081+ { 0, "user", N_("Connect to user session"),
1082+ NULL, NULL, &user, NULL },
1083
1084 NIH_OPTION_LAST
1085 };
1086@@ -97,6 +108,11 @@
1087 {
1088 char ** args;
1089 DBusConnection * connection;
1090+ char * pidfile_path = NULL;
1091+ char * pidfile = NULL;
1092+ char *user_session_addr = NULL;
1093+ nih_local char ** user_session_path = NULL;
1094+ char * path_element = NULL;
1095 struct udev * udev;
1096 struct udev_monitor *udev_monitor;
1097 int ret;
1098@@ -113,8 +129,19 @@
1099 if (! args)
1100 exit (1);
1101
1102+ if (user) {
1103+ user_session_addr = getenv ("UPSTART_SESSION");
1104+ if (! user_session_addr) {
1105+ nih_fatal (_("UPSTART_SESSION isn't set in environment"));
1106+ exit (EXIT_FAILURE);
1107+ }
1108+ }
1109+
1110 /* Initialise the connection to Upstart */
1111- connection = NIH_SHOULD (nih_dbus_connect (DBUS_ADDRESS_UPSTART, upstart_disconnected));
1112+ connection = NIH_SHOULD (nih_dbus_connect (user
1113+ ? user_session_addr
1114+ : DBUS_ADDRESS_UPSTART,
1115+ upstart_disconnected));
1116 if (! connection) {
1117 NihError *err;
1118
1119@@ -153,6 +180,35 @@
1120
1121 /* Become daemon */
1122 if (daemonise) {
1123+ /* Deal with the pidfile location when becoming a daemon.
1124+ * We need to be able to run one bridge per upstart daemon.
1125+ * Store the PID file in XDG_RUNTIME_DIR or HOME and include the pid of
1126+ * the Upstart instance (last part of the DBus path) in the filename.
1127+ */
1128+
1129+ if (user) {
1130+ /* Extract PID from UPSTART_SESSION */
1131+ user_session_path = nih_str_split (NULL, user_session_addr, "/", TRUE);
1132+
1133+ for (int i = 0; user_session_path && user_session_path[i]; i++)
1134+ path_element = user_session_path[i];
1135+
1136+ if (! path_element) {
1137+ nih_fatal (_("Invalid value for UPSTART_SESSION"));
1138+ exit (1);
1139+ }
1140+
1141+ pidfile_path = getenv ("XDG_RUNTIME_DIR");
1142+ if (!pidfile_path)
1143+ pidfile_path = getenv ("HOME");
1144+
1145+ if (pidfile_path) {
1146+ NIH_MUST (nih_strcat_sprintf (&pidfile, NULL, "%s/%s.%s.pid",
1147+ pidfile_path, program_invocation_short_name, path_element));
1148+ nih_main_set_pidfile (pidfile);
1149+ }
1150+ }
1151+
1152 if (nih_main_daemonise () < 0) {
1153 NihError *err;
1154
1155@@ -163,10 +219,12 @@
1156
1157 exit (1);
1158 }
1159-
1160- /* Send all logging output to syslog */
1161- openlog (program_name, LOG_PID, LOG_DAEMON);
1162- nih_log_set_logger (nih_logger_syslog);
1163+
1164+ if (!user) {
1165+ /* Send all logging output to syslog for system bridge */
1166+ openlog (program_name, LOG_PID, LOG_DAEMON);
1167+ nih_log_set_logger (nih_logger_syslog);
1168+ }
1169 }
1170
1171 /* Handle TERM and INT signals gracefully */
1172
1173=== modified file 'util/telinit.c'
1174--- util/telinit.c 2014-03-10 13:43:50 +0000
1175+++ util/telinit.c 2015-01-17 15:39:44 +0000
1176@@ -160,27 +160,73 @@
1177 int
1178 restart_upstart (void)
1179 {
1180- nih_local NihDBusProxy *upstart = NULL;
1181- DBusPendingCall *ret;
1182+ nih_local NihDBusProxy *upstart = NULL;
1183+ NihError *err;
1184+ int ret;
1185
1186 upstart = upstart_open (NULL);
1187 if (! upstart)
1188 return -1;
1189
1190- /* Fire and forget:
1191- *
1192- * Ask Upstart to restart itself using the async interface to
1193- * avoid the client-side complaining if and when it detects that
1194- * Upstart has severed all connections to perform the re-exec.
1195- */
1196- ret = upstart_restart (upstart, NULL, NULL, NULL, 0);
1197- dbus_connection_flush(upstart->connection);
1198-
1199- /* We don't care about the return code, but we have to keep
1200- * the compiler happy.
1201- */
1202- if (ret != (DBusPendingCall *)TRUE)
1203- return 0;
1204+ /* Ask Upstart to restart itself.
1205+ *
1206+ * Since it is not possible to serialise a D-Bus connection,
1207+ * Upstart is forced to sever all D-Bus client connections,
1208+ * including this one.
1209+ *
1210+ * Further, since the user expects telinit to block _until the
1211+ * re-exec has finished and Upstart is accepting connections
1212+ * once again_, the only solution is to wait for the forced
1213+ * disconnect, then poll until it is possible to create a new
1214+ * connection.
1215+ *
1216+ * Note that we don't (can't) care about the return code since
1217+ * it's not reliable:
1218+ *
1219+ * - either the re-exec request completed and D-Bus returned zero
1220+ * before Upstart started the re-exec.
1221+ *
1222+ * - or the re-exec request completed but upstart started the
1223+ * re-exec (severing all D-Bus connections) before D-Bus got a
1224+ * chance to finish cleanly meaning we receive a return of -1.
1225+ *
1226+ * We cannot know exactly what happened so have to allow for
1227+ * both scenarios. Note the implicit assumption that the re-exec
1228+ * request itself was accepted. If this assumption is incorrect
1229+ * (should not be possible), the worst case scenario is that
1230+ * upstart does not re-exec and then we quickly drop out of the
1231+ * reconnect block since it never went offline.
1232+ */
1233+ ret = upstart_restart_sync (NULL, upstart);
1234+
1235+ if (ret < 0) {
1236+ err = nih_error_get ();
1237+ nih_free (err);
1238+ }
1239+
1240+ nih_free (upstart);
1241+
1242+ nih_debug ("Waiting for upstart to finish re-exec");
1243+
1244+ /* We believe Upstart is now in the process of
1245+ * re-exec'ing so attempt forever to reconnect.
1246+ *
1247+ * This sounds dangerous but there is no other option,
1248+ * and a connection must be possible unless the system
1249+ * is completely broken.
1250+ */
1251+ while (TRUE) {
1252+
1253+ upstart = upstart_open (NULL);
1254+ if (upstart)
1255+ break;
1256+
1257+ err = nih_error_get ();
1258+ nih_free (err);
1259+
1260+ /* Avoid DoS'ing the system whilst we wait */
1261+ usleep (100000);
1262+ }
1263
1264 return 0;
1265 }

Subscribers

People subscribed via source and target branches