Merge lp:~jamesodhunt/upstart/upstream-socket-bridge into lp:upstart

Proposed by James Hunt
Status: Merged
Merged at revision: 1307
Proposed branch: lp:~jamesodhunt/upstart/upstream-socket-bridge
Merge into: lp:upstart
Diff against target: 2186 lines (+1594/-97)
22 files modified
.bzrignore (+4/-0)
Makefile.am (+1/-1)
configure.ac (+5/-2)
dbus/com.ubuntu.Upstart.xml (+7/-0)
extra/Makefile.am (+113/-0)
extra/conf/upstart-socket-bridge.conf (+16/-0)
extra/conf/upstart-udev-bridge.conf (+14/-0)
extra/man/socket-event.7 (+92/-0)
extra/man/upstart-socket-bridge.8 (+47/-0)
extra/man/upstart-udev-bridge.8 (+35/-0)
extra/upstart-socket-bridge.c (+644/-0)
extra/upstart-udev-bridge.c (+310/-0)
init/control.c (+38/-9)
init/control.h (+4/-0)
init/event.c (+13/-0)
init/event.h (+1/-0)
init/event_operator.c (+59/-0)
init/event_operator.h (+8/-0)
init/job.c (+3/-0)
init/job.h (+3/-0)
po/POTFILES.in (+2/-0)
po/upstart.pot (+175/-85)
To merge this branch: bzr merge lp:~jamesodhunt/upstart/upstream-socket-bridge
Reviewer Review Type Date Requested Status
Upstart Developers Pending
Review via email: mp+61036@code.launchpad.net

Description of the change

Minor fixes and documentation for upstart-socket-bridge:

* extra/Makefile.am: Added socket-bridge.conf and manual pages
  to distribution.
* extra/upstart-socket-bridge.c: job_add_socket(): memset fix (before, only
  part of the Socket object was being initialized).
* New files:
  - extra/conf/upstart-socket-bridge.conf: Job configuration file for
    socket bridge.
  - extra/man/socket-event.7: Man page for socket event. Naming is due
    to collision with existing socket(7) page.
  - extra/man/upstart-socket-bridge.8: Man page for socket bridge.

To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '.bzrignore'
2--- .bzrignore 2010-12-10 04:03:25 +0000
3+++ .bzrignore 2011-05-15 18:31:10 +0000
4@@ -59,3 +59,7 @@
5 util/shutdown
6 util/telinit
7 util/test_*
8+extra/com.ubuntu.Upstart.[ch]
9+extra/com.ubuntu.Upstart.Job.[ch]
10+extra/upstart-socket-bridge
11+extra/upstart-udev-bridge
12
13=== modified file 'Makefile.am'
14--- Makefile.am 2010-02-04 03:42:29 +0000
15+++ Makefile.am 2011-05-15 18:31:10 +0000
16@@ -1,6 +1,6 @@
17 ## Process this file with automake to produce Makefile.in
18
19-SUBDIRS = intl dbus init util conf doc contrib po
20+SUBDIRS = intl dbus init util extra conf doc contrib po
21
22 EXTRA_DIST = HACKING
23
24
25=== modified file 'configure.ac'
26--- configure.ac 2011-03-22 17:53:17 +0000
27+++ configure.ac 2011-05-15 18:31:10 +0000
28@@ -30,6 +30,9 @@
29 PKG_CHECK_MODULES([NIH], [libnih >= 1.0.2])
30 PKG_CHECK_MODULES([NIH_DBUS], [libnih-dbus >= 1.0.0])
31 PKG_CHECK_MODULES([DBUS], [dbus-1 >= 1.2.16])
32+PKG_CHECK_MODULES([UDEV], [libudev >= 146], [have_udev=yes], [have_udev=no])
33+
34+AM_CONDITIONAL([HAVE_UDEV], [test "$have_udev" = yes])
35
36 # Checks for header files.
37 AC_CHECK_HEADERS([valgrind/valgrind.h])
38@@ -63,7 +66,7 @@
39
40
41 AC_CONFIG_FILES([ Makefile intl/Makefile
42- dbus/Makefile init/Makefile util/Makefile conf/Makefile
43- doc/Makefile contrib/Makefile po/Makefile.in ])
44+ dbus/Makefile init/Makefile util/Makefile extra/Makefile
45+ conf/Makefile doc/Makefile contrib/Makefile po/Makefile.in ])
46 AC_CONFIG_HEADERS([config.h])
47 AC_OUTPUT
48
49=== modified file 'dbus/com.ubuntu.Upstart.xml'
50--- dbus/com.ubuntu.Upstart.xml 2009-07-03 16:08:10 +0000
51+++ dbus/com.ubuntu.Upstart.xml 2011-05-15 18:31:10 +0000
52@@ -49,6 +49,13 @@
53 <arg name="env" type="as" direction="in" />
54 <arg name="wait" type="b" direction="in" />
55 </method>
56+ <method name="EmitEventWithFile">
57+ <annotation name="com.netsplit.Nih.Method.Async" value="true" />
58+ <arg name="name" type="s" direction="in" />
59+ <arg name="env" type="as" direction="in" />
60+ <arg name="wait" type="b" direction="in" />
61+ <arg name="file" type="h" direction="in" />
62+ </method>
63
64 <!-- Basic information about Upstart -->
65 <property name="version" type="s" access="read" />
66
67=== added directory 'extra'
68=== added file 'extra/Makefile.am'
69--- extra/Makefile.am 1970-01-01 00:00:00 +0000
70+++ extra/Makefile.am 2011-05-15 18:31:10 +0000
71@@ -0,0 +1,113 @@
72+## Process this file with automake to produce Makefile.in
73+
74+AM_CFLAGS = \
75+ $(NIH_CFLAGS) \
76+ $(NIH_DBUS_CFLAGS) \
77+ $(DBUS_CFLAGS) \
78+ $(UDEV_CFLAGS)
79+
80+AM_CPPFLAGS = \
81+ -DLOCALEDIR="\"$(localedir)\"" \
82+ -DSBINDIR="\"$(sbindir)\"" \
83+ -I$(top_builddir) -I$(top_srcdir) -iquote$(builddir) -iquote$(srcdir) \
84+ -I$(top_srcdir)/intl
85+
86+
87+initdir = $(sysconfdir)/init
88+
89+
90+sbin_PROGRAMS = \
91+ upstart-socket-bridge
92+
93+dist_init_DATA = \
94+ conf/upstart-socket-bridge.conf
95+
96+dist_man_MANS = \
97+ man/upstart-socket-bridge.8 \
98+ man/socket-event.7
99+
100+upstart_socket_bridge_SOURCES = \
101+ upstart-socket-bridge.c
102+nodist_upstart_socket_bridge_SOURCES = \
103+ $(com_ubuntu_Upstart_OUTPUTS) \
104+ $(com_ubuntu_Upstart_Job_OUTPUTS)
105+upstart_socket_bridge_LDADD = \
106+ $(LTLIBINTL) \
107+ $(NIH_LIBS) \
108+ $(NIH_DBUS_LIBS) \
109+ $(DBUS_LIBS)
110+
111+
112+if HAVE_UDEV
113+dist_init_DATA += \
114+ conf/upstart-udev-bridge.conf
115+
116+dist_man_MANS += \
117+ man/upstart-udev-bridge.8
118+
119+
120+sbin_PROGRAMS += \
121+ upstart-udev-bridge
122+
123+upstart_udev_bridge_SOURCES = \
124+ upstart-udev-bridge.c
125+nodist_upstart_udev_bridge_SOURCES = \
126+ $(com_ubuntu_Upstart_OUTPUTS)
127+upstart_udev_bridge_LDADD = \
128+ $(LTLIBINTL) \
129+ $(NIH_LIBS) \
130+ $(NIH_DBUS_LIBS) \
131+ $(DBUS_LIBS) \
132+ $(UDEV_LIBS)
133+else
134+EXTRA_DIST = \
135+ man/upstart-udev-bridge.8
136+endif
137+
138+
139+com_ubuntu_Upstart_OUTPUTS = \
140+ com.ubuntu.Upstart.c \
141+ com.ubuntu.Upstart.h
142+
143+com_ubuntu_Upstart_XML = \
144+ ../dbus/com.ubuntu.Upstart.xml
145+
146+$(com_ubuntu_Upstart_OUTPUTS): $(com_ubuntu_Upstart_XML)
147+ $(AM_V_GEN)$(NIH_DBUS_TOOL) \
148+ --package=$(PACKAGE) \
149+ --mode=proxy --prefix=upstart \
150+ --default-interface=com.ubuntu.Upstart0_6 \
151+ --output=$@ $<
152+
153+
154+com_ubuntu_Upstart_Job_OUTPUTS = \
155+ com.ubuntu.Upstart.Job.c \
156+ com.ubuntu.Upstart.Job.h
157+
158+com_ubuntu_Upstart_Job_XML = \
159+ ../dbus/com.ubuntu.Upstart.Job.xml
160+
161+$(com_ubuntu_Upstart_Job_OUTPUTS): $(com_ubuntu_Upstart_Job_XML)
162+ $(AM_V_GEN)$(NIH_DBUS_TOOL) \
163+ --package=$(PACKAGE) \
164+ --mode=proxy --prefix=job_class \
165+ --default-interface=com.ubuntu.Upstart0_6.Job \
166+ --output=$@ $<
167+
168+
169+# These have to be built sources because we can't compile object files
170+# without the header file existing first
171+BUILT_SOURCES = \
172+ $(com_ubuntu_Upstart_OUTPUTS) \
173+ $(com_ubuntu_Upstart_Job_OUTPUTS)
174+
175+CLEANFILES = \
176+ $(com_ubuntu_Upstart_OUTPUTS) \
177+ $(com_ubuntu_Upstart_Job_OUTPUTS)
178+
179+
180+clean-local:
181+ rm -f *.gcno *.gcda
182+
183+maintainer-clean-local:
184+ rm -f *.gcov
185
186=== added directory 'extra/conf'
187=== added file 'extra/conf/upstart-socket-bridge.conf'
188--- extra/conf/upstart-socket-bridge.conf 1970-01-01 00:00:00 +0000
189+++ extra/conf/upstart-socket-bridge.conf 2011-05-15 18:31:10 +0000
190@@ -0,0 +1,16 @@
191+# upstart-socket-bridge - Bridge socket events into upstart
192+#
193+# This helper daemon receives socket(7) events and
194+# emits equivalent Upstart events.
195+
196+description "Bridge socket events into upstart"
197+
198+emits socket
199+
200+start on net-device-up IFACE=lo
201+stop on runlevel [!2345]
202+
203+expect daemon
204+respawn
205+
206+exec upstart-socket-bridge --daemon
207
208=== added file 'extra/conf/upstart-udev-bridge.conf'
209--- extra/conf/upstart-udev-bridge.conf 1970-01-01 00:00:00 +0000
210+++ extra/conf/upstart-udev-bridge.conf 2011-05-15 18:31:10 +0000
211@@ -0,0 +1,14 @@
212+# upstart-udev-bridge - Bridge udev events into upstart
213+#
214+# This helper daemon receives udev events from the netlink socket and
215+# emits equivalent Upstart events.
216+
217+description "Bridge udev events into upstart"
218+
219+start on starting udev
220+stop on stopped udev
221+
222+expect daemon
223+respawn
224+
225+exec upstart-udev-bridge --daemon
226
227=== added directory 'extra/man'
228=== added file 'extra/man/socket-event.7'
229--- extra/man/socket-event.7 1970-01-01 00:00:00 +0000
230+++ extra/man/socket-event.7 2011-05-15 18:31:10 +0000
231@@ -0,0 +1,92 @@
232+.TH socket\-event 8 2011-03-08 upstart
233+.\"
234+.SH NAME
235+socket \- event signalling that a socket connection has been made
236+.\"
237+.SH SYNOPSIS
238+.B socket
239+.BI PROTO\fR= PROTO
240+.BI PORT\fR= PORT
241+.BI ADDR\fR= ADDR
242+
243+.B socket
244+.BI PROTO\fR= PROTO
245+.BI PATH\fR= PATH
246+.\"
247+.SH DESCRIPTION
248+
249+The
250+.B socket
251+event is generated by the
252+.BR upstart\-socket\-bridge (8)
253+daemon when a socket connection is made whose details match the
254+socket event condition and environment specified in a jobs
255+.B start on
256+or
257+.B stop on
258+stanza.
259+
260+When an incoming connection is detected, the file descriptor
261+representing the socket is passed to the job in question to allow it to
262+.BR accept (2)
263+the connection. Additionally, the environment variable
264+.B UPSTART_JOB
265+will contain the name of the event ("socket") and the environment
266+variable
267+.B UPSTART_FDS
268+will contain the number of the file descriptor corresponding to the
269+listening socket.
270+.\"
271+.SH EXAMPLES
272+.\"
273+.SS Internet socket
274+Start web server when first client connects from localhost:
275+.RS
276+.nf
277+
278+start on socket PROTO=inet PORT=80 ADDR=127.0.0.1
279+.fi
280+.RE
281+.\"
282+.SS Local socket
283+.P
284+.RS
285+.nf
286+
287+start on socket PROTO=unix PATH=/var/run/.s.pgsql.1234
288+.fi
289+.FE
290+.\"
291+.SS Abstract socket
292+.P
293+
294+.RS
295+.nf
296+
297+start on socket PROTO=unix PATH=@/at/upstart/example
298+.fi
299+.FE
300+.\"
301+.SH AUTHOR
302+Written by Scott James Remnant
303+.RB < scott@netsplit.com >
304+
305+Manual page written by James Hunt
306+.RB < james.hunt@ubuntu.com >
307+.\"
308+.SH BUGS
309+Report bugs at
310+.RB < https://launchpad.net/upstart/+bugs >
311+.\"
312+.SH COPYRIGHT
313+Copyright \(co 2011 Canonical Ltd.
314+.PP
315+This is free software; see the source for copying conditions. There is NO
316+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
317+.\"
318+.SH SEE ALSO
319+.BR init (5)
320+.BR init (8)
321+.BR socket (2)
322+.BR socket (7)
323+.BR upstart\-socket\-bridge (8)
324
325=== added file 'extra/man/upstart-socket-bridge.8'
326--- extra/man/upstart-socket-bridge.8 1970-01-01 00:00:00 +0000
327+++ extra/man/upstart-socket-bridge.8 2011-05-15 18:31:10 +0000
328@@ -0,0 +1,47 @@
329+.TH upstart-socket-bridge 8 2011-03-08 upstart
330+.\"
331+.SH NAME
332+upstart-socket-bridge \- Bridge between Upstart and sockets
333+.\"
334+.SH SYNOPSIS
335+.B upstart-socket-bridge
336+.RI [ OPTIONS ]...
337+.\"
338+.SH DESCRIPTION
339+The
340+.B upstart-socket-bridge
341+queries the Upstart
342+.BR init (8)
343+daemon for all job configurations which
344+.B start on
345+or
346+.B stop on
347+the socket event. It then waits for an incoming connection on each
348+specified
349+.BR socket (7)
350+and when detected emits the socket event (\fBsocket\-event\fP (7)),
351+setting a number of environment variables for the job to query.
352+.\"
353+.SH AUTHOR
354+Written by Scott James Remnant
355+.RB < scott@netsplit.com >
356+
357+Manual page written by James Hunt
358+.RB < james.hunt@ubuntu.com >
359+.\"
360+.SH BUGS
361+Report bugs at
362+.RB < https://launchpad.net/upstart/+bugs >
363+.\"
364+.SH COPYRIGHT
365+Copyright \(co 2011 Canonical Ltd.
366+.PP
367+This is free software; see the source for copying conditions. There is NO
368+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
369+.\"
370+.SH SEE ALSO
371+.BR init (5)
372+.BR init (8)
373+.BR socket (2)
374+.BR socket (7)
375+.BR socket\-event (7)
376
377=== added file 'extra/man/upstart-udev-bridge.8'
378--- extra/man/upstart-udev-bridge.8 1970-01-01 00:00:00 +0000
379+++ extra/man/upstart-udev-bridge.8 2011-05-15 18:31:10 +0000
380@@ -0,0 +1,35 @@
381+.TH upstart-udev-bridge 8 2009-09-07 upstart
382+.\"
383+.SH NAME
384+upstart-udev-bridge \- Bridge between Upstart and udev
385+.\"
386+.SH SYNOPSIS
387+.B upstart-udev-bridge
388+.RI [ OPTIONS ]...
389+.\"
390+.SH DESCRIPTION
391+.B upstart-udev-bridge
392+receives information about kernel uevents that
393+.BR udev (8)
394+has completed and creates
395+.BR init (8)
396+events for them.
397+
398+This is a temporary tool until
399+.BR init (8)
400+itself gains the functionality to read them directly; you should not
401+rely on its behaviour.
402+.\"
403+.SH AUTHOR
404+Written by Scott James Remnant
405+.RB < scott@netsplit.com >
406+.\"
407+.SH BUGS
408+Report bugs at
409+.RB < https://launchpad.net/ubuntu/+source/upstart/+bugs >
410+.\"
411+.SH COPYRIGHT
412+Copyright \(co 2009 Canonical Ltd.
413+.PP
414+This is free software; see the source for copying conditions. There is NO
415+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
416
417=== added file 'extra/upstart-socket-bridge.c'
418--- extra/upstart-socket-bridge.c 1970-01-01 00:00:00 +0000
419+++ extra/upstart-socket-bridge.c 2011-05-15 18:31:10 +0000
420@@ -0,0 +1,644 @@
421+/* upstart
422+ *
423+ * Copyright © 2010 Canonical Ltd.
424+ * Author: Scott James Remnant <scott@netsplit.com>.
425+ *
426+ * This program is free software; you can redistribute it and/or modify
427+ * it under the terms of the GNU General Public License version 2, as
428+ * published by the Free Software Foundation.
429+ *
430+ * This program is distributed in the hope that it will be useful,
431+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
432+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
433+ * GNU General Public License for more details.
434+ *
435+ * You should have received a copy of the GNU General Public License along
436+ * with this program; if not, write to the Free Software Foundation, Inc.,
437+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
438+ */
439+
440+#ifdef HAVE_CONFIG_H
441+# include <config.h>
442+#endif /* HAVE_CONFIG_H */
443+
444+
445+#include <sys/epoll.h>
446+#include <sys/types.h>
447+#include <sys/socket.h>
448+#include <sys/un.h>
449+
450+#include <netinet/in.h>
451+#include <arpa/inet.h>
452+
453+#include <errno.h>
454+#include <stdlib.h>
455+#include <string.h>
456+#include <syslog.h>
457+#include <unistd.h>
458+
459+#include <nih/macros.h>
460+#include <nih/alloc.h>
461+#include <nih/list.h>
462+#include <nih/hash.h>
463+#include <nih/string.h>
464+#include <nih/io.h>
465+#include <nih/option.h>
466+#include <nih/main.h>
467+#include <nih/logging.h>
468+#include <nih/error.h>
469+
470+#include <nih-dbus/dbus_connection.h>
471+#include <nih-dbus/dbus_proxy.h>
472+
473+#include "dbus/upstart.h"
474+#include "com.ubuntu.Upstart.h"
475+#include "com.ubuntu.Upstart.Job.h"
476+
477+
478+/* Structure we use for tracking jobs */
479+typedef struct job {
480+ NihList entry;
481+ char *path;
482+ NihList sockets;
483+} Job;
484+
485+/* Structure we use for tracking listening sockets */
486+typedef struct socket {
487+ NihList entry;
488+
489+ union {
490+ struct sockaddr addr;
491+ struct sockaddr_in sin_addr;
492+ struct sockaddr_un sun_addr;
493+ };
494+ socklen_t addrlen;
495+
496+ int sock;
497+} Socket;
498+
499+
500+/* Prototypes for static functions */
501+static void epoll_watcher (void *data, NihIoWatch *watch,
502+ NihIoEvents events);
503+static void upstart_job_added (void *data, NihDBusMessage *message,
504+ const char *job);
505+static void upstart_job_removed (void *data, NihDBusMessage *message,
506+ const char *job);
507+static void job_add_socket (Job *job, char **socket_info);
508+static void socket_destroy (Socket *socket);
509+static void upstart_disconnected (DBusConnection *connection);
510+static void emit_event_reply (Socket *sock, NihDBusMessage *message);
511+static void emit_event_error (Socket *sock, NihDBusMessage *message);
512+
513+
514+/**
515+ * daemonise:
516+ *
517+ * Set to TRUE if we should become a daemon, rather than just running
518+ * in the foreground.
519+ **/
520+static int daemonise = FALSE;
521+
522+/**
523+ * epoll_fd:
524+ *
525+ * Shared epoll file descriptor for listening on.
526+ **/
527+static int epoll_fd = -1;
528+
529+/**
530+ * jobs:
531+ *
532+ * Jobs that we're monitoring.
533+ **/
534+static NihHash *jobs = NULL;
535+
536+/**
537+ * upstart:
538+ *
539+ * Proxy to Upstart daemon.
540+ **/
541+static NihDBusProxy *upstart = NULL;
542+
543+
544+/**
545+ * options:
546+ *
547+ * Command-line options accepted by this program.
548+ **/
549+static NihOption options[] = {
550+ { 0, "daemon", N_("Detach and run in the background"),
551+ NULL, NULL, &daemonise, NULL },
552+
553+ NIH_OPTION_LAST
554+};
555+
556+
557+int
558+main (int argc,
559+ char *argv[])
560+{
561+ char ** args;
562+ DBusConnection *connection;
563+ char ** job_class_paths;
564+ int ret;
565+
566+ nih_main_init (argv[0]);
567+
568+ nih_option_set_synopsis (_("Bridge socket events into upstart"));
569+ nih_option_set_help (
570+ _("By default, upstart-socket-bridge does not detach from the "
571+ "console and remains in the foreground. Use the --daemon "
572+ "option to have it detach."));
573+
574+ args = nih_option_parser (NULL, argc, argv, options, FALSE);
575+ if (! args)
576+ exit (1);
577+
578+ /* Create an epoll file descriptor for listening on; use this so
579+ * we can do edge triggering rather than level.
580+ */
581+ epoll_fd = epoll_create1 (0);
582+ if (epoll_fd < 0) {
583+ nih_fatal ("%s: %s", _("Could not create epoll descriptor"),
584+ strerror (errno));
585+ exit (1);
586+ }
587+
588+ NIH_MUST (nih_io_add_watch (NULL, epoll_fd, NIH_IO_READ,
589+ epoll_watcher, NULL));
590+
591+ /* Allocate jobs hash table */
592+ jobs = NIH_MUST (nih_hash_string_new (NULL, 0));
593+
594+ /* Initialise the connection to Upstart */
595+ connection = NIH_SHOULD (nih_dbus_connect (DBUS_ADDRESS_UPSTART, upstart_disconnected));
596+ if (! connection) {
597+ NihError *err;
598+
599+ err = nih_error_get ();
600+ nih_fatal ("%s: %s", _("Could not connect to Upstart"),
601+ err->message);
602+ nih_free (err);
603+
604+ exit (1);
605+ }
606+
607+ upstart = NIH_SHOULD (nih_dbus_proxy_new (NULL, connection,
608+ NULL, DBUS_PATH_UPSTART,
609+ NULL, NULL));
610+ if (! upstart) {
611+ NihError *err;
612+
613+ err = nih_error_get ();
614+ nih_fatal ("%s: %s", _("Could not create Upstart proxy"),
615+ err->message);
616+ nih_free (err);
617+
618+ exit (1);
619+ }
620+
621+ /* Connect signals to be notified when jobs come and go */
622+ if (! nih_dbus_proxy_connect (upstart, &upstart_com_ubuntu_Upstart0_6, "JobAdded",
623+ (NihDBusSignalHandler)upstart_job_added, NULL)) {
624+ NihError *err;
625+
626+ err = nih_error_get ();
627+ nih_fatal ("%s: %s", _("Could not create JobAdded signal connection"),
628+ err->message);
629+ nih_free (err);
630+
631+ exit (1);
632+ }
633+
634+ if (! nih_dbus_proxy_connect (upstart, &upstart_com_ubuntu_Upstart0_6, "JobRemoved",
635+ (NihDBusSignalHandler)upstart_job_removed, NULL)) {
636+ NihError *err;
637+
638+ err = nih_error_get ();
639+ nih_fatal ("%s: %s", _("Could not create JobRemoved signal connection"),
640+ err->message);
641+ nih_free (err);
642+
643+ exit (1);
644+ }
645+
646+ /* Request a list of all current jobs */
647+ if (upstart_get_all_jobs_sync (NULL, upstart, &job_class_paths) < 0) {
648+ NihError *err;
649+
650+ err = nih_error_get ();
651+ nih_fatal ("%s: %s", _("Could not obtain job list"),
652+ err->message);
653+ nih_free (err);
654+
655+ exit (1);
656+ }
657+
658+ for (char **job_class_path = job_class_paths;
659+ job_class_path && *job_class_path; job_class_path++)
660+ upstart_job_added (NULL, NULL, *job_class_path);
661+
662+ nih_free (job_class_paths);
663+
664+ /* Become daemon */
665+ if (daemonise) {
666+ if (nih_main_daemonise () < 0) {
667+ NihError *err;
668+
669+ err = nih_error_get ();
670+ nih_fatal ("%s: %s", _("Unable to become daemon"),
671+ err->message);
672+ nih_free (err);
673+
674+ exit (1);
675+ }
676+
677+ /* Send all logging output to syslog */
678+ openlog (program_name, LOG_PID, LOG_DAEMON);
679+ nih_log_set_logger (nih_logger_syslog);
680+ }
681+
682+ /* Handle TERM and INT signals gracefully */
683+ nih_signal_set_handler (SIGTERM, nih_signal_handler);
684+ NIH_MUST (nih_signal_add_handler (NULL, SIGTERM, nih_main_term_signal, NULL));
685+
686+ if (! daemonise) {
687+ nih_signal_set_handler (SIGINT, nih_signal_handler);
688+ NIH_MUST (nih_signal_add_handler (NULL, SIGINT, nih_main_term_signal, NULL));
689+ }
690+
691+ ret = nih_main_loop ();
692+
693+ return ret;
694+}
695+
696+
697+static void
698+epoll_watcher (void * data,
699+ NihIoWatch *watch,
700+ NihIoEvents events)
701+{
702+ struct epoll_event event[1024];
703+ int num_events;
704+
705+ num_events = epoll_wait (epoll_fd, event, 1024, 0);
706+ if (num_events < 0) {
707+ nih_error ("%s: %s", _("Error from epoll"), strerror (errno));
708+ return;
709+ } else if (num_events == 0)
710+ return;
711+
712+ for (int i = 0; i < num_events; i++) {
713+ Socket *sock = (Socket *)event[i].data.ptr;
714+ nih_local char **env = NULL;
715+ size_t env_len = 0;
716+ char *var;
717+ DBusPendingCall *pending_call;
718+
719+ if (event[i].events & EPOLLIN)
720+ nih_debug ("%p EPOLLIN", sock);
721+ if (event[i].events & EPOLLERR)
722+ nih_debug ("%p EPOLLERR", sock);
723+ if (event[i].events & EPOLLHUP)
724+ nih_debug ("%p EPOLLHUP", sock);
725+
726+ env = NIH_MUST (nih_str_array_new (NULL));
727+
728+ switch (sock->addr.sa_family) {
729+ case AF_INET:
730+ NIH_MUST (nih_str_array_add (&env, NULL, &env_len,
731+ "PROTO=inet"));
732+
733+ var = NIH_MUST (nih_sprintf (NULL, "PORT=%d",
734+ ntohs (sock->sin_addr.sin_port)));
735+ NIH_MUST (nih_str_array_addp (&env, NULL, &env_len,
736+ var));
737+ nih_discard (var);
738+
739+ var = NIH_MUST (nih_sprintf (NULL, "ADDR=%s",
740+ inet_ntoa (sock->sin_addr.sin_addr)));
741+ NIH_MUST (nih_str_array_addp (&env, NULL, &env_len,
742+ var));
743+ nih_discard (var);
744+ break;
745+ case AF_UNIX:
746+ NIH_MUST (nih_str_array_add (&env, NULL, &env_len,
747+ "PROTO=unix"));
748+
749+ var = NIH_MUST (nih_sprintf (NULL, "PATH=%s",
750+ sock->sun_addr.sun_path));
751+ NIH_MUST (nih_str_array_addp (&env, NULL, &env_len,
752+ var));
753+ nih_discard (var);
754+ break;
755+ default:
756+ nih_assert_not_reached ();
757+ }
758+
759+ pending_call = NIH_SHOULD (upstart_emit_event_with_file (
760+ upstart, "socket", env, TRUE,
761+ sock->sock,
762+ (UpstartEmitEventWithFileReply)emit_event_reply,
763+ (NihDBusErrorHandler)emit_event_error,
764+ sock,
765+ NIH_DBUS_TIMEOUT_NEVER));
766+ if (! pending_call) {
767+ NihError *err;
768+
769+ err = nih_error_get ();
770+ nih_warn ("%s: %s", _("Could not send socket event"),
771+ err->message);
772+ nih_free (err);
773+ }
774+
775+ dbus_pending_call_unref (pending_call);
776+
777+ // might be EPOLLIN
778+ // might be EPOLLERR
779+ // might be EPOLLHUP
780+ }
781+}
782+
783+
784+static void
785+upstart_job_added (void * data,
786+ NihDBusMessage *message,
787+ const char * job_class_path)
788+{
789+ nih_local NihDBusProxy *job_class = NULL;
790+ nih_local char ***start_on = NULL;
791+ nih_local char ***stop_on = NULL;
792+ Job *job;
793+
794+ nih_assert (job_class_path != NULL);
795+
796+ /* Obtain a proxy to the job */
797+ job_class = nih_dbus_proxy_new (NULL, upstart->connection,
798+ upstart->name, job_class_path,
799+ NULL, NULL);
800+ if (! job_class) {
801+ NihError *err;
802+
803+ err = nih_error_get ();
804+ nih_error ("Could not create proxy for job %s: %s",
805+ job_class_path, err->message);
806+ nih_free (err);
807+
808+ return;
809+ }
810+
811+ job_class->auto_start = FALSE;
812+
813+ /* Obtain the start_on and stop_on properties of the job */
814+ if (job_class_get_start_on_sync (NULL, job_class, &start_on) < 0) {
815+ NihError *err;
816+
817+ err = nih_error_get ();
818+ nih_error ("Could not obtain job start condition %s: %s",
819+ job_class_path, err->message);
820+ nih_free (err);
821+
822+ return;
823+ }
824+
825+ if (job_class_get_stop_on_sync (NULL, job_class, &stop_on) < 0) {
826+ NihError *err;
827+
828+ err = nih_error_get ();
829+ nih_error ("Could not obtain job stop condition %s: %s",
830+ job_class_path, err->message);
831+ nih_free (err);
832+
833+ return;
834+ }
835+
836+ /* Free any existing record for the job (should never happen,
837+ * but worth being safe).
838+ */
839+ job = (Job *)nih_hash_lookup (jobs, job_class_path);
840+ if (job)
841+ nih_free (job);
842+
843+ /* Create new record for the job */
844+ job = NIH_MUST (nih_new (NULL, Job));
845+ job->path = NIH_MUST (nih_strdup (job, job_class_path));
846+
847+ nih_list_init (&job->entry);
848+ nih_list_init (&job->sockets);
849+
850+ /* Find out whether this job listens for any socket events */
851+ for (char ***event = start_on; event && *event && **event; event++)
852+ if (! strcmp (**event, "socket"))
853+ job_add_socket (job, *event);
854+ for (char ***event = stop_on; event && *event && **event; event++)
855+ if (! strcmp (**event, "socket"))
856+ job_add_socket (job, *event);
857+
858+ /* If we didn't end up with any sockets, free the job and move on */
859+ if (NIH_LIST_EMPTY (&job->sockets)) {
860+ nih_free (job);
861+ return;
862+ }
863+
864+ nih_debug ("Job got added %s", job_class_path);
865+
866+ nih_alloc_set_destructor (job, nih_list_destroy);
867+ nih_hash_add (jobs, &job->entry);
868+}
869+
870+static void
871+upstart_job_removed (void * data,
872+ NihDBusMessage *message,
873+ const char * job_path)
874+{
875+ Job *job;
876+
877+ nih_assert (job_path != NULL);
878+
879+ job = (Job *)nih_hash_lookup (jobs, job_path);
880+ if (job) {
881+ nih_debug ("Job went away %s", job_path);
882+ nih_free (job);
883+ }
884+}
885+
886+
887+static void
888+job_add_socket (Job * job,
889+ char **socket_info)
890+{
891+ Socket *sock;
892+ nih_local char *error = NULL;
893+ int components = 0;
894+ struct epoll_event event;
895+
896+ nih_assert (job != NULL);
897+ nih_assert (socket_info != NULL);
898+ nih_assert (! strcmp(socket_info[0], "socket"));
899+
900+ sock = NIH_MUST (nih_new (job, Socket));
901+ memset (sock, 0, sizeof (Socket));
902+ sock->sock = -1;
903+
904+ nih_list_init (&sock->entry);
905+
906+ nih_debug ("Found socket");
907+ for (char **env = socket_info + 1; env && *env; env++) {
908+ char *val;
909+ size_t name_len;
910+
911+ val = strchr (*env, '=');
912+ if (! val) {
913+ nih_warn ("Ignored socket event without variable name in %s",
914+ job->path);
915+ goto error;
916+ }
917+
918+ name_len = val - *env;
919+ val++;
920+
921+ if (! strncmp (*env, "PROTO", name_len)) {
922+ if (! strcmp (val, "inet")) {
923+ sock->addrlen = sizeof sock->sin_addr;
924+ sock->sin_addr.sin_family = AF_INET;
925+ sock->sin_addr.sin_addr.s_addr = INADDR_ANY;
926+ components = 1;
927+ } else if (! strcmp (val, "unix")) {
928+ sock->addrlen = sizeof sock->sun_addr;
929+ sock->sun_addr.sun_family = AF_UNIX;
930+ components = 1;
931+ } else {
932+ nih_warn ("Ignored socket event with unknown PROTO=%s in %s",
933+ val, job->path);
934+ goto error;
935+ }
936+
937+ } else if (! strncmp (*env, "PORT", name_len)
938+ && (sock->sin_addr.sin_family == AF_INET)) {
939+ sock->sin_addr.sin_port = htons (atoi (val));
940+ components--;
941+
942+ } else if (! strncmp (*env, "ADDR", name_len)
943+ && (sock->sin_addr.sin_family == AF_INET)) {
944+ if (inet_aton (val, &(sock->sin_addr.sin_addr)) == 0) {
945+ nih_warn ("Ignored socket event with invalid ADDR=%s in %s",
946+ val, job->path);
947+ goto error;
948+ }
949+
950+ } else if (! strncmp (*env, "PATH", name_len)
951+ && (sock->sun_addr.sun_family == AF_UNIX)) {
952+ strncpy (sock->sun_addr.sun_path, val,
953+ sizeof sock->sun_addr.sun_path);
954+
955+ if (sock->sun_addr.sun_path[0] == '@')
956+ sock->sun_addr.sun_path[0] = '\0';
957+
958+ components--;
959+
960+ } else {
961+ nih_warn ("Ignored socket event with unknown variable %.*s in %s",
962+ (int)name_len, *env, job->path);
963+ goto error;
964+ }
965+ }
966+
967+ /* Missing any required components? */
968+ if (components) {
969+ nih_warn ("Ignored incomplete socket event in %s",
970+ job->path);
971+ goto error;
972+ }
973+
974+ /* Let's try and set this baby up */
975+ sock->sock = socket (sock->addr.sa_family, SOCK_STREAM, 0);
976+ if (sock->sock < 0) {
977+ nih_warn ("Failed to create socket in %s: %s",
978+ job->path, strerror (errno));
979+ goto error;
980+ }
981+
982+ int opt = 1;
983+ if (setsockopt (sock->sock, SOL_SOCKET, SO_REUSEADDR,
984+ &opt, sizeof opt) < 0) {
985+ nih_warn ("Failed to set socket reuse in %s: %s",
986+ job->path, strerror (errno));
987+ goto error;
988+ }
989+
990+ if (bind (sock->sock, &sock->addr, sock->addrlen) < 0) {
991+ nih_warn ("Failed to bind socket in %s: %s",
992+ job->path, strerror (errno));
993+ goto error;
994+ }
995+
996+ if (listen (sock->sock, SOMAXCONN) < 0) {
997+ nih_warn ("Failed to listen on socket in %s: %s",
998+ job->path, strerror (errno));
999+ goto error;
1000+ }
1001+
1002+ /* We have a listening socket, now we want to be notified when someone
1003+ * connects; but we just want one notification, we don't want to get
1004+ * a DDoS of wake-ups while waiting for the service to start.
1005+ *
1006+ * The solution is to use epoll in edge-triggered mode, this will
1007+ * fire only on initial connection until a new one comes in.
1008+ */
1009+ event.events = EPOLLIN | EPOLLET;
1010+ event.data.ptr = sock;
1011+
1012+ if (epoll_ctl (epoll_fd, EPOLL_CTL_ADD, sock->sock, &event) < 0) {
1013+ nih_warn ("Failed to watch socket in %s: %s",
1014+ job->path, strerror (errno));
1015+ goto error;
1016+ }
1017+
1018+ /* Okay then, add to the job */
1019+ nih_alloc_set_destructor (sock, socket_destroy);
1020+ nih_list_add (&job->sockets, &sock->entry);
1021+
1022+ return;
1023+
1024+error:
1025+ if (sock->sock != -1)
1026+ close (sock->sock);
1027+ nih_free (sock);
1028+}
1029+
1030+static void
1031+socket_destroy (Socket *sock)
1032+{
1033+ epoll_ctl (epoll_fd, EPOLL_CTL_DEL, sock->sock, NULL);
1034+ close (sock->sock);
1035+
1036+ nih_list_destroy (&sock->entry);
1037+}
1038+
1039+
1040+static void
1041+upstart_disconnected (DBusConnection *connection)
1042+{
1043+ nih_fatal (_("Disconnected from Upstart"));
1044+ nih_main_loop_exit (1);
1045+}
1046+
1047+
1048+static void
1049+emit_event_reply (Socket * sock,
1050+ NihDBusMessage *message)
1051+{
1052+ nih_debug ("Event completed");
1053+}
1054+
1055+static void
1056+emit_event_error (Socket * sock,
1057+ NihDBusMessage *message)
1058+{
1059+ NihError *err;
1060+
1061+ err = nih_error_get ();
1062+ nih_warn ("%s: %s", _("Error emitting socket event"), err->message);
1063+ nih_free (err);
1064+}
1065
1066=== added file 'extra/upstart-udev-bridge.c'
1067--- extra/upstart-udev-bridge.c 1970-01-01 00:00:00 +0000
1068+++ extra/upstart-udev-bridge.c 2011-05-15 18:31:10 +0000
1069@@ -0,0 +1,310 @@
1070+/* upstart
1071+ *
1072+ * Copyright © 2009 Canonical Ltd.
1073+ * Author: Scott James Remnant <scott@netsplit.com>.
1074+ *
1075+ * This program is free software; you can redistribute it and/or modify
1076+ * it under the terms of the GNU General Public License version 2, as
1077+ * published by the Free Software Foundation.
1078+ *
1079+ * This program is distributed in the hope that it will be useful,
1080+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1081+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1082+ * GNU General Public License for more details.
1083+ *
1084+ * You should have received a copy of the GNU General Public License along
1085+ * with this program; if not, write to the Free Software Foundation, Inc.,
1086+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
1087+ */
1088+
1089+#ifdef HAVE_CONFIG_H
1090+# include <config.h>
1091+#endif /* HAVE_CONFIG_H */
1092+
1093+
1094+#include <libudev.h>
1095+
1096+#include <stdlib.h>
1097+#include <string.h>
1098+#include <syslog.h>
1099+
1100+#include <nih/macros.h>
1101+#include <nih/alloc.h>
1102+#include <nih/string.h>
1103+#include <nih/io.h>
1104+#include <nih/option.h>
1105+#include <nih/main.h>
1106+#include <nih/logging.h>
1107+#include <nih/error.h>
1108+
1109+#include <nih-dbus/dbus_connection.h>
1110+#include <nih-dbus/dbus_proxy.h>
1111+
1112+#include "dbus/upstart.h"
1113+#include "com.ubuntu.Upstart.h"
1114+
1115+
1116+/* Prototypes for static functions */
1117+static void udev_monitor_watcher (struct udev_monitor *udev_monitor,
1118+ NihIoWatch *watch, NihIoEvents events);
1119+static void upstart_disconnected (DBusConnection *connection);
1120+static void emit_event_error (void *data, NihDBusMessage *message);
1121+
1122+
1123+/**
1124+ * daemonise:
1125+ *
1126+ * Set to TRUE if we should become a daemon, rather than just running
1127+ * in the foreground.
1128+ **/
1129+static int daemonise = FALSE;
1130+
1131+/**
1132+ * upstart:
1133+ *
1134+ * Proxy to Upstart daemon.
1135+ **/
1136+static NihDBusProxy *upstart = NULL;
1137+
1138+
1139+/**
1140+ * options:
1141+ *
1142+ * Command-line options accepted by this program.
1143+ **/
1144+static NihOption options[] = {
1145+ { 0, "daemon", N_("Detach and run in the background"),
1146+ NULL, NULL, &daemonise, NULL },
1147+
1148+ NIH_OPTION_LAST
1149+};
1150+
1151+
1152+int
1153+main (int argc,
1154+ char *argv[])
1155+{
1156+ char ** args;
1157+ DBusConnection * connection;
1158+ struct udev * udev;
1159+ struct udev_monitor *udev_monitor;
1160+ int ret;
1161+
1162+ nih_main_init (argv[0]);
1163+
1164+ nih_option_set_synopsis (_("Bridge udev events into upstart"));
1165+ nih_option_set_help (
1166+ _("By default, upstart-udev-bridge does not detach from the "
1167+ "console and remains in the foreground. Use the --daemon "
1168+ "option to have it detach."));
1169+
1170+ args = nih_option_parser (NULL, argc, argv, options, FALSE);
1171+ if (! args)
1172+ exit (1);
1173+
1174+ /* Initialise the connection to Upstart */
1175+ connection = NIH_SHOULD (nih_dbus_connect (DBUS_ADDRESS_UPSTART, upstart_disconnected));
1176+ if (! connection) {
1177+ NihError *err;
1178+
1179+ err = nih_error_get ();
1180+ nih_fatal ("%s: %s", _("Could not connect to Upstart"),
1181+ err->message);
1182+ nih_free (err);
1183+
1184+ exit (1);
1185+ }
1186+
1187+ upstart = NIH_SHOULD (nih_dbus_proxy_new (NULL, connection,
1188+ NULL, DBUS_PATH_UPSTART,
1189+ NULL, NULL));
1190+ if (! upstart) {
1191+ NihError *err;
1192+
1193+ err = nih_error_get ();
1194+ nih_fatal ("%s: %s", _("Could not create Upstart proxy"),
1195+ err->message);
1196+ nih_free (err);
1197+
1198+ exit (1);
1199+ }
1200+
1201+ /* Initialise the connection to udev */
1202+ nih_assert (udev = udev_new ());
1203+ nih_assert (udev_monitor = udev_monitor_new_from_netlink (udev, "udev"));
1204+ nih_assert (udev_monitor_enable_receiving (udev_monitor) == 0);
1205+ udev_monitor_set_receive_buffer_size(udev_monitor, 128*1024*1024);
1206+
1207+ NIH_MUST (nih_io_add_watch (NULL, udev_monitor_get_fd (udev_monitor),
1208+ NIH_IO_READ,
1209+ (NihIoWatcher)udev_monitor_watcher,
1210+ udev_monitor));
1211+
1212+ /* Become daemon */
1213+ if (daemonise) {
1214+ if (nih_main_daemonise () < 0) {
1215+ NihError *err;
1216+
1217+ err = nih_error_get ();
1218+ nih_fatal ("%s: %s", _("Unable to become daemon"),
1219+ err->message);
1220+ nih_free (err);
1221+
1222+ exit (1);
1223+ }
1224+
1225+ /* Send all logging output to syslog */
1226+ openlog (program_name, LOG_PID, LOG_DAEMON);
1227+ nih_log_set_logger (nih_logger_syslog);
1228+ }
1229+
1230+ /* Handle TERM and INT signals gracefully */
1231+ nih_signal_set_handler (SIGTERM, nih_signal_handler);
1232+ NIH_MUST (nih_signal_add_handler (NULL, SIGTERM, nih_main_term_signal, NULL));
1233+
1234+ if (! daemonise) {
1235+ nih_signal_set_handler (SIGINT, nih_signal_handler);
1236+ NIH_MUST (nih_signal_add_handler (NULL, SIGINT, nih_main_term_signal, NULL));
1237+ }
1238+
1239+ ret = nih_main_loop ();
1240+
1241+ return ret;
1242+}
1243+
1244+
1245+static void
1246+udev_monitor_watcher (struct udev_monitor *udev_monitor,
1247+ NihIoWatch * watch,
1248+ NihIoEvents events)
1249+{
1250+ struct udev_device * udev_device;
1251+ const char * subsystem;
1252+ const char * action;
1253+ const char * kernel;
1254+ const char * devpath;
1255+ const char * devname;
1256+ nih_local char * name = NULL;
1257+ nih_local char ** env = NULL;
1258+ size_t env_len = 0;
1259+ DBusPendingCall * pending_call;
1260+
1261+ udev_device = udev_monitor_receive_device (udev_monitor);
1262+ if (! udev_device)
1263+ return;
1264+
1265+ subsystem = udev_device_get_subsystem (udev_device);
1266+ action = udev_device_get_action (udev_device);
1267+ kernel = udev_device_get_sysname (udev_device);
1268+ devpath = udev_device_get_devpath (udev_device);
1269+ devname = udev_device_get_devnode (udev_device);
1270+
1271+ if (! strcmp (action, "add")) {
1272+ name = NIH_MUST (nih_sprintf (NULL, "%s-device-added",
1273+ subsystem));
1274+ } else if (! strcmp (action, "change")) {
1275+ name = NIH_MUST (nih_sprintf (NULL, "%s-device-changed",
1276+ subsystem));
1277+ } else if (! strcmp (action, "remove")) {
1278+ name = NIH_MUST (nih_sprintf (NULL, "%s-device-removed",
1279+ subsystem));
1280+ } else {
1281+ name = NIH_MUST (nih_sprintf (NULL, "%s-device-%s",
1282+ subsystem, action));
1283+ }
1284+
1285+ env = NIH_MUST (nih_str_array_new (NULL));
1286+
1287+ if (kernel) {
1288+ nih_local char *var = NULL;
1289+
1290+ var = NIH_MUST (nih_sprintf (NULL, "KERNEL=%s", kernel));
1291+ NIH_MUST (nih_str_array_addp (&env, NULL, &env_len, var));
1292+ }
1293+
1294+ if (devpath) {
1295+ nih_local char *var = NULL;
1296+
1297+ var = NIH_MUST (nih_sprintf (NULL, "DEVPATH=%s", devpath));
1298+ NIH_MUST (nih_str_array_addp (&env, NULL, &env_len, var));
1299+ }
1300+
1301+ if (devname) {
1302+ nih_local char *var = NULL;
1303+
1304+ var = NIH_MUST (nih_sprintf (NULL, "DEVNAME=%s", devname));
1305+ NIH_MUST (nih_str_array_addp (&env, NULL, &env_len, var));
1306+ }
1307+
1308+ if (subsystem) {
1309+ nih_local char *var = NULL;
1310+
1311+ var = NIH_MUST (nih_sprintf (NULL, "SUBSYSTEM=%s", subsystem));
1312+ NIH_MUST (nih_str_array_addp (&env, NULL, &env_len, var));
1313+ }
1314+
1315+ if (action) {
1316+ nih_local char *var = NULL;
1317+
1318+ var = NIH_MUST (nih_sprintf (NULL, "ACTION=%s", action));
1319+ NIH_MUST (nih_str_array_addp (&env, NULL, &env_len, var));
1320+ }
1321+
1322+ for (struct udev_list_entry *list_entry = udev_device_get_properties_list_entry (udev_device);
1323+ list_entry != NULL;
1324+ list_entry = udev_list_entry_get_next (list_entry)) {
1325+ const char * key;
1326+ nih_local char *var = NULL;
1327+
1328+ key = udev_list_entry_get_name (list_entry);
1329+ if (! strcmp (key, "DEVPATH"))
1330+ continue;
1331+ if (! strcmp (key, "DEVNAME"))
1332+ continue;
1333+ if (! strcmp (key, "SUBSYSTEM"))
1334+ continue;
1335+ if (! strcmp (key, "ACTION"))
1336+ continue;
1337+
1338+ var = NIH_MUST (nih_sprintf (NULL, "%s=%s", key,
1339+ udev_list_entry_get_value (list_entry)));
1340+ NIH_MUST (nih_str_array_addp (&env, NULL, &env_len, var));
1341+ }
1342+
1343+ nih_debug ("%s %s", name, devname);
1344+
1345+ pending_call = NIH_SHOULD (upstart_emit_event (upstart,
1346+ name, env, FALSE,
1347+ NULL, emit_event_error, NULL,
1348+ NIH_DBUS_TIMEOUT_NEVER));
1349+ if (! pending_call) {
1350+ NihError *err;
1351+
1352+ err = nih_error_get ();
1353+ nih_warn ("%s", err->message);
1354+ nih_free (err);
1355+ }
1356+
1357+ dbus_pending_call_unref (pending_call);
1358+
1359+ udev_device_unref (udev_device);
1360+}
1361+
1362+
1363+static void
1364+upstart_disconnected (DBusConnection *connection)
1365+{
1366+ nih_fatal (_("Disconnected from Upstart"));
1367+ nih_main_loop_exit (1);
1368+}
1369+
1370+static void
1371+emit_event_error (void * data,
1372+ NihDBusMessage *message)
1373+{
1374+ NihError *err;
1375+
1376+ err = nih_error_get ();
1377+ nih_warn ("%s", err->message);
1378+ nih_free (err);
1379+}
1380
1381=== modified file 'init/control.c'
1382--- init/control.c 2009-07-11 11:47:12 +0000
1383+++ init/control.c 2011-05-15 18:31:10 +0000
1384@@ -25,8 +25,10 @@
1385
1386 #include <dbus/dbus.h>
1387
1388+#include <fcntl.h>
1389 #include <stdio.h>
1390 #include <string.h>
1391+#include <unistd.h>
1392
1393 #include <nih/macros.h>
1394 #include <nih/alloc.h>
1395@@ -462,13 +464,24 @@
1396 }
1397
1398
1399+int
1400+control_emit_event (void *data,
1401+ NihDBusMessage *message,
1402+ const char *name,
1403+ char * const *env,
1404+ int wait)
1405+{
1406+ return control_emit_event_with_file (data, message, name, env, wait, -1);
1407+}
1408+
1409 /**
1410- * control_emit_event:
1411+ * control_emit_event_with_file:
1412 * @data: not used,
1413 * @message: D-Bus connection and message received,
1414 * @name: name of event to emit,
1415 * @env: environment of environment,
1416- * @wait: whether to wait for event completion before returning.
1417+ * @wait: whether to wait for event completion before returning,
1418+ * @file: file descriptor.
1419 *
1420 * Implements the top half of the EmitEvent method of the com.ubuntu.Upstart
1421 * interface, the bottom half may be found in event_finished().
1422@@ -488,11 +501,12 @@
1423 * Returns: zero on success, negative value on raised error.
1424 **/
1425 int
1426-control_emit_event (void *data,
1427- NihDBusMessage *message,
1428- const char *name,
1429- char * const *env,
1430- int wait)
1431+control_emit_event_with_file (void *data,
1432+ NihDBusMessage *message,
1433+ const char *name,
1434+ char * const *env,
1435+ int wait,
1436+ int file)
1437 {
1438 Event *event;
1439 Blocked *blocked;
1440@@ -505,6 +519,7 @@
1441 if (! strlen (name)) {
1442 nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
1443 _("Name may not be empty string"));
1444+ close (file);
1445 return -1;
1446 }
1447
1448@@ -512,19 +527,33 @@
1449 if (! environ_all_valid (env)) {
1450 nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
1451 _("Env must be KEY=VALUE pairs"));
1452+ close (file);
1453 return -1;
1454 }
1455
1456 /* Make the event and block the message on it */
1457 event = event_new (NULL, name, (char **)env);
1458- if (! event)
1459- nih_return_system_error (-1);
1460+ if (! event) {
1461+ nih_error_raise_system ();
1462+ close (file);
1463+ return -1;
1464+ }
1465+
1466+ event->fd = file;
1467+ if (event->fd >= 0) {
1468+ long flags;
1469+
1470+ flags = fcntl (event->fd, F_GETFD);
1471+ flags &= ~FD_CLOEXEC;
1472+ fcntl (event->fd, F_SETFD, flags);
1473+ }
1474
1475 if (wait) {
1476 blocked = blocked_new (event, BLOCKED_EMIT_METHOD, message);
1477 if (! blocked) {
1478 nih_error_raise_system ();
1479 nih_free (event);
1480+ close (file);
1481 return -1;
1482 }
1483
1484
1485=== modified file 'init/control.h'
1486--- init/control.h 2009-07-09 08:36:52 +0000
1487+++ init/control.h 2011-05-15 18:31:10 +0000
1488@@ -60,6 +60,10 @@
1489 const char *name, char * const *env,
1490 int wait)
1491 __attribute__ ((warn_unused_result));
1492+int control_emit_event_with_file (void *data, NihDBusMessage *message,
1493+ const char *name, char * const *env,
1494+ int wait, int file)
1495+ __attribute__ ((warn_unused_result));
1496
1497 int control_get_version (void *data, NihDBusMessage *message,
1498 char **version)
1499
1500=== modified file 'init/event.c'
1501--- init/event.c 2010-12-14 15:32:41 +0000
1502+++ init/event.c 2011-05-15 18:31:10 +0000
1503@@ -25,6 +25,7 @@
1504
1505
1506 #include <string.h>
1507+#include <unistd.h>
1508
1509 #include <nih/macros.h>
1510 #include <nih/alloc.h>
1511@@ -123,6 +124,8 @@
1512
1513 nih_list_init (&event->entry);
1514
1515+ event->fd = -1;
1516+
1517 event->progress = EVENT_PENDING;
1518 event->failed = FALSE;
1519
1520@@ -393,8 +396,16 @@
1521 job->start_env = env;
1522 nih_ref (job->start_env, job);
1523
1524+ nih_discard (env);
1525+ env = NULL;
1526+
1527 job_finished (job, FALSE);
1528
1529+ NIH_MUST (event_operator_fds (class->start_on, job,
1530+ &job->fds, &job->num_fds,
1531+ &job->start_env, &len,
1532+ "UPSTART_FDS"));
1533+
1534 event_operator_events (job->class->start_on,
1535 job, &job->blocking);
1536
1537@@ -459,6 +470,8 @@
1538 nih_free (blocked);
1539 }
1540
1541+ close (event->fd);
1542+
1543 if (event->failed) {
1544 char *name;
1545
1546
1547=== modified file 'init/event.h'
1548--- init/event.h 2009-07-09 08:36:52 +0000
1549+++ init/event.h 2011-05-15 18:31:10 +0000
1550@@ -63,6 +63,7 @@
1551
1552 char *name;
1553 char **env;
1554+ int fd;
1555
1556 EventProgress progress;
1557 int failed;
1558
1559=== modified file 'init/event_operator.c'
1560--- init/event_operator.c 2010-11-19 14:34:51 +0000
1561+++ init/event_operator.c 2011-05-15 18:31:10 +0000
1562@@ -552,6 +552,65 @@
1563 return *env;
1564 }
1565
1566+int *
1567+event_operator_fds (EventOperator *root,
1568+ const void *parent,
1569+ int **fds,
1570+ size_t *num_fds,
1571+ char ***env,
1572+ size_t *len,
1573+ const char *key)
1574+{
1575+ nih_local char *evlist = NULL;
1576+
1577+ nih_assert (root != NULL);
1578+ nih_assert (fds != NULL);
1579+ nih_assert (num_fds != NULL);
1580+ nih_assert (env != NULL);
1581+ nih_assert (len != NULL);
1582+ nih_assert (key != NULL);
1583+
1584+ /* Initialise the event list variable with the name given. */
1585+ evlist = nih_sprintf (NULL, "%s=", key);
1586+ if (! evlist)
1587+ return NULL;
1588+
1589+ *num_fds = 0;
1590+ NIH_TREE_FOREACH_FULL (&root->node, iter,
1591+ (NihTreeFilter)event_operator_filter, NULL) {
1592+ EventOperator *oper = (EventOperator *)iter;
1593+
1594+ if (oper->type != EVENT_MATCH)
1595+ continue;
1596+
1597+ nih_assert (oper->event != NULL);
1598+
1599+ if (oper->event->fd >= 0) {
1600+ *fds = nih_realloc (*fds, parent, sizeof (int) * (*num_fds + 1));
1601+ if (! *fds)
1602+ return NULL;
1603+
1604+ (*fds)[(*num_fds)++] = oper->event->fd;
1605+
1606+ if (evlist[strlen (evlist) - 1] != '=') {
1607+ if (! nih_strcat_sprintf (&evlist, NULL, " %d",
1608+ oper->event->fd))
1609+ return NULL;
1610+ } else {
1611+ if (! nih_strcat_sprintf (&evlist, NULL, "%d",
1612+ oper->event->fd))
1613+ return NULL;
1614+ }
1615+ }
1616+ }
1617+
1618+ if (*num_fds)
1619+ if (! environ_add (env, parent, len, TRUE, evlist))
1620+ return NULL;
1621+
1622+ return (void *)1;
1623+}
1624+
1625 /**
1626 * event_operator_events:
1627 * @root: operator tree to collect from,
1628
1629=== modified file 'init/event_operator.h'
1630--- init/event_operator.h 2009-06-23 09:29:35 +0000
1631+++ init/event_operator.h 2011-05-15 18:31:10 +0000
1632@@ -95,6 +95,14 @@
1633 char ** event_operator_environment (EventOperator *root, char ***env,
1634 const void *parent, size_t *len,
1635 const char *key);
1636+int *
1637+event_operator_fds (EventOperator *root,
1638+ const void *parent,
1639+ int **fds,
1640+ size_t *num_fds,
1641+ char ***env,
1642+ size_t *len,
1643+ const char *key);
1644 void event_operator_events (EventOperator *root,
1645 const void *parent, NihList *list);
1646
1647
1648=== modified file 'init/job.c'
1649--- init/job.c 2010-12-14 15:32:41 +0000
1650+++ init/job.c 2011-05-15 18:31:10 +0000
1651@@ -118,6 +118,9 @@
1652 goto error;
1653 }
1654
1655+ job->fds = NULL;
1656+ job->num_fds = 0;
1657+
1658 job->pid = nih_alloc (job, sizeof (pid_t) * PROCESS_LAST);
1659 if (! job->pid)
1660 goto error;
1661
1662=== modified file 'init/job.h'
1663--- init/job.h 2009-07-03 16:38:02 +0000
1664+++ init/job.h 2011-05-15 18:31:10 +0000
1665@@ -134,6 +134,9 @@
1666 char **stop_env;
1667 EventOperator *stop_on;
1668
1669+ int *fds;
1670+ size_t num_fds;
1671+
1672 pid_t *pid;
1673 Event *blocker;
1674 NihList blocking;
1675
1676=== modified file 'po/POTFILES.in'
1677--- po/POTFILES.in 2011-05-05 09:06:21 +0000
1678+++ po/POTFILES.in 2011-05-15 18:31:10 +0000
1679@@ -20,3 +20,5 @@
1680 util/runlevel.c
1681 util/shutdown.c
1682 util/telinit.c
1683+
1684+extra/upstart-udev-bridge.c
1685
1686=== modified file 'po/upstart.pot'
1687--- po/upstart.pot 2011-03-22 17:52:25 +0000
1688+++ po/upstart.pot 2011-05-15 18:31:10 +0000
1689@@ -6,12 +6,13 @@
1690 #, fuzzy
1691 msgid ""
1692 msgstr ""
1693-"Project-Id-Version: upstart 1.2\n"
1694+"Project-Id-Version: upstart 1.3\n"
1695 "Report-Msgid-Bugs-To: new@bugs.launchpad.net\n"
1696-"POT-Creation-Date: 2011-03-22 10:52-0700\n"
1697+"POT-Creation-Date: 2011-05-15 15:48+0100\n"
1698 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1699 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1700 "Language-Team: LANGUAGE <LL@li.org>\n"
1701+"Language: \n"
1702 "MIME-Version: 1.0\n"
1703 "Content-Type: text/plain; charset=CHARSET\n"
1704 "Content-Transfer-Encoding: 8bit\n"
1705@@ -46,305 +47,364 @@
1706 msgid "Configuration directory deleted"
1707 msgstr ""
1708
1709-#: init/control.c:155
1710+#: init/control.c:157
1711 msgid "Connection from private client"
1712 msgstr ""
1713
1714-#: init/control.c:290
1715+#: init/control.c:292
1716 msgid "Disconnected from system bus"
1717 msgstr ""
1718
1719-#: init/control.c:356 init/main.c:546
1720+#: init/control.c:358 init/main.c:546
1721 msgid "Reloading configuration"
1722 msgstr ""
1723
1724-#: init/control.c:396 init/control.c:507
1725+#: init/control.c:398 init/control.c:521
1726 msgid "Name may not be empty string"
1727 msgstr ""
1728
1729-#: init/control.c:405
1730+#: init/control.c:407
1731 #, c-format
1732 msgid "Unknown job: %s"
1733 msgstr ""
1734
1735-#: init/control.c:514 init/job_class.c:522 init/job_class.c:710
1736-#: init/job_class.c:829 init/job_class.c:953
1737+#: init/control.c:529 init/job_class.c:524 init/job_class.c:712
1738+#: init/job_class.c:831 init/job_class.c:955
1739 msgid "Env must be KEY=VALUE pairs"
1740 msgstr ""
1741
1742-#: init/control.c:666
1743+#: init/control.c:695
1744 msgid "The log priority given was not recognised"
1745 msgstr ""
1746
1747-#: init/event.c:273
1748+#: init/errors.h:58
1749+msgid "Illegal parameter"
1750+msgstr ""
1751+
1752+#: init/errors.h:59
1753+msgid "Unknown parameter"
1754+msgstr ""
1755+
1756+#: init/errors.h:60 init/errors.h:71
1757+msgid "Expected operator"
1758+msgstr ""
1759+
1760+#: init/errors.h:61
1761+msgid "Mismatched braces"
1762+msgstr ""
1763+
1764+#: init/errors.h:62
1765+msgid "Illegal interval, expected number of seconds"
1766+msgstr ""
1767+
1768+#: init/errors.h:63
1769+msgid "Illegal exit status, expected integer"
1770+msgstr ""
1771+
1772+#: init/errors.h:64
1773+msgid "Illegal signal status, expected integer"
1774+msgstr ""
1775+
1776+#: init/errors.h:65
1777+msgid "Illegal file creation mask, expected octal integer"
1778+msgstr ""
1779+
1780+#: init/errors.h:66
1781+msgid "Illegal nice value, expected -20 to 19"
1782+msgstr ""
1783+
1784+#: init/errors.h:67
1785+msgid "Illegal oom adjustment, expected -16 to 15 or 'never'"
1786+msgstr ""
1787+
1788+#: init/errors.h:68
1789+msgid "Illegal oom score adjustment, expected -999 to 1000 or 'never'"
1790+msgstr ""
1791+
1792+#: init/errors.h:69
1793+msgid "Illegal limit, expected 'unlimited' or integer"
1794+msgstr ""
1795+
1796+#: init/errors.h:70
1797+msgid "Expected event"
1798+msgstr ""
1799+
1800+#: init/errors.h:72
1801+msgid "Expected variable name before value"
1802+msgstr ""
1803+
1804+#: init/errors.h:73
1805+msgid "Mismatched parentheses"
1806+msgstr ""
1807+
1808+#: init/errors.h:74
1809+msgid "Name already taken"
1810+msgstr ""
1811+
1812+#: init/event.c:276
1813 #, c-format
1814 msgid "Handling %s event"
1815 msgstr ""
1816
1817-#: init/event.c:373
1818+#: init/event.c:376
1819 #, c-format
1820 msgid "Failed to obtain %s instance: %s"
1821 msgstr ""
1822
1823-#: init/event.c:448
1824+#: init/event.c:459
1825 msgid "Event failed"
1826 msgstr ""
1827
1828-#: init/job.c:223
1829+#: init/job.c:226
1830 #, c-format
1831 msgid "%s goal changed from %s to %s"
1832 msgstr ""
1833
1834-#: init/job.c:294
1835+#: init/job.c:297
1836 #, c-format
1837 msgid "%s state changed from %s to %s"
1838 msgstr ""
1839
1840-#: init/job.c:713 init/job.c:751
1841+#: init/job.c:716 init/job.c:754
1842 msgid "Job failed to start"
1843 msgstr ""
1844
1845-#: init/job.c:726 init/job.c:762
1846+#: init/job.c:729 init/job.c:765
1847 msgid "Job failed while stopping"
1848 msgstr ""
1849
1850-#: init/job.c:738 init/job.c:773
1851+#: init/job.c:741 init/job.c:776
1852 msgid "Job failed to restart"
1853 msgstr ""
1854
1855-#: init/job.c:966
1856+#: init/job.c:969
1857 msgid "stop"
1858 msgstr ""
1859
1860-#: init/job.c:968
1861+#: init/job.c:971
1862 msgid "start"
1863 msgstr ""
1864
1865-#: init/job.c:970
1866+#: init/job.c:973
1867 msgid "respawn"
1868 msgstr ""
1869
1870-#: init/job.c:1015
1871+#: init/job.c:1018
1872 msgid "waiting"
1873 msgstr ""
1874
1875-#: init/job.c:1017
1876+#: init/job.c:1020
1877 msgid "starting"
1878 msgstr ""
1879
1880-#: init/job.c:1019 init/process.c:80
1881+#: init/job.c:1022 init/process.c:80
1882 msgid "pre-start"
1883 msgstr ""
1884
1885-#: init/job.c:1021
1886+#: init/job.c:1024
1887 msgid "spawned"
1888 msgstr ""
1889
1890-#: init/job.c:1023 init/process.c:82
1891+#: init/job.c:1026 init/process.c:82
1892 msgid "post-start"
1893 msgstr ""
1894
1895-#: init/job.c:1025
1896+#: init/job.c:1028
1897 msgid "running"
1898 msgstr ""
1899
1900-#: init/job.c:1027 init/process.c:84
1901+#: init/job.c:1030 init/process.c:84
1902 msgid "pre-stop"
1903 msgstr ""
1904
1905-#: init/job.c:1029
1906+#: init/job.c:1032
1907 msgid "stopping"
1908 msgstr ""
1909
1910-#: init/job.c:1031
1911+#: init/job.c:1034
1912 msgid "killed"
1913 msgstr ""
1914
1915-#: init/job.c:1033 init/process.c:86
1916+#: init/job.c:1036 init/process.c:86
1917 msgid "post-stop"
1918 msgstr ""
1919
1920-#: init/job.c:1113 init/job_class.c:756
1921+#: init/job.c:1116 init/job_class.c:758
1922 #, c-format
1923 msgid "Job is already running: %s"
1924 msgstr ""
1925
1926-#: init/job.c:1177 init/job.c:1242 init/job_class.c:875 init/job_class.c:998
1927+#: init/job.c:1180 init/job.c:1245 init/job_class.c:877 init/job_class.c:1000
1928 #, c-format
1929 msgid "Job has already been stopped: %s"
1930 msgstr ""
1931
1932-#: init/job_class.c:559 init/job_class.c:604 init/job_class.c:867
1933-#: init/job_class.c:990
1934+#: init/job_class.c:561 init/job_class.c:606 init/job_class.c:869
1935+#: init/job_class.c:992
1936 #, c-format
1937 msgid "Unknown instance: %s"
1938 msgstr ""
1939
1940-#: init/job_process.c:279
1941+#: init/job_process.c:277
1942 #, c-format
1943 msgid "Failed to spawn %s %s process: %s"
1944 msgstr ""
1945
1946-#: init/job_process.c:285
1947+#: init/job_process.c:283
1948 msgid "Temporary process spawn error"
1949 msgstr ""
1950
1951-#: init/job_process.c:292
1952+#: init/job_process.c:290
1953 #, c-format
1954 msgid "%s %s process (%d)"
1955 msgstr ""
1956
1957-#: init/job_process.c:399
1958+#: init/job_process.c:403
1959 #, c-format
1960 msgid "Pausing %s (%d) [pre-exec] for debug"
1961 msgstr ""
1962
1963-#: init/job_process.c:453
1964+#: init/job_process.c:473
1965 #, c-format
1966 msgid "Failed to open system console: %s"
1967 msgstr ""
1968
1969-#: init/job_process.c:669
1970+#: init/job_process.c:697
1971+#, c-format
1972+msgid "unable to move script fd: %s"
1973+msgstr ""
1974+
1975+#: init/job_process.c:702
1976 #, c-format
1977 msgid "unable to open console: %s"
1978 msgstr ""
1979
1980-#: init/job_process.c:724
1981+#: init/job_process.c:757
1982 #, c-format
1983 msgid "unable to set \"%s\" resource limit: %s"
1984 msgstr ""
1985
1986-#: init/job_process.c:729
1987+#: init/job_process.c:762
1988 #, c-format
1989 msgid "unable to set priority: %s"
1990 msgstr ""
1991
1992-#: init/job_process.c:734
1993+#: init/job_process.c:767
1994 #, c-format
1995 msgid "unable to set oom adjustment: %s"
1996 msgstr ""
1997
1998-#: init/job_process.c:739
1999+#: init/job_process.c:772
2000 #, c-format
2001 msgid "unable to change root directory: %s"
2002 msgstr ""
2003
2004-#: init/job_process.c:744
2005+#: init/job_process.c:777
2006 #, c-format
2007 msgid "unable to change working directory: %s"
2008 msgstr ""
2009
2010-#: init/job_process.c:749
2011+#: init/job_process.c:782
2012 #, c-format
2013 msgid "unable to set trace: %s"
2014 msgstr ""
2015
2016-#: init/job_process.c:754
2017+#: init/job_process.c:787
2018 #, c-format
2019 msgid "unable to execute: %s"
2020 msgstr ""
2021
2022-#: init/job_process.c:785
2023-#, c-format
2024-msgid "Sending TERM signal to %s %s process (%d)"
2025-msgstr ""
2026-
2027-#: init/job_process.c:793
2028-#, c-format
2029-msgid "Failed to send TERM signal to %s %s process (%d): %s"
2030-msgstr ""
2031-
2032-#: init/job_process.c:833
2033-#, c-format
2034-msgid "Sending KILL signal to %s %s process (%d)"
2035-msgstr ""
2036-
2037-#: init/job_process.c:841
2038-#, c-format
2039-msgid "Failed to send KILL signal to %s %s process (%d): %s"
2040-msgstr ""
2041-
2042-#: init/job_process.c:901
2043+#: init/job_process.c:818 init/job_process.c:868
2044+#, c-format
2045+msgid "Sending %s signal to %s %s process (%d)"
2046+msgstr ""
2047+
2048+#: init/job_process.c:827 init/job_process.c:877
2049+#, c-format
2050+msgid "Failed to send %s signal to %s %s process (%d): %s"
2051+msgstr ""
2052+
2053+#: init/job_process.c:938
2054 #, c-format
2055 msgid "%s %s process (%d) terminated with status %d"
2056 msgstr ""
2057
2058-#: init/job_process.c:906
2059+#: init/job_process.c:943
2060 #, c-format
2061 msgid "%s %s process (%d) exited normally"
2062 msgstr ""
2063
2064-#: init/job_process.c:921
2065+#: init/job_process.c:958
2066 #, c-format
2067 msgid "%s %s process (%d) killed by %s signal"
2068 msgstr ""
2069
2070-#: init/job_process.c:925
2071+#: init/job_process.c:962
2072 #, c-format
2073 msgid "%s %s process (%d) killed by signal %d"
2074 msgstr ""
2075
2076-#: init/job_process.c:939
2077+#: init/job_process.c:976
2078 #, c-format
2079 msgid "%s %s process (%d) stopped by %s signal"
2080 msgstr ""
2081
2082-#: init/job_process.c:943
2083+#: init/job_process.c:980
2084 #, c-format
2085 msgid "%s %s process (%d) stopped by signal %d"
2086 msgstr ""
2087
2088-#: init/job_process.c:957
2089+#: init/job_process.c:994
2090 #, c-format
2091 msgid "%s %s process (%d) continued by %s signal"
2092 msgstr ""
2093
2094-#: init/job_process.c:961
2095+#: init/job_process.c:998
2096 #, c-format
2097 msgid "%s %s process (%d) continued by signal %d"
2098 msgstr ""
2099
2100-#: init/job_process.c:1096
2101+#: init/job_process.c:1133
2102 #, c-format
2103 msgid "%s respawning too fast, stopped"
2104 msgstr ""
2105
2106-#: init/job_process.c:1102
2107+#: init/job_process.c:1139
2108 #, c-format
2109 msgid "%s %s process ended, respawning"
2110 msgstr ""
2111
2112-#: init/job_process.c:1342
2113+#: init/job_process.c:1379
2114 #, c-format
2115 msgid "Failed to set ptrace options for %s %s process (%d): %s"
2116 msgstr ""
2117
2118-#: init/job_process.c:1355 init/job_process.c:1550
2119+#: init/job_process.c:1392 init/job_process.c:1587
2120 #, c-format
2121 msgid "Failed to continue traced %s %s process (%d): %s"
2122 msgstr ""
2123
2124-#: init/job_process.c:1395 init/job_process.c:1486 init/job_process.c:1541
2125+#: init/job_process.c:1432 init/job_process.c:1523 init/job_process.c:1578
2126 #, c-format
2127 msgid "Failed to detach traced %s %s process (%d): %s"
2128 msgstr ""
2129
2130-#: init/job_process.c:1435
2131+#: init/job_process.c:1472
2132 #, c-format
2133 msgid "Failed to deliver signal to traced %s %s process (%d): %s"
2134 msgstr ""
2135
2136-#: init/job_process.c:1470
2137+#: init/job_process.c:1507
2138 #, c-format
2139 msgid "Failed to obtain child process id for %s %s process (%d): %s"
2140 msgstr ""
2141
2142-#: init/job_process.c:1477
2143+#: init/job_process.c:1514
2144 #, c-format
2145 msgid "%s %s process (%d) became new process (%d)"
2146 msgstr ""
2147
2148-#: init/job_process.c:1536
2149+#: init/job_process.c:1573
2150 #, c-format
2151 msgid "%s %s process (%d) executable changed"
2152 msgstr ""
2153@@ -819,3 +879,33 @@
2154 #, c-format
2155 msgid "%s: illegal runlevel: %s\n"
2156 msgstr ""
2157+
2158+#: extra/upstart-udev-bridge.c:76
2159+msgid "Detach and run in the background"
2160+msgstr ""
2161+
2162+#: extra/upstart-udev-bridge.c:95
2163+msgid "Bridge udev events into upstart"
2164+msgstr ""
2165+
2166+#: extra/upstart-udev-bridge.c:97
2167+msgid ""
2168+"By default, upstart-udev-bridge does not detach from the console and remains "
2169+"in the foreground. Use the --daemon option to have it detach."
2170+msgstr ""
2171+
2172+#: extra/upstart-udev-bridge.c:111
2173+msgid "Could not connect to Upstart"
2174+msgstr ""
2175+
2176+#: extra/upstart-udev-bridge.c:125
2177+msgid "Could not create Upstart proxy"
2178+msgstr ""
2179+
2180+#: extra/upstart-udev-bridge.c:149
2181+msgid "Unable to become daemon"
2182+msgstr ""
2183+
2184+#: extra/upstart-udev-bridge.c:297
2185+msgid "Disconnected from Upstart"
2186+msgstr ""

Subscribers

People subscribed via source and target branches