Merge lp:~upstart-devel/upstart/0.9 into lp:upstart

Proposed by James Hunt on 2011-04-14
Status: Rejected
Rejected by: Steve Langasek on 2013-05-28
Proposed branch: lp:~upstart-devel/upstart/0.9
Merge into: lp:upstart
Diff against target: 17059 lines (+10051/-881) (has conflicts)
67 files modified
.bzrignore (+4/-0)
ChangeLog (+453/-0)
Makefile.am (+1/-1)
NEWS (+101/-0)
conf/rc-sysinit.conf (+2/-0)
configure.ac (+11/-2)
contrib/bash_completion/upstart (+34/-10)
dbus/Upstart.conf (+6/-36)
dbus/com.ubuntu.Upstart.xml (+7/-0)
dbus/upstart.h (+1/-1)
extra/Makefile.am (+126/-0)
extra/conf/upstart-socket-bridge.conf (+16/-0)
extra/conf/upstart-udev-bridge.conf (+16/-0)
extra/man/socket-event.7 (+92/-0)
extra/man/upstart-socket-bridge.8 (+47/-0)
extra/man/upstart-udev-bridge.8 (+57/-0)
extra/upstart-socket-bridge.c (+644/-0)
extra/upstart-udev-bridge.c (+310/-0)
init/Makefile.am (+25/-0)
init/conf.c (+510/-53)
init/conf.h (+45/-2)
init/control.c (+111/-19)
init/control.h (+18/-0)
init/event.c (+22/-1)
init/event.h (+6/-1)
init/event_operator.c (+59/-0)
init/event_operator.h (+8/-0)
init/job.c (+46/-2)
init/job.h (+4/-1)
init/job_class.c (+113/-23)
init/job_class.h (+5/-1)
init/job_process.c (+59/-0)
init/job_process.h (+3/-1)
init/main.c (+244/-46)
init/man/init.5 (+225/-51)
init/man/init.8 (+34/-5)
init/parse_conf.c (+6/-0)
init/parse_job.c (+20/-6)
init/parse_job.h (+4/-2)
init/paths.h (+90/-6)
init/session.c (+279/-0)
init/session.h (+87/-0)
init/tests/test_blocked.c (+4/-1)
init/tests/test_conf.c (+1310/-15)
init/tests/test_control.c (+15/-10)
init/tests/test_environ.c (+3/-0)
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/-64)
init/tests/test_job_process.c (+34/-29)
init/tests/test_parse_conf.c (+3/-0)
init/tests/test_parse_job.c (+285/-243)
init/tests/test_process.c (+3/-0)
init/tests/test_system.c (+3/-0)
po/POTFILES.in (+2/-0)
po/upstart.pot (+399/-73)
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 (+1030/-19)
util/initctl.h (+458/-0)
util/man/initctl.8 (+204/-35)
util/tests/test_initctl.c (+1184/-20)
Text conflict in ChangeLog
Text conflict in NEWS
Text conflict in configure.ac
Text conflict in init/conf.c
Text conflict in init/main.c
Text conflict in po/upstart.pot
To merge this branch: bzr merge lp:~upstart-devel/upstart/0.9
Reviewer Review Type Date Requested Status
Scott James Remnant (community) 2011-04-14 Needs Fixing on 2011-04-14
Review via email: mp+57694@code.launchpad.net

Description of the change

Hi Scott,

Now that the code is stabilising, here forthwith is the "0.9" branch containing the 4 branches we developed for natty...

1) lp:~canonical-scott/upstart/bridges
2) lp:~canonical-scott/upstart/session-support
3) lp:~jamesodhunt/upstart/override-support
4) lp:~jamesodhunt/upstart/upstart-job-visualisation

... with associated fixes to those branches.

Cheers,

James.

To post a comment you must log in.
Scott James Remnant (scott) wrote :

Please resubmit as individual merges for each change/set of changes

review: Needs Fixing
Scott James Remnant (scott) wrote :
Download full text (6.4 KiB)

Hi James, thanks for getting started on submitting this.

Unfortunately this is a massive merge with a large number of distinct
changes. These need to be submitted individually and separately. What's
more, I suspect that you don't mean to submit some of these changes as they
are Ubuntu-specific. I did a quick pass through the merge output and noted
at least:

 - changes to bash completion
 - indentation fixes (dbus/upstart.h)
 - massive manpage updates
 - supports d-bus session bus connection rather than system
 - disabling/changing of startup of event
 - alternative config dir
 - init-checkconf
 - initctl2dot

 - addition of socket bridge
 - addition of events-with-fds to upstart
 - addition of udev bridge
 - chroot session support
 - user session support
 - override file support

 - addition of "emits" tags to config files

There are also basic problems with this merge:

Text conflict in ChangeLog
Text conflict in NEWS
Text conflict in configure.ac
Text conflict in init/conf.c
Text conflict in init/main.c
Text conflict in po/upstart.pot

The individual submission branches should be cleaned up against trunk first

Scott

On Thu, Apr 14, 2011 at 7:47 AM, James Hunt <email address hidden>wrote:

> James Hunt has proposed merging lp:~upstart-devel/upstart/0.9 into
> lp:upstart.
>
> Requested reviews:
> Upstart Developers (upstart-devel)
>
> For more details, see:
> https://code.launchpad.net/~upstart-devel/upstart/0.9/+merge/57694
>
> Hi Scott,
>
> Now that the code is stabilising, here forthwith is the "0.9" branch
> containing the 4 branches we developed for natty...
>
> 1) lp:~canonical-scott/upstart/bridges
> 2) lp:~canonical-scott/upstart/session-support
> 3) lp:~jamesodhunt/upstart/override-support
> 4) lp:~jamesodhunt/upstart/upstart-job-visualisation
>
> ... with associated fixes to those branches.
>
> Cheers,
>
> James.
> --
> https://code.launchpad.net/~upstart-devel/upstart/0.9/+merge/57694
> Your team Upstart Developers is requested to review the proposed merge of
> lp:~upstart-devel/upstart/0.9 into lp:upstart.
>
> === modified file '.bzrignore'
> --- .bzrignore 2010-12-10 04:03:25 +0000
> +++ .bzrignore 2011-04-14 14:47:25 +0000
> @@ -59,3 +59,7 @@
> util/shutdown
> util/telinit
> util/test_*
> +extra/com.ubuntu.Upstart.[ch]
> +extra/com.ubuntu.Upstart.Job.[ch]
> +extra/upstart-socket-bridge
> +extra/upstart-udev-bridge
>
> === modified file 'ChangeLog'
> --- ChangeLog 2011-03-22 17:53:17 +0000
> +++ ChangeLog 2011-04-14 14:47:25 +0000
> @@ -1,3 +1,4 @@
> +<<<<<<< TREE
> 2011-03-22 Scott James Remnant <email address hidden>
>
> * configure.ac: Bump version to 1.3
> @@ -84,6 +85,414 @@
> the character before the ".conf" extension is not "/"
> * NEWS: Update.
>
> +=======
> +2011-04-06 James Hunt <email address hidden>
> +
> + * init/conf.c: conf_select_job(): Added Session parameter.
> + * init/control.c: control_get_job_by_name(): Handle multiple jobs
> with same
> + name (but different session) in job_classes hash.
> + * init/job_class.c:
> + - job_class_remove(): Added Session parameter.
> + - job_class_consider(): Handle multiple jobs with same nam...

Read more...

lp:~upstart-devel/upstart/0.9 updated on 2011-04-27
1286. By James Hunt on 2011-04-15

* init/conf.c:
  - conf_source_reload_file(): Added missing error return if override
    doesn't parse (code path currently unused).
  - Documentation updates.
* init/job.c: job_new(): Fix for nasty OOM scenario when an attempt is made
  to start a chroot job with same name as running single-instance non-chroot
  job. Previously, the path for a chrooted Job was set from the (nul) instance
  name of its parent JobClass. However, since that job instance name already
  existed outside the chroot and was already D-Bus registered,
  nih_dbus_object_new() (which allocates storage and is called by
  job_register()) returned NULL and kept doing so due to being called
  within NIH_MUST(). This resulted in OOM due to an as-yet unidentified
  D-Bus bug (possibly a leak in find_subtree_recurse()).
* init/session.h: Documentation updates.
* util/test_initctl.c: Cleaned up variable names
  in RUN_COMMAND macro.
* init/parse_job.c: Documentation updates.

1287. By James Hunt on 2011-04-15

* Bumped version to 0.9.6
* Updated Changelog and NEWS.

1288. By James Hunt on 2011-04-20

* control_get_job_by_name: Fix to relax session rigidity for user
  sessions (allow user sessions to see into the global
  namespace for backwards compatability) (LP: #767053).

1289. By James Hunt on 2011-04-20

* Bumped version to 0.9.7
* Updated Changelog and NEWS.

1290. By James Hunt on 2011-04-27

* scripts/init-checkconf.sh:
  - New function upstart_running.
  - We now check to ensure no other instance running.
  - Use list command rather than status since the latter requires an
    instance variable to be specified (LP: #770532).
  - Improve cleanup safety.
* scripts/man/init-checkconf.8: Added limitations section.

1291. By James Hunt on 2011-04-27

Updated changelog.

Unmerged revisions

1291. By James Hunt on 2011-04-27

Updated changelog.

1290. By James Hunt on 2011-04-27

* scripts/init-checkconf.sh:
  - New function upstart_running.
  - We now check to ensure no other instance running.
  - Use list command rather than status since the latter requires an
    instance variable to be specified (LP: #770532).
  - Improve cleanup safety.
* scripts/man/init-checkconf.8: Added limitations section.

1289. By James Hunt on 2011-04-20

* Bumped version to 0.9.7
* Updated Changelog and NEWS.

1288. By James Hunt on 2011-04-20

* control_get_job_by_name: Fix to relax session rigidity for user
  sessions (allow user sessions to see into the global
  namespace for backwards compatability) (LP: #767053).

1287. By James Hunt on 2011-04-15

* Bumped version to 0.9.6
* Updated Changelog and NEWS.

1286. By James Hunt on 2011-04-15

* init/conf.c:
  - conf_source_reload_file(): Added missing error return if override
    doesn't parse (code path currently unused).
  - Documentation updates.
* init/job.c: job_new(): Fix for nasty OOM scenario when an attempt is made
  to start a chroot job with same name as running single-instance non-chroot
  job. Previously, the path for a chrooted Job was set from the (nul) instance
  name of its parent JobClass. However, since that job instance name already
  existed outside the chroot and was already D-Bus registered,
  nih_dbus_object_new() (which allocates storage and is called by
  job_register()) returned NULL and kept doing so due to being called
  within NIH_MUST(). This resulted in OOM due to an as-yet unidentified
  D-Bus bug (possibly a leak in find_subtree_recurse()).
* init/session.h: Documentation updates.
* util/test_initctl.c: Cleaned up variable names
  in RUN_COMMAND macro.
* init/parse_job.c: Documentation updates.

1285. By James Hunt on 2011-04-06

* Bumped version to 0.9.5
* Updated Changelog and NEWS.

1284. By James Hunt on 2011-04-06

* init/conf.c: conf_select_job(): Added Session parameter.
* init/control.c: control_get_job_by_name(): Handle multiple jobs with same
  name (but different session) in job_classes hash.
* init/job_class.c:
  - job_class_remove(): Added Session parameter.
  - job_class_consider(): Handle multiple jobs with same name
    (but different session) in job_classes hash.
  - job_class_reconsider(): Handle multiple jobs with same name
    (but different session) in job_classes hash.
  - job_class_remove(): Handle incorrect session.
* init/job_process.c: job_process_spawn(): Updated for sessions and
  chroots.
* init/job_process.h: New enums for:
  - JOB_PROCESS_ERROR_SETUID
  - JOB_PROCESS_ERROR_SETGID
* init/session.c:
  - session_from_dbus(): Added ability to disable sessions.
  - Added disable_sessions variable, set via main().
* init/session.h: Added tabular comment summarising Session object
  contents for different environments.
* init/Makefile.am: Reverted special-casing for session.c.
* init/main.c: Addition of new command-line option "--no-sessions" to
  disable chroot+user sessions (providing a "traditional" Upstart
  environment. The primary use for this option is the test suite.
* init/man/init.8: Updates for "--no-sessions".
* init/tests/test_*.c: Replaced explicit Sessions with NULL
  session since tests are not yet session-aware (with the exception of
  test_job_process.c, all main() functions now set the
  UPSTART_NO_SESSIONS variable to disable sessions).
* util/tests/test_initctl.c:
  - START_UPSTART now specifies "--no-sessions"
  - test_check_config(): Added test for "--warn".
* scripts/init-checkconf.sh: Script now also checks any script
  sections found unless the new "--noscript" option is specified.
  Added required "--no-sessions" option to upstart_cmd to ensure Upstart
  treats clients requests in traditional manner.
* scripts/man/init-checkconf.8: Update for "--noscript".
* util/initctl.c: Added "--warn" option for check-config command to
  warn if any events or jobs are not known.

1283. By James Hunt on 2011-03-24

* init/tests/test_control.c: Added comment.
* scripts/initctl2dot.py: Fixes to handle 'emits' glob syntax:
  - header(): Change default node to be an event to simplify handling
    globs in 'emits' stanzas.
  - footer(): Updated for glob event nodes.
  - sanitize(): Protect against glob syntax.
  - show_event(): Update for glob event nodes.
  - show_job(): Explicit specification of record node.
  - show_edges(): Handle 'emits' glob syntax.

1282. By James Hunt on 2011-03-15

* po/upstart.pot: committed changes to file to resolve conflict on
  lp:ubuntu/upstart merge.

Preview Diff

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

Subscribers

People subscribed via source and target branches