Merge lp:~jamesodhunt/upstart/upstream-update-bash-completion into lp:upstart

Proposed by James Hunt
Status: Merged
Merged at revision: 1298
Proposed branch: lp:~jamesodhunt/upstart/upstream-update-bash-completion
Merge into: lp:upstart
Diff against target: 6318 lines (+4651/-373)
34 files modified
ChangeLog (+142/-0)
Makefile.am (+1/-1)
conf/rc-sysinit.conf (+2/-0)
configure.ac (+3/-2)
contrib/bash_completion/upstart (+96/-36)
dbus/upstart.h (+1/-1)
init/conf.c (+0/-1)
init/control.c (+33/-7)
init/control.h (+15/-1)
init/environ.c (+0/-1)
init/environ.h (+0/-1)
init/job_process.c (+0/-1)
init/job_process.h (+0/-1)
init/main.c (+229/-136)
init/man/init.5 (+1/-1)
init/man/init.8 (+23/-2)
init/paths.h (+16/-2)
init/tests/test_conf.c (+0/-1)
init/tests/test_control.c (+0/-1)
init/tests/test_environ.c (+0/-1)
init/tests/test_job_class.c (+0/-1)
init/tests/test_job_process.c (+0/-1)
po/upstart.pot (+268/-134)
scripts/Makefile.am (+25/-0)
scripts/init-checkconf.sh (+248/-0)
scripts/initctl2dot.py (+571/-0)
scripts/man/init-checkconf.8 (+73/-0)
scripts/man/initctl2dot.8 (+87/-0)
util/Makefile.am (+1/-1)
util/initctl.c (+1014/-17)
util/initctl.h (+458/-0)
util/man/initctl.8 (+163/-2)
util/reboot.c (+0/-1)
util/tests/test_initctl.c (+1181/-19)
To merge this branch: bzr merge lp:~jamesodhunt/upstart/upstream-update-bash-completion
Reviewer Review Type Date Requested Status
Upstart Developers Pending
Review via email: mp+63353@code.launchpad.net

Description of the change

* contrib/bash_completion/upstart:
  - Made function names more meaningful:
  - _upstart_jobs: Now returns a unique list
  - _upstart_events (nee _upstart_named_events ) now considers all
    "emits" tokens.
  - Updates for "check-config" and "show-config".
  - Added "--session" option.
  - Added "--no-wait" for emit, reload and restart.

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 'ChangeLog'
2--- ChangeLog 2011-05-12 20:42:28 +0000
3+++ ChangeLog 2011-06-03 09:50:59 +0000
4@@ -1,3 +1,145 @@
5+2011-06-02 James Hunt <james.hunt@ubuntu.com>
6+
7+ * contrib/bash_completion/upstart:
8+ - Made function names more meaningful:
9+ - _upstart_jobs: Now returns a unique list
10+ - _upstart_events (nee _upstart_named_events ) now considers all
11+ "emits" tokens.
12+ - Updates for "check-config" and "show-config".
13+ - Added "--session" option.
14+ - Added "--no-wait" for emit, reload and restart.
15+
16+2011-06-01 James Hunt <james.hunt@ubuntu.com>
17+
18+ Add D-Bus session support to initctl.
19+
20+ * util/initctl.c:
21+ - Added "--session" command-line option.
22+ - dbus_bus_type_setter(): New function used by option parser to
23+ distinguish system/session D-Bus bus type.
24+ - system_bus variable now replaced by two others: use_dbus (boolean)
25+ and dbus_bus_type.
26+ - upstart_open(): Updated to handle multiple D-Bus bus types.
27+ * util/man/initctl.8: Update for "--session" option.
28+ * util/tests/test_initctl.c: Updated to make use of use_dbus and
29+ dbus_bus_type rather than system_bus.
30+
31+ Add "show-config" command to initctl.
32+
33+ * util/initctl.c:
34+ - New functions:
35+ - job_class_condition_handler(): Handler function to retrieve job conditions.
36+ - job_class_condition_err_handler(): Handler error function for
37+ job_class_condition_handler().
38+ - job_class_parse_events(): Convert RPN "start on" and "stop on" conditions to
39+ human-readable format.
40+ - job_class_show_emits(): Display events which job emits.
41+ - job_class_show_conditions(): Make D-Bus calls to retrieve "start on" and
42+ "stop on" conditions.
43+ - show_config_action: Handle "show-config" command..
44+ * util/initctl.h: New file providing stack-handling functionality for
45+ RPN parsing for "show-config" command.
46+ * util/Makefile.am: Added initctl.h to initctl_SOURCES.
47+ * util/man/initctl.8: Updated for "show-config" command and associated
48+ options.
49+ * util/tests/test_initctl.c:
50+ - New macros START_UPSTART, STOP_UPSTART, RUN_COMMAND, CREATE_FILE and DELETE_FILE.
51+ These are required since due to the introduction of the
52+ "show-config" initctl command, initctl is no longer solely a proxy
53+ to Upstart: it now has some intelligence (it parses the
54+ "emits", "start on" and "stop on" conditions) and thus must be
55+ tested directly.
56+ - test_show_config(): New function to test "initctl show-config".
57+ - in_chroot(): New function to detect if tests are being run from
58+ within a chroot environment.
59+ - dbus_configured(): New function which performs a basic check to
60+ establish if D-Bus is configured correctly.
61+ - main(): Added call to test_show_config(), conditional on
62+ a non-chroot environment and a working D-Bus system.
63+
64+ Add "check-config" command to initctl.
65+
66+ * util/initctl.c:
67+ - New functions:
68+ - allow_event(): Determine if specified event is erroneous or not.
69+ Handles globbing.
70+ - allow_job(): Determine if specified job is erroneous or not.
71+ Handles variables (such as instance variables).
72+ - check_condition(): High-level function to handle checking start
73+ on/stop on conditions.
74+ - check_config_action: Handler for "check-config" command.
75+ - display_check_errors(): Display errors from expression tree nodes
76+ that are in error.
77+ - eval_expr_tree(): Evaluate expression tree.
78+ - ignored_events_setter(): handler for '--ignore-events' command-line
79+ option for "check-config" command.
80+ - tree_filter(): Used for filtering expression tree nodes.
81+ - show_config_action(): Update for check-config mode.
82+ - job_class_parse_events(): Update for check-config mode.
83+ - job_class_show_emits(): Update for check-config mode.
84+ * util/initctl.h:
85+ - Added structs for JobCondition, CheckConfigData and ExprNode.
86+ - New macros: MAKE_EXPR_NODE() and MAKE_JOB_CONDITION().
87+ * util/tests/test_initctl.c:
88+ - test_check_config(): New function to test "initctl check-config".
89+ - main(): Added call to test_check_config(), conditional on
90+ a non-chroot environment and a working D-Bus system.
91+ * util/man/initctl.8: Updated for "check-config" command and associated
92+ options.
93+ * conf/rc-sysinit.conf: Added "emits" stanza, required by
94+ "check-config".
95+
96+ Addition of initctl2dot script for visualisation.
97+
98+ * Makefile.am: Added scripts directory.
99+ * configure.ac: Updated AC_CONFIG_FILES for scripts/Makefile.
100+ * scripts/Makefile.am: Makefile for scripts.
101+ * scripts/initctl2dot.py: Python script to produce dot(1) graphs of
102+ "initctl show-config" output.
103+ * scripts/man/initctl2dot.8: Man page for initctl2dot.py script.
104+
105+ Addition of init-checkconf script.
106+
107+ * scripts/init-checkconf.sh: Script to determine if specified job
108+ config file is valid or not.
109+ * scripts/man/init-checkconf.8: Man page for init-checkconf.sh.
110+ * scripts/Makefile.am: Added init-checkconf script and man
111+ page.
112+
113+2011-05-31 James Hunt <james.hunt@ubuntu.com>
114+
115+ Add command-line option to use D-Bus session bus (for testing).
116+
117+ * init/control.c:
118+ - Added new boolean use_session_bus.
119+ - Updated comments.
120+ - control_handle_bus_type(): New function to allow selection of
121+ session bus via env var "UPSTART_USE_SESSION_BUS".
122+ Also logs use of session bus if use_session_bus set.
123+ - control_bus_open(): Now connects to either D-Bus system bus or session bus.
124+ * init/control.h: New define for USE_SESSION_BUS_ENV.
125+ * init/main.c: Addition of "--session" command-line option.
126+ * init/man/init.8: Update for new "--session" command-line option.
127+
128+ * Corrected copyright notices.
129+
130+ Add option to allow alternate location for job config files.
131+
132+ * init/main.c:
133+ - Added "--confdir <dir>" command-line option.
134+ - handle_confdir(): New function to select alternate confdir using env
135+ var "UPSTART_CONFDIR" or command-line option (for testing).
136+ * init/paths.h: Added define for CONFDIR_ENV.
137+ * init/man/init.8: Update for new "--confdir" command-line option.
138+
139+ Add ability to suppress initial event and/or change its name.
140+
141+ * init/main.c: New command-line options: "--no-startup-event" and
142+ "--startup-event". If "--no-startup-event" specified, log message as a
143+ debug aid.
144+ * init/man/init.8: Documentation for new command-line options:
145+ "--no-startup-event" and "--startup-event".
146+
147 2011-05-12 Marc - A. Dahlhaus <mad@wol.de>
148
149 * init/job_class.h (JobClass): Add kill signal member
150
151=== modified file 'Makefile.am'
152--- Makefile.am 2010-02-04 03:42:29 +0000
153+++ Makefile.am 2011-06-03 09:50:59 +0000
154@@ -1,6 +1,6 @@
155 ## Process this file with automake to produce Makefile.in
156
157-SUBDIRS = intl dbus init util conf doc contrib po
158+SUBDIRS = intl dbus init util conf doc contrib po scripts
159
160 EXTRA_DIST = HACKING
161
162
163=== modified file 'conf/rc-sysinit.conf'
164--- conf/rc-sysinit.conf 2010-02-04 03:59:06 +0000
165+++ conf/rc-sysinit.conf 2011-06-03 09:50:59 +0000
166@@ -13,6 +13,8 @@
167 # or by faking an old /etc/inittab entry
168 env DEFAULT_RUNLEVEL=2
169
170+emits runlevel
171+
172 # There can be no previous runlevel here, but there might be old
173 # information in /var/run/utmp that we pick up, and we don't want
174 # that.
175
176=== modified file 'configure.ac'
177--- configure.ac 2011-03-22 17:53:17 +0000
178+++ configure.ac 2011-06-03 09:50:59 +0000
179@@ -2,7 +2,7 @@
180
181 AC_PREREQ(2.61)
182 AC_INIT([upstart], [1.3], [upstart-devel@lists.ubuntu.com])
183-NIH_COPYRIGHT([[Copyright © 2011 Scott James Remnant, Google Inc., Canonical Ltd.]])
184+NIH_COPYRIGHT([[Copyright © 2011 Scott James Remnant, Canonical Ltd.]])
185 AC_CONFIG_SRCDIR([init/main.c])
186 AC_CONFIG_MACRO_DIR([m4])
187
188@@ -64,6 +64,7 @@
189
190 AC_CONFIG_FILES([ Makefile intl/Makefile
191 dbus/Makefile init/Makefile util/Makefile conf/Makefile
192- doc/Makefile contrib/Makefile po/Makefile.in ])
193+ doc/Makefile contrib/Makefile po/Makefile.in
194+ scripts/Makefile ])
195 AC_CONFIG_HEADERS([config.h])
196 AC_OUTPUT
197
198=== modified file 'contrib/bash_completion/upstart'
199--- contrib/bash_completion/upstart 2010-12-21 13:54:49 +0000
200+++ contrib/bash_completion/upstart 2011-06-03 09:50:59 +0000
201@@ -3,26 +3,28 @@
202 #
203 # We don't provide completion for 'init' itself for obvious reasons.
204 have initctl &&
205-_upstart_conf_events()
206-{
207- initctl list|awk '{print $1}'
208-} &&
209-_upstart_named_events()
210-{
211- (cd /etc/init && grep '^emits ' *.conf|sed 's/^emits //g')
212-} &&
213-_upstart_events()
214-{
215- (_upstart_conf_events;_upstart_named_events)|tr ' ' '\n'|sort -u
216-} &&
217-_upstart_startable_events()
218+_upstart_jobs()
219+{
220+ initctl list|awk '{print $1}'|sort -u
221+} &&
222+_upstart_startable_jobs()
223 {
224 initctl list|cut -d\, -f1|awk '$2 == "stop/waiting" {print $1}'
225 } &&
226-_upstart_stoppable_events()
227+_upstart_stoppable_jobs()
228 {
229 initctl list|cut -d\, -f1|awk '$2 == "start/running" {print $1}'
230 } &&
231+_upstart_events()
232+{
233+ # note that we don't provide the internal events such as "starting"
234+ # (and those from mountall) since the user should be using the
235+ # associated command to emit such events.
236+ (cd /etc/init && \
237+ egrep '^[[:space:]]*emits ' *.conf |\
238+ cut -d: -f2- | sed 's/^[[:space:]]*emits //g' |\
239+ tr ' ' '\n' | awk '{print $NF}' | grep -v ^$|sort -u)
240+} &&
241 _upstart_initctl()
242 {
243 _get_comp_words_by_ref cur prev
244@@ -32,34 +34,92 @@
245 case "$prev" in
246
247 start)
248- COMPREPLY=( $(compgen -W "-n --no-wait $(_upstart_startable_events)" -- ${cur}) )
249+ COMPREPLY=( $(compgen -W "-n --no-wait $(_upstart_startable_jobs)" -- ${cur}) )
250 return 0
251 ;;
252
253 stop)
254- COMPREPLY=( $(compgen -W "-n --no-wait $(_upstart_stoppable_events)" -- ${cur}) )
255+ COMPREPLY=( $(compgen -W "-n --no-wait $(_upstart_stoppable_jobs)" -- ${cur}) )
256 return 0
257 ;;
258
259 emit)
260- COMPREPLY=( $(compgen -W "$(_upstart_events)" -- ${cur}) )
261- return 0
262- ;;
263-
264- reload|restart|status)
265- COMPREPLY=( $(compgen -W "$(_upstart_conf_events)" -- ${cur}) )
266+ COMPREPLY=( $(compgen -W "-n --no-wait $(_upstart_events)" -- ${cur}) )
267+ return 0
268+ ;;
269+
270+ -i|--ignore-events)
271+ # handle visualisation options after check-config command
272+ for cmd in check-config
273+ do
274+ cwords=${COMP_WORDS[@]##}
275+ filtered_cwords=${COMP_WORDS[@]##${cmd}}
276+ if [ "$filtered_cwords" != "$cwords" ]
277+ then
278+ COMPREPLY=( $(compgen -W "$(_upstart_jobs)" -- ${cur}) )
279+ return 0
280+ fi
281+ done
282+ ;;
283+
284+ -e|--enumerate)
285+ # handle visualisation options after show-config command
286+ for cmd in show-config
287+ do
288+ cwords=${COMP_WORDS[@]##}
289+ filtered_cwords=${COMP_WORDS[@]##${cmd}}
290+ if [ "$filtered_cwords" != "$cwords" ]
291+ then
292+ COMPREPLY=( $(compgen -W "$(_upstart_jobs)" -- ${cur}) )
293+ return 0
294+ fi
295+ done
296+ ;;
297+
298+ reload|restart)
299+ COMPREPLY=( $(compgen -W "-n --no-wait $(_upstart_stoppable_jobs)" -- ${cur}) )
300+ return 0
301+ ;;
302+
303+ status)
304+ COMPREPLY=( $(compgen -W "$(_upstart_jobs)" -- ${cur}) )
305+ return 0
306+ ;;
307+
308+ check-config)
309+ COMPREPLY=( $(compgen -W "-w --warn -i --ignore-events= $(_upstart_jobs)" -- ${cur}) )
310+ return 0
311+ ;;
312+ show-config)
313+ COMPREPLY=( $(compgen -W "-e --enumerate $(_upstart_jobs)" -- ${cur}) )
314 return 0
315 ;;
316
317 -n|--no-wait)
318- # allow no wait after start/stop commands
319- for cmd in start stop
320+ # allow 'no wait' for certain commands
321+ for cmd in start stop restart emit
322 do
323 cwords=${COMP_WORDS[@]##}
324 filtered_cwords=${COMP_WORDS[@]##${cmd}}
325 if [ "$filtered_cwords" != "$cwords" ]
326 then
327- COMPREPLY=( $(compgen -W "$(_upstart_${cmd}able_events)" -- ${cur}) )
328+ case "$cmd" in
329+ start)
330+ COMPREPLY=( $(compgen -W "$(_upstart_startable_jobs)" -- ${cur}) )
331+ ;;
332+
333+ stop)
334+ COMPREPLY=( $(compgen -W "$(_upstart_stoppable_jobs)" -- ${cur}) )
335+ ;;
336+
337+ restart)
338+ COMPREPLY=( $(compgen -W "$(_upstart_stoppable_jobs)" -- ${cur}) )
339+ ;;
340+
341+ emit)
342+ COMPREPLY=( $(compgen -W "$(_upstart_events)" -- ${cur}) )
343+ ;;
344+ esac
345 return 0
346 fi
347 done
348@@ -71,7 +131,7 @@
349 ;;
350 esac
351
352- opts="--help --version -q --quiet -v --verbose --system --dest="
353+ opts="--help --version -q --quiet -v --verbose --session --system --dest="
354 cmds=$(initctl help|grep "^ [^ ]"|awk '{print $1}')
355
356 COMPREPLY=( $(compgen -W "${opts} ${cmds}" -- ${cur}) )
357@@ -84,7 +144,7 @@
358 COMPREPLY=()
359 _get_comp_words_by_ref cur prev
360
361- opts="--help --version -q --quiet -v --verbose --system --dest= \
362+ opts="--help --version -q --quiet -v --verbose --session --system --dest= \
363 -n --no-wait"
364
365 case "$prev" in
366@@ -94,7 +154,7 @@
367 ;;
368 esac
369
370- COMPREPLY=( $(compgen -W "$opts $(_upstart_startable_events)" -- ${cur}) )
371+ COMPREPLY=( $(compgen -W "$opts $(_upstart_startable_jobs)" -- ${cur}) )
372 return 0
373 } && complete -F _upstart_start start
374
375@@ -104,7 +164,7 @@
376 COMPREPLY=()
377 _get_comp_words_by_ref cur prev
378
379- opts="--help --version -q --quiet -v --verbose --system --dest= \
380+ opts="--help --version -q --quiet -v --verbose --session --system --dest= \
381 -n --no-wait"
382
383 case "$prev" in
384@@ -114,7 +174,7 @@
385 ;;
386 esac
387
388- COMPREPLY=( $(compgen -W "$opts $(_upstart_stoppable_events)" -- ${cur}) )
389+ COMPREPLY=( $(compgen -W "$opts $(_upstart_stoppable_jobs)" -- ${cur}) )
390 return 0
391 } && complete -F _upstart_stop stop
392
393@@ -124,7 +184,7 @@
394 COMPREPLY=()
395 _get_comp_words_by_ref cur prev
396
397- opts="--help --version -q --quiet -v --verbose --system --dest= \
398+ opts="--help --version -q --quiet -v --verbose --session --system --dest= \
399 -n --no-wait"
400
401 case "$prev" in
402@@ -134,7 +194,7 @@
403 ;;
404 esac
405
406- COMPREPLY=( $(compgen -W "$opts $(_upstart_events)" -- ${cur}) )
407+ COMPREPLY=( $(compgen -W "$opts $(_upstart_stoppable_jobs)" -- ${cur}) )
408 return 0
409
410 } && complete -F _upstart_restart restart
411@@ -145,7 +205,7 @@
412 COMPREPLY=()
413 _get_comp_words_by_ref cur prev
414
415- opts="--help --version -q --quiet -v --verbose --system --dest="
416+ opts="--help --version -q -d --detail -e --enumerate --quiet -v --verbose --session --system --dest="
417
418 case "$prev" in
419 --help|--version)
420@@ -154,7 +214,7 @@
421 ;;
422 esac
423
424- COMPREPLY=( $(compgen -W "$opts $(_upstart_events)" -- ${cur}) )
425+ COMPREPLY=( $(compgen -W "$opts $(_upstart_jobs)" -- ${cur}) )
426 return 0
427
428 } && complete -F _upstart_status status
429@@ -165,7 +225,7 @@
430 COMPREPLY=()
431 _get_comp_words_by_ref cur prev
432
433- opts="--help --version -q --quiet -v --verbose --system --dest="
434+ opts="--help --version -q --quiet -v --verbose --session --system --dest="
435
436 case "$prev" in
437 --help|--version)
438@@ -174,7 +234,7 @@
439 ;;
440 esac
441
442- COMPREPLY=( $(compgen -W "$opts $(_upstart_events)" -- ${cur}) )
443+ COMPREPLY=( $(compgen -W "$opts $(_upstart_stoppable_jobs)" -- ${cur}) )
444 return 0
445
446 } && complete -F _upstart_reload reload
447
448=== modified file 'dbus/upstart.h'
449--- dbus/upstart.h 2010-12-10 04:04:51 +0000
450+++ dbus/upstart.h 2011-06-03 09:50:59 +0000
451@@ -31,7 +31,7 @@
452 # define DBUS_SERVICE_UPSTART "com.ubuntu.TestUpstart"
453 # else
454 # define DBUS_SERVICE_UPSTART "com.ubuntu.Upstart"
455-#endif
456+# endif
457 #endif
458
459
460
461=== modified file 'init/conf.c'
462--- init/conf.c 2011-03-15 18:44:09 +0000
463+++ init/conf.c 2011-06-03 09:50:59 +0000
464@@ -2,7 +2,6 @@
465 *
466 * conf.c - configuration management
467 *
468- * Copyright © 2011 Google Inc.
469 * Copyright © 2009 Canonical Ltd.
470 * Author: Scott James Remnant <scott@netsplit.com>.
471 *
472
473=== modified file 'init/control.c'
474--- init/control.c 2009-07-11 11:47:12 +0000
475+++ init/control.c 2011-06-03 09:50:59 +0000
476@@ -2,7 +2,7 @@
477 *
478 * control.c - D-Bus connections, objects and methods
479 *
480- * Copyright © 2009 Canonical Ltd.
481+ * Copyright © 2009-2011 Canonical Ltd.
482 * Author: Scott James Remnant <scott@netsplit.com>.
483 *
484 * This program is free software; you can redistribute it and/or modify
485@@ -54,12 +54,19 @@
486
487 #include "com.ubuntu.Upstart.h"
488
489-
490 /* Prototypes for static functions */
491 static int control_server_connect (DBusServer *server, DBusConnection *conn);
492 static void control_disconnected (DBusConnection *conn);
493 static void control_register_all (DBusConnection *conn);
494
495+/**
496+ * use_session_bus:
497+ *
498+ * If TRUE, connect to the D-Bus sessio bus rather than the system bus.
499+ *
500+ * Used for testing.
501+ **/
502+int use_session_bus = FALSE;
503
504 /**
505 * control_server_address:
506@@ -78,7 +85,7 @@
507 /**
508 * control_bus:
509 *
510- * Open connection to D-Bus system bus. The connection may be opened with
511+ * Open connection to a D-Bus bus. The connection may be opened with
512 * control_bus_open() and if lost will become NULL.
513 **/
514 DBusConnection *control_bus = NULL;
515@@ -86,7 +93,7 @@
516 /**
517 * control_conns:
518 *
519- * Open control connections, including the connection to the D-Bus system
520+ * Open control connections, including the connection to a D-Bus
521 * bus and any private client connections.
522 **/
523 NihList *control_conns = NULL;
524@@ -190,8 +197,9 @@
525 /**
526 * control_bus_open:
527 *
528- * Open a connection to the D-Bus system bus and store it in the control_bus
529- * global. The connection is handled automatically in the main loop.
530+ * Open a connection to the appropriate D-Bus bus and store it in the
531+ * control_bus global. The connection is handled automatically
532+ * in the main loop.
533 *
534 * Returns: zero on success, negative value on raised error.
535 **/
536@@ -207,10 +215,13 @@
537
538 control_init ();
539
540+ control_handle_bus_type ();
541+
542 /* Connect to the D-Bus System Bus and hook everything up into
543 * our own main loop automatically.
544 */
545- conn = nih_dbus_bus (DBUS_BUS_SYSTEM, control_disconnected);
546+ conn = nih_dbus_bus (use_session_bus ? DBUS_BUS_SESSION : DBUS_BUS_SYSTEM,
547+ control_disconnected);
548 if (! conn)
549 return -1;
550
551@@ -669,3 +680,18 @@
552
553 return 0;
554 }
555+
556+/**
557+ * control_handle_bus_type:
558+ *
559+ * Determine D-Bus bus type to connect to.
560+ **/
561+void
562+control_handle_bus_type (void)
563+{
564+ if (getenv (USE_SESSION_BUS_ENV))
565+ use_session_bus = TRUE;
566+
567+ if (use_session_bus)
568+ nih_debug ("Using session bus");
569+}
570
571=== modified file 'init/control.h'
572--- init/control.h 2009-07-09 08:36:52 +0000
573+++ init/control.h 2011-06-03 09:50:59 +0000
574@@ -1,6 +1,6 @@
575 /* upstart
576 *
577- * Copyright © 2009 Canonical Ltd.
578+ * Copyright © 2009-2011 Canonical Ltd.
579 * Author: Scott James Remnant <scott@netsplit.com>.
580 *
581 * This program is free software; you can redistribute it and/or modify
582@@ -27,6 +27,18 @@
583 #include <nih-dbus/dbus_connection.h>
584 #include <nih-dbus/dbus_message.h>
585
586+/**
587+ * USE_SESSION_BUS_ENV:
588+ *
589+ * If this environment variable is set to any value, connect to
590+ * D-Bus session bus rather than the system bus.
591+ *
592+ * Used for testing.
593+ **/
594+#ifndef USE_SESSION_BUS_ENV
595+#define USE_SESSION_BUS_ENV "UPSTART_USE_SESSION_BUS"
596+#endif
597+
598
599 NIH_BEGIN_EXTERN
600
601@@ -72,6 +84,8 @@
602 const char *log_priority)
603 __attribute__ ((warn_unused_result));
604
605+void control_handle_bus_type (void);
606+
607 NIH_END_EXTERN
608
609 #endif /* INIT_CONTROL_H */
610
611=== modified file 'init/environ.c'
612--- init/environ.c 2011-03-16 22:42:48 +0000
613+++ init/environ.c 2011-06-03 09:50:59 +0000
614@@ -2,7 +2,6 @@
615 *
616 * environ.c - environment table utilities
617 *
618- * Copyright © 2011 Google Inc.
619 * Copyright © 2009 Canonical Ltd.
620 * Author: Scott James Remnant <scott@netsplit.com>.
621 *
622
623=== modified file 'init/environ.h'
624--- init/environ.h 2011-03-16 22:42:48 +0000
625+++ init/environ.h 2011-06-03 09:50:59 +0000
626@@ -1,6 +1,5 @@
627 /* upstart
628 *
629- * Copyright © 2011 Google Inc.
630 * Copyright © 2009 Canonical Ltd.
631 * Author: Scott James Remnant <scott@netsplit.com>.
632 *
633
634=== modified file 'init/job_process.c'
635--- init/job_process.c 2011-05-12 20:42:28 +0000
636+++ init/job_process.c 2011-06-03 09:50:59 +0000
637@@ -2,7 +2,6 @@
638 *
639 * job_process.c - job process handling
640 *
641- * Copyright © 2011 Google Inc.
642 * Copyright © 2011 Canonical Ltd.
643 * Author: Scott James Remnant <scott@netsplit.com>.
644 *
645
646=== modified file 'init/job_process.h'
647--- init/job_process.h 2011-05-12 19:21:16 +0000
648+++ init/job_process.h 2011-06-03 09:50:59 +0000
649@@ -1,6 +1,5 @@
650 /* upstart
651 *
652- * Copyright © 2011 Google Inc.
653 * Copyright © 2009 Canonical Ltd.
654 * Author: Scott James Remnant <scott@netsplit.com>.
655 *
656
657=== modified file 'init/main.c'
658--- init/main.c 2011-03-16 22:54:56 +0000
659+++ init/main.c 2011-06-03 09:50:59 +0000
660@@ -1,7 +1,6 @@
661 /* upstart
662 *
663- * Copyright © 2011 Google Inc.
664- * Copyright © 2010 Canonical Ltd.
665+ * Copyright © 2009-2011 Canonical Ltd.
666 * Author: Scott James Remnant <scott@netsplit.com>.
667 *
668 * This program is free software; you can redistribute it and/or modify
669@@ -71,6 +70,8 @@
670 static void usr1_handler (void *data, NihSignal *signal);
671 #endif /* DEBUG */
672
673+static void handle_confdir (void);
674+
675
676 /**
677 * argv0:
678@@ -90,13 +91,49 @@
679
680
681 /**
682+ * conf_dir:
683+ *
684+ * Full path to job configuration file directory.
685+ *
686+ **/
687+static char *conf_dir = NULL;
688+
689+/**
690+ * initial_event:
691+ *
692+ * Alternate event to emit at startup (rather than STARTUP_EVENT).
693+ **/
694+static char *initial_event = NULL;
695+
696+/**
697+ * disable_startup_event:
698+ *
699+ * If TRUE, do not emit a startup event.
700+ **/
701+static int disable_startup_event = FALSE;
702+
703+extern int use_session_bus;
704+
705+/**
706 * options:
707 *
708 * Command-line options we accept.
709 **/
710 static NihOption options[] = {
711+ { 0, "confdir", N_("specify alternative directory to load configuration files from"),
712+ NULL, "DIR", &conf_dir, NULL },
713+
714+ { 0, "no-startup-event", N_("do not emit any startup event (for testing)"),
715+ NULL, NULL, &disable_startup_event, NULL },
716+
717 { 0, "restart", NULL, NULL, NULL, &restart, NULL },
718
719+ { 0, "session", N_("use D-Bus session bus rather than system bus (for testing)"),
720+ NULL, NULL, &use_session_bus, NULL },
721+
722+ { 0, "startup-event", N_("specify an alternative initial event (for testing)"),
723+ NULL, "NAME", &initial_event, NULL },
724+
725 /* Ignore invalid options */
726 { '-', "--", NULL, NULL, NULL, NULL, NULL },
727
728@@ -124,94 +161,105 @@
729 if (! args)
730 exit (1);
731
732+ handle_confdir ();
733+ control_handle_bus_type ();
734+
735 #ifndef DEBUG
736- /* Check we're root */
737- if (getuid ()) {
738- nih_fatal (_("Need to be root"));
739- exit (1);
740- }
741-
742- /* Check we're process #1 */
743- if (getpid () > 1) {
744- execv (TELINIT, argv);
745- /* Ignore failure, probably just that telinit doesn't exist */
746-
747- nih_fatal (_("Not being executed as init"));
748- exit (1);
749- }
750-
751- /* Clear our arguments from the command-line, so that we show up in
752- * ps or top output as /sbin/init, with no extra flags.
753- *
754- * This is a very Linux-specific trick; by deleting the NULL
755- * terminator at the end of the last argument, we fool the kernel
756- * into believing we used a setproctitle()-a-like to extend the
757- * argument space into the environment space, and thus make it use
758- * strlen() instead of its own assumed length. In fact, we've done
759- * the exact opposite, and shrunk the command line length to just that
760- * of whatever is in argv[0].
761- *
762- * If we don't do this, and just write \0 over the rest of argv, for
763- * example; the command-line length still includes those \0s, and ps
764- * will show whitespace in their place.
765- */
766- if (argc > 1) {
767- char *arg_end;
768-
769- arg_end = argv[argc-1] + strlen (argv[argc-1]);
770- *arg_end = ' ';
771- }
772-
773-
774- /* Become the leader of a new session and process group, shedding
775- * any controlling tty (which we shouldn't have had anyway - but
776- * you never know what initramfs did).
777- */
778- setsid ();
779-
780- /* Set the standard file descriptors to the ordinary console device,
781- * resetting it to sane defaults unless we're inheriting from another
782- * init process which we know left it in a sane state.
783- */
784- if (system_setup_console (CONSOLE_OUTPUT, (! restart)) < 0)
785- nih_free (nih_error_get ());
786-
787- /* Set the PATH environment variable */
788- setenv ("PATH", PATH, TRUE);
789-
790- /* Switch to the root directory in case we were started from some
791- * strange place, or worse, some directory in the initramfs that's
792- * going to go away soon.
793- */
794- if (chdir ("/"))
795- nih_warn ("%s: %s", _("Unable to set root directory"),
796- strerror (errno));
797-
798- /* Mount the /proc and /sys filesystems, which are pretty much
799- * essential for any Linux system; not to mention used by
800- * ourselves.
801- */
802- if (system_mount ("proc", "/proc") < 0) {
803- NihError *err;
804-
805- err = nih_error_get ();
806- nih_warn ("%s: %s", _("Unable to mount /proc filesystem"),
807- err->message);
808- nih_free (err);
809- }
810-
811- if (system_mount ("sysfs", "/sys") < 0) {
812- NihError *err;
813-
814- err = nih_error_get ();
815- nih_warn ("%s: %s", _("Unable to mount /sys filesystem"),
816- err->message);
817- nih_free (err);
818- }
819+ if (use_session_bus == FALSE) {
820+
821+ /* Check we're root */
822+ if (getuid ()) {
823+ nih_fatal (_("Need to be root"));
824+ exit (1);
825+ }
826+
827+ /* Check we're process #1 */
828+ if (getpid () > 1) {
829+ execv (TELINIT, argv);
830+ /* Ignore failure, probably just that telinit doesn't exist */
831+
832+ nih_fatal (_("Not being executed as init"));
833+ exit (1);
834+ }
835+
836+ /* Clear our arguments from the command-line, so that we show up in
837+ * ps or top output as /sbin/init, with no extra flags.
838+ *
839+ * This is a very Linux-specific trick; by deleting the NULL
840+ * terminator at the end of the last argument, we fool the kernel
841+ * into believing we used a setproctitle()-a-like to extend the
842+ * argument space into the environment space, and thus make it use
843+ * strlen() instead of its own assumed length. In fact, we've done
844+ * the exact opposite, and shrunk the command line length to just that
845+ * of whatever is in argv[0].
846+ *
847+ * If we don't do this, and just write \0 over the rest of argv, for
848+ * example; the command-line length still includes those \0s, and ps
849+ * will show whitespace in their place.
850+ */
851+ if (argc > 1) {
852+ char *arg_end;
853+
854+ arg_end = argv[argc-1] + strlen (argv[argc-1]);
855+ *arg_end = ' ';
856+ }
857+
858+
859+ /* Become the leader of a new session and process group, shedding
860+ * any controlling tty (which we shouldn't have had anyway - but
861+ * you never know what initramfs did).
862+ */
863+ setsid ();
864+
865+ /* Set the standard file descriptors to the ordinary console device,
866+ * resetting it to sane defaults unless we're inheriting from another
867+ * init process which we know left it in a sane state.
868+ */
869+ if (system_setup_console (CONSOLE_OUTPUT, (! restart)) < 0)
870+ nih_free (nih_error_get ());
871+
872+ /* Set the PATH environment variable */
873+ setenv ("PATH", PATH, TRUE);
874+
875+ /* Switch to the root directory in case we were started from some
876+ * strange place, or worse, some directory in the initramfs that's
877+ * going to go away soon.
878+ */
879+ if (chdir ("/"))
880+ nih_warn ("%s: %s", _("Unable to set root directory"),
881+ strerror (errno));
882+
883+ /* Mount the /proc and /sys filesystems, which are pretty much
884+ * essential for any Linux system; not to mention used by
885+ * ourselves.
886+ */
887+ if (system_mount ("proc", "/proc") < 0) {
888+ NihError *err;
889+
890+ err = nih_error_get ();
891+ nih_warn ("%s: %s", _("Unable to mount /proc filesystem"),
892+ err->message);
893+ nih_free (err);
894+ }
895+
896+ if (system_mount ("sysfs", "/sys") < 0) {
897+ NihError *err;
898+
899+ err = nih_error_get ();
900+ nih_warn ("%s: %s", _("Unable to mount /sys filesystem"),
901+ err->message);
902+ nih_free (err);
903+ }
904+ } else {
905+ nih_log_set_priority (NIH_LOG_DEBUG);
906+ nih_debug ("Running with UID %d as PID %d (PPID %d)",
907+ (int)getuid (), (int)getpid (), (int)getppid ());
908+ }
909+
910 #else /* DEBUG */
911 nih_log_set_priority (NIH_LOG_DEBUG);
912- nih_debug ("Running as PID %d (PPID %d)",
913- (int)getpid (), (int)getppid ());
914+ nih_debug ("Running with UID %d as PID %d (PPID %d)",
915+ (int)getuid (), (int)getpid (), (int)getppid ());
916 #endif /* DEBUG */
917
918
919@@ -223,11 +271,13 @@
920 nih_signal_reset ();
921
922 #ifndef DEBUG
923- /* Catch fatal errors immediately rather than waiting for a new
924- * iteration through the main loop.
925- */
926- nih_signal_set_handler (SIGSEGV, crash_handler);
927- nih_signal_set_handler (SIGABRT, crash_handler);
928+ if (use_session_bus == FALSE) {
929+ /* Catch fatal errors immediately rather than waiting for a new
930+ * iteration through the main loop.
931+ */
932+ nih_signal_set_handler (SIGSEGV, crash_handler);
933+ nih_signal_set_handler (SIGABRT, crash_handler);
934+ }
935 #endif /* DEBUG */
936
937 /* Don't ignore SIGCHLD or SIGALRM, but don't respond to them
938@@ -238,33 +288,35 @@
939 nih_signal_set_handler (SIGALRM, nih_signal_handler);
940
941 #ifndef DEBUG
942- /* Ask the kernel to send us SIGINT when control-alt-delete is
943- * pressed; generate an event with the same name.
944- */
945- reboot (RB_DISABLE_CAD);
946- nih_signal_set_handler (SIGINT, nih_signal_handler);
947- NIH_MUST (nih_signal_add_handler (NULL, SIGINT, cad_handler, NULL));
948-
949- /* Ask the kernel to send us SIGWINCH when alt-uparrow is pressed;
950- * generate a keyboard-request event.
951- */
952- if (ioctl (0, KDSIGACCEPT, SIGWINCH) == 0) {
953- nih_signal_set_handler (SIGWINCH, nih_signal_handler);
954- NIH_MUST (nih_signal_add_handler (NULL, SIGWINCH,
955- kbd_handler, NULL));
956+ if (use_session_bus == FALSE) {
957+ /* Ask the kernel to send us SIGINT when control-alt-delete is
958+ * pressed; generate an event with the same name.
959+ */
960+ reboot (RB_DISABLE_CAD);
961+ nih_signal_set_handler (SIGINT, nih_signal_handler);
962+ NIH_MUST (nih_signal_add_handler (NULL, SIGINT, cad_handler, NULL));
963+
964+ /* Ask the kernel to send us SIGWINCH when alt-uparrow is pressed;
965+ * generate a keyboard-request event.
966+ */
967+ if (ioctl (0, KDSIGACCEPT, SIGWINCH) == 0) {
968+ nih_signal_set_handler (SIGWINCH, nih_signal_handler);
969+ NIH_MUST (nih_signal_add_handler (NULL, SIGWINCH,
970+ kbd_handler, NULL));
971+ }
972+
973+ /* powstatd sends us SIGPWR when it changes /etc/powerstatus */
974+ nih_signal_set_handler (SIGPWR, nih_signal_handler);
975+ NIH_MUST (nih_signal_add_handler (NULL, SIGPWR, pwr_handler, NULL));
976+
977+ /* SIGHUP instructs us to re-load our configuration */
978+ nih_signal_set_handler (SIGHUP, nih_signal_handler);
979+ NIH_MUST (nih_signal_add_handler (NULL, SIGHUP, hup_handler, NULL));
980+
981+ /* SIGUSR1 instructs us to reconnect to D-Bus */
982+ nih_signal_set_handler (SIGUSR1, nih_signal_handler);
983+ NIH_MUST (nih_signal_add_handler (NULL, SIGUSR1, usr1_handler, NULL));
984 }
985-
986- /* powstatd sends us SIGPWR when it changes /etc/powerstatus */
987- nih_signal_set_handler (SIGPWR, nih_signal_handler);
988- NIH_MUST (nih_signal_add_handler (NULL, SIGPWR, pwr_handler, NULL));
989-
990- /* SIGHUP instructs us to re-load our configuration */
991- nih_signal_set_handler (SIGHUP, nih_signal_handler);
992- NIH_MUST (nih_signal_add_handler (NULL, SIGHUP, hup_handler, NULL));
993-
994- /* SIGUSR1 instructs us to reconnect to D-Bus */
995- nih_signal_set_handler (SIGUSR1, nih_signal_handler);
996- NIH_MUST (nih_signal_add_handler (NULL, SIGUSR1, usr1_handler, NULL));
997 #endif /* DEBUG */
998
999
1000@@ -279,25 +331,27 @@
1001
1002 /* Read configuration */
1003 NIH_MUST (conf_source_new (NULL, CONFFILE, CONF_FILE));
1004- NIH_MUST (conf_source_new (NULL, CONFDIR, CONF_JOB_DIR));
1005+ NIH_MUST (conf_source_new (NULL, conf_dir, CONF_JOB_DIR));
1006
1007 conf_reload ();
1008
1009 /* Create a listening server for private connections. */
1010- while (control_server_open () < 0) {
1011- NihError *err;
1012+ if (use_session_bus == FALSE) {
1013+ while (control_server_open () < 0) {
1014+ NihError *err;
1015
1016- err = nih_error_get ();
1017- if (err->number != ENOMEM) {
1018- nih_warn ("%s: %s", _("Unable to listen for private connections"),
1019- err->message);
1020+ err = nih_error_get ();
1021+ if (err->number != ENOMEM) {
1022+ nih_warn ("%s: %s", _("Unable to listen for private connections"),
1023+ err->message);
1024+ nih_free (err);
1025+ break;
1026+ }
1027 nih_free (err);
1028- break;
1029 }
1030- nih_free (err);
1031 }
1032
1033- /* Open connection to the system bus; we normally expect this to
1034+ /* Open connection to the appropriate D-Bus bus; we normally expect this to
1035 * fail and will try again later - don't let ENOMEM stop us though.
1036 */
1037 while (control_bus_open () < 0) {
1038@@ -313,21 +367,32 @@
1039 }
1040
1041 #ifndef DEBUG
1042- /* Now that the startup is complete, send all further logging output
1043- * to kmsg instead of to the console.
1044- */
1045- if (system_setup_console (CONSOLE_NONE, FALSE) < 0)
1046- nih_free (nih_error_get ());
1047+ if (use_session_bus == FALSE) {
1048+ /* Now that the startup is complete, send all further logging output
1049+ * to kmsg instead of to the console.
1050+ */
1051+ if (system_setup_console (CONSOLE_NONE, FALSE) < 0)
1052+ nih_free (nih_error_get ());
1053
1054- nih_log_set_logger (logger_kmsg);
1055+ nih_log_set_logger (logger_kmsg);
1056+ }
1057 #endif /* DEBUG */
1058
1059
1060 /* Generate and run the startup event or read the state from the
1061 * init daemon that exec'd us
1062 */
1063- if (! restart) {
1064- NIH_MUST (event_new (NULL, STARTUP_EVENT, NULL));
1065+ if (! restart ) {
1066+ if (disable_startup_event) {
1067+ nih_debug ("Startup event disabled");
1068+ } else {
1069+ NIH_MUST (event_new (NULL,
1070+ initial_event
1071+ ? initial_event
1072+ : STARTUP_EVENT,
1073+ NULL));
1074+ }
1075+
1076 } else {
1077 sigset_t mask;
1078
1079@@ -573,3 +638,31 @@
1080 }
1081 }
1082 #endif /* DEBUG */
1083+
1084+/**
1085+ * handle_confdir:
1086+ *
1087+ * Determine where system configuration files should be loaded from.
1088+ **/
1089+static void
1090+handle_confdir (void)
1091+{
1092+ char *dir;
1093+
1094+ /* user has already specified directory on command-line */
1095+ if (conf_dir)
1096+ goto out;
1097+
1098+ conf_dir = CONFDIR;
1099+
1100+ dir = getenv (CONFDIR_ENV);
1101+ if (! dir)
1102+ return;
1103+
1104+ conf_dir = dir;
1105+
1106+out:
1107+ nih_debug ("Using alternate configuration directory %s",
1108+ conf_dir);
1109+}
1110+
1111
1112=== modified file 'init/man/init.5'
1113--- init/man/init.5 2011-05-12 20:42:28 +0000
1114+++ init/man/init.5 2011-06-03 09:50:59 +0000
1115@@ -288,7 +288,7 @@
1116 and
1117 .B post-stop
1118 scripts are run with the environment of the events or commands that
1119-stopped the job. THe
1120+stopped the job. The
1121 .B UPSTART_STOP_EVENTS
1122 environment variable contains the list of events that stopped the job,
1123 it will not be present if the job was stopped manually.
1124
1125=== modified file 'init/man/init.8'
1126--- init/man/init.8 2010-02-04 19:26:17 +0000
1127+++ init/man/init.8 2011-06-03 09:50:59 +0000
1128@@ -1,4 +1,4 @@
1129-.TH init 8 2010-02-04 "Upstart"
1130+.TH init 8 2011-05-31 "Upstart"
1131 .\"
1132 .SH NAME
1133 init \- Upstart process management daemon
1134@@ -64,6 +64,27 @@
1135 by placing them on the kernel command-line.
1136 .\"
1137 .TP
1138+.B \-\-confdir \fIdirectory\fP
1139+Read job configuration files from a directory other than
1140+\fI/etc/init\fP.
1141+.\"
1142+.TP
1143+.B \-\-no\-startup\-event
1144+Suppress emission of the initial startup event. This option should only
1145+be used for testing since it will stop the
1146+.BR init (8)
1147+daemon from starting \fBany\fP jobs automatically.
1148+.\"
1149+.TP
1150+.B \-\-session
1151+Connect to the D\-Bus session bus. This should only be used for testing.
1152+.\"
1153+.TP
1154+.B \-\-startup-event \fIevent\fP
1155+Specify a different initial startup event from the standard
1156+.BR startup (7) .
1157+.\"
1158+.TP
1159 .B --verbose
1160 Outputs verbose messages about job state changes and event emissions to the
1161 system console or log, useful for debugging boot.
1162@@ -90,7 +111,7 @@
1163 .RB < https://launchpad.net/upstart/+bugs >
1164 .\"
1165 .SH COPYRIGHT
1166-Copyright \(co 2010 Canonical Ltd.
1167+Copyright \(co 2009-2011 Canonical Ltd.
1168 .br
1169 This is free software; see the source for copying conditions. There is NO
1170 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1171
1172=== modified file 'init/paths.h'
1173--- init/paths.h 2010-02-26 15:27:14 +0000
1174+++ init/paths.h 2011-06-03 09:50:59 +0000
1175@@ -1,6 +1,6 @@
1176 /* upstart
1177 *
1178- * Copyright © 2010 Canonical Ltd.
1179+ * Copyright © 2010-2011 Canonical Ltd.
1180 * Author: Scott James Remnant <scott@netsplit.com>.
1181 *
1182 * This program is free software; you can redistribute it and/or modify
1183@@ -67,7 +67,7 @@
1184 /**
1185 * CONFDIR:
1186 *
1187- * Top-level directory of the system configuration files.
1188+ * Default top-level directory of the system configuration files.
1189 **/
1190 #ifndef CONFDIR
1191 #define CONFDIR "/etc/init"
1192@@ -75,6 +75,20 @@
1193
1194
1195 /**
1196+ * CONFDIR_ENV:
1197+ *
1198+ * If this environment variable is set, read configuration files
1199+ * from the location specified, rather than CONFDIR.
1200+ *
1201+ * Value is expected to be the full path to an alternative job
1202+ * configuration directory.
1203+ **/
1204+#ifndef CONFDIR_ENV
1205+#define CONFDIR_ENV "UPSTART_CONFDIR"
1206+#endif
1207+
1208+
1209+/**
1210 * SHELL:
1211 *
1212 * This is the shell binary used whenever we need special processing for
1213
1214=== modified file 'init/tests/test_conf.c'
1215--- init/tests/test_conf.c 2011-02-17 23:38:17 +0000
1216+++ init/tests/test_conf.c 2011-06-03 09:50:59 +0000
1217@@ -2,7 +2,6 @@
1218 *
1219 * test_conf.c - test suite for init/conf.c
1220 *
1221- * Copyright © 2011 Google Inc.
1222 * Copyright © 2009 Canonical Ltd.
1223 * Author: Scott James Remnant <scott@netsplit.com>.
1224 *
1225
1226=== modified file 'init/tests/test_control.c'
1227--- init/tests/test_control.c 2011-03-16 22:42:48 +0000
1228+++ init/tests/test_control.c 2011-06-03 09:50:59 +0000
1229@@ -2,7 +2,6 @@
1230 *
1231 * test_dbus.c - test suite for init/dbus.c
1232 *
1233- * Copyright © 2011 Google Inc.
1234 * Copyright © 2010 Canonical Ltd.
1235 * Author: Scott James Remnant <scott@netsplit.com>.
1236 *
1237
1238=== modified file 'init/tests/test_environ.c'
1239--- init/tests/test_environ.c 2011-03-16 22:42:48 +0000
1240+++ init/tests/test_environ.c 2011-06-03 09:50:59 +0000
1241@@ -2,7 +2,6 @@
1242 *
1243 * test_environ.c - test suite for init/environ.c
1244 *
1245- * Copyright © 2011 Google Inc.
1246 * Copyright © 2009 Canonical Ltd.
1247 * Author: Scott James Remnant <scott@netsplit.com>.
1248 *
1249
1250=== modified file 'init/tests/test_job_class.c'
1251--- init/tests/test_job_class.c 2011-05-12 20:42:28 +0000
1252+++ init/tests/test_job_class.c 2011-06-03 09:50:59 +0000
1253@@ -2,7 +2,6 @@
1254 *
1255 * test_job_class.c - test suite for init/job_class.c
1256 *
1257- * Copyright © 2011 Google Inc.
1258 * Copyright © 2010 Canonical Ltd.
1259 * Author: Scott James Remnant <scott@netsplit.com>.
1260 *
1261
1262=== modified file 'init/tests/test_job_process.c'
1263--- init/tests/test_job_process.c 2011-05-12 19:21:16 +0000
1264+++ init/tests/test_job_process.c 2011-06-03 09:50:59 +0000
1265@@ -2,7 +2,6 @@
1266 *
1267 * test_job_process.c - test suite for init/job_process.c
1268 *
1269- * Copyright © 2011 Google Inc.
1270 * Copyright © 2011 Canonical Ltd.
1271 * Author: Scott James Remnant <scott@netsplit.com>.
1272 *
1273
1274=== modified file 'po/upstart.pot'
1275--- po/upstart.pot 2011-03-22 17:52:25 +0000
1276+++ po/upstart.pot 2011-06-03 09:50:59 +0000
1277@@ -6,76 +6,141 @@
1278 #, fuzzy
1279 msgid ""
1280 msgstr ""
1281-"Project-Id-Version: upstart 1.2\n"
1282+"Project-Id-Version: upstart 1.3\n"
1283 "Report-Msgid-Bugs-To: new@bugs.launchpad.net\n"
1284-"POT-Creation-Date: 2011-03-22 10:52-0700\n"
1285+"POT-Creation-Date: 2011-06-01 13:58+0100\n"
1286 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1287 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1288 "Language-Team: LANGUAGE <LL@li.org>\n"
1289+"Language: \n"
1290 "MIME-Version: 1.0\n"
1291 "Content-Type: text/plain; charset=CHARSET\n"
1292 "Content-Transfer-Encoding: 8bit\n"
1293
1294-#: init/conf.c:238
1295+#: init/conf.c:237
1296 msgid "Unable to load configuration"
1297 msgstr ""
1298
1299-#: init/conf.c:271
1300+#: init/conf.c:270
1301 #, c-format
1302 msgid "Loading configuration from %s"
1303 msgstr ""
1304
1305-#: init/conf.c:308
1306+#: init/conf.c:307
1307 #, c-format
1308 msgid "Handling deletion of %s"
1309 msgstr ""
1310
1311-#: init/conf.c:379
1312+#: init/conf.c:378
1313 msgid "Unable to watch configuration file"
1314 msgstr ""
1315
1316-#: init/conf.c:457
1317+#: init/conf.c:456
1318 msgid "Unable to watch configuration directory"
1319 msgstr ""
1320
1321-#: init/conf.c:569 init/conf.c:653
1322+#: init/conf.c:568 init/conf.c:652
1323 msgid "Error while loading configuration file"
1324 msgstr ""
1325
1326-#: init/conf.c:609
1327+#: init/conf.c:608
1328 msgid "Configuration directory deleted"
1329 msgstr ""
1330
1331-#: init/control.c:155
1332+#: init/control.c:162
1333 msgid "Connection from private client"
1334 msgstr ""
1335
1336-#: init/control.c:290
1337+#: init/control.c:301
1338 msgid "Disconnected from system bus"
1339 msgstr ""
1340
1341-#: init/control.c:356 init/main.c:546
1342+#: init/control.c:367 init/main.c:611
1343 msgid "Reloading configuration"
1344 msgstr ""
1345
1346-#: init/control.c:396 init/control.c:507
1347+#: init/control.c:407 init/control.c:518
1348 msgid "Name may not be empty string"
1349 msgstr ""
1350
1351-#: init/control.c:405
1352+#: init/control.c:416
1353 #, c-format
1354 msgid "Unknown job: %s"
1355 msgstr ""
1356
1357-#: init/control.c:514 init/job_class.c:522 init/job_class.c:710
1358-#: init/job_class.c:829 init/job_class.c:953
1359+#: init/control.c:525 init/job_class.c:524 init/job_class.c:712
1360+#: init/job_class.c:831 init/job_class.c:955
1361 msgid "Env must be KEY=VALUE pairs"
1362 msgstr ""
1363
1364-#: init/control.c:666
1365+#: init/control.c:677
1366 msgid "The log priority given was not recognised"
1367 msgstr ""
1368
1369+#: init/errors.h:58
1370+msgid "Illegal parameter"
1371+msgstr ""
1372+
1373+#: init/errors.h:59
1374+msgid "Unknown parameter"
1375+msgstr ""
1376+
1377+#: init/errors.h:60 init/errors.h:71
1378+msgid "Expected operator"
1379+msgstr ""
1380+
1381+#: init/errors.h:61
1382+msgid "Mismatched braces"
1383+msgstr ""
1384+
1385+#: init/errors.h:62
1386+msgid "Illegal interval, expected number of seconds"
1387+msgstr ""
1388+
1389+#: init/errors.h:63
1390+msgid "Illegal exit status, expected integer"
1391+msgstr ""
1392+
1393+#: init/errors.h:64
1394+msgid "Illegal signal status, expected integer"
1395+msgstr ""
1396+
1397+#: init/errors.h:65
1398+msgid "Illegal file creation mask, expected octal integer"
1399+msgstr ""
1400+
1401+#: init/errors.h:66
1402+msgid "Illegal nice value, expected -20 to 19"
1403+msgstr ""
1404+
1405+#: init/errors.h:67
1406+msgid "Illegal oom adjustment, expected -16 to 15 or 'never'"
1407+msgstr ""
1408+
1409+#: init/errors.h:68
1410+msgid "Illegal oom score adjustment, expected -999 to 1000 or 'never'"
1411+msgstr ""
1412+
1413+#: init/errors.h:69
1414+msgid "Illegal limit, expected 'unlimited' or integer"
1415+msgstr ""
1416+
1417+#: init/errors.h:70
1418+msgid "Expected event"
1419+msgstr ""
1420+
1421+#: init/errors.h:72
1422+msgid "Expected variable name before value"
1423+msgstr ""
1424+
1425+#: init/errors.h:73
1426+msgid "Mismatched parentheses"
1427+msgstr ""
1428+
1429+#: init/errors.h:74
1430+msgid "Name already taken"
1431+msgstr ""
1432+
1433 #: init/event.c:273
1434 #, c-format
1435 msgid "Handling %s event"
1436@@ -164,241 +229,252 @@
1437 msgid "post-stop"
1438 msgstr ""
1439
1440-#: init/job.c:1113 init/job_class.c:756
1441+#: init/job.c:1113 init/job_class.c:758
1442 #, c-format
1443 msgid "Job is already running: %s"
1444 msgstr ""
1445
1446-#: init/job.c:1177 init/job.c:1242 init/job_class.c:875 init/job_class.c:998
1447+#: init/job.c:1177 init/job.c:1242 init/job_class.c:877 init/job_class.c:1000
1448 #, c-format
1449 msgid "Job has already been stopped: %s"
1450 msgstr ""
1451
1452-#: init/job_class.c:559 init/job_class.c:604 init/job_class.c:867
1453-#: init/job_class.c:990
1454+#: init/job_class.c:561 init/job_class.c:606 init/job_class.c:869
1455+#: init/job_class.c:992
1456 #, c-format
1457 msgid "Unknown instance: %s"
1458 msgstr ""
1459
1460-#: init/job_process.c:279
1461+#: init/job_process.c:276
1462 #, c-format
1463 msgid "Failed to spawn %s %s process: %s"
1464 msgstr ""
1465
1466-#: init/job_process.c:285
1467+#: init/job_process.c:282
1468 msgid "Temporary process spawn error"
1469 msgstr ""
1470
1471-#: init/job_process.c:292
1472+#: init/job_process.c:289
1473 #, c-format
1474 msgid "%s %s process (%d)"
1475 msgstr ""
1476
1477-#: init/job_process.c:399
1478+#: init/job_process.c:402
1479 #, c-format
1480 msgid "Pausing %s (%d) [pre-exec] for debug"
1481 msgstr ""
1482
1483-#: init/job_process.c:453
1484+#: init/job_process.c:472
1485 #, c-format
1486 msgid "Failed to open system console: %s"
1487 msgstr ""
1488
1489-#: init/job_process.c:669
1490+#: init/job_process.c:696
1491+#, c-format
1492+msgid "unable to move script fd: %s"
1493+msgstr ""
1494+
1495+#: init/job_process.c:701
1496 #, c-format
1497 msgid "unable to open console: %s"
1498 msgstr ""
1499
1500-#: init/job_process.c:724
1501+#: init/job_process.c:756
1502 #, c-format
1503 msgid "unable to set \"%s\" resource limit: %s"
1504 msgstr ""
1505
1506-#: init/job_process.c:729
1507+#: init/job_process.c:761
1508 #, c-format
1509 msgid "unable to set priority: %s"
1510 msgstr ""
1511
1512-#: init/job_process.c:734
1513+#: init/job_process.c:766
1514 #, c-format
1515 msgid "unable to set oom adjustment: %s"
1516 msgstr ""
1517
1518-#: init/job_process.c:739
1519+#: init/job_process.c:771
1520 #, c-format
1521 msgid "unable to change root directory: %s"
1522 msgstr ""
1523
1524-#: init/job_process.c:744
1525+#: init/job_process.c:776
1526 #, c-format
1527 msgid "unable to change working directory: %s"
1528 msgstr ""
1529
1530-#: init/job_process.c:749
1531+#: init/job_process.c:781
1532 #, c-format
1533 msgid "unable to set trace: %s"
1534 msgstr ""
1535
1536-#: init/job_process.c:754
1537+#: init/job_process.c:786
1538 #, c-format
1539 msgid "unable to execute: %s"
1540 msgstr ""
1541
1542-#: init/job_process.c:785
1543-#, c-format
1544-msgid "Sending TERM signal to %s %s process (%d)"
1545-msgstr ""
1546-
1547-#: init/job_process.c:793
1548-#, c-format
1549-msgid "Failed to send TERM signal to %s %s process (%d): %s"
1550-msgstr ""
1551-
1552-#: init/job_process.c:833
1553-#, c-format
1554-msgid "Sending KILL signal to %s %s process (%d)"
1555-msgstr ""
1556-
1557-#: init/job_process.c:841
1558-#, c-format
1559-msgid "Failed to send KILL signal to %s %s process (%d): %s"
1560-msgstr ""
1561-
1562-#: init/job_process.c:901
1563+#: init/job_process.c:817 init/job_process.c:867
1564+#, c-format
1565+msgid "Sending %s signal to %s %s process (%d)"
1566+msgstr ""
1567+
1568+#: init/job_process.c:826 init/job_process.c:876
1569+#, c-format
1570+msgid "Failed to send %s signal to %s %s process (%d): %s"
1571+msgstr ""
1572+
1573+#: init/job_process.c:937
1574 #, c-format
1575 msgid "%s %s process (%d) terminated with status %d"
1576 msgstr ""
1577
1578-#: init/job_process.c:906
1579+#: init/job_process.c:942
1580 #, c-format
1581 msgid "%s %s process (%d) exited normally"
1582 msgstr ""
1583
1584-#: init/job_process.c:921
1585+#: init/job_process.c:957
1586 #, c-format
1587 msgid "%s %s process (%d) killed by %s signal"
1588 msgstr ""
1589
1590-#: init/job_process.c:925
1591+#: init/job_process.c:961
1592 #, c-format
1593 msgid "%s %s process (%d) killed by signal %d"
1594 msgstr ""
1595
1596-#: init/job_process.c:939
1597+#: init/job_process.c:975
1598 #, c-format
1599 msgid "%s %s process (%d) stopped by %s signal"
1600 msgstr ""
1601
1602-#: init/job_process.c:943
1603+#: init/job_process.c:979
1604 #, c-format
1605 msgid "%s %s process (%d) stopped by signal %d"
1606 msgstr ""
1607
1608-#: init/job_process.c:957
1609+#: init/job_process.c:993
1610 #, c-format
1611 msgid "%s %s process (%d) continued by %s signal"
1612 msgstr ""
1613
1614-#: init/job_process.c:961
1615+#: init/job_process.c:997
1616 #, c-format
1617 msgid "%s %s process (%d) continued by signal %d"
1618 msgstr ""
1619
1620-#: init/job_process.c:1096
1621+#: init/job_process.c:1132
1622 #, c-format
1623 msgid "%s respawning too fast, stopped"
1624 msgstr ""
1625
1626-#: init/job_process.c:1102
1627+#: init/job_process.c:1138
1628 #, c-format
1629 msgid "%s %s process ended, respawning"
1630 msgstr ""
1631
1632-#: init/job_process.c:1342
1633+#: init/job_process.c:1378
1634 #, c-format
1635 msgid "Failed to set ptrace options for %s %s process (%d): %s"
1636 msgstr ""
1637
1638-#: init/job_process.c:1355 init/job_process.c:1550
1639+#: init/job_process.c:1391 init/job_process.c:1586
1640 #, c-format
1641 msgid "Failed to continue traced %s %s process (%d): %s"
1642 msgstr ""
1643
1644-#: init/job_process.c:1395 init/job_process.c:1486 init/job_process.c:1541
1645+#: init/job_process.c:1431 init/job_process.c:1522 init/job_process.c:1577
1646 #, c-format
1647 msgid "Failed to detach traced %s %s process (%d): %s"
1648 msgstr ""
1649
1650-#: init/job_process.c:1435
1651+#: init/job_process.c:1471
1652 #, c-format
1653 msgid "Failed to deliver signal to traced %s %s process (%d): %s"
1654 msgstr ""
1655
1656-#: init/job_process.c:1470
1657+#: init/job_process.c:1506
1658 #, c-format
1659 msgid "Failed to obtain child process id for %s %s process (%d): %s"
1660 msgstr ""
1661
1662-#: init/job_process.c:1477
1663+#: init/job_process.c:1513
1664 #, c-format
1665 msgid "%s %s process (%d) became new process (%d)"
1666 msgstr ""
1667
1668-#: init/job_process.c:1536
1669+#: init/job_process.c:1572
1670 #, c-format
1671 msgid "%s %s process (%d) executable changed"
1672 msgstr ""
1673
1674-#: init/main.c:117
1675+#: init/main.c:123
1676+msgid "specify alternative directory to load configuration files from"
1677+msgstr ""
1678+
1679+#: init/main.c:126
1680+msgid "do not emit any startup event (for testing)"
1681+msgstr ""
1682+
1683+#: init/main.c:131
1684+msgid "use D-Bus session bus rather than system bus (for testing)"
1685+msgstr ""
1686+
1687+#: init/main.c:134
1688+msgid "specify an alternative initial event (for testing)"
1689+msgstr ""
1690+
1691+#: init/main.c:154
1692 msgid "Process management daemon."
1693 msgstr ""
1694
1695-#: init/main.c:119
1696+#: init/main.c:156
1697 msgid ""
1698 "This daemon is normally executed by the kernel and given process id 1 to "
1699 "denote its special status. When executed by a user process, it will "
1700 "actually run /sbin/telinit."
1701 msgstr ""
1702
1703-#: init/main.c:130 util/reboot.c:167 util/shutdown.c:363 util/telinit.c:148
1704+#: init/main.c:172 util/reboot.c:166 util/shutdown.c:363 util/telinit.c:148
1705 msgid "Need to be root"
1706 msgstr ""
1707
1708-#: init/main.c:139
1709+#: init/main.c:181
1710 msgid "Not being executed as init"
1711 msgstr ""
1712
1713-#: init/main.c:187 init/main.c:456
1714+#: init/main.c:229 init/main.c:521
1715 msgid "Unable to set root directory"
1716 msgstr ""
1717
1718-#: init/main.c:198
1719+#: init/main.c:240
1720 msgid "Unable to mount /proc filesystem"
1721 msgstr ""
1722
1723-#: init/main.c:207
1724+#: init/main.c:249
1725 msgid "Unable to mount /sys filesystem"
1726 msgstr ""
1727
1728-#: init/main.c:292
1729+#: init/main.c:345
1730 msgid "Unable to listen for private connections"
1731 msgstr ""
1732
1733-#: init/main.c:473
1734+#: init/main.c:538
1735 #, c-format
1736 msgid "Caught %s, core dumped"
1737 msgstr ""
1738
1739-#: init/main.c:477
1740+#: init/main.c:542
1741 #, c-format
1742 msgid "Caught %s, unable to dump core"
1743 msgstr ""
1744
1745-#: init/main.c:563
1746+#: init/main.c:628
1747 msgid "Reconnecting to system bus"
1748 msgstr ""
1749
1750-#: init/main.c:569
1751+#: init/main.c:634
1752 msgid "Unable to connect to the system bus"
1753 msgstr ""
1754
1755@@ -406,76 +482,110 @@
1756 msgid "main"
1757 msgstr ""
1758
1759-#: util/initctl.c:145
1760+#: util/initctl.c:305
1761 msgid "Unable to connect to system bus"
1762 msgstr ""
1763
1764-#: util/initctl.c:154
1765+#: util/initctl.c:306
1766+msgid "Unable to connect to session bus"
1767+msgstr ""
1768+
1769+#: util/initctl.c:315
1770 #, c-format
1771 msgid "%s: --dest given without --system\n"
1772 msgstr ""
1773
1774-#: util/initctl.c:162
1775+#: util/initctl.c:323
1776 msgid "Unable to connect to Upstart"
1777 msgstr ""
1778
1779-#: util/initctl.c:348 util/initctl.c:483 util/initctl.c:611 util/initctl.c:745
1780-#: util/initctl.c:850
1781+#: util/initctl.c:509 util/initctl.c:644 util/initctl.c:772 util/initctl.c:907
1782+#: util/initctl.c:1012
1783 #, c-format
1784 msgid "%s: missing job name\n"
1785 msgstr ""
1786
1787-#: util/initctl.c:796
1788+#: util/initctl.c:958
1789 msgid "Not running"
1790 msgstr ""
1791
1792-#: util/initctl.c:1065
1793+#: util/initctl.c:1314
1794 #, c-format
1795 msgid "%s: missing event name\n"
1796 msgstr ""
1797
1798-#: util/initctl.c:1261
1799+#: util/initctl.c:1511
1800+msgid "Invalid job class"
1801+msgstr ""
1802+
1803+#: util/initctl.c:2108
1804+msgid "unknown event"
1805+msgstr ""
1806+
1807+#: util/initctl.c:2112
1808+msgid "unknown job"
1809+msgstr ""
1810+
1811+#: util/initctl.c:2213
1812+msgid "use D-Bus session bus to connect to init daemon (for testing)"
1813+msgstr ""
1814+
1815+#: util/initctl.c:2215
1816 msgid "use D-Bus system bus to connect to init daemon"
1817 msgstr ""
1818
1819-#: util/initctl.c:1263
1820-msgid "destination well-known name on system bus"
1821+#: util/initctl.c:2217
1822+msgid "destination well-known name on D-Bus bus"
1823 msgstr ""
1824
1825-#: util/initctl.c:1276
1826+#: util/initctl.c:2230
1827 msgid "do not wait for job to start before exiting"
1828 msgstr ""
1829
1830-#: util/initctl.c:1288
1831+#: util/initctl.c:2242
1832 msgid "do not wait for job to stop before exiting"
1833 msgstr ""
1834
1835-#: util/initctl.c:1300
1836+#: util/initctl.c:2254
1837 msgid "do not wait for job to restart before exiting"
1838 msgstr ""
1839
1840-#: util/initctl.c:1339
1841+#: util/initctl.c:2293
1842 msgid "do not wait for event to finish before exiting"
1843 msgstr ""
1844
1845-#: util/initctl.c:1378
1846+#: util/initctl.c:2334
1847+msgid ""
1848+"enumerate list of events and jobs causing job created from job config to "
1849+"start/stop"
1850+msgstr ""
1851+
1852+#: util/initctl.c:2347
1853+msgid "ignore specified list of events (comma-separated)"
1854+msgstr ""
1855+
1856+#: util/initctl.c:2349
1857+msgid "Generate warning for any unreachable events/jobs"
1858+msgstr ""
1859+
1860+#: util/initctl.c:2358
1861 msgid "Job"
1862 msgstr ""
1863
1864-#: util/initctl.c:1385
1865+#: util/initctl.c:2365
1866 msgid "Event"
1867 msgstr ""
1868
1869-#: util/initctl.c:1393 util/initctl.c:1405 util/initctl.c:1416
1870-#: util/initctl.c:1427 util/initctl.c:1434
1871+#: util/initctl.c:2373 util/initctl.c:2385 util/initctl.c:2396
1872+#: util/initctl.c:2407 util/initctl.c:2414
1873 msgid "JOB [KEY=VALUE]..."
1874 msgstr ""
1875
1876-#: util/initctl.c:1394
1877+#: util/initctl.c:2374
1878 msgid "Start job."
1879 msgstr ""
1880
1881-#: util/initctl.c:1395
1882+#: util/initctl.c:2375
1883 msgid ""
1884 "JOB is the name of the job that is to be started, this may be followed by "
1885 "zero or more environment variables to be defined in the new job.\n"
1886@@ -485,11 +595,11 @@
1887 "an existing instance is already running."
1888 msgstr ""
1889
1890-#: util/initctl.c:1406
1891+#: util/initctl.c:2386
1892 msgid "Stop job."
1893 msgstr ""
1894
1895-#: util/initctl.c:1407
1896+#: util/initctl.c:2387
1897 msgid ""
1898 "JOB is the name of the job that is to be stopped, this may be followed by "
1899 "zero or more environment variables to be passed to the job's pre-stop and "
1900@@ -499,11 +609,11 @@
1901 "decide which of multiple instances will be stopped."
1902 msgstr ""
1903
1904-#: util/initctl.c:1417
1905+#: util/initctl.c:2397
1906 msgid "Restart job."
1907 msgstr ""
1908
1909-#: util/initctl.c:1418
1910+#: util/initctl.c:2398
1911 msgid ""
1912 "JOB is the name of the job that is to be restarted, this may be followed by "
1913 "zero or more environment variables to be defined in the job after "
1914@@ -513,66 +623,66 @@
1915 "decide which of multiple instances will be restarted."
1916 msgstr ""
1917
1918-#: util/initctl.c:1428
1919+#: util/initctl.c:2408
1920 msgid "Send HUP signal to job."
1921 msgstr ""
1922
1923-#: util/initctl.c:1429
1924+#: util/initctl.c:2409
1925 msgid ""
1926 "JOB is the name of the job that is to be sent the signal, this may be "
1927 "followed by zero or more environment variables to distinguish between job "
1928 "instances.\n"
1929 msgstr ""
1930
1931-#: util/initctl.c:1435
1932+#: util/initctl.c:2415
1933 msgid "Query status of job."
1934 msgstr ""
1935
1936-#: util/initctl.c:1436
1937+#: util/initctl.c:2416
1938 msgid ""
1939 "JOB is the name of the job that is to be queried, this may be followed by "
1940 "zero or more environment variables to distguish between job instances.\n"
1941 msgstr ""
1942
1943-#: util/initctl.c:1442
1944+#: util/initctl.c:2422
1945 msgid "List known jobs."
1946 msgstr ""
1947
1948-#: util/initctl.c:1443
1949+#: util/initctl.c:2423
1950 msgid "The known jobs and their current status will be output."
1951 msgstr ""
1952
1953-#: util/initctl.c:1446
1954+#: util/initctl.c:2426
1955 msgid "EVENT [KEY=VALUE]..."
1956 msgstr ""
1957
1958-#: util/initctl.c:1447
1959+#: util/initctl.c:2427
1960 msgid "Emit an event."
1961 msgstr ""
1962
1963-#: util/initctl.c:1448
1964+#: util/initctl.c:2428
1965 msgid ""
1966 "EVENT is the name of an event the init daemon should emit, this may be "
1967 "followed by zero or more environment variables to be included in the event.\n"
1968 msgstr ""
1969
1970-#: util/initctl.c:1454
1971+#: util/initctl.c:2434
1972 msgid "Reload the configuration of the init daemon."
1973 msgstr ""
1974
1975-#: util/initctl.c:1458
1976+#: util/initctl.c:2438
1977 msgid "Request the version of the init daemon."
1978 msgstr ""
1979
1980-#: util/initctl.c:1461
1981+#: util/initctl.c:2441
1982 msgid "[PRIORITY]"
1983 msgstr ""
1984
1985-#: util/initctl.c:1462
1986+#: util/initctl.c:2442
1987 msgid "Change the minimum priority of log messages from the init daemon"
1988 msgstr ""
1989
1990-#: util/initctl.c:1464
1991+#: util/initctl.c:2444
1992 msgid ""
1993 "PRIORITY may be one of:\n"
1994 " `debug' (messages useful for debugging upstart are logged, equivalent to --"
1995@@ -589,59 +699,83 @@
1996 "Without arguments, this outputs the current log priority."
1997 msgstr ""
1998
1999-#: util/reboot.c:114
2000+#: util/initctl.c:2461 util/initctl.c:2467
2001+msgid "[CONF]"
2002+msgstr ""
2003+
2004+#: util/initctl.c:2462
2005+msgid "Show emits, start on and stop on details for job configurations."
2006+msgstr ""
2007+
2008+#: util/initctl.c:2463
2009+msgid ""
2010+"If CONF specified, show configuration details for single job configuration, "
2011+"else show details for all jobs configurations.\n"
2012+msgstr ""
2013+
2014+#: util/initctl.c:2468
2015+msgid "Check for unreachable jobs/event conditions."
2016+msgstr ""
2017+
2018+#: util/initctl.c:2469
2019+msgid ""
2020+"List all jobs and events which cannot be satisfied by currently available "
2021+"job configuration files"
2022+msgstr ""
2023+
2024+#: util/reboot.c:113
2025 msgid "don't sync before reboot or halt"
2026 msgstr ""
2027
2028-#: util/reboot.c:116
2029+#: util/reboot.c:115
2030 msgid "force reboot or halt, don't call shutdown(8)"
2031 msgstr ""
2032
2033-#: util/reboot.c:118
2034+#: util/reboot.c:117
2035 msgid "switch off the power when called as halt"
2036 msgstr ""
2037
2038-#: util/reboot.c:120
2039+#: util/reboot.c:119
2040 msgid "don't actually reboot or halt, just write wtmp record"
2041 msgstr ""
2042
2043-#: util/reboot.c:145
2044+#: util/reboot.c:144
2045 msgid "Halt the system."
2046 msgstr ""
2047
2048-#: util/reboot.c:148
2049+#: util/reboot.c:147
2050 msgid "Power off the system."
2051 msgstr ""
2052
2053-#: util/reboot.c:151
2054+#: util/reboot.c:150
2055 msgid "Reboot the system."
2056 msgstr ""
2057
2058-#: util/reboot.c:155
2059+#: util/reboot.c:154
2060 msgid ""
2061 "This command is intended to instruct the kernel to reboot or halt the "
2062 "system; when run without the -f option, or when in a system runlevel other "
2063 "than 0 or 6, it will actually execute /sbin/shutdown.\n"
2064 msgstr ""
2065
2066-#: util/reboot.c:211
2067+#: util/reboot.c:210
2068 msgid "Calling shutdown"
2069 msgstr ""
2070
2071-#: util/reboot.c:214
2072+#: util/reboot.c:213
2073 #, c-format
2074 msgid "Unable to execute shutdown: %s"
2075 msgstr ""
2076
2077-#: util/reboot.c:235
2078+#: util/reboot.c:234
2079 msgid "Rebooting"
2080 msgstr ""
2081
2082-#: util/reboot.c:239
2083+#: util/reboot.c:238
2084 msgid "Halting"
2085 msgstr ""
2086
2087-#: util/reboot.c:243
2088+#: util/reboot.c:242
2089 msgid "Powering off"
2090 msgstr ""
2091
2092
2093=== added directory 'scripts'
2094=== added file 'scripts/Makefile.am'
2095--- scripts/Makefile.am 1970-01-01 00:00:00 +0000
2096+++ scripts/Makefile.am 2011-06-03 09:50:59 +0000
2097@@ -0,0 +1,25 @@
2098+## Process this file with automake to produce Makefile.in
2099+
2100+EXTRA_DIST = \
2101+ initctl2dot.py \
2102+ init-checkconf.sh
2103+
2104+dist_man_MANS = \
2105+ man/initctl2dot.8 \
2106+ man/init-checkconf.8
2107+
2108+install-exec-hook: $(EXTRA_DIST)
2109+ [ ! -d "$(DESTDIR)/$(bindir)" ] && mkdir -p "$(DESTDIR)/$(bindir)"; \
2110+ for file in $(EXTRA_DIST); do \
2111+ from=`echo "$$file" | sed '$(transform)'`; \
2112+ to=`basename $$from | cut -d. -f1`; \
2113+ echo " cp '$(srcdir)/$$from' '$(DESTDIR)$(bindir)/$$to'"; \
2114+ cp "$(srcdir)/$$from" "$(DESTDIR)$(bindir)/$$to"; \
2115+ done
2116+
2117+uninstall-hook:
2118+ for file in $(EXTRA_DIST); do \
2119+ inst=`basename $$file | cut -d. -f1`; \
2120+ echo " rm -f '$(DESTDIR)$(bindir)/$$inst'"; \
2121+ rm -f "$(DESTDIR)$(bindir)/$$inst"; \
2122+ done
2123
2124=== added file 'scripts/init-checkconf.sh'
2125--- scripts/init-checkconf.sh 1970-01-01 00:00:00 +0000
2126+++ scripts/init-checkconf.sh 2011-06-03 09:50:59 +0000
2127@@ -0,0 +1,248 @@
2128+#!/bin/bash
2129+#---------------------------------------------------------------------
2130+# Script to determine if specified config file is valid or not.
2131+# By default, two checks are performed:
2132+#
2133+# - Ensure Upstart can parse overall file successfully
2134+# - Ensure all script sections are parseable by shell
2135+#
2136+#---------------------------------------------------------------------
2137+#
2138+# Copyright (C) 2011 Canonical Ltd.
2139+#
2140+# Author: James Hunt <james.hunt@canonical.com>
2141+#
2142+# This program is free software: you can redistribute it and/or modify
2143+# it under the terms of the GNU General Public License as published by
2144+# the Free Software Foundation, version 3 of the License.
2145+#
2146+# This program is distributed in the hope that it will be useful,
2147+# but WITHOUT ANY WARRANTY; without even the implied warranty of
2148+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2149+# GNU General Public License for more details.
2150+#
2151+# You should have received a copy of the GNU General Public License
2152+# along with this program. If not, see <http://www.gnu.org/licenses/>.
2153+#
2154+#---------------------------------------------------------------------
2155+
2156+script_name=${0##*/}
2157+confdir=$(mktemp -d /tmp/${script_name}.XXXXXXXXXX)
2158+upstart_path=/sbin/init
2159+initctl_path=/sbin/initctl
2160+debug_enabled=n
2161+file_valid=n
2162+running=n
2163+check_scripts=y
2164+
2165+cleanup()
2166+{
2167+ if [ ! -z "$upstart_pid" ]
2168+ then
2169+ debug "stopping secondary Upstart (running with PID $upstart_pid)"
2170+ kill -0 "$upstart_pid" >/dev/null 2>&1 && \
2171+ kill -9 "$upstart_pid" >/dev/null 2>&1
2172+ fi
2173+
2174+ [ -d "$confdir" ] && rm -rf "$confdir"
2175+ [ $file_valid = y ] && exit 0
2176+ exit 1
2177+}
2178+
2179+usage()
2180+{
2181+cat <<EOT
2182+Description: Determine if specified Upstart (init(8)) job configuration
2183+ file is valid.
2184+
2185+Usage: $script_name [options] -f <conf_file>
2186+ $script_name [options] <conf_file>
2187+
2188+Options:
2189+
2190+ -d, --debug : Show some debug output.
2191+ -f <file>, : Job configuration file to check.
2192+ --file=<file> (no default).
2193+ -i <path>, : Specify path to initctl binary
2194+ --initctl-path=<path> (default=$initctl_path).
2195+ -s, --noscript : Do not check script sections.
2196+ -x <path> : Specify path to init daemon binary
2197+ --upstart-path=<path> (default=$upstart_path).
2198+ -h, --help : Show this help.
2199+
2200+EOT
2201+}
2202+
2203+debug()
2204+{
2205+ msg="$*"
2206+ [ $debug_enabled = y ] && echo "DEBUG: $msg"
2207+}
2208+
2209+error()
2210+{
2211+ msg="$*"
2212+ printf "ERROR: %s\n" "$msg" >&2
2213+}
2214+
2215+die()
2216+{
2217+ error "$*"
2218+ exit 1
2219+}
2220+
2221+# Return 0 if Upstart is running on the D-Bus session bus, else 1.
2222+upstart_running()
2223+{
2224+ dbus-send --session --print-reply \
2225+ --dest='com.ubuntu.Upstart' /com/ubuntu/Upstart \
2226+ org.freedesktop.DBus.Properties.GetAll \
2227+ string:'com.ubuntu.Upstart0_6' >/dev/null 2>&1
2228+}
2229+
2230+trap cleanup EXIT INT TERM
2231+
2232+args=$(getopt \
2233+ -n "$script_name" \
2234+ -a \
2235+ --options="df:hi:sx:" \
2236+ --longoptions="debug file: help initctl-path: noscript upstart-path:" \
2237+ -- "$@")
2238+
2239+eval set -- "$args"
2240+[ $? -ne 0 ] && { usage; exit 1; }
2241+[ $# -eq 0 ] && { usage; exit 0; }
2242+
2243+while [ $# -gt 0 ]
2244+do
2245+ case "$1" in
2246+ -d|--debug)
2247+ debug_enabled=y
2248+ ;;
2249+
2250+ -f|--file)
2251+ file="$2"
2252+ shift
2253+ ;;
2254+
2255+ -h|--help)
2256+ usage
2257+ exit 0
2258+ ;;
2259+
2260+ -i|--initctl-path)
2261+ initctl_path="$2"
2262+ shift
2263+ ;;
2264+
2265+ -s|--noscript)
2266+ check_scripts=n
2267+ ;;
2268+
2269+ -x|--upstart-path)
2270+ upstart_path="$2"
2271+ shift
2272+ ;;
2273+
2274+ --)
2275+ shift
2276+ break
2277+ ;;
2278+ esac
2279+ shift
2280+done
2281+
2282+[ -z "$file" ] && file="$1"
2283+
2284+# safety first
2285+[ "$(id -u)" -eq 0 ] && die "cannot run as root"
2286+
2287+[ -z "$file" ] && die "must specify configuration file"
2288+[ ! -f "$file" ] && die "file $file does not exist"
2289+
2290+debug "upstart_path=$upstart_path"
2291+debug "initctl_path=$initctl_path"
2292+
2293+for cmd in "$upstart_path" "$initctl_path"
2294+do
2295+ [ -f "$cmd" ] || die "Path $cmd does not exist"
2296+ [ -x "$cmd" ] || die "File $cmd not executable"
2297+ "$cmd" --help | grep -q -- --session || die "version of $cmd too old"
2298+done
2299+
2300+# this is the only safe way to run another instance of Upstart
2301+"$upstart_path" --help|grep -q -- --no-startup-event || die "$upstart_path too old"
2302+
2303+debug "confdir=$confdir"
2304+debug "file=$file"
2305+
2306+filename=$(basename $file)
2307+
2308+echo "$filename" | egrep -q '\.conf$' || die "file must end in .conf"
2309+
2310+job="${filename%.conf}"
2311+
2312+cp "$file" "$confdir"
2313+debug "job=$job"
2314+
2315+upstart_running
2316+[ $? -eq 0 ] && die "Another instance of this program is already running"
2317+debug "ok - no other running instances detected"
2318+
2319+upstart_out="$(mktemp --tmpdir "${script_name}-upstart-output.XXXXXXXXXX")"
2320+debug "upstart_out=$upstart_out"
2321+
2322+upstart_cmd=$(printf \
2323+ "%s --session --no-sessions --no-startup-event --verbose --confdir %s" \
2324+ "$upstart_path" \
2325+ "$confdir")
2326+debug "upstart_cmd=$upstart_cmd"
2327+
2328+nohup $upstart_cmd >"$upstart_out" 2>&1 &
2329+upstart_pid=$!
2330+
2331+# Stop the shell outputting a message when Upstart is killed.
2332+# We handle this ourselves in cleanup().
2333+disown
2334+
2335+# wait for Upstart to initialize
2336+for i in $(seq 1 5)
2337+do
2338+ debug "Waiting for Upstart to reply over D-Bus (attempt $i)"
2339+ upstart_running
2340+ if [ $? -eq 0 ]
2341+ then
2342+ running=y
2343+ break
2344+ fi
2345+ sleep 1
2346+done
2347+
2348+[ $running = n ] && die "failed to ask Upstart to check conf file"
2349+
2350+debug "Secondary Upstart ($upstart_cmd) running with PID $upstart_pid"
2351+
2352+if [ "$check_scripts" = y ]
2353+then
2354+ for section in pre-start post-start script pre-stop post-stop
2355+ do
2356+ if egrep -q "\<${section}\>" "$file"
2357+ then
2358+ cmd='sed -n "/^ *${section}/,/^ *end script/p" $file | /bin/sh -n 2>&1'
2359+ errors=$(eval "$cmd")
2360+ [ $? -ne 0 ] && \
2361+ die "$(printf "File $file: shell syntax invalid in $section section:\n${errors}")"
2362+ fi
2363+ done
2364+fi
2365+
2366+"$initctl_path" --session list|grep -q "^${job}"
2367+if [ $? -eq 0 ]
2368+then
2369+ file_valid=y
2370+ echo "File $file: syntax ok"
2371+ exit 0
2372+fi
2373+
2374+errors=$(grep "$job" "$upstart_out"|sed "s,${confdir}/,,g")
2375+die "$(printf "File $file: syntax invalid:\n${errors}")"
2376
2377=== added file 'scripts/initctl2dot.py'
2378--- scripts/initctl2dot.py 1970-01-01 00:00:00 +0000
2379+++ scripts/initctl2dot.py 2011-06-03 09:50:59 +0000
2380@@ -0,0 +1,571 @@
2381+#!/usr/bin/python
2382+# -*- coding: utf-8 -*-
2383+#---------------------------------------------------------------------
2384+#
2385+# Copyright © 2011 Canonical Ltd.
2386+#
2387+# Author: James Hunt <james.hunt@canonical.com>
2388+#
2389+# This program is free software; you can redistribute it and/or modify
2390+# it under the terms of the GNU General Public License version 2, as
2391+# published by the Free Software Foundation.
2392+#
2393+# This program is distributed in the hope that it will be useful,
2394+# but WITHOUT ANY WARRANTY; without even the implied warranty of
2395+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2396+# GNU General Public License for more details.
2397+#
2398+# You should have received a copy of the GNU General Public License along
2399+# with this program; if not, write to the Free Software Foundation, Inc.,
2400+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
2401+#---------------------------------------------------------------------
2402+
2403+#---------------------------------------------------------------------
2404+# Script to take output of "initctl show-config -e" and convert it into
2405+# a Graphviz DOT language (".dot") file for procesing with dot(1), etc.
2406+#
2407+# Notes:
2408+#
2409+# - Slightly laborious logic used to satisfy graphviz requirement that
2410+# all nodes be defined before being referenced.
2411+#
2412+# Usage:
2413+#
2414+# initctl show-config -e > initctl.out
2415+# initctl2dot -f initctl.out -o upstart.dot
2416+# dot -Tpng -o upstart.png upstart.dot
2417+#
2418+# Or more simply:
2419+#
2420+# initctl2dot -o - | dot -Tpng -o upstart.png
2421+#
2422+# See also:
2423+#
2424+# - dot(1).
2425+# - initctl(8).
2426+# - http://www.graphviz.org.
2427+#---------------------------------------------------------------------
2428+
2429+import sys
2430+import re
2431+import fnmatch
2432+import os
2433+from string import split
2434+import datetime
2435+from subprocess import (Popen, PIPE)
2436+from optparse import OptionParser
2437+
2438+jobs = {}
2439+events = {}
2440+cmd = "initctl --system show-config -e"
2441+script_name = os.path.basename(sys.argv[0])
2442+
2443+job_events = [ 'starting', 'started', 'stopping', 'stopped' ]
2444+
2445+# list of jobs to restict output to
2446+restrictions_list = []
2447+
2448+default_color_emits = 'green'
2449+default_color_start_on = 'blue'
2450+default_color_stop_on = 'red'
2451+default_color_event = 'thistle'
2452+default_color_job = '#DCDCDC' # "Gainsboro"
2453+default_color_text = 'black'
2454+default_color_bg = 'white'
2455+
2456+default_outfile = 'upstart.dot'
2457+
2458+
2459+def header(ofh):
2460+ global options
2461+
2462+ str = "digraph upstart {\n"
2463+
2464+ # make the default node an event to simplify glob code
2465+ str += " node [shape=\"diamond\", fontcolor=\"%s\", fillcolor=\"%s\", style=\"filled\"];\n" \
2466+ % (options.color_event_text, options.color_event)
2467+ str += " rankdir=LR;\n"
2468+ str += " overlap=false;\n"
2469+ str += " bgcolor=\"%s\";\n" % options.color_bg
2470+ str += " fontcolor=\"%s\";\n" % options.color_text
2471+
2472+ ofh.write(str)
2473+
2474+
2475+def footer(ofh):
2476+ global options
2477+
2478+ epilog = "overlap=false;\n"
2479+ epilog += "label=\"Generated on %s by %s\\n" % \
2480+ (str(datetime.datetime.now()), script_name)
2481+
2482+ if options.restrictions:
2483+ epilog += "(subset, "
2484+ else:
2485+ epilog += "("
2486+
2487+ if options.infile:
2488+ epilog += "from file data).\\n"
2489+ else:
2490+ epilog += "from '%s' on host %s).\\n" % \
2491+ (cmd, os.uname()[1])
2492+
2493+ epilog += "Boxes of color %s denote jobs.\\n" % options.color_job
2494+ epilog += "Solid diamonds of color %s denote events.\\n" % options.color_event
2495+ epilog += "Dotted diamonds denote 'glob' events.\\n"
2496+ epilog += "Emits denoted by %s lines.\\n" % options.color_emits
2497+ epilog += "Start on denoted by %s lines.\\n" % options.color_start_on
2498+ epilog += "Stop on denoted by %s lines.\\n" % options.color_stop_on
2499+ epilog += "\";\n"
2500+ epilog += "}\n"
2501+ ofh.write(epilog)
2502+
2503+
2504+# Map dash to underscore since graphviz node names cannot
2505+# contain dashes. Also remove dollars and colons
2506+def sanitise(s):
2507+ return s.replace('-', '_').replace('$', 'dollar_').replace('[', \
2508+ 'lbracket').replace(']', 'rbracket').replace('!', \
2509+ 'bang').replace(':', '_').replace('*', 'star').replace('?', 'question')
2510+
2511+
2512+# Convert a dollar in @name to a unique-ish new name, based on @job and
2513+# return it. Used for very rudimentary instance handling.
2514+def encode_dollar(job, name):
2515+ if name[0] == '$':
2516+ name = job + ':' + name
2517+ return name
2518+
2519+
2520+def mk_node_name(name):
2521+ return sanitise(name)
2522+
2523+
2524+# Jobs and events can have identical names, so prefix them to namespace
2525+# them off.
2526+def mk_job_node_name(name):
2527+ return mk_node_name('job_' + name)
2528+
2529+
2530+def mk_event_node_name(name):
2531+ return mk_node_name('event_' + name)
2532+
2533+
2534+def show_event(ofh, name):
2535+ global options
2536+ str = "%s [label=\"%s\", shape=diamond, fontcolor=\"%s\", fillcolor=\"%s\"," % \
2537+ (mk_event_node_name(name), name, options.color_event_text, options.color_event)
2538+
2539+ if '*' in name:
2540+ str += " style=\"dotted\""
2541+ else:
2542+ str += " style=\"filled\""
2543+
2544+ str += "];\n"
2545+
2546+ ofh.write(str)
2547+
2548+def show_events(ofh):
2549+ global events
2550+ global options
2551+ global restrictions_list
2552+
2553+ events_to_show = []
2554+
2555+ if restrictions_list:
2556+ for job in restrictions_list:
2557+
2558+ # We want all events emitted by the jobs in the restrictions_list.
2559+ events_to_show += jobs[job]['emits']
2560+
2561+ # We also want all events that jobs in restrictions_list start/stop
2562+ # on.
2563+ events_to_show += jobs[job]['start on']['event']
2564+ events_to_show += jobs[job]['stop on']['event']
2565+
2566+ # We also want all events emitted by all jobs that jobs in the
2567+ # restrictions_list start/stop on. Finally, we want all events
2568+ # emmitted by those jobs in the restrictions_list that we
2569+ # start/stop on.
2570+ for j in jobs[job]['start on']['job']:
2571+ if jobs.has_key(j) and jobs[j].has_key('emits'):
2572+ events_to_show += jobs[j]['emits']
2573+
2574+ for j in jobs[job]['stop on']['job']:
2575+ if jobs.has_key(j) and jobs[j].has_key('emits'):
2576+ events_to_show += jobs[j]['emits']
2577+ else:
2578+ events_to_show = events
2579+
2580+ for e in events_to_show:
2581+ show_event(ofh, e)
2582+
2583+
2584+def show_job(ofh, name):
2585+ global options
2586+
2587+ ofh.write("""
2588+ %s [shape=\"record\", label=\"<job> %s | { <start> start on | <stop> stop on }\", fontcolor=\"%s\", style=\"filled\", fillcolor=\"%s\"];
2589+ """ % (mk_job_node_name(name), name, options.color_job_text, options.color_job))
2590+
2591+
2592+def show_jobs(ofh):
2593+ global jobs
2594+ global options
2595+ global restrictions_list
2596+
2597+ if restrictions_list:
2598+ jobs_to_show = restrictions_list
2599+ else:
2600+ jobs_to_show = jobs
2601+
2602+ for j in jobs_to_show:
2603+ show_job(ofh, j)
2604+ # add those jobs which are referenced by existing jobs, but which
2605+ # might not be available as .conf files. For example, plymouth.conf
2606+ # references gdm *or* kdm, but you are unlikely to have both
2607+ # installed.
2608+ for s in jobs[j]['start on']['job']:
2609+ if s not in jobs_to_show:
2610+ show_job(ofh, s)
2611+
2612+ for s in jobs[j]['stop on']['job']:
2613+ if s not in jobs_to_show:
2614+ show_job(ofh, s)
2615+
2616+ if not restrictions_list:
2617+ return
2618+
2619+ # Having displayed the jobs in restrictions_list,
2620+ # we now need to display all jobs that *those* jobs
2621+ # start on/stop on.
2622+ for j in restrictions_list:
2623+ for job in jobs[j]['start on']['job']:
2624+ show_job(ofh, job)
2625+ for job in jobs[j]['stop on']['job']:
2626+ show_job(ofh, job)
2627+
2628+ # Finally, show all jobs which emit events that jobs in the
2629+ # restrictions_list care about.
2630+ for j in restrictions_list:
2631+
2632+ for e in jobs[j]['start on']['event']:
2633+ for k in jobs:
2634+ if e in jobs[k]['emits']:
2635+ show_job(ofh, k)
2636+
2637+ for e in jobs[j]['stop on']['event']:
2638+ for k in jobs:
2639+ if e in jobs[k]['emits']:
2640+ show_job(ofh, k)
2641+
2642+
2643+def show_edge(ofh, from_node, to_node, color):
2644+ ofh.write("%s -> %s [color=\"%s\"];\n" % (from_node, to_node, color))
2645+
2646+
2647+def show_start_on_job_edge(ofh, from_job, to_job):
2648+ global options
2649+ show_edge(ofh, "%s:start" % mk_job_node_name(from_job),
2650+ "%s:job" % mk_job_node_name(to_job), options.color_start_on)
2651+
2652+
2653+def show_start_on_event_edge(ofh, from_job, to_event):
2654+ global options
2655+ show_edge(ofh, "%s:start" % mk_job_node_name(from_job),
2656+ mk_event_node_name(to_event), options.color_start_on)
2657+
2658+
2659+def show_stop_on_job_edge(ofh, from_job, to_job):
2660+ global options
2661+ show_edge(ofh, "%s:stop" % mk_job_node_name(from_job),
2662+ "%s:job" % mk_job_node_name(to_job), options.color_stop_on)
2663+
2664+
2665+def show_stop_on_event_edge(ofh, from_job, to_event):
2666+ global options
2667+ show_edge(ofh, "%s:stop" % mk_job_node_name(from_job),
2668+ mk_event_node_name(to_event), options.color_stop_on)
2669+
2670+
2671+def show_job_emits_edge(ofh, from_job, to_event):
2672+ global options
2673+ show_edge(ofh, "%s:job" % mk_job_node_name(from_job),
2674+ mk_event_node_name(to_event), options.color_emits)
2675+
2676+
2677+def show_edges(ofh):
2678+ global events
2679+ global jobs
2680+ global options
2681+ global restrictions_list
2682+
2683+ glob_jobs = {}
2684+
2685+ if restrictions_list:
2686+ jobs_list = restrictions_list
2687+ else:
2688+ jobs_list = jobs
2689+
2690+ for job in jobs_list:
2691+
2692+ for s in jobs[job]['start on']['job']:
2693+ show_start_on_job_edge(ofh, job, s)
2694+
2695+ for s in jobs[job]['start on']['event']:
2696+ show_start_on_event_edge(ofh, job, s)
2697+
2698+ for s in jobs[job]['stop on']['job']:
2699+ show_stop_on_job_edge(ofh, job, s)
2700+
2701+ for s in jobs[job]['stop on']['event']:
2702+ show_stop_on_event_edge(ofh, job, s)
2703+
2704+ for e in jobs[job]['emits']:
2705+ if '*' in e:
2706+ # handle glob patterns in 'emits'
2707+ glob_events = []
2708+ for _e in events:
2709+ if e != _e and fnmatch.fnmatch(_e, e):
2710+ glob_events.append(_e)
2711+ glob_jobs[job] = glob_events
2712+
2713+ show_job_emits_edge(ofh, job, e)
2714+
2715+ if not restrictions_list:
2716+ continue
2717+
2718+ # Add links to events emitted by all jobs which current job
2719+ # start/stops on
2720+ for j in jobs[job]['start on']['job']:
2721+ if not jobs.has_key(j):
2722+ continue
2723+ for e in jobs[j]['emits']:
2724+ show_job_emits_edge(ofh, j, e)
2725+
2726+ for j in jobs[job]['stop on']['job']:
2727+ for e in jobs[j]['emits']:
2728+ show_job_emits_edge(ofh, j, e)
2729+
2730+ # Create links from jobs (which advertise they emits a class of
2731+ # events, via the glob syntax) to all the events they create.
2732+ for g in glob_jobs:
2733+ for ge in glob_jobs[g]:
2734+ show_job_emits_edge(ofh, g, ge)
2735+
2736+ if not restrictions_list:
2737+ return
2738+
2739+ # Add jobs->event links to jobs which emit events that current job
2740+ # start/stops on.
2741+ for j in restrictions_list:
2742+
2743+ for e in jobs[j]['start on']['event']:
2744+ for k in jobs:
2745+ if e in jobs[k]['emits'] and e not in restrictions_list:
2746+ show_job_emits_edge(ofh, k, e)
2747+
2748+ for e in jobs[j]['stop on']['event']:
2749+ for k in jobs:
2750+ if e in jobs[k]['emits'] and e not in restrictions_list:
2751+ show_job_emits_edge(ofh, k, e)
2752+
2753+
2754+def read_data():
2755+ global jobs
2756+ global events
2757+ global options
2758+ global cmd
2759+ global job_events
2760+
2761+ if options.infile:
2762+ try:
2763+ ifh = open(options.infile, 'r')
2764+ except:
2765+ sys.exit("ERROR: cannot read file '%s'" % options.infile)
2766+ else:
2767+ try:
2768+ ifh = Popen(split(cmd), stdout=PIPE).stdout
2769+ except:
2770+ sys.exit("ERROR: cannot run '%s'" % cmd)
2771+
2772+ for line in ifh.readlines():
2773+ record = {}
2774+ line = line.rstrip()
2775+
2776+ result = re.match('^\s+start on ([^,]+) \(job:\s*([^,]*), env:', line)
2777+ if result:
2778+ _event = encode_dollar(job, result.group(1))
2779+ _job = result.group(2)
2780+ if _job:
2781+ jobs[job]['start on']['job'][_job] = 1
2782+ else:
2783+ jobs[job]['start on']['event'][_event] = 1
2784+ events[_event] = 1
2785+ continue
2786+
2787+ result = re.match('^\s+stop on ([^,]+) \(job:\s*([^,]*), env:', line)
2788+ if result:
2789+ _event = encode_dollar(job, result.group(1))
2790+ _job = result.group(2)
2791+ if _job:
2792+ jobs[job]['stop on']['job'][_job] = 1
2793+ else:
2794+ jobs[job]['stop on']['event'][_event] = 1
2795+ events[_event] = 1
2796+ continue
2797+
2798+ if re.match('^\s+emits', line):
2799+ event = (line.lstrip().split())[1]
2800+ event = encode_dollar(job, event)
2801+ events[event] = 1
2802+ jobs[job]['emits'][event] = 1
2803+ else:
2804+ tokens = (line.lstrip().split())
2805+
2806+ if len(tokens) != 1:
2807+ sys.exit("ERROR: invalid line: %s" % line.lstrip())
2808+
2809+ job_record = {}
2810+
2811+ start_on = {}
2812+ start_on_jobs = {}
2813+ start_on_events = {}
2814+
2815+ stop_on = {}
2816+ stop_on_jobs = {}
2817+ stop_on_events = {}
2818+
2819+ emits = {}
2820+
2821+ start_on['job'] = start_on_jobs
2822+ start_on['event'] = start_on_events
2823+
2824+ stop_on['job'] = stop_on_jobs
2825+ stop_on['event'] = stop_on_events
2826+
2827+ job_record['start on'] = start_on
2828+ job_record['stop on'] = stop_on
2829+ job_record['emits'] = emits
2830+
2831+ job = (tokens)[0]
2832+ jobs[job] = job_record
2833+
2834+
2835+def main():
2836+ global jobs
2837+ global options
2838+ global cmd
2839+ global default_color_emits
2840+ global default_color_start_on
2841+ global default_color_stop_on
2842+ global default_color_event
2843+ global default_color_job
2844+ global default_color_text
2845+ global default_color_bg
2846+ global restrictions_list
2847+
2848+ description = "Convert initctl(8) output to GraphViz dot(1) format."
2849+ epilog = \
2850+ "See http://www.graphviz.org/doc/info/colors.html for available colours."
2851+
2852+ parser = OptionParser(description=description, epilog=epilog)
2853+
2854+ parser.add_option("-r", "--restrict-to-jobs",
2855+ dest="restrictions",
2856+ help="Limit display of 'start on' and 'stop on' conditions to " +
2857+ "specified jobs (comma-separated list).")
2858+
2859+ parser.add_option("-f", "--infile",
2860+ dest="infile",
2861+ help="File to read '%s' output from. If not specified, " \
2862+ "initctl will be run automatically." % cmd)
2863+
2864+ parser.add_option("-o", "--outfile",
2865+ dest="outfile",
2866+ help="File to write output to (default=%s)" % default_outfile)
2867+
2868+ parser.add_option("--color-emits",
2869+ dest="color_emits",
2870+ help="Specify color for 'emits' lines (default=%s)." %
2871+ default_color_emits)
2872+
2873+ parser.add_option("--color-start-on",
2874+ dest="color_start_on",
2875+ help="Specify color for 'start on' lines (default=%s)." %
2876+ default_color_start_on)
2877+
2878+ parser.add_option("--color-stop-on",
2879+ dest="color_stop_on",
2880+ help="Specify color for 'stop on' lines (default=%s)." %
2881+ default_color_stop_on)
2882+
2883+ parser.add_option("--color-event",
2884+ dest="color_event",
2885+ help="Specify color for event boxes (default=%s)." %
2886+ default_color_event)
2887+
2888+ parser.add_option("--color-text",
2889+ dest="color_text",
2890+ help="Specify color for summary text (default=%s)." %
2891+ default_color_text)
2892+
2893+ parser.add_option("--color-bg",
2894+ dest="color_bg",
2895+ help="Specify background color for diagram (default=%s)." %
2896+ default_color_bg)
2897+
2898+ parser.add_option("--color-event-text",
2899+ dest="color_event_text",
2900+ help="Specify color for text in event boxes (default=%s)." %
2901+ default_color_text)
2902+
2903+ parser.add_option("--color-job-text",
2904+ dest="color_job_text",
2905+ help="Specify color for text in job boxes (default=%s)." %
2906+ default_color_text)
2907+
2908+ parser.add_option("--color-job",
2909+ dest="color_job",
2910+ help="Specify color for job boxes (default=%s)." %
2911+ default_color_job)
2912+
2913+ parser.set_defaults(color_emits=default_color_emits,
2914+ color_start_on=default_color_start_on,
2915+ color_stop_on=default_color_stop_on,
2916+ color_event=default_color_event,
2917+ color_job=default_color_job,
2918+ color_job_text=default_color_text,
2919+ color_event_text=default_color_text,
2920+ color_text=default_color_text,
2921+ color_bg=default_color_bg,
2922+ outfile=default_outfile)
2923+
2924+ (options, args) = parser.parse_args()
2925+
2926+ if options.outfile == '-':
2927+ ofh = sys.stdout
2928+ else:
2929+ try:
2930+ ofh = open(options.outfile, "w")
2931+ except:
2932+ sys.exit("ERROR: cannot open file %s for writing" % options.outfile)
2933+
2934+ if options.restrictions:
2935+ restrictions_list = options.restrictions.split(",")
2936+
2937+ read_data()
2938+
2939+ for job in restrictions_list:
2940+ if not job in jobs:
2941+ sys.exit("ERROR: unknown job %s" % job)
2942+
2943+ header(ofh)
2944+ show_events(ofh)
2945+ show_jobs(ofh)
2946+ show_edges(ofh)
2947+ footer(ofh)
2948+
2949+
2950+if __name__ == "__main__":
2951+ main()
2952
2953=== added directory 'scripts/man'
2954=== added file 'scripts/man/init-checkconf.8'
2955--- scripts/man/init-checkconf.8 1970-01-01 00:00:00 +0000
2956+++ scripts/man/init-checkconf.8 2011-06-03 09:50:59 +0000
2957@@ -0,0 +1,73 @@
2958+.TH init\-checkconf 8 2011-04-06 "Upstart"
2959+.\"
2960+.SH NAME
2961+init\-checkconf \- manual page for init-checkconf
2962+.\"
2963+.SH SYNOPSIS
2964+.B init\-checkconf
2965+.RI [ OPTIONS ] " file "
2966+
2967+.B init\-checkconf
2968+.RI [ OPTIONS ] " " "\-f" " file "
2969+.\"
2970+.SH DESCRIPTION
2971+Determine if specified Upstart
2972+.BR init (8)
2973+job configuration file is valid.
2974+.P
2975+By default, two checks are performed:
2976+.IP \(bu 4
2977+Ensure Upstart can parse overall file successfully
2978+.IP \(bu 4
2979+Ensure all script sections are parseable by shell
2980+.P
2981+.\"
2982+.SH OPTIONS
2983+.TP
2984+.BR \-d " , " \-\-debug
2985+Show some debug output.
2986+.TP
2987+.BR \-f " \fIfile\fP" " , " \-\-file=\fIfile\fP
2988+Specify job configuration file to check.
2989+.TP
2990+.BR \-i " \fIpath\fP" " , " \-\-initctl\-path=\fIpath\fP
2991+Specify path to
2992+.BR initctl (8)
2993+binary.
2994+.TP
2995+.BR \-s " , " \-\-noscript
2996+Do not check script sections.
2997+.TP
2998+.BR \-x " \fIpath\fP" " , " \-\-upstart\-path=\fIpath\fP
2999+Specify path to
3000+.BR init (8)
3001+binary.
3002+.TP
3003+.BR \-h " , " \-\-help
3004+Display usage statement.
3005+.\"
3006+.SH AUTHOR
3007+Written by James Hunt
3008+.RB < james.hunt@ubuntu.com >
3009+.\"
3010+.SH LIMITATIONS
3011+.IP \(bu 4
3012+This program will not run as the root user.
3013+.IP \(bu 4
3014+It is not possible for a user to run multiple simultaneous
3015+instances of this program.
3016+.\"
3017+.SH REPORTING BUGS
3018+Report bugs at
3019+.RB < https://launchpad.net/upstart/+bugs >
3020+.\"
3021+.SH COPYRIGHT
3022+Copyright \(co 2011 Canonical Ltd.
3023+.br
3024+This is free software; see the source for copying conditions. There is NO
3025+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
3026+.\"
3027+.SH SEE ALSO
3028+.BR sh (1)
3029+.BR init (5)
3030+.BR init (8)
3031
3032=== added file 'scripts/man/initctl2dot.8'
3033--- scripts/man/initctl2dot.8 1970-01-01 00:00:00 +0000
3034+++ scripts/man/initctl2dot.8 2011-06-03 09:50:59 +0000
3035@@ -0,0 +1,87 @@
3036+.TH initctl2dot 8 2011-03-07 "Upstart"
3037+.\"
3038+.SH NAME
3039+initctl2dot \- manual page for initctl2dot
3040+.\"
3041+.SH SYNOPSIS
3042+.B initctl2dot
3043+.RI [ OPTIONS ]
3044+.\"
3045+.SH DESCRIPTION
3046+Convert
3047+.BR initctl (8)
3048+output to GraphViz
3049+.BR dot (1)
3050+format.
3051+
3052+With no options,
3053+.BR initctl (8)
3054+will be invoked automatically and the output written to file
3055+\fIupstart.dot\fP.
3056+.\"
3057+.SH OPTIONS
3058+.TP
3059+.B -h
3060+Display usage statement.
3061+.TP
3062+\fB-f\fP \fIINFILE\fP , \fP--infile\fP=\fIINFILE\fP
3063+File to read
3064+.BR initctl (8)
3065+output from ("initctl show-config -e"). If not specified,
3066+.BR initctl (8)
3067+will be run automatically.
3068+.TP
3069+\fB-w\fP \fIOUTFILE\fP , \fP--outfile\fP=\fIOUTFILE\fP
3070+File to write output to.
3071+.TP
3072+\fB-r\fP \fIRESTRICTIONS\fP , \fP--restrict-to-jobs\fP=\fIRESTRICTIONS\fP
3073+Limit display of
3074+.B start on
3075+and
3076+.B stop on
3077+conditions to comma-separated list of jobs.
3078+.TP
3079+\fB--color-emits\fP=\fICOLOR_EMITS\fP
3080+Specify color for 'emits' lines.
3081+.TP
3082+\fB--color-start-on\fP=\fICOLOR_START_ON\fP
3083+Specify color for 'start on' lines.
3084+.TP
3085+\fB--color-stop-on\fP=\fICOLOR_STOP_ON\fP
3086+Specify color for 'stop on' lines.
3087+.TP
3088+\fB--color-event\fP=\fICOLOR_EVENT\fP
3089+Specify color for event boxes.
3090+.TP
3091+\fB--color-text\fP=\fICOLOR_TEXT\fP
3092+Specify color for summary text.
3093+.TP
3094+\fB--color-bg\fP=\fICOLOR_BG\fP
3095+Specify background color for diagram.
3096+.TP
3097+\fB--color-event-text\fP=\fICOLOR_EVENT_TEXT\fP
3098+Specify color for text in event boxes.
3099+.TP
3100+\fB--color-job-text\fP=\fICOLOR_JOB_TEXT\fP
3101+Specify color for text in job boxes.
3102+.TP
3103+\fB--color-job\fP=\fICOLOR_JOB\fP
3104+Specify color for job boxes.
3105+.\"
3106+.SH AUTHOR
3107+Written by James Hunt
3108+.RB < james.hunt@ubuntu.com >
3109+.\"
3110+.SH REPORTING BUGS
3111+Report bugs at
3112+.RB < https://launchpad.net/upstart/+bugs >
3113+.\"
3114+.SH COPYRIGHT
3115+Copyright \(co 2011 Canonical Ltd.
3116+.br
3117+This is free software; see the source for copying conditions. There is NO
3118+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
3119+.\"
3120+.SH SEE ALSO
3121+.BR init (8)
3122+.BR initctl (8)
3123
3124=== modified file 'util/Makefile.am'
3125--- util/Makefile.am 2011-03-16 22:49:20 +0000
3126+++ util/Makefile.am 2011-06-03 09:50:59 +0000
3127@@ -29,7 +29,7 @@
3128 telinit
3129
3130 initctl_SOURCES = \
3131- initctl.c
3132+ initctl.c initctl.h
3133 nodist_initctl_SOURCES = \
3134 $(com_ubuntu_Upstart_OUTPUTS) \
3135 $(com_ubuntu_Upstart_Job_OUTPUTS) \
3136
3137=== modified file 'util/initctl.c'
3138--- util/initctl.c 2010-02-04 19:08:07 +0000
3139+++ util/initctl.c 2011-06-03 09:50:59 +0000
3140@@ -29,6 +29,7 @@
3141 #include <stdio.h>
3142 #include <stdlib.h>
3143 #include <unistd.h>
3144+#include <fnmatch.h>
3145
3146 #include <nih/macros.h>
3147 #include <nih/alloc.h>
3148@@ -38,10 +39,13 @@
3149 #include <nih/command.h>
3150 #include <nih/logging.h>
3151 #include <nih/error.h>
3152+#include <nih/hash.h>
3153+#include <nih/tree.h>
3154
3155 #include <nih-dbus/dbus_error.h>
3156 #include <nih-dbus/dbus_proxy.h>
3157 #include <nih-dbus/errors.h>
3158+#include <nih-dbus/dbus_connection.h>
3159
3160 #include "dbus/upstart.h"
3161
3162@@ -49,6 +53,9 @@
3163 #include "com.ubuntu.Upstart.Job.h"
3164 #include "com.ubuntu.Upstart.Instance.h"
3165
3166+#include "../init/events.h"
3167+#include "initctl.h"
3168+
3169
3170 /* Prototypes for local functions */
3171 NihDBusProxy *upstart_open (const void *parent)
3172@@ -63,6 +70,43 @@
3173 static void reply_handler (int *ret, NihDBusMessage *message);
3174 static void error_handler (void *data, NihDBusMessage *message);
3175
3176+static void job_class_condition_handler (void *data,
3177+ NihDBusMessage *message,
3178+ char ** const *value);
3179+
3180+static void job_class_condition_err_handler (void *data,
3181+ NihDBusMessage *message);
3182+
3183+static void job_class_parse_events (const ConditionHandlerData *data,
3184+ char ** const *variant_array);
3185+
3186+static void job_class_show_emits (const void *parent,
3187+ NihDBusProxy *job_class_proxy, const char *job_class_name);
3188+
3189+static void job_class_show_conditions (NihDBusProxy *job_class_proxy,
3190+ const char *job_class_name);
3191+
3192+static void eval_expr_tree (const char *expr, NihList **stack);
3193+
3194+static int check_condition (const char *job_class,
3195+ const char *condition, NihList *condition_list,
3196+ int *job_class_displayed)
3197+ __attribute__ ((warn_unused_result));
3198+
3199+static int tree_filter (void *data, NihTree *node);
3200+
3201+static void display_check_errors (const char *job_class,
3202+ const char *condition, NihTree *node);
3203+
3204+static int allow_job (const char *job);
3205+static int allow_event (const char *event);
3206+
3207+#ifndef TEST
3208+
3209+static int dbus_bus_type_setter (NihOption *option, const char *arg);
3210+static int ignored_events_setter (NihOption *option, const char *arg);
3211+
3212+#endif
3213
3214 /* Prototypes for option and command functions */
3215 int start_action (NihCommand *command, char * const *args);
3216@@ -75,15 +119,26 @@
3217 int reload_configuration_action (NihCommand *command, char * const *args);
3218 int version_action (NihCommand *command, char * const *args);
3219 int log_priority_action (NihCommand *command, char * const *args);
3220-
3221-
3222-/**
3223- * system_bus:
3224- *
3225- * Whether to connect to the init daemon on the D-Bus system bus or
3226- * privately.
3227- **/
3228-int system_bus = -1;
3229+int show_config_action (NihCommand *command, char * const *args);
3230+int check_config_action (NihCommand *command, char * const *args);
3231+
3232+
3233+/**
3234+ * use_dbus:
3235+ *
3236+ * If 1, connect using a D-Bus bus.
3237+ * If 0, connect using private connection.
3238+ * If -1, determine appropriate connection based on UID.
3239+ */
3240+int use_dbus = -1;
3241+
3242+/**
3243+ * dbus_bus_type:
3244+ *
3245+ * D-Bus bus to connect to (DBUS_BUS_SYSTEM or DBUS_BUS_SESSION), or -1
3246+ * to have an appropriate bus selected.
3247+ */
3248+int dbus_bus_type = -1;
3249
3250 /**
3251 * dest_name:
3252@@ -107,6 +162,107 @@
3253 **/
3254 int no_wait = FALSE;
3255
3256+/**
3257+ * enumerate_events:
3258+ *
3259+ * If TRUE, list out all events/jobs that a particular job *may require* to
3260+ * be run: essentially any event/job mentioned in a job configuration files
3261+ * "start on" / "stop on" condition. Used for showing dependencies
3262+ * between jobs and events.
3263+ **/
3264+int enumerate_events = FALSE;
3265+
3266+/**
3267+ * check_config_mode:
3268+ *
3269+ * If TRUE, parse all job configuration files looking for unreachable
3270+ * jobs/events.
3271+ **/
3272+int check_config_mode = FALSE;
3273+
3274+/**
3275+ * check_config_warn:
3276+ *
3277+ * If TRUE, check-config will generate a warning for *any* unreachable
3278+ * events/jobs.
3279+ **/
3280+int check_config_warn = FALSE;
3281+
3282+/**
3283+ * check_config_data:
3284+ *
3285+ * Used to record details of all known jobs and events.
3286+ **/
3287+CheckConfigData check_config_data;
3288+
3289+/**
3290+ * NihOption setter function to handle selection of appropriate D-Bus
3291+ * bus.
3292+ *
3293+ * Always returns 1 denoting success.
3294+ **/
3295+int
3296+dbus_bus_type_setter (NihOption *option, const char *arg)
3297+{
3298+ nih_assert (option);
3299+
3300+ if (! strcmp (option->long_option, "system")) {
3301+ use_dbus = TRUE;
3302+ dbus_bus_type = DBUS_BUS_SYSTEM;
3303+ }
3304+ else if (! strcmp (option->long_option, "session")) {
3305+ use_dbus = TRUE;
3306+ dbus_bus_type = DBUS_BUS_SESSION;
3307+ }
3308+
3309+ return 1;
3310+}
3311+
3312+
3313+/**
3314+ * NihOption setter function to handle specification of events to
3315+ * ignore.
3316+ *
3317+ * Returns 1 on success, else 0.
3318+ **/
3319+int
3320+ignored_events_setter (NihOption *option, const char *arg)
3321+{
3322+ NihError *err;
3323+ char **events;
3324+ char **event;
3325+ NihListEntry *entry;
3326+
3327+ nih_assert (option);
3328+ nih_assert (arg);
3329+
3330+ if (! check_config_data.ignored_events_hash)
3331+ check_config_data.ignored_events_hash = NIH_MUST (nih_hash_string_new (NULL, 0));
3332+
3333+ events = nih_str_split (NULL, arg, ",", TRUE);
3334+
3335+ if (!events) {
3336+ goto error;
3337+ }
3338+
3339+ for (event = events; event && *event; ++event) {
3340+ entry = NIH_MUST (nih_list_entry_new (check_config_data.ignored_events_hash));
3341+ entry->str = NIH_MUST (nih_strdup (entry, *event));
3342+ nih_hash_add (check_config_data.ignored_events_hash, &entry->entry);
3343+ }
3344+
3345+ nih_free (events);
3346+
3347+ return 1;
3348+
3349+error:
3350+ err = nih_error_get ();
3351+ nih_error ("%s", err->message);
3352+ nih_free (err);
3353+
3354+ return 0;
3355+}
3356+
3357
3358 /**
3359 * upstart_open:
3360@@ -132,17 +288,22 @@
3361 DBusConnection *connection;
3362 NihDBusProxy * upstart;
3363
3364- if (system_bus < 0)
3365- system_bus = getuid () ? TRUE : FALSE;
3366+ if (use_dbus < 0)
3367+ use_dbus = getuid () ? TRUE : FALSE;
3368+ if (use_dbus >= 0 && dbus_bus_type < 0)
3369+ dbus_bus_type = DBUS_BUS_SYSTEM;
3370
3371 dbus_error_init (&dbus_error);
3372- if (system_bus) {
3373+ if (use_dbus) {
3374 if (! dest_name)
3375 dest_name = DBUS_SERVICE_UPSTART;
3376
3377- connection = dbus_bus_get (DBUS_BUS_SYSTEM, &dbus_error);
3378+ connection = dbus_bus_get (dbus_bus_type, &dbus_error);
3379 if (! connection) {
3380- nih_error ("%s: %s", _("Unable to connect to system bus"),
3381+ nih_error ("%s: %s",
3382+ dbus_bus_type == DBUS_BUS_SYSTEM
3383+ ? _("Unable to connect to system bus")
3384+ : _("Unable to connect to session bus"),
3385 dbus_error.message);
3386 dbus_error_free (&dbus_error);
3387 return NULL;
3388@@ -209,7 +370,7 @@
3389 * of the returned string are freed, the returned string will also be
3390 * freed.
3391 *
3392- * Returns: newly allocated string or NULL on raised error..
3393+ * Returns: newly allocated string or NULL on raised error.
3394 **/
3395 char *
3396 job_status (const void * parent,
3397@@ -663,6 +824,7 @@
3398 (JobClassRestartReply)start_reply_handler,
3399 error_handler, &job_path,
3400 NIH_DBUS_TIMEOUT_NEVER);
3401+
3402 if (! pending_call)
3403 goto error;
3404 }
3405@@ -1039,6 +1201,93 @@
3406 return 1;
3407 }
3408
3409+/**
3410+ * show_config_action:
3411+ * @command: NihCommand invoked,
3412+ * @args: command-line arguments.
3413+ *
3414+ * This function is called for the "show-config" command.
3415+ *
3416+ * Returns: command exit status.
3417+ **/
3418+int
3419+show_config_action (NihCommand * command,
3420+ char * const *args)
3421+{
3422+ nih_local NihDBusProxy *upstart = NULL;
3423+ nih_local char **job_class_paths = NULL;
3424+ const char *upstart_job_class = NULL;
3425+ NihError *err;
3426+
3427+ nih_assert (command != NULL);
3428+ nih_assert (args != NULL);
3429+
3430+ upstart = upstart_open (NULL);
3431+ if (! upstart)
3432+ return 1;
3433+
3434+ if (args[0]) {
3435+ /* Single job specified */
3436+ upstart_job_class = args[0];
3437+ job_class_paths = NIH_MUST (nih_alloc (NULL, 2*sizeof (char *)));
3438+ job_class_paths[1] = NULL;
3439+
3440+ if (upstart_get_job_by_name_sync (NULL, upstart, upstart_job_class,
3441+ job_class_paths) < 0)
3442+ goto error;
3443+ } else {
3444+ /* Obtain a list of jobs */
3445+ if (upstart_get_all_jobs_sync (NULL, upstart, &job_class_paths) < 0)
3446+ goto error;
3447+ }
3448+
3449+ for (char **job_class_path = job_class_paths;
3450+ job_class_path && *job_class_path; job_class_path++) {
3451+ nih_local NihDBusProxy *job_class = NULL;
3452+ nih_local char *job_class_name = NULL;
3453+
3454+ job_class = nih_dbus_proxy_new (NULL, upstart->connection,
3455+ upstart->name, *job_class_path,
3456+ NULL, NULL);
3457+ if (! job_class)
3458+ goto error;
3459+
3460+ job_class->auto_start = FALSE;
3461+
3462+ if (job_class_get_name_sync (NULL, job_class, &job_class_name) < 0)
3463+ goto error;
3464+
3465+ if (! check_config_mode)
3466+ nih_message ("%s", job_class_name);
3467+
3468+ job_class_show_emits (NULL, job_class, job_class_name);
3469+ job_class_show_conditions (job_class, job_class_name);
3470+
3471+ /* Add any jobs *without* "start on"/"stop on" conditions
3472+ * to ensure we have a complete list of jobs for check-config to work with.
3473+ */
3474+ if (check_config_mode) {
3475+ JobCondition *entry;
3476+
3477+ entry = (JobCondition *)nih_hash_lookup (check_config_data.job_class_hash,
3478+ job_class_name);
3479+ if (!entry) {
3480+ MAKE_JOB_CONDITION (check_config_data.job_class_hash,
3481+ entry, job_class_name);
3482+ nih_hash_add (check_config_data.job_class_hash, &entry->list);
3483+ }
3484+ }
3485+ }
3486+
3487+ return 0;
3488+
3489+error:
3490+ err = nih_error_get ();
3491+ nih_error ("%s", err->message);
3492+ nih_free (err);
3493+
3494+ return 1;
3495+}
3496
3497 /**
3498 * emit_action:
3499@@ -1216,6 +1465,80 @@
3500 }
3501
3502
3503+/**
3504+ * check_config_action:
3505+ * @command: NihCommand invoked,
3506+ * @args: command-line arguments.
3507+ *
3508+ * This function is called for the "check-config" command.
3509+ *
3510+ * Returns: command exit status.
3511+ **/
3512+int
3513+check_config_action (NihCommand *command,
3514+ char * const *args)
3515+{
3516+ int ret;
3517+ char *no_args[1] = { NULL };
3518+ char *job_class = NULL;
3519+
3520+ check_config_data.job_class_hash = NIH_MUST (nih_hash_string_new (NULL, 0));
3521+ check_config_data.event_hash = NIH_MUST (nih_hash_string_new (NULL, 0));
3522+
3523+ if (! check_config_data.ignored_events_hash)
3524+ check_config_data.ignored_events_hash =
3525+ NIH_MUST (nih_hash_string_new (NULL, 0));
3526+
3527+ /* Tell other functions we are running in a special mode */
3528+ check_config_mode = TRUE;
3529+
3530+ /* Obtain emits, start on and stop on data.
3531+ *
3532+ * Note: we pass null args since we always want details of all jobs.
3533+ */
3534+ ret = show_config_action (command, no_args);
3535+
3536+ if (ret)
3537+ return 0;
3538+
3539+ if (args[0]) {
3540+ NihList *entry;
3541+ job_class = args[0];
3542+
3543+ entry = nih_hash_lookup (check_config_data.job_class_hash, job_class);
3544+
3545+ if (! entry) {
3546+ nih_error ("%s: %s", _("Invalid job class"), job_class);
3547+ return 1;
3548+ }
3549+ }
3550+
3551+ NIH_HASH_FOREACH (check_config_data.job_class_hash, iter) {
3552+ JobCondition *j = (JobCondition *)iter;
3553+ int job_class_displayed = FALSE;
3554+
3555+ if (job_class && strcmp (job_class, j->job_class) != 0) {
3556+ /* user specified a job on the command-line,
3557+ * so only show that one.
3558+ */
3559+ continue;
3560+ }
3561+
3562+ ret += check_condition (j->job_class, "start on", j->start_on,
3563+ &job_class_displayed);
3564+
3565+ ret += check_condition (j->job_class, "stop on" , j->stop_on,
3566+ &job_class_displayed);
3567+ }
3568+
3569+ nih_free (check_config_data.job_class_hash);
3570+ nih_free (check_config_data.event_hash);
3571+ if (! check_config_data.ignored_events_hash)
3572+ nih_free (check_config_data.ignored_events_hash);
3573+
3574+ return ret ? 1 : 0;
3575+}
3576+
3577 static void
3578 start_reply_handler (char ** job_path,
3579 NihDBusMessage *message,
3580@@ -1250,6 +1573,635 @@
3581 nih_free (err);
3582 }
3583
3584+/**
3585+ * job_class_parse_events:
3586+ * @condition_data: type of condition we are parsing (used as an indicator to
3587+ * user) and name of job,
3588+ * @variant_array: pointer to array of variants.
3589+ *
3590+ * The array of variants encodes the event operator tree in
3591+ * Reverse Polish Notation (RPN).
3592+ *
3593+ * Each variant is itself an array. There are two types:
3594+ *
3595+ * - An "Operator" (array length == 1).
3596+ *
3597+ * Operators are: "/AND" and "/OR".
3598+ *
3599+ * - An "Event" (array length >= 1).
3600+ *
3601+ * Each Event comprises a name (array element zero), followed by zero or
3602+ * more "Event Matches". If the first Event Match is of the form "JOB=name",
3603+ * or is a single token "name" (crucially not containining "="), then
3604+ * 'name' refers to the job which emitted the event.
3605+ **/
3606+void
3607+job_class_parse_events (const ConditionHandlerData *data, char ** const *variant_array)
3608+{
3609+ char ** const *variant;
3610+ char **arg;
3611+ char *token;
3612+ nih_local NihList *rpn_stack = NULL;
3613+ char *name = NULL;
3614+ const char *stanza_name;
3615+ const char *job_class_name;
3616+
3617+ nih_assert (data);
3618+
3619+ stanza_name = ((ConditionHandlerData *)data)->condition_name;
3620+ job_class_name = ((ConditionHandlerData *)data)->job_class_name;
3621+
3622+ if (! variant_array || ! *variant_array || ! **variant_array)
3623+ return;
3624+
3625+ STACK_CREATE (rpn_stack);
3626+ STACK_SHOW (rpn_stack);
3627+
3628+ for (variant = variant_array; variant && *variant && **variant; variant++, name = NULL) {
3629+
3630+ /* token is either the first token beyond the stanza name (ie the event name),
3631+ * or an operator.
3632+ */
3633+ token = **variant;
3634+
3635+ if (IS_OPERATOR (token)) {
3636+ /* Used to hold result of combining top two stack elements. */
3637+ nih_local char *new_token = NULL;
3638+
3639+ nih_local NihList *first = NULL;
3640+ nih_local NihList *second = NULL;
3641+
3642+ if (enumerate_events) {
3643+ /* We only care about operands in this mode. */
3644+ continue;
3645+ }
3646+
3647+ if (check_config_mode) {
3648+ /* Save token verbatim. */
3649+ new_token = NIH_MUST (nih_strdup (NULL, token));
3650+ STACK_PUSH_NEW_ELEM (rpn_stack, new_token);
3651+ continue;
3652+ }
3653+
3654+ first = NIH_MUST (nih_list_new (NULL));
3655+ second = NIH_MUST (nih_list_new (NULL));
3656+
3657+ /* Found an operator, so pop 2 values off stack,
3658+ * combine them and push back onto stack.
3659+ */
3660+ STACK_POP (rpn_stack, first);
3661+ STACK_POP (rpn_stack, second);
3662+
3663+ new_token = NIH_MUST (nih_strdup (NULL, ""));
3664+ new_token = NIH_MUST (nih_strcat_sprintf (&new_token,
3665+ NULL,
3666+ "(%s %s %s)",
3667+ ((NihListEntry *)second)->str,
3668+ IS_OP_AND (token) ? "and" : "or",
3669+ ((NihListEntry *)first)->str));
3670+
3671+ STACK_PUSH_NEW_ELEM (rpn_stack, new_token);
3672+ } else {
3673+ /* Save operand token (event or job), add
3674+ * arguments (job names and env vars) and push
3675+ * onto stack. If we are enumerating_events,
3676+ * this records the environment only.
3677+ */
3678+ nih_local char *element = NULL;
3679+ int i;
3680+
3681+ element = NIH_MUST (nih_strdup (NULL,
3682+ enumerate_events ? "" : token));
3683+
3684+ /* Handle arguments (job names and env vars). */
3685+ arg = (*variant)+1;
3686+
3687+ for (i=0; arg[i] && *arg[i]; i++) {
3688+ if ((enumerate_events || check_config_mode) && IS_JOB_EVENT (token)) {
3689+ if (!name) {
3690+ GET_JOB_NAME (name, i, arg[i]);
3691+ if (name)
3692+ continue;
3693+ }
3694+ }
3695+
3696+ if (! check_config_mode) {
3697+ element = NIH_MUST (nih_strcat (&element, NULL, " "));
3698+ element = NIH_MUST (nih_strcat (&element, NULL, arg[i]));
3699+ }
3700+ }
3701+
3702+ if (enumerate_events) {
3703+ nih_message (" %s %s (job:%s%s, env:%s)",
3704+ stanza_name,
3705+ token,
3706+ name ? " " : "",
3707+ name ? name : "",
3708+ element);
3709+ } else {
3710+ if (check_config_mode) {
3711+ element = NIH_MUST (nih_sprintf (NULL, "%s%s%s",
3712+ token,
3713+ name ? " " : "",
3714+ name ? name : ""));
3715+ }
3716+ STACK_PUSH_NEW_ELEM (rpn_stack, element);
3717+ }
3718+
3719+ }
3720+ }
3721+
3722+ if (enumerate_events)
3723+ return;
3724+
3725+ if (check_config_mode) {
3726+ int add = 0;
3727+ JobCondition *entry;
3728+
3729+ /* Create job class entry if necessary */
3730+ entry = (JobCondition *)nih_hash_lookup (check_config_data.job_class_hash, job_class_name);
3731+
3732+ if (!entry) {
3733+ add = 1;
3734+ MAKE_JOB_CONDITION (check_config_data.job_class_hash, entry, job_class_name);
3735+ }
3736+
3737+ /* Unstitch the conditions from the stack and stash them
3738+ * in the appropriate list for the job in question.
3739+ */
3740+ NIH_LIST_FOREACH_SAFE (rpn_stack, iter) {
3741+ NihListEntry *node = (NihListEntry *)iter;
3742+ NihList *l = !strcmp (stanza_name, "start on")
3743+ ? entry->start_on
3744+ : entry->stop_on;
3745+ nih_ref (node, l);
3746+ nih_unref (node, rpn_stack);
3747+ nih_list_add_after (l, &node->entry);
3748+ }
3749+
3750+ if (add)
3751+ nih_hash_add (check_config_data.job_class_hash, &entry->list);
3752+
3753+ return;
3754+ }
3755+
3756+ /* Handle case where a single event was specified (there
3757+ * was no operator to pop the entry off the stack).
3758+ */
3759+ if (! STACK_EMPTY (rpn_stack)) {
3760+ if (! enumerate_events) {
3761+ /* Our job is done: show the user what we found. */
3762+ nih_message (" %s %s", stanza_name,
3763+ STACK_PEEK (rpn_stack));
3764+ }
3765+ }
3766+}
3767+
3768+/**
3769+ * job_class_show_conditions:
3770+ * @job_class_proxy: D-Bus proxy for job class.
3771+ * @job_class_name: Name of config whose conditions we wish to display.
3772+ *
3773+ * Register D-Bus call-backs to display job classes start on and stop on
3774+ * conditions.
3775+ **/
3776+void
3777+job_class_show_conditions (NihDBusProxy *job_class_proxy, const char *job_class_name)
3778+{
3779+ DBusPendingCall *pending_call;
3780+ NihError *err;
3781+ ConditionHandlerData start_data, stop_data;
3782+
3783+ nih_assert (job_class_proxy);
3784+ nih_assert (job_class_name);
3785+
3786+ start_data.condition_name = "start on";
3787+ start_data.job_class_name = job_class_name;
3788+
3789+ stop_data.condition_name = "stop on";
3790+ stop_data.job_class_name = job_class_name;
3791+
3792+ pending_call = job_class_get_start_on (job_class_proxy,
3793+ job_class_condition_handler,
3794+ job_class_condition_err_handler,
3795+ &start_data,
3796+ NIH_DBUS_TIMEOUT_NEVER);
3797+
3798+ if (!pending_call)
3799+ goto error;
3800+
3801+ /* wait for completion */
3802+ dbus_pending_call_block (pending_call);
3803+ dbus_pending_call_unref (pending_call);
3804+
3805+ pending_call = job_class_get_stop_on (job_class_proxy,
3806+ job_class_condition_handler,
3807+ job_class_condition_err_handler,
3808+ &stop_data,
3809+ NIH_DBUS_TIMEOUT_NEVER);
3810+
3811+ if (!pending_call)
3812+ goto error;
3813+
3814+ /* wait for completion */
3815+ dbus_pending_call_block (pending_call);
3816+ dbus_pending_call_unref (pending_call);
3817+
3818+ return;
3819+
3820+error:
3821+ err = nih_error_get ();
3822+ nih_error ("%s", err->message);
3823+ nih_free (err);
3824+}
3825+
3826+/**
3827+ * job_class_show_emits:
3828+ * @parent: parent object,
3829+ * @job_class_proxy: D-Bus proxy for job class,
3830+ * @job_class_name: Name of job class that emits an event.
3831+ *
3832+ * Display events job class emits to user.
3833+ **/
3834+void
3835+job_class_show_emits (const void *parent, NihDBusProxy *job_class_proxy, const char *job_class_name)
3836+{
3837+ NihError *err;
3838+ nih_local char **job_emits = NULL;
3839+
3840+ nih_assert (job_class_proxy);
3841+
3842+ if (job_class_get_emits_sync (parent, job_class_proxy, &job_emits) < 0) {
3843+ goto error;
3844+ }
3845+
3846+ if (job_emits && *job_emits) {
3847+ char **p = job_emits;
3848+ while (*p) {
3849+ if (check_config_mode) {
3850+ /* Record event for later */
3851+ NihListEntry *node = NIH_MUST (nih_list_entry_new (check_config_data.event_hash));
3852+ node->str = NIH_MUST (nih_strdup (node, *p));
3853+ nih_hash_add_unique (check_config_data.event_hash, &node->entry);
3854+ }
3855+ else {
3856+ nih_message (" emits %s", *p);
3857+ }
3858+ p++;
3859+ }
3860+ }
3861+
3862+ return;
3863+
3864+error:
3865+ err = nih_error_get ();
3866+ nih_error ("%s", err->message);
3867+ nih_free (err);
3868+}
3869+
3870+/**
3871+ * job_class_condition_handler:
3872+ * @data: data passed via job_class_get_start_on() or job_class_get_stop_on(),
3873+ * @message: D-Bus message received,
3874+ * @value: array of variants generated by D-Bus call we are registering
3875+ * with.
3876+ *
3877+ * Handler for D-Bus message encoding a job classes "start on" or
3878+ * "stop on" condtions.
3879+ **/
3880+void
3881+job_class_condition_handler (void *data, NihDBusMessage *message, char ** const *value)
3882+{
3883+ job_class_parse_events ((const ConditionHandlerData *)data, value);
3884+}
3885+
3886+/**
3887+ * job_class_condition_err_handler:
3888+ *
3889+ * @data data passed via job_class_get_start_on() or job_class_get_stop_on(),
3890+ * @message: D-Bus message received.
3891+ *
3892+ * Error handler for D-Bus message encoding a job classes "start on" or
3893+ * "stop on" conditions.
3894+ **/
3895+void
3896+job_class_condition_err_handler (void *data, NihDBusMessage *message)
3897+{
3898+ /* no remedial action possible */
3899+}
3900+
3901+
3902+/**
3903+ * eval_expr_tree:
3904+ *
3905+ * @expr: expression to consider (see ExprNode),
3906+ * @stack: stack used to hold evaluated expressions.
3907+ *
3908+ * Evaluate @expr, in the context of @stack, creating ExprNode
3909+ * nodes as necessary.
3910+ *
3911+ * See ExprNode for details of @token.
3912+ **/
3913+void
3914+eval_expr_tree (const char *expr, NihList **stack)
3915+{
3916+ NihList *s;
3917+
3918+ nih_assert (stack);
3919+
3920+ s = *stack;
3921+
3922+ if (IS_OPERATOR (expr)) {
3923+ ExprNode *node, *first, *second;
3924+ NihListEntry *tmp = NULL;
3925+ NihListEntry *le;
3926+
3927+ /* make node for operator */
3928+ MAKE_EXPR_NODE (NULL, node, expr);
3929+
3930+ /* pop */
3931+ nih_assert (! NIH_LIST_EMPTY (s));
3932+ tmp = (NihListEntry *)nih_list_remove (s->next);
3933+
3934+ /* re-parent */
3935+ nih_ref (tmp, node);
3936+ nih_unref (tmp, s);
3937+
3938+ first = (ExprNode *)tmp->data;
3939+ nih_assert (first->value != -1);
3940+
3941+ /* attach to operator node */
3942+ nih_tree_add (&node->node, &first->node, NIH_TREE_LEFT);
3943+
3944+
3945+ /* pop */
3946+ nih_assert (! NIH_LIST_EMPTY (s));
3947+ tmp = (NihListEntry *)nih_list_remove (s->next);
3948+
3949+ /* re-parent */
3950+ nih_ref (tmp, node);
3951+ nih_unref (tmp, s);
3952+
3953+ second = (ExprNode *)tmp->data;
3954+ nih_assert (second->value != -1);
3955+
3956+ /* attach to operator node */
3957+ nih_tree_add (&node->node, &second->node, NIH_TREE_RIGHT);
3958+
3959+
3960+ /* Determine truth value for
3961+ * this node based on children
3962+ * and type of operator.
3963+ */
3964+ if (IS_OP_AND (expr) || check_config_warn)
3965+ node->value = first->value && second->value;
3966+ else
3967+ node->value = first->value || second->value;
3968+
3969+ /* Create list entry and hook
3970+ * node onto it.
3971+ */
3972+ le = NIH_MUST (nih_new (s, NihListEntry));
3973+ nih_list_init (&le->entry);
3974+ le->data = node;
3975+
3976+ /* push operator node */
3977+ nih_list_add_after (s, &le->entry);
3978+
3979+ } else {
3980+ char *event = NULL;
3981+ char *job = NULL;
3982+ NihListEntry *le;
3983+ ExprNode *en;
3984+ int errors = 0;
3985+
3986+ le = NIH_MUST (nih_new (s, NihListEntry));
3987+ nih_list_init (&le->entry);
3988+
3989+ MAKE_EXPR_NODE (le, en, expr);
3990+ le->data = en;
3991+
3992+ event = en->expr;
3993+
3994+ /* Determine the type of operand node we
3995+ * have.
3996+ */
3997+ job = strchr (en->expr, ' ');
3998+
3999+ /* found a job */
4000+ if (job) {
4001+ job++;
4002+ *(job-1) = '\0';
4003+
4004+ if (! allow_job (job)) {
4005+ errors++;
4006+
4007+ /* remember the error for later */
4008+ en->job_in_error = job;
4009+ }
4010+ }
4011+
4012+ /* handle event */
4013+ if (! allow_event (event)) {
4014+ errors++;
4015+ /* remember the error for later */
4016+ en->event_in_error = en->expr;
4017+ }
4018+
4019+ /* Determine if this this node is in error (0 means yes) */
4020+ en->value = errors ? 0 : 1;
4021+
4022+ nih_list_add_after (s, &le->entry);
4023+ }
4024+}
4025+
4026+
4027+/**
4028+ * check_condition:
4029+ *
4030+ * @job_class: name of job class,
4031+ * @condition: name of condition,
4032+ * @condition_list: conditions to check.
4033+ * @job_class_displayed: Will be set to TRUE when an error node is found
4034+ * and the job class has been displayed to the user.
4035+ *
4036+ * Evaluate all expression tree nodes in @condition_list looking for
4037+ * errors.
4038+ *
4039+ * Returns error count.
4040+ **/
4041+int
4042+check_condition (const char *job_class, const char *condition, NihList *condition_list,
4043+ int *job_class_displayed)
4044+{
4045+ nih_local NihList *stack = NULL;
4046+ NihTree *root = NULL;
4047+ int errors = 0;
4048+
4049+ nih_assert (job_class);
4050+ nih_assert (condition);
4051+
4052+ if (! condition_list || NIH_LIST_EMPTY (condition_list))
4053+ return 0;
4054+
4055+ STACK_CREATE (stack);
4056+ STACK_SHOW (stack);
4057+
4058+ NIH_LIST_FOREACH (condition_list, iter) {
4059+ NihListEntry *e = (NihListEntry *)iter;
4060+
4061+ eval_expr_tree (e->str, &stack);
4062+ }
4063+
4064+ root = &(((ExprNode *)((NihListEntry *)stack->next)->data)->node);
4065+
4066+ if (! root)
4067+ /* no conditions found */
4068+ return 0;
4069+
4070+ /* Look through the expression tree for nodes in error and
4071+ * display them.
4072+ */
4073+ NIH_TREE_FOREACH_PRE_FULL (root, iter, tree_filter, root) {
4074+ ExprNode *e = (ExprNode *)iter;
4075+
4076+ if ( e->value != 1 ) {
4077+ errors++;
4078+ if ( *job_class_displayed == FALSE) {
4079+ nih_message ("%s", job_class);
4080+ *job_class_displayed = TRUE;
4081+ }
4082+
4083+ display_check_errors (job_class, condition, iter);
4084+ break;
4085+ }
4086+ }
4087+ return errors;
4088+}
4089+
4090+/**
4091+ * display_check_errors:
4092+ *
4093+ * @job_class: name of job class,
4094+ * @condition: name of condition,
4095+ * @node: tree node that is in error.
4096+ *
4097+ * Display error details from expression tree nodes
4098+ * that are in error.
4099+ *
4100+ * Note that this function should only be passed operand nodes or the
4101+ * root node.
4102+ **/
4103+void
4104+display_check_errors (const char *job_class, const char *condition, NihTree *node)
4105+{
4106+ nih_assert (job_class);
4107+ nih_assert (node);
4108+
4109+ NIH_TREE_FOREACH_POST (node, iter) {
4110+ ExprNode *expr = (ExprNode *)iter;
4111+ const char *event = expr->event_in_error;
4112+ const char *job = expr->job_in_error;
4113+
4114+ if (event)
4115+ nih_message (" %s: %s %s", condition,
4116+ _("unknown event"), event);
4117+
4118+ if (job)
4119+ nih_message (" %s: %s %s", condition,
4120+ _("unknown job"), job);
4121+ }
4122+}
4123+
4124+
4125+/**
4126+ * tree_filter:
4127+ *
4128+ * @data: node representing root of tree,
4129+ * @node: node to consider.
4130+ *
4131+ * Node filter for NIH_TREE_FOREACH_PRE_FULL that ensures only
4132+ * operator nodes and the root node are to be considered.
4133+ *
4134+ * Returns FALSE if node should be considered, else TRUE.
4135+ *
4136+ **/
4137+int
4138+tree_filter (void *data, NihTree *node)
4139+{
4140+ NihTree *root = (NihTree *)data;
4141+ ExprNode *e = (ExprNode *)node;
4142+
4143+ nih_assert (root);
4144+ nih_assert (e);
4145+
4146+ if (IS_OPERATOR (e->expr) || node == root)
4147+ return FALSE;
4148+
4149+ /* ignore */
4150+ return TRUE;
4151+}
4152+
4153+
4154+/**
4155+ * allow_job:
4156+ *
4157+ * @job: name of job to check.
4158+ *
4159+ * Returns TRUE if @job is recognized or can be ignored,
4160+ * else FALSE.
4161+ **/
4162+int
4163+allow_job (const char *job)
4164+{
4165+ NihList *found;
4166+
4167+ nih_assert (job);
4168+
4169+ found = nih_hash_lookup (check_config_data.job_class_hash, job);
4170+
4171+ /* The second part of this test ensures we ignore the (unusual)
4172+ * situation whereby the condition references a
4173+ * variable (for example an instance).
4174+ */
4175+ if (!found && job[0] != '$')
4176+ return FALSE;
4177+
4178+ return TRUE;
4179+}
4180+
4181+
4182+/**
4183+ * allow_event:
4184+ *
4185+ * @event: name of event to check.
4186+ *
4187+ * Returns TRUE if @event is recognized or can be ignored,
4188+ * else FALSE.
4189+ **/
4190+int
4191+allow_event (const char *event)
4192+{
4193+ nih_assert (event);
4194+
4195+ NIH_HASH_FOREACH (check_config_data.event_hash, iter) {
4196+ NihListEntry *entry = (NihListEntry *)iter;
4197+
4198+ /* handles expansion of any globs */
4199+ if (fnmatch (entry->str, event, 0) == 0)
4200+ goto out;
4201+ }
4202+
4203+ if (IS_INIT_EVENT (event) ||
4204+ nih_hash_lookup (check_config_data.ignored_events_hash, event))
4205+ goto out;
4206+
4207+ return FALSE;
4208+
4209+out:
4210+ return TRUE;
4211+}
4212+
4213
4214 #ifndef TEST
4215 /**
4216@@ -1258,9 +2210,11 @@
4217 * Command-line options accepted for all arguments.
4218 **/
4219 static NihOption options[] = {
4220+ { 0, "session", N_("use D-Bus session bus to connect to init daemon (for testing)"),
4221+ NULL, NULL, NULL, dbus_bus_type_setter },
4222 { 0, "system", N_("use D-Bus system bus to connect to init daemon"),
4223- NULL, NULL, &system_bus, NULL },
4224- { 0, "dest", N_("destination well-known name on system bus"),
4225+ NULL, NULL, NULL, dbus_bus_type_setter },
4226+ { 0, "dest", N_("destination well-known name on D-Bus bus"),
4227 NULL, "NAME", &dest_name, NULL },
4228
4229 NIH_OPTION_LAST
4230@@ -1371,6 +2325,32 @@
4231
4232
4233 /**
4234+ * show_config_options:
4235+ *
4236+ * Command-line options accepted for the show-config command.
4237+ **/
4238+NihOption show_config_options[] = {
4239+ { 'e', "enumerate",
4240+ N_("enumerate list of events and jobs causing job "
4241+ "created from job config to start/stop"),
4242+ NULL, NULL, &enumerate_events, NULL },
4243+
4244+ NIH_OPTION_LAST
4245+};
4246+
4247+/**
4248+ * check_config_options:
4249+ *
4250+ * Command-line options accepted for the check-config command.
4251+ **/
4252+NihOption check_config_options[] = {
4253+ { 'i', "ignore-events", N_("ignore specified list of events (comma-separated)"),
4254+ NULL, "EVENT_LIST", NULL, ignored_events_setter },
4255+ { 'w', "warn", N_("Generate warning for any unreachable events/jobs"),
4256+ NULL, NULL, &check_config_warn, NULL },
4257+ NIH_OPTION_LAST
4258+};
4259+/**
4260 * job_group:
4261 *
4262 * Group of commands related to jobs.
4263@@ -1478,10 +2458,27 @@
4264 "Without arguments, this outputs the current log priority."),
4265 NULL, log_priority_options, log_priority_action },
4266
4267+ { "show-config", N_("[CONF]"),
4268+ N_("Show emits, start on and stop on details for job configurations."),
4269+ N_("If CONF specified, show configuration details for single job "
4270+ "configuration, else show details for all jobs configurations.\n"),
4271+ NULL, show_config_options, show_config_action },
4272+
4273+ { "check-config", N_("[CONF]"),
4274+ N_("Check for unreachable jobs/event conditions."),
4275+ N_("List all jobs and events which cannot be satisfied by "
4276+ "currently available job configuration files"),
4277+ NULL, check_config_options, check_config_action },
4278+
4279+
4280 NIH_COMMAND_LAST
4281 };
4282
4283
4284+
4285+
4286+
4287+
4288 int
4289 main (int argc,
4290 char *argv[])
4291
4292=== added file 'util/initctl.h'
4293--- util/initctl.h 1970-01-01 00:00:00 +0000
4294+++ util/initctl.h 2011-06-03 09:50:59 +0000
4295@@ -0,0 +1,458 @@
4296+/* upstart
4297+ *
4298+ * Copyright © 2011 Canonical Ltd.
4299+ * Author: James Hunt <james.hunt@canonical.com>
4300+ *
4301+ * This program is free software; you can redistribute it and/or modify
4302+ * it under the terms of the GNU General Public License version 2, as
4303+ * published by the Free Software Foundation.
4304+ *
4305+ * This program is distributed in the hope that it will be useful,
4306+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4307+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4308+ * GNU General Public License for more details.
4309+ *
4310+ * You should have received a copy of the GNU General Public License along
4311+ * with this program; if not, write to the Free Software Foundation, Inc.,
4312+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
4313+ */
4314+
4315+#ifndef INITCTL_H
4316+#define INITCTL_H
4317+
4318+/**
4319+ * IS_OP_AND:
4320+ * @token: string token to check.
4321+ *
4322+ * Return TRUE if @token is an 'AND' operator, else FALSE.
4323+ **/
4324+#define IS_OP_AND(token) \
4325+ (! strcmp ((token), "/AND"))
4326+
4327+/**
4328+ * IS_OP_OR:
4329+ * @token: string token to check.
4330+ *
4331+ * Return TRUE if @token is an 'OR' operator, else FALSE.
4332+ **/
4333+#define IS_OP_OR(token) \
4334+ (! strcmp ((token), "/OR"))
4335+
4336+/**
4337+ * IS_OPERATOR
4338+ * @token: string token to check.
4339+ *
4340+ * Return TRUE if @token is either an 'AND' or an 'OR' operator,
4341+ * else FALSE.
4342+ **/
4343+#define IS_OPERATOR(token) \
4344+ IS_OP_AND (token) || IS_OP_OR (token)
4345+
4346+
4347+/**
4348+ * GET_JOB_NAME:
4349+ *
4350+ * @var: char pointer variable which will be set to the name
4351+ * of a job, or NULL,
4352+ * @index: zero-based index of tokens where zero represents
4353+ * the first token after the initial token,
4354+ * @token: string to check.
4355+ *
4356+ * Determine name of job considering the specified token and its
4357+ * index. If not a job, sets @name to NULL.
4358+ *
4359+ * Handles the following cases:
4360+ *
4361+ * [start|stop] on <job_event> foo
4362+ * (index==0, job="foo" => name="foo")
4363+ *
4364+ * [start|stop] on <job_event> JOB=foo
4365+ * (index==0, job="JOB=foo" => name="foo")
4366+ *
4367+ * [start|stop] on <job_event> A=B JOB=foo
4368+ * (index==1, job="JOB=foo" => name="foo")
4369+ *
4370+ * [start|stop] on <job_event> A=B c=hello JOB=foo
4371+ * (index==2, job="JOB=foo" => name="foo")
4372+ *
4373+ * [start|stop] on <job_event> $JOB A=B c=hello
4374+ * (index==0, job="$JOB" => name="$JOB")
4375+ *
4376+ **/
4377+#define GET_JOB_NAME(var, index, token) \
4378+{ \
4379+ char *_##var; \
4380+ \
4381+ nih_assert (index >= 0); \
4382+ nih_assert (token); \
4383+ \
4384+ var = NULL; \
4385+ \
4386+ _##var = strstr (token, "JOB="); \
4387+ \
4388+ if (_##var && _##var == token) \
4389+ var = _##var + strlen ("JOB="); \
4390+ else if (index == 0 ) { \
4391+ if (!strstr (token, "=")) \
4392+ var = token; \
4393+ } \
4394+}
4395+
4396+
4397+/**
4398+ * IS_JOB_EVENT:
4399+ * @token: string to check.
4400+ *
4401+ * Return TRUE if specified token refers to a standard job event, else
4402+ * FALSE.
4403+ **/
4404+#define IS_JOB_EVENT(token) \
4405+ (!strcmp (token, JOB_STARTING_EVENT) || \
4406+ !strcmp (token, JOB_STARTED_EVENT) || \
4407+ !strcmp (token, JOB_STOPPING_EVENT) || \
4408+ !strcmp (token, JOB_STOPPED_EVENT))
4409+
4410+/**
4411+ * IS_INIT_EVENT:
4412+ * @token: string to check.
4413+ *
4414+ * Return TRUE if specified token refers to an event emitted internally,
4415+ * else FALSE.
4416+ *
4417+ * Note: the raw string entries below are required to accommodate
4418+ * production versus debug builds (STARTUP_EVENT changes name depending
4419+ * on build type).
4420+ **/
4421+#define IS_INIT_EVENT(token) \
4422+ (!strcmp (token, STARTUP_EVENT) || \
4423+ !strcmp (token, "debug") || \
4424+ !strcmp (token, "startup") || \
4425+ !strcmp (token, CTRLALTDEL_EVENT) || \
4426+ !strcmp (token, KBDREQUEST_EVENT) || \
4427+ !strcmp (token, PWRSTATUS_EVENT) || \
4428+ IS_JOB_EVENT (token))
4429+
4430+/**
4431+ * STACK_EMPTY:
4432+ * @stack: address of stack to check.
4433+ *
4434+ * Return TRUE if @stack is empty, else FALSE.
4435+ **/
4436+#define STACK_EMPTY(stack) \
4437+ (NIH_LIST_EMPTY (stack))
4438+
4439+/**
4440+ * STACK_CREATE:
4441+ * @name: nih_list variable to assign stack to.
4442+ **/
4443+#define STACK_CREATE(name) \
4444+ name = NIH_MUST (nih_list_new (NULL))
4445+/**
4446+ * STACK_SHOW_POP:
4447+ * @stack: Address of stack,
4448+ * @str: string representing element popped off stack.
4449+ *
4450+ * Display message to denote that @str has been popped off @stack.
4451+ * Does nothing if debug build not enabled.
4452+ *
4453+ * Note: we cannot assert that stack is not empty since a caller may
4454+ * have just removed the last entry before calling us. Thus, it is up to
4455+ * the caller to perform such checks.
4456+ *
4457+ * Does nothing if debug build not enabled.
4458+ **/
4459+#ifdef DEBUG_STACK
4460+#define STACK_SHOW_POP(stack, str) \
4461+ STACK_SHOW_CHANGE (stack, "popped", str)
4462+#else
4463+#define STACK_SHOW_POP(stack, str)
4464+#endif
4465+
4466+/**
4467+ * STACK_SHOW_PUSH:
4468+ * @stack: Address of stack,
4469+ * @str: string representing element pushed onto stack.
4470+ *
4471+ * Display message to denote that @str has been pushed onto @stack.
4472+ *
4473+ * Does nothing if debug build not enabled.
4474+ **/
4475+#ifdef DEBUG_STACK
4476+#define STACK_SHOW_PUSH(stack, str) \
4477+ STACK_SHOW_CHANGE (stack, "pushed", str) \
4478+ \
4479+ nih_assert (! STACK_EMPTY (stack))
4480+#else
4481+#define STACK_SHOW_PUSH(stack, str)
4482+#endif
4483+
4484+/**
4485+ * STACK_SHOW:
4486+ * @stack: Address of stack.
4487+ *
4488+ * Display contents of @stack.
4489+ *
4490+ * Does nothing if debug build not enabled.
4491+ **/
4492+#ifdef DEBUG_STACK
4493+#define STACK_SHOW(stack) \
4494+{ \
4495+ size_t depth = 0; \
4496+ \
4497+ nih_assert (stack); \
4498+ \
4499+ NIH_LIST_FOREACH (stack, iter) { \
4500+ depth++; \
4501+ } \
4502+ \
4503+ if (STACK_EMPTY (stack)) { \
4504+ nih_message ("STACK@%p: empty", stack); \
4505+ } else { \
4506+ for (NihList *iter = (stack)->next; \
4507+ iter != (stack) && \
4508+ ((NihListEntry *)iter)->str; \
4509+ iter = iter->next, depth--) { \
4510+ nih_message ("STACK@%p[%u]='%s'", \
4511+ (void *)stack, \
4512+ (unsigned int)(depth-1), \
4513+ ((NihListEntry *)iter)->str); \
4514+ } \
4515+ } \
4516+}
4517+#else
4518+#define STACK_SHOW(stack)
4519+#endif
4520+
4521+/**
4522+ * STACK_SHOW_CHANGE:
4523+ * @stack: Address of stack,
4524+ * @msg: message to show a stack change,
4525+ * @element_str: string representing element changed on @stack.
4526+ *
4527+ * Display a message showing that the stack has been changed.
4528+ *
4529+ * Does nothing if debug build not enabled.
4530+ **/
4531+#ifdef DEBUG_STACK
4532+#define STACK_SHOW_CHANGE(stack, msg, element_str) \
4533+ nih_assert (msg); \
4534+ nih_assert (element_str); \
4535+ \
4536+ nih_message ("STACK@%p: %s '%s'", \
4537+ (void *)stack, msg, element_str); \
4538+ \
4539+ STACK_SHOW (stack); \
4540+ \
4541+ nih_message (" "); /* spacer */
4542+#else
4543+#define STACK_SHOW_CHANGE(stack, msg, element_str)
4544+#endif
4545+
4546+/**
4547+ * STACK_PUSH:
4548+ * @stack: Address of stack,
4549+ * @elem: element of type NihListEntry to add to stack.
4550+ *
4551+ * Add @elem to @stack and display message showing how stack changed.
4552+ **/
4553+#define STACK_PUSH(stack, elem) \
4554+ nih_list_add_after (stack, &(elem)->entry); \
4555+ \
4556+ STACK_SHOW_PUSH (stack, \
4557+ ((NihListEntry *)(elem))->str); \
4558+ \
4559+ nih_assert (! STACK_EMPTY (stack))
4560+
4561+/**
4562+ * STACK_PUSH_NEW_ELEM:
4563+ * @stack: Address of stack,
4564+ * @string: String to convert into a new NihListEntry
4565+ * stack element and push onto @stack.
4566+ *
4567+ * Create new stack element from @string and push onto @stack,
4568+ * displaying a message showing how stack changed.
4569+ **/
4570+#define STACK_PUSH_NEW_ELEM(stack, string) \
4571+{ \
4572+ NihListEntry *e; \
4573+ \
4574+ nih_assert (stack); \
4575+ nih_assert (string); \
4576+ \
4577+ e = NIH_MUST (nih_new (stack, NihListEntry)); \
4578+ nih_list_init (&e->entry); \
4579+ e->str = NIH_MUST (nih_strdup (e, string)); \
4580+ STACK_PUSH (stack, e); \
4581+}
4582+
4583+/**
4584+ * STACK_POP:
4585+ * @stack: Address of stack,
4586+ * @list: list which top stack element will be added to.
4587+ *
4588+ * Remove top element from @stack, returning to caller as @list
4589+ * and display message showing how stack changed.
4590+ *
4591+ * Note that @list is assumed to have had nih_list_new() called
4592+ * on it already.
4593+ **/
4594+#define STACK_POP(stack, list) \
4595+ nih_assert (stack); \
4596+ nih_assert ((stack)->next); \
4597+ \
4598+ list = nih_list_add (list, (stack)->next); \
4599+ STACK_SHOW_POP (stack, \
4600+ ((NihListEntry *)(list))->str)
4601+
4602+/**
4603+ * STACK_PEEK:
4604+ * @stack: Address of stack.
4605+ *
4606+ * Return string value of top element on stack.
4607+ **/
4608+#define STACK_PEEK(stack) \
4609+ (((NihListEntry *)(stack)->next)->str)
4610+
4611+/**
4612+ * JobCondition:
4613+ *
4614+ * @list: list that @list lives on,
4615+ * @job_class: name of job class,
4616+ * @start_on: start on conditions,
4617+ * @stop_on: stop on conditions.
4618+ *
4619+ * Structure used to represent a job classes start on and stop on
4620+ * conditions.
4621+ *
4622+ * Note that @start_on and @stop_on are lists of NihListEntry
4623+ * objects containing string data.
4624+ *
4625+ *
4626+ **/
4627+typedef struct condition {
4628+ NihList list;
4629+
4630+ const char *job_class;
4631+ NihList *start_on;
4632+ NihList *stop_on;
4633+} JobCondition;
4634+
4635+/**
4636+ * CheckConfigData:
4637+ *
4638+ * @job_class_hash: Job classes (.conf files)
4639+ * currently installed,
4640+ * @event_hash: Events that are documented
4641+ * as being emitted,
4642+ * @ignored_events_hash: Rvents we wish to ignore.
4643+ *
4644+ * Notes:
4645+ *
4646+ * Keys for @job_class_hash are job class names and values
4647+ * are of type JobCondition.
4648+ *
4649+ * Keys of @event_hash are event names and values are of type
4650+ * NihListEntry holding the event name as a string.
4651+ *
4652+ * Keys of @ignored_events_hash are event names and values are of type
4653+ * NihListEntry holding the event name as a string.
4654+ **/
4655+typedef struct check_config_data {
4656+ NihHash *job_class_hash;
4657+ NihHash *event_hash;
4658+ NihHash *ignored_events_hash;
4659+} CheckConfigData;
4660+
4661+
4662+/**
4663+ * ConditionHandlerData:
4664+ *
4665+ * @condition_name: "start on" or "stop on",
4666+ * @job_class_name: name of *.conf file less the extension.
4667+ *
4668+ * Used to pass multiple values to job_class_get_start_on() /
4669+ * job_class_get_stop_on() handlers.
4670+ *
4671+ **/
4672+typedef struct condition_handler_data {
4673+ const char *condition_name;
4674+ const char *job_class_name;
4675+} ConditionHandlerData;
4676+
4677+
4678+/**
4679+ * ExprNode:
4680+ *
4681+ * @node: tree which node lives in,
4682+ * @expr: string representing the expression,
4683+ * @job_in_error: if not NULL, points to the appropriate portion of
4684+ * @expr where the erroneous job is,
4685+ * @event_in_error: if not NULL, points to the appropriate portion of
4686+ * @expr where the erroneous event is,
4687+ * @value: Truth value of this node (and its children, if any).
4688+ *
4689+ * Node representing an expression.
4690+ *
4691+ * Notes:
4692+ *
4693+ * @expr can be one of:
4694+ *
4695+ * - operator:
4696+ * - IS_OP_AND()
4697+ * - IS_OP_OR()
4698+ * - operand:
4699+ * - "<event>"
4700+ * - "<event> <job>"
4701+ *
4702+ * @value can be:
4703+ *
4704+ * - 0 denoting node (and its children) are in error.
4705+ * - 1 denoting no errors in this node or its children.
4706+ * - -1 denoting an uninitialized value.
4707+ */
4708+typedef struct expression_node {
4709+ NihTree node;
4710+
4711+ char *expr;
4712+ const char *job_in_error;
4713+ const char *event_in_error;
4714+ int value;
4715+} ExprNode;
4716+
4717+
4718+/**
4719+ * MAKE_EXPR_NODE:
4720+ *
4721+ * @parent: parent object,
4722+ * @entry: pointer to ExprNode to initialize,
4723+ * @str: string expression which will be copied into @entry.
4724+ *
4725+ * Allocate storage for an ExprNode pointer and initialize.
4726+ **/
4727+#define MAKE_EXPR_NODE(parent, entry, str) \
4728+ entry = NIH_MUST (nih_new (parent, ExprNode)); \
4729+ nih_tree_init (&(entry)->node); \
4730+ (entry)->expr = (str) \
4731+ ? NIH_MUST (nih_strdup (entry, (str))) \
4732+ : NULL; \
4733+ (entry)->job_in_error = NULL; \
4734+ (entry)->event_in_error = NULL; \
4735+ (entry)->value = -1
4736+
4737+/**
4738+ * MAKE_JOB_CONDITION:
4739+ *
4740+ * @parent: parent object,
4741+ * @entry: pointer to JobCondition to initialize,
4742+ * @str: string expression which will be copied into @entry.
4743+ *
4744+ * Allocate storage for an JobCondition pointer and initialize.
4745+ **/
4746+#define MAKE_JOB_CONDITION(parent, entry, str) \
4747+ entry = NIH_MUST (nih_new (parent, JobCondition)); \
4748+ nih_list_init (&(entry)->list); \
4749+ (entry)->job_class = NIH_MUST (nih_strdup (entry, str)); \
4750+ (entry)->start_on = NIH_MUST (nih_list_new (entry)); \
4751+ (entry)->stop_on = NIH_MUST (nih_list_new (entry))
4752+
4753+#endif /* INITCTL_H */
4754
4755=== modified file 'util/man/initctl.8'
4756--- util/man/initctl.8 2010-02-04 19:08:07 +0000
4757+++ util/man/initctl.8 2011-06-03 09:50:59 +0000
4758@@ -1,4 +1,4 @@
4759-.TH initctl 8 2010-02-04 "Upstart"
4760+.TH initctl 8 2011-06-01 "Upstart"
4761 .\"
4762 .SH NAME
4763 initctl \- init daemon control tool
4764@@ -33,6 +33,12 @@
4765 .\"
4766 .SH OPTIONS
4767 .TP
4768+.B --session
4769+Connect to
4770+.BR init (8)
4771+daemon using the D-Bus session bus (for testing purposes only).
4772+.\"
4773+.TP
4774 .B --system
4775 Communication with the
4776 .BR init (8)
4777@@ -339,6 +345,161 @@
4778 .BR init (8)
4779 daemon will log and ouputs to standard output.
4780 .\"
4781+.TP
4782+.B show-config
4783+.RI [ OPTIONS "] [" CONF "]"
4784+
4785+Display emits, start on and stop on job configuration details (in that
4786+order) for specified job configuration, \fICONF\fP. If \fICONF\fP is not
4787+specified, list information for all valid job configurations.
4788+
4789+Note that a job configuration is the name of a job configuration file,
4790+without the extension. Note too that this information is static: it
4791+does not refer to any running job.
4792+
4793+For each event emitted, a separate line is displayed beginning with two
4794+space characters followed by, \'emits \fIevent\fP\' where \'\fIevent\fP\'
4795+denotes a single emitted event.
4796+
4797+The \fBstart on\fP and \fBstop on\fP conditions
4798+are listed on separate lines beginning with two space characters and
4799+followed by \'start on\' and \'stop on\' respectively and ending with
4800+the appropriate condition.
4801+
4802+If a job configuration has no emits, start on, or stop on conditions,
4803+the name of the job configuration will be displayed with no further
4804+details.
4805+
4806+Note that the \fBstart on\fP and \fBstop on\fP conditions will be fully
4807+bracketed, regardless of whether they appear like this in the job
4808+configuration file. This is useful to see how the
4809+.BR init (8)
4810+daemon perceives the condition.
4811+
4812+Example output:
4813+
4814+.nf
4815+foo
4816+ emits boing
4817+ emits blip
4818+ start on (starting A and (B or C var=2))
4819+ stop on (bar HELLO=world testing=123 or stopping wibble)
4820+.fi
4821+
4822+.B OPTIONS
4823+.RS
4824+.IP "\fB\-e\fP, \fB\-\-enumerate\fP"
4825+
4826+If specified, rather than listing the precise \fBstart on\fP and \fBstop
4827+on\fP conditions, outputs the emits lines along with one line for each
4828+event or job the \fICONF\fP in question \fImay\fP be started or stopped
4829+by if it were to become a job. If the start on condition specifies a
4830+non-job event, this will be listed verbatim, whereas for a job event,
4831+the name of the \fIjob\fP as opposed to the event the job emits will be
4832+listed.
4833+
4834+The type of entity, its triggering event (if appropriate) and its full
4835+environment is displayed in brackets following its name for clarity.
4836+
4837+This option is useful for tools which generate graphs of relationships
4838+between jobs and events. It is also instructive since it shows how the
4839+.BR init (8)
4840+daemon has parsed the job configuration file.
4841+
4842+Example output (an analog of the default output format above):
4843+
4844+.nf
4845+foo
4846+ emits boing
4847+ emits blip
4848+ start on starting (job: A, env:)
4849+ start on B (job:, env:)
4850+ start on C (job:, env: var=2)
4851+ stop on bar (job:, env: HELLO=world testing=123)
4852+ stop on stopping (job: wibble, event: stopping, env:)
4853+.fi
4854+.RE
4855+.\"
4856+.TP
4857+.B check-config
4858+.RI [ OPTIONS "] [" CONF "]"
4859+
4860+Considers all job configurations looking for jobs that cannot be started
4861+or stopped, given the currently available job configurations. This is
4862+achieved by considering the start on, stop on and emits stanzas for each
4863+job configuration and identifying unreachable scenarios.
4864+
4865+This option is useful for determining the impact of adding or removing
4866+job configuration files.
4867+
4868+Note that to use this command, it is necessary to ensure that all job
4869+configuration files advertise the events they emit correctly.
4870+
4871+If errors are identified, the name of the job configuration will be
4872+displayed. Subsequent lines will show the failed conditions for the job
4873+configuration, one per line. Condition lines begin with two spaces and
4874+are followed with either "start on: " or "stop on: ", the word
4875+"unknown", the type of entity that is not known and finally its name.
4876+
4877+Note that only job configurations that are logically in error (those
4878+with unsatisfiable conditions) will be displayed. Note too that job
4879+configurations that are syntactically invalid may trigger an error if
4880+they would cause a condition to be in error.
4881+
4882+Assuming job configuration file \fI/etc/init/foo.conf\fP contains the
4883+following:
4884+
4885+.nf
4886+ start on starting grape
4887+ stop on peach
4888+.fi
4889+
4890+The check-config command might display:
4891+
4892+.nf
4893+ foo
4894+ start on: unknown job grape
4895+ stop on: unknown event peach
4896+.fi
4897+
4898+If any errors are detected, the exit code will be 1 (one). If all checks pass,
4899+the exit code will be 0 (zero).
4900+
4901+Note that for complex start on and stop on conditions, this command may
4902+give what appears to be misleading output when an error condition is
4903+found since all expressions in the failing condition that are in error
4904+will generate error output. For example, if job configuration
4905+\fI/etc/init/bar.conf\fP contains the following:
4906+
4907+.nf
4908+ start on (A and (started B or (starting C or D)))
4909+.fi
4910+
4911+And only event A can be satisfied, the output will be:
4912+
4913+.nf
4914+ bar
4915+ start on: unknown job B
4916+ start on: unknown job C
4917+ start on: unknown event D
4918+.fi
4919+
4920+.B OPTIONS
4921+.RS
4922+.IP "\fB-i\fP \fI[EVENTS]\fP, \fB\-\-ignore\-events\fP \fI[EVENTS]\fP"
4923+
4924+If specified, the argument should be a list of comma-separated events to
4925+ignore when checking the job configuration files.
4926+
4927+This option may be useful to ignore errors if a particular job
4928+configuration file does not advertise it emits an event.
4929+
4930+Note that internal events (such as \fBstartup\fP(7) and
4931+\fBstarting\fP(7)) are automatically ignored.
4932+.IP "\fB-w\fP, \fB\-\-warn\fP"
4933+If specified, treat \fIany\fP unknown jobs and events as errors.
4934+
4935+.\"
4936 .SH AUTHOR
4937 Written by Scott James Remnant
4938 .RB < scott@netsplit.com >
4939@@ -348,7 +509,7 @@
4940 .RB < https://launchpad.net/upstart/+bugs >
4941 .\"
4942 .SH COPYRIGHT
4943-Copyright \(co 2010 Canonical Ltd.
4944+Copyright \(co 2010-2011 Canonical Ltd.
4945 .br
4946 This is free software; see the source for copying conditions. There is NO
4947 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
4948
4949=== modified file 'util/reboot.c'
4950--- util/reboot.c 2011-03-16 22:18:22 +0000
4951+++ util/reboot.c 2011-06-03 09:50:59 +0000
4952@@ -1,6 +1,5 @@
4953 /* upstart
4954 *
4955- * Copyright © 2011 Google Inc.
4956 * Copyright © 2010 Canonical Ltd.
4957 * Author: Scott James Remnant <scott@netsplit.com>.
4958 *
4959
4960=== modified file 'util/tests/test_initctl.c'
4961--- util/tests/test_initctl.c 2010-02-04 20:43:33 +0000
4962+++ util/tests/test_initctl.c 2011-06-03 09:50:59 +0000
4963@@ -3,7 +3,8 @@
4964 * test_initctl.c - test suite for util/initctl.c
4965 *
4966 * Copyright © 2010 Canonical Ltd.
4967- * Author: Scott James Remnant <scott@netsplit.com>.
4968+ * Authors: Scott James Remnant <scott@netsplit.com>,
4969+ * James Hunt <james.hunt@canonical.com>.
4970 *
4971 * This program is free software; you can redistribute it and/or modify
4972 * it under the terms of the GNU General Public License version 2, as
4973@@ -27,6 +28,8 @@
4974 #include <stdio.h>
4975 #include <signal.h>
4976 #include <unistd.h>
4977+#include <sys/types.h>
4978+#include <sys/stat.h>
4979
4980 #include <nih-dbus/dbus_error.h>
4981 #include <nih-dbus/dbus_connection.h>
4982@@ -40,11 +43,192 @@
4983 #include <nih/main.h>
4984 #include <nih/command.h>
4985 #include <nih/error.h>
4986+#include <nih/string.h>
4987
4988 #include "dbus/upstart.h"
4989
4990-
4991-extern int system_bus;
4992+/* remember we run from the 'util' directory */
4993+#define UPSTART_BINARY "../init/init"
4994+#define INITCTL_BINARY "./initctl --session"
4995+
4996+#define BUFFER_SIZE 1024
4997+
4998+/**
4999+ * START_UPSTART:
5000+ *
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches