Merge lp:~stgraber/upstart/upstart-events-bridge into lp:upstart

Proposed by Stéphane Graber
Status: Merged
Merged at revision: 1421
Proposed branch: lp:~stgraber/upstart/upstart-events-bridge
Merge into: lp:upstart
Diff against target: 444 lines (+405/-2)
4 files modified
extra/Makefile.am (+17/-2)
extra/conf/upstart-event-bridge.conf (+16/-0)
extra/man/upstart-event-bridge.8 (+68/-0)
extra/upstart-event-bridge.c (+304/-0)
To merge this branch: bzr merge lp:~stgraber/upstart/upstart-events-bridge
Reviewer Review Type Date Requested Status
James Hunt Approve
Review via email: mp+140693@code.launchpad.net

Description of the change

This introduces a new upstart-event-bridge, started once dbus is start in
the user session and which then relays events from the system upstart to the
session upstart.

Events are all prefixed with ":sys:" and a special even also exists for when
the system upstart is restarted (":sys:restarted").

Testing was only done with the current upstart listening to the session bus,
but it should still work fine once we have the full user session support
implemented.

To post a comment you must log in.
Revision history for this message
James Hunt (jamesodhunt) wrote :

* extra/man/upstart-event-bridge.8:
  - 'See events(7)' should be upstart-events(7).
  - Can you mention that this should (generally) run as a non-priv user, 1 per Session Init.
* extra/upstart-event-bridge.c: I'm wondering if we want to not forward output to syslog in the daemonise case? Users may prefer to have the output logged to ~/.cache/upstart/upstart-event-bridge.log.

1418. By Stéphane Graber

Update manpage

1419. By Stéphane Graber

Remove logging to syslog

Revision history for this message
James Hunt (jamesodhunt) wrote :

LGTM - merged.

review: Approve
Revision history for this message
Steve Langasek (vorlon) wrote :

On Wed, Dec 19, 2012 at 02:55:24PM -0000, Stéphane Graber wrote:
> This introduces a new upstart-event-bridge, started once dbus is start in
> the user session and which then relays events from the system upstart to the
> session upstart.

> Events are all prefixed with ":sys:" and a special even also exists for when
> the system upstart is restarted (":sys:restarted").

> Testing was only done with the current upstart listening to the session bus,
> but it should still work fine once we have the full user session support
> implemented.

What's the rationale for implementing this over the user dbus, instead of
having the user session's init process connecting to upstart directly? dbus
looks like needless indirection here to me.

Revision history for this message
Stéphane Graber (stgraber) wrote :

Because it's the only way to catch the Restarted event. If we connected to the upstart system socket instead (assuming we can as a user, haven't checked), we'd loose the connection and have to reconnect, most likely loosing the Restarted event in the process.

Revision history for this message
Steve Langasek (vorlon) wrote :

On Wed, Dec 19, 2012 at 06:03:28PM -0000, Stéphane Graber wrote:

> Because it's the only way to catch the Restarted event. If we connected to
> the upstart system socket instead (assuming we can as a user, haven't
> checked), we'd loose the connection and have to reconnect, most likely
> loosing the Restarted event in the process.

Sorry, what I meant was, why are we using dbus on the *user session* side?
The user session init should be able to connect directly to the system bus,
with no need for this separate bridge process that's dependent on having a
session bus running.

Revision history for this message
Stéphane Graber (stgraber) wrote :

Ah right, well, we figured it was the easiest way to implement it, would make it much easier to support scenario where we use upstart for the user session but not for the system itself (thinking of Debian there). I vaguely remember something else being mentioned, maybe James can refresh my memory there.

For the session bus, that part should be easy to improve by using upstart's own socket for the user session. This feature doesn't exist yet though so I could use it. It's on my todo for tomorrow, so after that I should be able to avoid using the session bus.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'extra/Makefile.am'
--- extra/Makefile.am 2011-06-06 15:49:43 +0000
+++ extra/Makefile.am 2012-12-19 17:07:26 +0000
@@ -17,13 +17,16 @@
1717
1818
19sbin_PROGRAMS = \19sbin_PROGRAMS = \
20 upstart-socket-bridge20 upstart-socket-bridge \
21 upstart-event-bridge
2122
22dist_init_DATA = \23dist_init_DATA = \
23 conf/upstart-socket-bridge.conf24 conf/upstart-socket-bridge.conf \
25 conf/upstart-event-bridge.conf
2426
25dist_man_MANS = \27dist_man_MANS = \
26 man/upstart-socket-bridge.8 \28 man/upstart-socket-bridge.8 \
29 man/upstart-event-bridge.8 \
27 man/socket-event.730 man/socket-event.7
2831
29upstart_socket_bridge_SOURCES = \32upstart_socket_bridge_SOURCES = \
@@ -37,6 +40,18 @@
37 $(NIH_DBUS_LIBS) \40 $(NIH_DBUS_LIBS) \
38 $(DBUS_LIBS)41 $(DBUS_LIBS)
3942
43upstart_event_bridge_SOURCES = \
44 upstart-event-bridge.c
45nodist_upstart_event_bridge_SOURCES = \
46 $(com_ubuntu_Upstart_OUTPUTS) \
47 $(com_ubuntu_Upstart_Job_OUTPUTS)
48upstart_event_bridge_LDADD = \
49 $(LTLIBINTL) \
50 $(NIH_LIBS) \
51 $(NIH_DBUS_LIBS) \
52 $(DBUS_LIBS)
53
54
4055
41if HAVE_UDEV56if HAVE_UDEV
42dist_init_DATA += \57dist_init_DATA += \
4358
=== added file 'extra/conf/upstart-event-bridge.conf'
--- extra/conf/upstart-event-bridge.conf 1970-01-01 00:00:00 +0000
+++ extra/conf/upstart-event-bridge.conf 2012-12-19 17:07:26 +0000
@@ -0,0 +1,16 @@
1# upstart-events-bridge - Bridge system upstarts events into session upstart
2#
3# This helper daemon receives system upstart events from the DBus system bus
4# and emits equivalent events (with a :sys:) prefix to the session bus
5
6description "Bridge Upstart system events into session Upstart"
7
8emits :sys:*
9
10start on started dbus
11stop on stopped dbus
12
13expect daemon
14respawn
15
16exec upstart-events-bridge --daemon
017
=== added file 'extra/man/upstart-event-bridge.8'
--- extra/man/upstart-event-bridge.8 1970-01-01 00:00:00 +0000
+++ extra/man/upstart-event-bridge.8 2012-12-19 17:07:26 +0000
@@ -0,0 +1,68 @@
1.TH upstart\-events\-bridge 8 2011-03-08 upstart
2.\"
3.SH NAME
4upstart\-events\-bridge \- Bridge between system Upstart and session Upstart
5.\"
6.SH SYNOPSIS
7.B upstart\-events\-bridge
8.RI [ OPTIONS ]...
9.\"
10.SH DESCRIPTION
11.B upstart\-events\-bridge
12receives information about Upstart system
13.BR events (8)
14have completed and creates Upstart session events for them.
15
16It emits events which match the pattern ":sys:*". Forwarding any event that's
17triggered on the system upstart as well as a virtual "restarted" event when
18upstart itself is restarted (during upgrades).
19
20See \fBupstart-events\fP(7) and for further details.
21
22This bridge should be run as a user, after the session bus has been setup and
23only once per session init.
24
25.\"
26.SH OPTIONS
27.\"
28.TP
29.B \-\-daemon
30Detach and run in the background.
31.\"
32.TP
33.B \-\-debug
34Enable debugging output.
35.\"
36.TP
37.B \-\-help
38Show brief usage summary.
39.\"
40.TP
41.B \-\-verbose
42Enable verbose output.
43.\"
44.SH EXAMPLES
45
46Some examples of Upstart events generated by this bridge:
47.IP :sys:restarted
48Event emitted when the system Upstart is restarted.
49.IP :sys:*
50Any event emitted on the system Upstart.
51.\"
52.SH AUTHOR
53Written by Stéphane Graber
54.RB < stgraber@ubuntu.com >
55.\"
56.SH BUGS
57Report bugs at
58.RB < https://launchpad.net/ubuntu/+source/upstart/+bugs >
59.\"
60.SH COPYRIGHT
61Copyright \(co 2012 Canonical Ltd.
62.PP
63This is free software; see the source for copying conditions. There is NO
64warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
65.SH SEE ALSO
66.BR init (5)
67.BR init (8)
68.BR events (7)
069
=== added file 'extra/upstart-event-bridge.c'
--- extra/upstart-event-bridge.c 1970-01-01 00:00:00 +0000
+++ extra/upstart-event-bridge.c 2012-12-19 17:07:26 +0000
@@ -0,0 +1,304 @@
1/* upstart
2 *
3 * Copyright © 2012 Canonical Ltd.
4 * Author: Stéphane Graber <stgraber@ubuntu.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2, as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20#ifdef HAVE_CONFIG_H
21# include <config.h>
22#endif /* HAVE_CONFIG_H */
23
24
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <ctype.h>
29
30#include <nih/macros.h>
31#include <nih/alloc.h>
32#include <nih/string.h>
33#include <nih/io.h>
34#include <nih/option.h>
35#include <nih/main.h>
36#include <nih/logging.h>
37#include <nih/error.h>
38
39#include <nih-dbus/dbus_connection.h>
40#include <nih-dbus/dbus_proxy.h>
41
42#include "dbus/upstart.h"
43#include "com.ubuntu.Upstart.h"
44
45
46/* Prototypes for static functions */
47static void upstart_disconnected (DBusConnection *connection);
48static void upstart_forward_event (void *data, NihDBusMessage *message,
49 const char *path);
50static void upstart_forward_restarted (void *data, NihDBusMessage *message,
51 const char *path);
52static void emit_event_error (void *data, NihDBusMessage *message);
53
54/**
55 * daemonise:
56 *
57 * Set to TRUE if we should become a daemon, rather than just running
58 * in the foreground.
59 **/
60static int daemonise = FALSE;
61
62/**
63 * system_upstart:
64 *
65 * Proxy to system Upstart daemon.
66 **/
67static NihDBusProxy *system_upstart = NULL;
68
69/**
70 * session_upstart:
71 *
72 * Proxy to session Upstart daemon.
73 **/
74static NihDBusProxy *session_upstart = NULL;
75
76/**
77 * options:
78 *
79 * Command-line options accepted by this program.
80 **/
81static NihOption options[] = {
82 { 0, "daemon", N_("Detach and run in the background"),
83 NULL, NULL, &daemonise, NULL },
84
85 NIH_OPTION_LAST
86};
87
88
89int
90main (int argc,
91 char *argv[])
92{
93 char ** args;
94 DBusConnection * system_connection;
95 DBusConnection * session_connection;
96 int ret;
97
98
99 nih_main_init (argv[0]);
100
101 nih_option_set_synopsis (_("Bridge system upstart events into session upstart"));
102 nih_option_set_help (
103 _("By default, upstart-event-bridge does not detach from the "
104 "console and remains in the foreground. Use the --daemon "
105 "option to have it detach."));
106
107 args = nih_option_parser (NULL, argc, argv, options, FALSE);
108 if (! args)
109 exit (1);
110
111 /* Initialise the connection to system Upstart */
112 system_connection = NIH_SHOULD (nih_dbus_bus (DBUS_BUS_SYSTEM, upstart_disconnected));
113
114 if (! system_connection) {
115 NihError *err;
116
117 err = nih_error_get ();
118 nih_fatal ("%s: %s", _("Could not connect to system Upstart"),
119 err->message);
120 nih_free (err);
121
122 exit (1);
123 }
124
125 system_upstart = NIH_SHOULD (nih_dbus_proxy_new (NULL, system_connection,
126 DBUS_SERVICE_UPSTART, DBUS_PATH_UPSTART,
127 NULL, NULL));
128 if (! system_upstart) {
129 NihError *err;
130
131 err = nih_error_get ();
132 nih_fatal ("%s: %s", _("Could not create Upstart proxy"),
133 err->message);
134 nih_free (err);
135
136 exit (1);
137 }
138
139 if (! nih_dbus_proxy_connect (system_upstart, &upstart_com_ubuntu_Upstart0_6, "EventEmitted",
140 (NihDBusSignalHandler)upstart_forward_event, NULL)) {
141 NihError *err;
142
143 err = nih_error_get ();
144 nih_fatal ("%s: %s", _("Could not create EventEmitted signal connection"),
145 err->message);
146 nih_free (err);
147
148 exit (1);
149 }
150
151 if (! nih_dbus_proxy_connect (system_upstart, &upstart_com_ubuntu_Upstart0_6, "Restarted",
152 (NihDBusSignalHandler)upstart_forward_restarted, NULL)) {
153 NihError *err;
154
155 err = nih_error_get ();
156 nih_fatal ("%s: %s", _("Could not create Restarted signal connection"),
157 err->message);
158 nih_free (err);
159
160 exit (1);
161 }
162
163 /* Initialise the connection to session Upstart */
164 session_connection = nih_dbus_bus (DBUS_BUS_SESSION, upstart_disconnected);
165
166 if (! session_connection) {
167 NihError *err;
168
169 err = nih_error_get ();
170 nih_fatal ("%s: %s", _("Could not connect to session Upstart"),
171 err->message);
172 nih_free (err);
173
174 exit (1);
175 }
176
177 session_upstart = NIH_SHOULD (nih_dbus_proxy_new (NULL, session_connection,
178 DBUS_SERVICE_UPSTART, DBUS_PATH_UPSTART,
179 NULL, NULL));
180 if (! session_upstart) {
181 NihError *err;
182
183 err = nih_error_get ();
184 nih_fatal ("%s: %s", _("Could not create Upstart proxy"),
185 err->message);
186 nih_free (err);
187
188 exit (1);
189 }
190
191 /* Become daemon */
192 if (daemonise) {
193 if (nih_main_daemonise () < 0) {
194 NihError *err;
195
196 err = nih_error_get ();
197 nih_fatal ("%s: %s", _("Unable to become daemon"),
198 err->message);
199 nih_free (err);
200
201 exit (1);
202 }
203 }
204
205 /* Handle TERM and INT signals gracefully */
206 nih_signal_set_handler (SIGTERM, nih_signal_handler);
207 NIH_MUST (nih_signal_add_handler (NULL, SIGTERM, nih_main_term_signal, NULL));
208
209 if (! daemonise) {
210 nih_signal_set_handler (SIGINT, nih_signal_handler);
211 NIH_MUST (nih_signal_add_handler (NULL, SIGINT, nih_main_term_signal, NULL));
212 }
213
214 ret = nih_main_loop ();
215
216 return ret;
217}
218
219static void
220upstart_disconnected (DBusConnection *connection)
221{
222 nih_fatal (_("Disconnected from Upstart"));
223 nih_main_loop_exit (1);
224}
225
226static void
227upstart_forward_event (void * data,
228 NihDBusMessage *message,
229 const char * path)
230{
231 char * event_name = NULL;
232 nih_local char * new_event_name = NULL;
233 char ** event_env = NULL;
234 int event_env_count = 0;
235 DBusError error;
236 DBusPendingCall * pending_call;
237
238 dbus_error_init (&error);
239
240 /* Extract information from the original event */
241 if (!dbus_message_get_args (message->message, &error,
242 DBUS_TYPE_STRING, &event_name,
243 DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &event_env, &event_env_count,
244 DBUS_TYPE_INVALID)) {
245 nih_error("DBUS error: %s", error.message);
246 dbus_error_free(&error);
247 return;
248 }
249
250 nih_assert (event_name != NULL);
251
252 /* Build the new event name */
253 NIH_MUST (nih_strcat_sprintf (&new_event_name, NULL, ":sys:%s", event_name));
254
255 /* Re-transmit the event */
256 pending_call = upstart_emit_event (session_upstart,
257 new_event_name, event_env, FALSE,
258 NULL, emit_event_error, NULL,
259 NIH_DBUS_TIMEOUT_NEVER);
260
261 if (! pending_call) {
262 NihError *err;
263 err = nih_error_get ();
264 nih_warn ("%s", err->message);
265 nih_free (err);
266 }
267
268 dbus_pending_call_unref (pending_call);
269 dbus_free_string_array (event_env);
270}
271
272static void
273upstart_forward_restarted (void * data,
274 NihDBusMessage *message,
275 const char * path)
276{
277 DBusPendingCall * pending_call;
278
279 /* Re-transmit the event */
280 pending_call = upstart_emit_event (session_upstart,
281 ":sys:restarted", NULL, FALSE,
282 NULL, emit_event_error, NULL,
283 NIH_DBUS_TIMEOUT_NEVER);
284
285 if (! pending_call) {
286 NihError *err;
287 err = nih_error_get ();
288 nih_warn ("%s", err->message);
289 nih_free (err);
290 }
291
292 dbus_pending_call_unref (pending_call);
293}
294
295static void
296emit_event_error (void * data,
297 NihDBusMessage *message)
298{
299 NihError *err;
300
301 err = nih_error_get ();
302 nih_warn ("%s", err->message);
303 nih_free (err);
304}

Subscribers

People subscribed via source and target branches