Merge lp:~stgraber/upstart/upstart-make-event-bridge-usable into lp:upstart

Proposed by Stéphane Graber
Status: Merged
Merged at revision: 1430
Proposed branch: lp:~stgraber/upstart/upstart-make-event-bridge-usable
Merge into: lp:upstart
Diff against target: 168 lines (+58/-17)
2 files modified
extra/conf/upstart-event-bridge.conf (+1/-2)
extra/upstart-event-bridge.c (+57/-15)
To merge this branch: bzr merge lp:~stgraber/upstart/upstart-make-event-bridge-usable
Reviewer Review Type Date Requested Status
James Hunt Approve
Review via email: mp+144399@code.launchpad.net

Description of the change

This branch addresses a few problems with the current implementation of the
event bridge.

== PID file handling ==
In the past, when started with --daemon, nih would try to create a pidfile
under /run, which would obviously fail when running as a user.
The first change is to instead use XDG_RUNTIME_DIR or HOME as the preferred
location for the pidfile.

This brings us to the second problem with the pidfile. A single user may have
multiple upstart instances running at the same time, each of those would
require its own event bridge. So the pidfile can't be unique to the user.

This one was fixed in two ways:
 - upstart-event-bridge.conf no longer uses --daemon, so by default no pidfile
   will be created at all.
 - When called with --daemon, the pidfile now includes the PID of the upstart
   instance, taken from the value of UPSTART_SESSION (last field).

== DBus socket ==
When the event bridge was initially written, we didn't have a private socket
for the user instance, so the bridge was connecting to the DBus session bus.
However, we know have that private socket and no longer use the session bus by
default.

So this branch now changes the default bus from the session bus to the upstart
user session private bus.

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

* extra/upstart-event-bridge.c: main():
  - Looks like user_session_path should be nih_local, whilst path_element should just be 'char *'?
  - If $HOME is not set, we fail to start. That's probably reasonable though as we display a couple
    of errors in that scenario.

review: Needs Fixing
1432. By Stéphane Graber

Change which variables are nih_local and which aren't as that was resulting in segfaults when starting with --daemon.

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

> * extra/upstart-event-bridge.c: main():
> - Looks like user_session_path should be nih_local, whilst path_element
> should just be 'char *'?

Done. While testing that change, I also noticed a couple more that shouldn't be nih_local as they were causing segfaults in daemon mode. I didn't spot those earlier because I didn't think of running the daemon under strace to catch any potential segfault on exit of the child.

> - If $HOME is not set, we fail to start. That's probably reasonable though
> as we display a couple
> of errors in that scenario.

Right, the only other thing I could think of was trying to write in CWD but if HOME isn't set, it's fairly likely to be somewhere you can't write to anyway (or shouldn't at least).
The main problem here is that libnih doesn't let you use the daemonise function without also creating a pidfile.

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

> > - If $HOME is not set, we fail to start. That's probably reasonable though
> > as we display a couple
> > of errors in that scenario.
>
> Right, the only other thing I could think of was trying to write in CWD but if
> HOME isn't set, it's fairly likely to be somewhere you can't write to anyway
> (or shouldn't at least).
> The main problem here is that libnih doesn't let you use the daemonise
> function without also creating a pidfile.

Spam /tmp/ ?! or /run/upstart/ those should be writable.
Even to $HOMEless mere mortals.

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

/run/upstart shouldn't be user writable. /tmp should work but is really kind of wrong for a pidfile.
So I think I'll stick to the current implementation, which by the way doesn't prevent the daemon from starting at all, it just prints an extra error on the console and doesn't create the pidfile.

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

Agreed. LGTM - merged.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'extra/conf/upstart-event-bridge.conf'
2--- extra/conf/upstart-event-bridge.conf 2013-01-10 18:44:12 +0000
3+++ extra/conf/upstart-event-bridge.conf 2013-01-23 19:20:39 +0000
4@@ -10,7 +10,6 @@
5 start on started dbus
6 stop on stopped dbus
7
8-expect daemon
9 respawn
10
11-exec upstart-event-bridge --daemon
12+exec upstart-event-bridge
13
14=== modified file 'extra/upstart-event-bridge.c'
15--- extra/upstart-event-bridge.c 2012-12-19 17:02:33 +0000
16+++ extra/upstart-event-bridge.c 2013-01-23 19:20:39 +0000
17@@ -1,6 +1,6 @@
18 /* upstart
19 *
20- * Copyright © 2012 Canonical Ltd.
21+ * Copyright © 2012-2013 Canonical Ltd.
22 * Author: Stéphane Graber <stgraber@ubuntu.com>
23 *
24 * This program is free software; you can redistribute it and/or modify
25@@ -67,11 +67,11 @@
26 static NihDBusProxy *system_upstart = NULL;
27
28 /**
29- * session_upstart:
30+ * user_upstart:
31 *
32- * Proxy to session Upstart daemon.
33+ * Proxy to user Upstart daemon instance.
34 **/
35-static NihDBusProxy *session_upstart = NULL;
36+static NihDBusProxy *user_upstart = NULL;
37
38 /**
39 * options:
40@@ -92,13 +92,18 @@
41 {
42 char ** args;
43 DBusConnection * system_connection;
44- DBusConnection * session_connection;
45+ DBusConnection * user_connection;
46 int ret;
47+ char * pidfile_path = NULL;
48+ char * pidfile = NULL;
49+ char * user_session_addr = NULL;
50+ nih_local char ** user_session_path = NULL;
51+ char * path_element = NULL;
52
53
54 nih_main_init (argv[0]);
55
56- nih_option_set_synopsis (_("Bridge system upstart events into session upstart"));
57+ nih_option_set_synopsis (_("Bridge system upstart events into the user session upstart"));
58 nih_option_set_help (
59 _("By default, upstart-event-bridge does not detach from the "
60 "console and remains in the foreground. Use the --daemon "
61@@ -108,6 +113,12 @@
62 if (! args)
63 exit (1);
64
65+ user_session_addr = getenv ("UPSTART_SESSION");
66+ if (! user_session_addr) {
67+ nih_fatal (_("UPSTART_SESSION isn't set in environment"));
68+ exit (1);
69+ }
70+
71 /* Initialise the connection to system Upstart */
72 system_connection = NIH_SHOULD (nih_dbus_bus (DBUS_BUS_SYSTEM, upstart_disconnected));
73
74@@ -160,24 +171,24 @@
75 exit (1);
76 }
77
78- /* Initialise the connection to session Upstart */
79- session_connection = nih_dbus_bus (DBUS_BUS_SESSION, upstart_disconnected);
80+ /* Initialise the connection to user session Upstart */
81+ user_connection = NIH_SHOULD (nih_dbus_connect (user_session_addr, upstart_disconnected));
82
83- if (! session_connection) {
84+ if (! user_connection) {
85 NihError *err;
86
87 err = nih_error_get ();
88- nih_fatal ("%s: %s", _("Could not connect to session Upstart"),
89+ nih_fatal ("%s: %s", _("Could not connect to the user session Upstart"),
90 err->message);
91 nih_free (err);
92
93 exit (1);
94 }
95
96- session_upstart = NIH_SHOULD (nih_dbus_proxy_new (NULL, session_connection,
97- DBUS_SERVICE_UPSTART, DBUS_PATH_UPSTART,
98+ user_upstart = NIH_SHOULD (nih_dbus_proxy_new (NULL, user_connection,
99+ NULL, DBUS_PATH_UPSTART,
100 NULL, NULL));
101- if (! session_upstart) {
102+ if (! user_upstart) {
103 NihError *err;
104
105 err = nih_error_get ();
106@@ -190,6 +201,32 @@
107
108 /* Become daemon */
109 if (daemonise) {
110+ /* Deal with the pidfile location when becoming a daemon.
111+ * We need to be able to run one bridge per upstart daemon.
112+ * Store the PID file in XDG_RUNTIME_DIR or HOME and include the pid of
113+ * the Upstart instance (last part of the DBus path) in the filename.
114+ */
115+
116+ /* Extract PID from UPSTART_SESSION */
117+ user_session_path = nih_str_split (NULL, user_session_addr, "/", TRUE);
118+ for (int i = 0; user_session_path[i] != NULL; i++)
119+ path_element = user_session_path[i];
120+
121+ if (! path_element) {
122+ nih_fatal (_("Invalid value for UPSTART_SESSION"));
123+ exit (1);
124+ }
125+
126+ pidfile_path = getenv ("XDG_RUNTIME_DIR");
127+ if (!pidfile_path)
128+ pidfile_path = getenv ("HOME");
129+
130+ if (pidfile_path) {
131+ NIH_MUST (nih_strcat_sprintf (&pidfile, NULL, "%s/upstart-event-bridge.%s.pid",
132+ pidfile_path, path_element));
133+ nih_main_set_pidfile (pidfile);
134+ }
135+
136 if (nih_main_daemonise () < 0) {
137 NihError *err;
138
139@@ -213,6 +250,11 @@
140
141 ret = nih_main_loop ();
142
143+ /* Destroy any PID file we may have created */
144+ if (daemonise) {
145+ nih_main_unlink_pidfile();
146+ }
147+
148 return ret;
149 }
150
151@@ -253,7 +295,7 @@
152 NIH_MUST (nih_strcat_sprintf (&new_event_name, NULL, ":sys:%s", event_name));
153
154 /* Re-transmit the event */
155- pending_call = upstart_emit_event (session_upstart,
156+ pending_call = upstart_emit_event (user_upstart,
157 new_event_name, event_env, FALSE,
158 NULL, emit_event_error, NULL,
159 NIH_DBUS_TIMEOUT_NEVER);
160@@ -277,7 +319,7 @@
161 DBusPendingCall * pending_call;
162
163 /* Re-transmit the event */
164- pending_call = upstart_emit_event (session_upstart,
165+ pending_call = upstart_emit_event (user_upstart,
166 ":sys:restarted", NULL, FALSE,
167 NULL, emit_event_error, NULL,
168 NIH_DBUS_TIMEOUT_NEVER);

Subscribers

People subscribed via source and target branches