Merge lp:~jamesodhunt/upstart/upstream-session-support into lp:upstart

Proposed by James Hunt
Status: Merged
Merged at revision: 1305
Proposed branch: lp:~jamesodhunt/upstart/upstream-session-support
Merge into: lp:upstart
Diff against target: 13125 lines (+6395/-1019)
56 files modified
ChangeLog (+219/-0)
Makefile.am (+1/-1)
TESTING.sessions (+264/-0)
conf/rc-sysinit.conf (+2/-0)
configure.ac (+3/-2)
contrib/bash_completion/upstart (+96/-36)
dbus/Upstart.conf (+6/-36)
dbus/upstart.h (+1/-1)
init/Makefile.am (+12/-0)
init/conf.c (+10/-5)
init/conf.h (+5/-2)
init/control.c (+73/-10)
init/control.h (+15/-1)
init/environ.c (+0/-1)
init/environ.h (+0/-1)
init/event.c (+10/-0)
init/event.h (+5/-1)
init/job.c (+44/-3)
init/job.h (+1/-1)
init/job_class.c (+113/-23)
init/job_class.h (+5/-1)
init/job_process.c (+59/-1)
init/job_process.h (+4/-3)
init/main.c (+234/-136)
init/man/init.5 (+131/-41)
init/man/init.8 (+32/-4)
init/parse_job.c (+4/-2)
init/parse_job.h (+4/-3)
init/paths.h (+25/-2)
init/session.c (+279/-0)
init/session.h (+87/-0)
init/tests/test_blocked.c (+4/-1)
init/tests/test_conf.c (+15/-13)
init/tests/test_control.c (+15/-11)
init/tests/test_environ.c (+3/-1)
init/tests/test_event.c (+28/-25)
init/tests/test_event_operator.c (+3/-0)
init/tests/test_job.c (+71/-76)
init/tests/test_job_class.c (+56/-65)
init/tests/test_job_process.c (+34/-30)
init/tests/test_parse_conf.c (+3/-0)
init/tests/test_parse_job.c (+263/-260)
init/tests/test_process.c (+3/-0)
init/tests/test_system.c (+3/-0)
po/upstart.pot (+292/-148)
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-session-support
Reviewer Review Type Date Requested Status
Upstart Developers Pending
Review via email: mp+63567@code.launchpad.net

This proposal supersedes a proposal from 2011-06-03.

Description of the change

Addition of session support, for user sessions and chroot sessions.

Code is lp:~canonical-scott/upstart/session-support plus associated fixes:

  Add session support. Note that there are no automatically runnable and
  explicit tests yet. However, see TESTING.sessions.

  * TESTING.sessions: ASCII (reStructuredText) document explaining
    how to run manual tests for session support (for chroots).
  * dbus/Upstart.conf: Simplified to support allowing users to invoke
    all methods (since Upstart now isolates commands by user).
  * init/Makefile.am: Added session.[ch] files.
  * init/session.c: New file. Note that session_from_dbus() will disable sessions
    (by returning the NULL session) if environment variable "UPSTART_NO_SESSIONS"
    is set to any value (used by tests).
  * init/session.h: New file.
  * init/parse_job.h: parse_job(): Add session pointer to prototype.
  * init/parse_job.c:
    - parse_job(): Add session parameter.
    - Update calls to job_class_new() to pass session pointer.
  * init/job.c: job_new(): Crucial change to ensure chroot sessions have
    a unique D-Bus name (LP:#728531).
  * init/job_class.c:
    - job_class_new(): Add session parameter and session support.
    - job_class_remove(): Add session parameter to prototype.
    - job_class_consider(): Only consider jobs from the appropriate session.
    - job_class_reconsider(): Only consider jobs from the appropriate session.
    - job_class_start(): Disallow out-of-session modification.
    - job_class_stop(): Disallow out-of-session modification.
    - job_class_restart(): Disallow out-of-session modification.
  * init/main.c: Add "--no-sessions" command-line option to disable
    sessions and revert to traditional behaviour.
  * init/job_class.h:
    - job_class_new(): Add session pointer to prototype.
    - JobClass: Add session member.
  * init/job_process.c: job_process_spawn():
    - Call chroot(2) for chroot sessions.
    - Call setuid(2) for user session jobs.
  * init/job.c:
    - job_emit_event(): Set session for event.
    - job_start(): Disallow out-of-session modification.
    - job_stop(): Disallow out-of-session modification.
    - job_restart(): Disallow out-of-session modification.
  * init/event.h: Event: Add session member.
  * init/event.c:
    - event_new(): initialize session to NULL.
    - event_pending_handle_jobs(): Add session handling.
    - event_finished(): Set session for failure event.
  * init/control.c:
    - control_get_job_by_name(): Add session handling.
    - control_get_all_jobs(): Add session handling.
    - control_emit_event(): Add session handling.
  * init/conf.c:
    - conf_source_new(): Initialise session to NULL.
    - conf_reload_path(): Pass session to parse_job().
    - conf_select_job(): Add session parameter.
  * init/conf.h:
    - ConfSource: Add session member.
    - conf_select_job(): Add session parameter to prototype.
  * All tests updated to set "UPSTART_NO_SESSIONS".

To post a comment you must log in.
1261. By James Hunt

* init/man/init.5: Update for User Jobs.
* init/man/init.8: Mention $HOME/.init/ for User Jobs.

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

Subscribers

People subscribed via source and target branches