Merge lp:~jamesodhunt/upstart/upstream-man-pages-updates into lp:upstart

Proposed by James Hunt
Status: Merged
Merged at revision: 1299
Proposed branch: lp:~jamesodhunt/upstart/upstream-man-pages-updates
Merge into: lp:upstart
Diff against target: 6857 lines (+4794/-440)
34 files modified
ChangeLog (+159/-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 (+87/-34)
init/man/init.8 (+26/-4)
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 (+200/-34)
util/reboot.c (+0/-1)
util/tests/test_initctl.c (+1181/-19)
To merge this branch: bzr merge lp:~jamesodhunt/upstart/upstream-man-pages-updates
Reviewer Review Type Date Requested Status
Upstart Developers Pending
Review via email: mp+63359@code.launchpad.net

Description of the change

Man page updates.

* init/man/init.5:
  - Quoted dashes.
  - Explain handling of duplicated stanzas.
  - "respawn": Document default count and interval.
  - "emits": Reference "initctl check-config".
  - Added BUGS section.
  - Added copyright.
* init/man/init.8:
  - Quoted dashes.
  - See Also: Added control-alt-delete(7).
* util/man/initctl.8:
  - Quoted dashes.
  - "restart": Clarified meaning.
  - "list": Explained "stop/waiting" jobs.

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

Subscribers

People subscribed via source and target branches