Merge lp:upstart into lp:~daniel-sonck/upstart/cron-replacement

Proposed by Daniël Sonck
Status: Merged
Approved by: Daniël Sonck
Approved revision: 1329
Merged at revision: 1284
Proposed branch: lp:upstart
Merge into: lp:~daniel-sonck/upstart/cron-replacement
Diff against target: 18561 lines (+11017/-1183) (has conflicts)
73 files modified
.bzrignore (+4/-0)
ChangeLog (+365/-0)
Makefile.am (+1/-1)
NEWS (+35/-1)
TESTING.sessions (+289/-0)
conf/rc-sysinit.conf (+2/-0)
configure.ac (+7/-3)
contrib/bash_completion/upstart (+96/-36)
contrib/vim/syntax/upstart.vim (+61/-27)
dbus/Upstart.conf (+6/-36)
dbus/com.ubuntu.Upstart.xml (+7/-0)
dbus/upstart.h (+1/-1)
extra/Makefile.am (+125/-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 (+12/-0)
init/conf.c (+504/-55)
init/conf.h (+45/-2)
init/control.c (+111/-19)
init/control.h (+19/-1)
init/environ.c (+0/-1)
init/environ.h (+0/-1)
init/event.c (+22/-0)
init/event.h (+6/-1)
init/event_operator.c (+59/-0)
init/event_operator.h (+8/-0)
init/job.c (+47/-3)
init/job.h (+4/-1)
init/job_class.c (+115/-67)
init/job_class.h (+62/-2)
init/job_process.c (+122/-14)
init/job_process.h (+5/-3)
init/main.c (+297/-134)
init/man/init.5 (+236/-48)
init/man/init.8 (+32/-4)
init/parse_conf.c (+6/-0)
init/parse_job.c (+21/-7)
init/parse_job.h (+4/-2)
init/paths.h (+75/-2)
init/session.c (+320/-0)
init/session.h (+89/-0)
init/tests/test_blocked.c (+4/-1)
init/tests/test_conf.c (+1310/-15)
init/tests/test_control.c (+15/-11)
init/tests/test_environ.c (+3/-1)
init/tests/test_event.c (+28/-25)
init/tests/test_event_operator.c (+3/-0)
init/tests/test_job.c (+71/-76)
init/tests/test_job_class.c (+56/-65)
init/tests/test_job_process.c (+34/-30)
init/tests/test_parse_conf.c (+3/-0)
init/tests/test_parse_job.c (+302/-260)
init/tests/test_process.c (+3/-0)
init/tests/test_system.c (+3/-0)
po/POTFILES.in (+2/-0)
po/upstart.pot (+352/-155)
scripts/Makefile.am (+25/-0)
scripts/init-checkconf.sh (+248/-0)
scripts/initctl2dot.py (+571/-0)
scripts/man/init-checkconf.8 (+73/-0)
scripts/man/initctl2dot.8 (+87/-0)
util/Makefile.am (+1/-1)
util/initctl.c (+1014/-17)
util/initctl.h (+458/-0)
util/man/initctl.8 (+207/-34)
util/reboot.c (+0/-1)
util/tests/test_initctl.c (+1189/-19)
util/tests/test_user_sessions.sh (+553/-0)
Text conflict in init/main.c
To merge this branch: bzr merge lp:upstart
Reviewer Review Type Date Requested Status
Daniël Sonck Approve
Review via email: mp+79391@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Daniël Sonck (daniel-sonck) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file '.bzrignore'
--- .bzrignore 2010-12-10 04:03:25 +0000
+++ .bzrignore 2011-10-14 11:09:18 +0000
@@ -59,3 +59,7 @@
59util/shutdown59util/shutdown
60util/telinit60util/telinit
61util/test_*61util/test_*
62extra/com.ubuntu.Upstart.[ch]
63extra/com.ubuntu.Upstart.Job.[ch]
64extra/upstart-socket-bridge
65extra/upstart-udev-bridge
6266
=== modified file 'ChangeLog'
--- ChangeLog 2011-05-12 20:42:28 +0000
+++ ChangeLog 2011-10-14 11:09:18 +0000
@@ -1,3 +1,368 @@
12011-08-11 Scott James Remnant <keybuk@google.com>
2
3 * init/job_process.c (job_process_spawn): Can't return on
4 dup2() error, we're in the child. Return an error back to
5 the child properly.
6
7 * init/job_process.c (job_process_spawn), init/main.c: error
8 should be ENOENT
9
10 * init/job_class.c, init/job_class.h: Move constants into the
11 header file so they can be found from other source files.
12 * init/job_process.c (job_process_spawn): Only adjust the OOM
13 score if it isn't the default
14 * init/main.c: Apply the default OOM score to the init process
15 itself.
16
17 * init/main.c: Deal with failure to setup the system console by
18 falling back to /dev/null, so we don't end up without default fds
19 and castrate the process.
20
212011-08-10 Scott James Remnant <keybuk@google.com>
22
23 * init/job_class.c (job_class_new): nit, use #defines for the default
24 nice level and oom score adjustment.
25
262011-07-25 James Hunt <james.hunt@ubuntu.com>
27
28 * init/job_process.c: job_process_spawn():
29 - Added dup2() return check.
30 * TESTING.sessions: Updated with information on user sessions.
31 * init/job_process.c:
32 - job_process_spawn():
33 - Change group before user and do it as early as possible.
34 - Ensure non-priv user is able to read script fd. Default system
35 behaviour is seemingly not consistent/defined, so force it
36 to be (LP: #813052)
37 - Ensure cwd for user job is home directory by default.
38 - job_process_error_read():
39 - Added handling for JOB_PROCESS_ERROR_SETUID and
40 JOB_PROCESS_ERROR_SETGID (LP: #807293).
41 - Added new entry for JOB_PROCESS_ERROR_CHOWN.
42 * init/job_process.h:
43 - Added entry for JOB_PROCESS_ERROR_CHOWN in JobProcessErrorType.
44 * init/man/init.5: Update for user jobs explaining behaviour of stanzas
45 which manipulate system resource limits and when the init
46 daemon reads the users job directory.
47 * util/tests/test_user_sessions.sh: New script for testing user sessions
48 (NOTE: this is *NOT* run automatically).
49 * init/session.c: session_from_dbus(): Handle case where a users
50 home directory is changed or where a uid is re-used for a
51 different username.
52 * init/session.h: Updated comments for Session object.
53 * init/man/init.5: Explain that symbolic links are not supported.
54
552011-07-22 James Hunt <james.hunt@ubuntu.com>
56
57 * util/man/initctl.8: Clarify semantics of restart(8)
58 command (LP: #731225).
59
602011-07-20 James Hunt <james.hunt@ubuntu.com>
61
62 * util/tests/test_initctl.c:
63 - test_show_config(): /* fall through :) */
64 - test_check_config(): Manually start and stop dbus-daemon to work
65 around change in dbus autostart behaviour which causes issues when
66 running the tests in a chroot and non-X11 environment (see dbus commit
67 cea055514a9dfc74e7f0515cf4a256da10a891bc).
68
692011-06-14 James Hunt <james.hunt@ubuntu.com>
70
71 * NEWS: Release 1.3
72
732011-06-14 James Hunt <james.hunt@ubuntu.com>
74
75 * contrib/vim/syntax/upstart.vim: Updates for kill, oom, expect
76 and limit.
77
782011-06-07 Scott James Remnant <scott@netsplit.com>
79
80 * init/job_process.c (job_process_spawn): Make sure we don't close
81 our own file descriptor if it already has the right value.
82
832011-06-06 James Hunt <james.hunt@ubuntu.com>
84
85 Add override file support.
86
87 * init/conf.c:
88 - conf_reload_path(): Now takes an extra override_path parameter.
89 - is_conf_file() / is_conf_file_std() / is_conf_file_override(): New
90 functions to determine type of given file path.
91 - toggle_conf_name(): New function which convert a conf file
92 name to an override name and vice versa.
93 - majority of remaining functions updated to handle override
94 files.
95 * init/conf.h: Prototypes.
96 * init/job_class.c: Whitespace.
97 * init/man/init.5: Updated to document override file support.
98 * init/man/init.8: Added reference to control-alt-delete(7) man page.
99 * init/paths.h: New macros CONF_EXT_OVERRIDE, CONF_EXT_STD,
100 IS_CONF_FILE_OVERRIDE and IS_CONF_FILE_STD.
101 * init/parse_conf.c: Added assertion to remind us forcibly to add
102 override-handling code for directories if we ever allow content in
103 'init.conf'.
104 * init/parse_job.c (parse_job): Additional parameter 'update' to
105 allow override files to replace existing Job details.
106 * init/parse_job.h: Updated parse_job() prototype.
107 * init/test_conf.c
108 - New macros TEST_ENSURE_CLEAN_ENV() and
109 TEST_FORCE_WATCH_UPDATE().
110 - test_override(): New function.
111 - test_toggle_conf_name(): New function.
112 * init/test_parse_job.c:
113 - Updated for extra parse_job() parameter.
114 - added a test feature to test_parse_job() to exercise new
115 parameter to parse_job().
116 * util/man/initctl.8: Clarified what it means to restart a job.
117
118 Add udev and socket bridges.
119
120 * Makefile.am: Added extra directory.
121 * New files:
122 - extra/Makefile.am
123 - extra/conf/upstart-socket-bridge.conf
124 - extra/conf/upstart-udev-bridge.conf
125 - extra/man/socket-event.7
126 - extra/man/upstart-socket-bridge.8
127 - extra/man/upstart-udev-bridge.8
128 - extra/upstart-socket-bridge.c
129 - extra/upstart-udev-bridge.c
130 * configure.ac:
131 - Check for udev (for upstart-udev-bridge).
132 - Add extra/Makefile to AC_CONFIG_FILES.
133 * dbus/com.ubuntu.Upstart.xml: Add EmitEventWithFile method.
134 * init/control.c:
135 - control_emit_event(): Now a wrapper for control_emit_event_with_file.
136 - control_emit_event_with_file(): New function that operates on an fd.
137 * init/control.h: Prototype for control_emit_event_with_file().
138 * init/event.c:
139 - event_new(): Initialize event fd.
140 - event_pending_handle_jobs(): Now calls event_operator_fds().
141 * init/event.c: Add fd to Event struct.
142 * init/event_operator.c: event_operator_fds(): New function.
143 * init/event_operator.h: Prototype for event_operator_fds().
144 * init/job.c: job_new(): Initialize fd members.
145 * init/job.h: Add fds and num_fds to Job struct.
146
1472011-06-03 James Hunt <james.hunt@ubuntu.com>
148
149 Add session support. Note that there are no automatically runnable and
150 explicit tests yet. However, see TESTING.sessions.
151
152 * TESTING.sessions: ASCII (reStructuredText) document explaining
153 how to run manual tests for session support (for chroots).
154 * dbus/Upstart.conf: Simplified to support allowing users to invoke
155 all methods (since Upstart now isolates commands by user).
156 * init/Makefile.am: Added session.[ch] files.
157 * init/session.c: New file. Note that session_from_dbus() will disable sessions
158 (by returning the NULL session) if environment variable "UPSTART_NO_SESSIONS"
159 is set to any value (used by tests).
160 * init/session.h: New file.
161 * init/parse_job.h: parse_job(): Add session pointer to prototype.
162 * init/parse_job.c:
163 - parse_job(): Add session parameter.
164 - Update calls to job_class_new() to pass session pointer.
165 * init/job.c: job_new(): Crucial change to ensure chroot sessions have
166 a unique D-Bus name (LP:#728531).
167 * init/job_class.c:
168 - job_class_new(): Add session parameter and session support.
169 - job_class_remove(): Add session parameter to prototype.
170 - job_class_consider(): Only consider jobs from the appropriate session.
171 - job_class_reconsider(): Only consider jobs from the appropriate session.
172 - job_class_start(): Disallow out-of-session modification.
173 - job_class_stop(): Disallow out-of-session modification.
174 - job_class_restart(): Disallow out-of-session modification.
175 * init/main.c: Add "--no-sessions" command-line option to disable
176 sessions and revert to traditional behaviour.
177 * init/job_class.h:
178 - job_class_new(): Add session pointer to prototype.
179 - JobClass: Add session member.
180 * init/job_process.c: job_process_spawn():
181 - Call chroot(2) for chroot sessions.
182 - Call setuid(2) for user session jobs.
183 * init/job.c:
184 - job_emit_event(): Set session for event.
185 - job_start(): Disallow out-of-session modification.
186 - job_stop(): Disallow out-of-session modification.
187 - job_restart(): Disallow out-of-session modification.
188 * init/event.h: Event: Add session member.
189 * init/event.c:
190 - event_new(): initialize session to NULL.
191 - event_pending_handle_jobs(): Add session handling.
192 - event_finished(): Set session for failure event.
193 * init/control.c:
194 - control_get_job_by_name(): Add session handling.
195 - control_get_all_jobs(): Add session handling.
196 - control_emit_event(): Add session handling.
197 * init/conf.c:
198 - conf_source_new(): Initialise session to NULL.
199 - conf_reload_path(): Pass session to parse_job().
200 - conf_select_job(): Add session parameter.
201 * init/conf.h:
202 - ConfSource: Add session member.
203 - conf_select_job(): Add session parameter to prototype.
204 * All tests updated to set "UPSTART_NO_SESSIONS" (to disable
205 sessions).
206
2072011-06-02 James Hunt <james.hunt@ubuntu.com>
208
209 * contrib/bash_completion/upstart:
210 - Made function names more meaningful:
211 - _upstart_jobs: Now returns a unique list
212 - _upstart_events (nee _upstart_named_events ) now considers all
213 "emits" tokens.
214 - Updates for "check-config" and "show-config".
215 - Added "--session" option.
216 - Added "--no-wait" for emit, reload and restart.
217
218 Man page updates.
219
220 * init/man/init.5:
221 - Quoted dashes.
222 - Explain handling of duplicated stanzas.
223 - "respawn": Document default count and interval.
224 - "emits": Reference "initctl check-config".
225 - Added BUGS section.
226 - Added copyright.
227 * init/man/init.8:
228 - Quoted dashes.
229 - See Also: Added control-alt-delete(7).
230 * util/man/initctl.8:
231 - Quoted dashes.
232 - "restart": Clarified meaning.
233 - "list": Explained "stop/waiting" jobs.
234
2352011-06-01 James Hunt <james.hunt@ubuntu.com>
236
237 Add D-Bus session support to initctl.
238
239 * util/initctl.c:
240 - Added "--session" command-line option.
241 - dbus_bus_type_setter(): New function used by option parser to
242 distinguish system/session D-Bus bus type.
243 - system_bus variable now replaced by two others: use_dbus (boolean)
244 and dbus_bus_type.
245 - upstart_open(): Updated to handle multiple D-Bus bus types.
246 * util/man/initctl.8: Update for "--session" option.
247 * util/tests/test_initctl.c: Updated to make use of use_dbus and
248 dbus_bus_type rather than system_bus.
249
250 Add "show-config" command to initctl.
251
252 * util/initctl.c:
253 - New functions:
254 - job_class_condition_handler(): Handler function to retrieve job conditions.
255 - job_class_condition_err_handler(): Handler error function for
256 job_class_condition_handler().
257 - job_class_parse_events(): Convert RPN "start on" and "stop on" conditions to
258 human-readable format.
259 - job_class_show_emits(): Display events which job emits.
260 - job_class_show_conditions(): Make D-Bus calls to retrieve "start on" and
261 "stop on" conditions.
262 - show_config_action: Handle "show-config" command..
263 * util/initctl.h: New file providing stack-handling functionality for
264 RPN parsing for "show-config" command.
265 * util/Makefile.am: Added initctl.h to initctl_SOURCES.
266 * util/man/initctl.8: Updated for "show-config" command and associated
267 options.
268 * util/tests/test_initctl.c:
269 - New macros START_UPSTART, STOP_UPSTART, RUN_COMMAND, CREATE_FILE and DELETE_FILE.
270 These are required since due to the introduction of the
271 "show-config" initctl command, initctl is no longer solely a proxy
272 to Upstart: it now has some intelligence (it parses the
273 "emits", "start on" and "stop on" conditions) and thus must be
274 tested directly.
275 - test_show_config(): New function to test "initctl show-config".
276 - in_chroot(): New function to detect if tests are being run from
277 within a chroot environment.
278 - dbus_configured(): New function which performs a basic check to
279 establish if D-Bus is configured correctly.
280 - main(): Added call to test_show_config(), conditional on
281 a non-chroot environment and a working D-Bus system.
282
283 Add "check-config" command to initctl.
284
285 * util/initctl.c:
286 - New functions:
287 - allow_event(): Determine if specified event is erroneous or not.
288 Handles globbing.
289 - allow_job(): Determine if specified job is erroneous or not.
290 Handles variables (such as instance variables).
291 - check_condition(): High-level function to handle checking start
292 on/stop on conditions.
293 - check_config_action: Handler for "check-config" command.
294 - display_check_errors(): Display errors from expression tree nodes
295 that are in error.
296 - eval_expr_tree(): Evaluate expression tree.
297 - ignored_events_setter(): handler for '--ignore-events' command-line
298 option for "check-config" command.
299 - tree_filter(): Used for filtering expression tree nodes.
300 - show_config_action(): Update for check-config mode.
301 - job_class_parse_events(): Update for check-config mode.
302 - job_class_show_emits(): Update for check-config mode.
303 * util/initctl.h:
304 - Added structs for JobCondition, CheckConfigData and ExprNode.
305 - New macros: MAKE_EXPR_NODE() and MAKE_JOB_CONDITION().
306 * util/tests/test_initctl.c:
307 - test_check_config(): New function to test "initctl check-config".
308 - main(): Added call to test_check_config(), conditional on
309 a non-chroot environment and a working D-Bus system.
310 * util/man/initctl.8: Updated for "check-config" command and associated
311 options.
312 * conf/rc-sysinit.conf: Added "emits" stanza, required by
313 "check-config".
314
315 Addition of initctl2dot script for visualisation.
316
317 * Makefile.am: Added scripts directory.
318 * configure.ac: Updated AC_CONFIG_FILES for scripts/Makefile.
319 * scripts/Makefile.am: Makefile for scripts.
320 * scripts/initctl2dot.py: Python script to produce dot(1) graphs of
321 "initctl show-config" output.
322 * scripts/man/initctl2dot.8: Man page for initctl2dot.py script.
323
324 Addition of init-checkconf script.
325
326 * scripts/init-checkconf.sh: Script to determine if specified job
327 config file is valid or not.
328 * scripts/man/init-checkconf.8: Man page for init-checkconf.sh.
329 * scripts/Makefile.am: Added init-checkconf script and man
330 page.
331
3322011-05-31 James Hunt <james.hunt@ubuntu.com>
333
334 Add command-line option to use D-Bus session bus (for testing).
335
336 * init/control.c:
337 - Added new boolean use_session_bus.
338 - Updated comments.
339 - control_handle_bus_type(): New function to allow selection of
340 session bus via env var "UPSTART_USE_SESSION_BUS".
341 Also logs use of session bus if use_session_bus set.
342 - control_bus_open(): Now connects to either D-Bus system bus or session bus.
343 * init/control.h: New define for USE_SESSION_BUS_ENV.
344 * init/main.c: Addition of "--session" command-line option.
345 * init/man/init.8: Update for new "--session" command-line option.
346
347 * Corrected copyright notices.
348
349 Add option to allow alternate location for job config files.
350
351 * init/main.c:
352 - Added "--confdir <dir>" command-line option.
353 - handle_confdir(): New function to select alternate confdir using env
354 var "UPSTART_CONFDIR" or command-line option (for testing).
355 * init/paths.h: Added define for CONFDIR_ENV.
356 * init/man/init.8: Update for new "--confdir" command-line option.
357
358 Add ability to suppress initial event and/or change its name.
359
360 * init/main.c: New command-line options: "--no-startup-event" and
361 "--startup-event". If "--no-startup-event" specified, log message as a
362 debug aid.
363 * init/man/init.8: Documentation for new command-line options:
364 "--no-startup-event" and "--startup-event".
365
12011-05-12 Marc - A. Dahlhaus <mad@wol.de>3662011-05-12 Marc - A. Dahlhaus <mad@wol.de>
2367
3 * init/job_class.h (JobClass): Add kill signal member368 * init/job_class.h (JobClass): Add kill signal member
4369
=== modified file 'Makefile.am'
--- Makefile.am 2010-02-04 03:42:29 +0000
+++ Makefile.am 2011-10-14 11:09:18 +0000
@@ -1,6 +1,6 @@
1## Process this file with automake to produce Makefile.in1## Process this file with automake to produce Makefile.in
22
3SUBDIRS = intl dbus init util conf doc contrib po3SUBDIRS = intl dbus init util extra conf doc contrib po scripts
44
5EXTRA_DIST = HACKING5EXTRA_DIST = HACKING
66
77
=== modified file 'NEWS'
--- NEWS 2011-03-22 17:53:17 +0000
+++ NEWS 2011-10-14 11:09:18 +0000
@@ -1,4 +1,38 @@
11.3 xxxx-xx-xx11.4 xxxx-xx-xx
2
31.3 2011-06-14 "Concordia"
4
5 * New upstart-socket-bridge application which allows jobs to be
6 started when an incoming client socket connection is initiated
7 (requires a suitably modified server daemon since jobs only
8 need call accept(2) before reading from the socket).
9 * User session support allowing non-privileged users to
10 manipulate their own jobs (not available within a chroot
11 environment).
12 * Chroot support allowing jobs to be controlled within chroot
13 environments.
14 * Updated bash completion script.
15 * Updated vim syntax script.
16 * init-checkconf script used to check syntax of Job
17 Configuration Files (including script sections).
18 * initctl2dot script to convert initctl(8) output to GraphViz
19 dot(1) format for analysing relationships between jobs and
20 events.
21 * New "check-config" initctl command to check for jobs whose
22 * "start on" and "stop on" events cannot be satisfied.
23 * New "show-config" initctl command to display "start on", "stop
24 on" and emits" information in parseable format.
25 * New initctl command-line option: "--session" for D-Bus
26 session connection.
27 * New init command line options (mostly for testing):
28 - "--session" for D-Bus session bus.
29 - "--confdir <dir>".
30 - "--startup-event <event>".
31 - "--no-startup-event".
32 * New "kill signal" stanza to allow override of SIGTERM when
33 stopping jobs.
34 * Add support for the oom_score_adj procfs API.
35 * Improved POSIX compliance when running shell scripts.
236
31.2 2011-03-22 "This sort of thing is my bag, baby"371.2 2011-03-22 "This sort of thing is my bag, baby"
438
539
=== added file 'TESTING.sessions'
--- TESTING.sessions 1970-01-01 00:00:00 +0000
+++ TESTING.sessions 2011-10-14 11:09:18 +0000
@@ -0,0 +1,289 @@
1.. contents::
2
3=============================
4Testing Sessions with Upstart
5=============================
6
7Upstart now has support for two types of "sessions":
8
9* user sessions
10
11* chroots sessions
12
13Such sessions are implemented by asociating a separate Upstart session
14with every chroot environment and every non-privileged user.
15
16The session support does not yet provide full tests (as would be run by
17"``make check``"). This is mostly due to the complexity of automatically
18testing some of the scenarios below.
19
20This document attempts to outline the minimum set of tests that should
21be performed to ensure that session support works as expected.
22
23Assumptions
24===========
25
26You are running an Ubuntu or Debian system.
27
28User Sessions
29=============
30
31User sessions can be minimally tested using the script provided::
32
33 util/tests/test_user_sessions.sh
34
35Notes:
36
37- Run "``test_user_sessions.sh -h``" to understand what this script does.
38
39- that this script needs to be run on a system where the version of
40 ``/sbin/init`` has session support since the ``/sbin/init`` binary
41 itself will be tested. For this reason, the script cannot be run as part
42 of the "``make check``" run.
43
44- The script will complain loudly if any of the tests fail and tell you
45 how to raise a bug.
46
47Chroot Sessions
48===============
49
50Setup
51-----
52
53#. Install a chroot environement (such as ``schroot(1)``) and configure it.
54#. run, "``debootstrap(8)``" to install the same release as you are running into your chroot.
55#. Create the following files *outside* your chroot.
56
57 - ``/etc/init/foo.conf``::
58
59 start on wibble
60
61 script
62 exec 2>>/tmp/foo.$$.log
63 set -x
64 echo "foo: stat=`stat /`"
65 echo "foo: env=`env`"
66 sleep 999
67 end script
68
69 - ``/etc/init/outside_chroot.conf``::
70
71 start on A
72
73 script
74 exec 2>>/tmp/outside_chroot.$$.log
75 set -x
76 echo "in_chroot: stat=`stat /`"
77 echo "in_chroot: env=`env`"
78 sleep 999
79 end script
80
81#. Create following files inside chroot environment.
82
83 - ``/path/to/chroot/etc/init/foo.conf``::
84
85 start on wibble
86
87 script
88 exec 2>>/tmp/foo.$$.log
89 set -x
90 echo "foo: stat=`stat /`"
91 echo "foo: env=`env`"
92 sleep 999
93 end script
94
95 - ``/path/to/chroot/etc/init/in_chroot.conf``::
96
97 start on A
98
99 script
100 exec 2>>/tmp/in_chroot.$$.log
101 set -x
102 echo "in_chroot: stat=`stat /`"
103 echo "in_chroot: env=`env`"
104 sleep 999
105 end script
106
107
108Run as non-``root`` with no chroot
109----------------------------------
110
111- ``initctl list``
112
113 Ensure list is contents of ``/etc/init/``: the command below should
114 return no output::
115
116 cmp <(initctl list|awk '{print $1}'|sort -u) <(cd /etc/init && ls *.conf|cut -d: -f2-|sed 's/\.conf//g'|sort -u)
117
118- ``initctl status cron``
119
120 Should work.
121
122- ``initctl show-config``
123
124 Should work.
125
126- ``initctl check-config``
127
128 Should work.
129
130- ``start foo``
131
132 Should fail ("``initctl: Rejected send message``").
133
134- ``stop cron``
135
136 Should fail ("``initctl: Rejected send message``").
137
138- ``restart cron``
139
140 Should fail ("``initctl: Rejected send message``").
141
142- ``initctl emit bar``
143
144 Should fail ("``initctl: Rejected send message``").
145
146Run as ``root`` with no chroot
147------------------------------
148
149- ``initctl list``
150
151 Ensure list is contents of ``/etc/init/``: command below should return no output::
152
153 cmp <(initctl list|awk '{print $1}'|sort -u) <(cd /etc/init && ls *.conf|cut -d: -f2-|sed 's/\.conf//g'|sort -u)
154
155- ``initctl status outside_chroot``
156
157 Should work.
158
159- ``initctl status in_chroot``
160
161 Should fail with message::
162
163 initct: Unknown job: in_chroot
164
165- ``initctl show-config``
166
167 Should work.
168
169- ``initctl check-config``
170
171 Should work.
172
173- ``start in_chroot``
174
175 Should fail with message::
176
177 initct: Unknown job: in_chroot
178
179- ``start outside_chroot``
180
181 Should work.
182
183- ``stop in_chroot``
184
185 Should fail with message::
186
187 initct: Unknown job: in_chroot
188
189- ``restart outside_chroot``
190
191 Should work.
192
193- ``stop outside_chroot``
194
195 Should work.
196
197- ``initctl emit wibble``
198
199 - Ensure ``/etc/init/foo.conf`` runs by looking at the log and ensuring
200 the inode for the stat of '``/``' is the same as running "``stat /``" on
201 the command-line.
202
203 * Ensure ``/path/to/chroot/etc/init/foo.conf`` does *NOT* run.
204
205- ``initctl emit A``
206
207 - Ensure ``/etc/init/outside_chroot.conf`` runs.
208
209 - Ensure ``/path/to/chroot/etc/init/in_chroot.conf`` does *NOT* run.
210
211Run as ``root`` inside a chroot
212-------------------------------
213
214- ``initctl list``
215
216 Ensure list is contents of ``/path/to/chroot/etc/init/``: command below should return no output::
217
218 cmp <(initctl list|awk '{print $1}'|sort -u) <(cd /etc/init && ls *.conf|cut -d: -f2-|sed 's/\.conf//g'|sort -u)
219
220- ``initctl status in_chroot``
221
222 Should work.
223
224- ``initctl status outside_chroot``
225
226 Should fail with message::
227
228 initct: Unknown job: outside_chroot
229
230- ``initctl show-config``
231
232 Should work.
233
234- ``initctl check-config``
235
236 Should work.
237
238- ``start outside_chroot``
239
240 Should fail with message::
241
242 initct: Unknown job: outside_chroot
243
244- ``stop outside_chroot``
245
246 Should fail with message::
247
248 initct: Unknown job: outside_chroot
249
250- ``start in_chroot``
251
252 Should work.
253
254- ``restart in_chroot``
255
256 Should work.
257
258- ``stop in_chroot``
259
260 Should work.
261
262- ``initctl emit wibble``
263
264 - Ensure ``/path/to/chroot/etc/init/foo.conf`` runs by looking at the log and ensuring
265 the inode for the stat of '``/``' is the same as running "``stat /``" on the command-line.
266
267 - Ensure ``/etc/init/foo.conf`` does *NOT* run.
268
269- ``initctl emit A``
270
271 - Ensure ``/path/to/chroot/etc/init/in_chroot.conf`` runs.
272
273 - Ensure ``/etc/init/outside_chroot.conf`` does *NOT* run.
274
275Run as non-root inside a chroot
276-------------------------------
277
278Not supported.
279
280Run with ``--no-sessions``
281--------------------------
282
283The "``--no-sessions``" option makes Upstart behave as it used to prior to
284the introduction of session support.
285
286#. Reboot system and specify "``--no-sessions``" on kernel command-line.
287
288#. Ensure "``initctl list``" within a chroot displays the same list as
289 "``initctl list``" run outside of any chroot environment.
0290
=== modified file 'conf/rc-sysinit.conf'
--- conf/rc-sysinit.conf 2010-02-04 03:59:06 +0000
+++ conf/rc-sysinit.conf 2011-10-14 11:09:18 +0000
@@ -13,6 +13,8 @@
13# or by faking an old /etc/inittab entry13# or by faking an old /etc/inittab entry
14env DEFAULT_RUNLEVEL=214env DEFAULT_RUNLEVEL=2
1515
16emits runlevel
17
16# There can be no previous runlevel here, but there might be old18# There can be no previous runlevel here, but there might be old
17# information in /var/run/utmp that we pick up, and we don't want19# information in /var/run/utmp that we pick up, and we don't want
18# that.20# that.
1921
=== modified file 'configure.ac'
--- configure.ac 2011-03-22 17:53:17 +0000
+++ configure.ac 2011-10-14 11:09:18 +0000
@@ -1,8 +1,8 @@
1# Process this file with autoconf to produce a configure script.1# Process this file with autoconf to produce a configure script.
22
3AC_PREREQ(2.61)3AC_PREREQ(2.61)
4AC_INIT([upstart], [1.3], [upstart-devel@lists.ubuntu.com])4AC_INIT([upstart], [1.4], [upstart-devel@lists.ubuntu.com])
5NIH_COPYRIGHT([[Copyright © 2011 Scott James Remnant, Google Inc., Canonical Ltd.]])5NIH_COPYRIGHT([[Copyright © 2011 Scott James Remnant, Canonical Ltd.]])
6AC_CONFIG_SRCDIR([init/main.c])6AC_CONFIG_SRCDIR([init/main.c])
7AC_CONFIG_MACRO_DIR([m4])7AC_CONFIG_MACRO_DIR([m4])
88
@@ -30,6 +30,9 @@
30PKG_CHECK_MODULES([NIH], [libnih >= 1.0.2])30PKG_CHECK_MODULES([NIH], [libnih >= 1.0.2])
31PKG_CHECK_MODULES([NIH_DBUS], [libnih-dbus >= 1.0.0])31PKG_CHECK_MODULES([NIH_DBUS], [libnih-dbus >= 1.0.0])
32PKG_CHECK_MODULES([DBUS], [dbus-1 >= 1.2.16])32PKG_CHECK_MODULES([DBUS], [dbus-1 >= 1.2.16])
33PKG_CHECK_MODULES([UDEV], [libudev >= 146], [have_udev=yes], [have_udev=no])
34
35AM_CONDITIONAL([HAVE_UDEV], [test "$have_udev" = yes])
3336
34# Checks for header files.37# Checks for header files.
35AC_CHECK_HEADERS([valgrind/valgrind.h])38AC_CHECK_HEADERS([valgrind/valgrind.h])
@@ -64,6 +67,7 @@
6467
65AC_CONFIG_FILES([ Makefile intl/Makefile68AC_CONFIG_FILES([ Makefile intl/Makefile
66 dbus/Makefile init/Makefile util/Makefile conf/Makefile69 dbus/Makefile init/Makefile util/Makefile conf/Makefile
67 doc/Makefile contrib/Makefile po/Makefile.in ])70 extra/Makefile doc/Makefile contrib/Makefile po/Makefile.in
71 scripts/Makefile ])
68AC_CONFIG_HEADERS([config.h])72AC_CONFIG_HEADERS([config.h])
69AC_OUTPUT73AC_OUTPUT
7074
=== modified file 'contrib/bash_completion/upstart'
--- contrib/bash_completion/upstart 2010-12-21 13:54:49 +0000
+++ contrib/bash_completion/upstart 2011-10-14 11:09:18 +0000
@@ -3,26 +3,28 @@
3#3#
4# We don't provide completion for 'init' itself for obvious reasons.4# We don't provide completion for 'init' itself for obvious reasons.
5have initctl &&5have initctl &&
6_upstart_conf_events()6_upstart_jobs()
7{7{
8 initctl list|awk '{print $1}'8 initctl list|awk '{print $1}'|sort -u
9} &&9} &&
10_upstart_named_events()10_upstart_startable_jobs()
11{
12 (cd /etc/init && grep '^emits ' *.conf|sed 's/^emits //g')
13} &&
14_upstart_events()
15{
16 (_upstart_conf_events;_upstart_named_events)|tr ' ' '\n'|sort -u
17} &&
18_upstart_startable_events()
19{11{
20 initctl list|cut -d\, -f1|awk '$2 == "stop/waiting" {print $1}'12 initctl list|cut -d\, -f1|awk '$2 == "stop/waiting" {print $1}'
21} &&13} &&
22_upstart_stoppable_events()14_upstart_stoppable_jobs()
23{15{
24 initctl list|cut -d\, -f1|awk '$2 == "start/running" {print $1}'16 initctl list|cut -d\, -f1|awk '$2 == "start/running" {print $1}'
25} &&17} &&
18_upstart_events()
19{
20 # note that we don't provide the internal events such as "starting"
21 # (and those from mountall) since the user should be using the
22 # associated command to emit such events.
23 (cd /etc/init && \
24 egrep '^[[:space:]]*emits ' *.conf |\
25 cut -d: -f2- | sed 's/^[[:space:]]*emits //g' |\
26 tr ' ' '\n' | awk '{print $NF}' | grep -v ^$|sort -u)
27} &&
26_upstart_initctl()28_upstart_initctl()
27{29{
28 _get_comp_words_by_ref cur prev30 _get_comp_words_by_ref cur prev
@@ -32,34 +34,92 @@
32 case "$prev" in34 case "$prev" in
3335
34 start)36 start)
35 COMPREPLY=( $(compgen -W "-n --no-wait $(_upstart_startable_events)" -- ${cur}) )37 COMPREPLY=( $(compgen -W "-n --no-wait $(_upstart_startable_jobs)" -- ${cur}) )
36 return 038 return 0
37 ;;39 ;;
3840
39 stop)41 stop)
40 COMPREPLY=( $(compgen -W "-n --no-wait $(_upstart_stoppable_events)" -- ${cur}) )42 COMPREPLY=( $(compgen -W "-n --no-wait $(_upstart_stoppable_jobs)" -- ${cur}) )
41 return 043 return 0
42 ;;44 ;;
4345
44 emit)46 emit)
45 COMPREPLY=( $(compgen -W "$(_upstart_events)" -- ${cur}) )47 COMPREPLY=( $(compgen -W "-n --no-wait $(_upstart_events)" -- ${cur}) )
46 return 048 return 0
47 ;;49 ;;
4850
49 reload|restart|status)51 -i|--ignore-events)
50 COMPREPLY=( $(compgen -W "$(_upstart_conf_events)" -- ${cur}) )52 # handle visualisation options after check-config command
53 for cmd in check-config
54 do
55 cwords=${COMP_WORDS[@]##}
56 filtered_cwords=${COMP_WORDS[@]##${cmd}}
57 if [ "$filtered_cwords" != "$cwords" ]
58 then
59 COMPREPLY=( $(compgen -W "$(_upstart_jobs)" -- ${cur}) )
60 return 0
61 fi
62 done
63 ;;
64
65 -e|--enumerate)
66 # handle visualisation options after show-config command
67 for cmd in show-config
68 do
69 cwords=${COMP_WORDS[@]##}
70 filtered_cwords=${COMP_WORDS[@]##${cmd}}
71 if [ "$filtered_cwords" != "$cwords" ]
72 then
73 COMPREPLY=( $(compgen -W "$(_upstart_jobs)" -- ${cur}) )
74 return 0
75 fi
76 done
77 ;;
78
79 reload|restart)
80 COMPREPLY=( $(compgen -W "-n --no-wait $(_upstart_stoppable_jobs)" -- ${cur}) )
81 return 0
82 ;;
83
84 status)
85 COMPREPLY=( $(compgen -W "$(_upstart_jobs)" -- ${cur}) )
86 return 0
87 ;;
88
89 check-config)
90 COMPREPLY=( $(compgen -W "-w --warn -i --ignore-events= $(_upstart_jobs)" -- ${cur}) )
91 return 0
92 ;;
93 show-config)
94 COMPREPLY=( $(compgen -W "-e --enumerate $(_upstart_jobs)" -- ${cur}) )
51 return 095 return 0
52 ;;96 ;;
5397
54 -n|--no-wait)98 -n|--no-wait)
55 # allow no wait after start/stop commands99 # allow 'no wait' for certain commands
56 for cmd in start stop100 for cmd in start stop restart emit
57 do101 do
58 cwords=${COMP_WORDS[@]##}102 cwords=${COMP_WORDS[@]##}
59 filtered_cwords=${COMP_WORDS[@]##${cmd}}103 filtered_cwords=${COMP_WORDS[@]##${cmd}}
60 if [ "$filtered_cwords" != "$cwords" ]104 if [ "$filtered_cwords" != "$cwords" ]
61 then105 then
62 COMPREPLY=( $(compgen -W "$(_upstart_${cmd}able_events)" -- ${cur}) )106 case "$cmd" in
107 start)
108 COMPREPLY=( $(compgen -W "$(_upstart_startable_jobs)" -- ${cur}) )
109 ;;
110
111 stop)
112 COMPREPLY=( $(compgen -W "$(_upstart_stoppable_jobs)" -- ${cur}) )
113 ;;
114
115 restart)
116 COMPREPLY=( $(compgen -W "$(_upstart_stoppable_jobs)" -- ${cur}) )
117 ;;
118
119 emit)
120 COMPREPLY=( $(compgen -W "$(_upstart_events)" -- ${cur}) )
121 ;;
122 esac
63 return 0123 return 0
64 fi124 fi
65 done125 done
@@ -71,7 +131,7 @@
71 ;;131 ;;
72 esac132 esac
73133
74 opts="--help --version -q --quiet -v --verbose --system --dest="134 opts="--help --version -q --quiet -v --verbose --session --system --dest="
75 cmds=$(initctl help|grep "^ [^ ]"|awk '{print $1}')135 cmds=$(initctl help|grep "^ [^ ]"|awk '{print $1}')
76136
77 COMPREPLY=( $(compgen -W "${opts} ${cmds}" -- ${cur}) )137 COMPREPLY=( $(compgen -W "${opts} ${cmds}" -- ${cur}) )
@@ -84,7 +144,7 @@
84 COMPREPLY=()144 COMPREPLY=()
85 _get_comp_words_by_ref cur prev145 _get_comp_words_by_ref cur prev
86146
87 opts="--help --version -q --quiet -v --verbose --system --dest= \147 opts="--help --version -q --quiet -v --verbose --session --system --dest= \
88 -n --no-wait"148 -n --no-wait"
89149
90 case "$prev" in150 case "$prev" in
@@ -94,7 +154,7 @@
94 ;;154 ;;
95 esac155 esac
96156
97 COMPREPLY=( $(compgen -W "$opts $(_upstart_startable_events)" -- ${cur}) )157 COMPREPLY=( $(compgen -W "$opts $(_upstart_startable_jobs)" -- ${cur}) )
98 return 0158 return 0
99} && complete -F _upstart_start start159} && complete -F _upstart_start start
100160
@@ -104,7 +164,7 @@
104 COMPREPLY=()164 COMPREPLY=()
105 _get_comp_words_by_ref cur prev165 _get_comp_words_by_ref cur prev
106166
107 opts="--help --version -q --quiet -v --verbose --system --dest= \167 opts="--help --version -q --quiet -v --verbose --session --system --dest= \
108 -n --no-wait"168 -n --no-wait"
109169
110 case "$prev" in170 case "$prev" in
@@ -114,7 +174,7 @@
114 ;;174 ;;
115 esac175 esac
116176
117 COMPREPLY=( $(compgen -W "$opts $(_upstart_stoppable_events)" -- ${cur}) )177 COMPREPLY=( $(compgen -W "$opts $(_upstart_stoppable_jobs)" -- ${cur}) )
118 return 0178 return 0
119} && complete -F _upstart_stop stop179} && complete -F _upstart_stop stop
120180
@@ -124,7 +184,7 @@
124 COMPREPLY=()184 COMPREPLY=()
125 _get_comp_words_by_ref cur prev185 _get_comp_words_by_ref cur prev
126186
127 opts="--help --version -q --quiet -v --verbose --system --dest= \187 opts="--help --version -q --quiet -v --verbose --session --system --dest= \
128 -n --no-wait"188 -n --no-wait"
129189
130 case "$prev" in190 case "$prev" in
@@ -134,7 +194,7 @@
134 ;;194 ;;
135 esac195 esac
136196
137 COMPREPLY=( $(compgen -W "$opts $(_upstart_events)" -- ${cur}) )197 COMPREPLY=( $(compgen -W "$opts $(_upstart_stoppable_jobs)" -- ${cur}) )
138 return 0198 return 0
139199
140} && complete -F _upstart_restart restart200} && complete -F _upstart_restart restart
@@ -145,7 +205,7 @@
145 COMPREPLY=()205 COMPREPLY=()
146 _get_comp_words_by_ref cur prev206 _get_comp_words_by_ref cur prev
147207
148 opts="--help --version -q --quiet -v --verbose --system --dest="208 opts="--help --version -q -d --detail -e --enumerate --quiet -v --verbose --session --system --dest="
149209
150 case "$prev" in210 case "$prev" in
151 --help|--version)211 --help|--version)
@@ -154,7 +214,7 @@
154 ;;214 ;;
155 esac215 esac
156216
157 COMPREPLY=( $(compgen -W "$opts $(_upstart_events)" -- ${cur}) )217 COMPREPLY=( $(compgen -W "$opts $(_upstart_jobs)" -- ${cur}) )
158 return 0218 return 0
159219
160} && complete -F _upstart_status status220} && complete -F _upstart_status status
@@ -165,7 +225,7 @@
165 COMPREPLY=()225 COMPREPLY=()
166 _get_comp_words_by_ref cur prev226 _get_comp_words_by_ref cur prev
167227
168 opts="--help --version -q --quiet -v --verbose --system --dest="228 opts="--help --version -q --quiet -v --verbose --session --system --dest="
169229
170 case "$prev" in230 case "$prev" in
171 --help|--version)231 --help|--version)
@@ -174,7 +234,7 @@
174 ;;234 ;;
175 esac235 esac
176236
177 COMPREPLY=( $(compgen -W "$opts $(_upstart_events)" -- ${cur}) )237 COMPREPLY=( $(compgen -W "$opts $(_upstart_stoppable_jobs)" -- ${cur}) )
178 return 0238 return 0
179239
180} && complete -F _upstart_reload reload240} && complete -F _upstart_reload reload
181241
=== modified file 'contrib/vim/syntax/upstart.vim'
--- contrib/vim/syntax/upstart.vim 2011-01-27 18:52:25 +0000
+++ contrib/vim/syntax/upstart.vim 2011-10-14 11:09:18 +0000
@@ -1,10 +1,11 @@
1" Vim syntax file1" Vim syntax file
2" Language: Upstart job files2" Language: Upstart job files
3" Maintainer: Michael Biebl <biebl@debian.org>3" Maintainer: Michael Biebl <biebl@debian.org>
4" Last Change: 2007 Feb 134" James Hunt <james.hunt@ubuntu.com>
5" Last Change: 2011 Jun 14
5" License: GPL v26" License: GPL v2
6" Version: 0.17" Version: 0.3
7" Remark: Syntax highlighting for upstart job files.8" Remark: Syntax highlighting for Upstart (init(8)) job files.
8"9"
9" It is inspired by the initng syntax file and includes sh.vim to do the10" It is inspired by the initng syntax file and includes sh.vim to do the
10" highlighting of script blocks.11" highlighting of script blocks.
@@ -14,11 +15,8 @@
14elseif exists("b:current_syntax")15elseif exists("b:current_syntax")
15 finish16 finish
16endif17endif
17
18setlocal iskeyword=@,48-57,-,.
1918
20let is_bash = 119let is_bash = 1
21"unlet! b:current_syntax
22syn include @Shell syntax/sh.vim20syn include @Shell syntax/sh.vim
2321
24syn case match22syn case match
@@ -33,9 +31,12 @@
33syn cluster upstartShellCluster contains=@Shell31syn cluster upstartShellCluster contains=@Shell
3432
35" one argument33" one argument
36syn keyword upstartStatement description author version34syn keyword upstartStatement description author version instance expect
37syn keyword upstartStatement pid kill normal console env umask nice limit chroot chdir exec35syn keyword upstartStatement pid kill normal console env exit export
38syn keyword upstartStatement expect export36syn keyword upstartStatement umask nice oom chroot chdir exec
37
38" two arguments
39syn keyword upstartStatement limit
3940
40" one or more arguments (events)41" one or more arguments (events)
41syn keyword upstartStatement emits42syn keyword upstartStatement emits
@@ -43,29 +44,62 @@
43syn keyword upstartStatement on start stop44syn keyword upstartStatement on start stop
4445
45" flag, no parameter46" flag, no parameter
46syn keyword upstartStatement daemon respawn service instance task47syn keyword upstartStatement respawn service instance manual debug task
4748
48" prefix for exec or script49" prefix for exec or script
49syn keyword upstartOption pre-start post-start pre-stop post-stop50syn keyword upstartOption pre-start post-start pre-stop post-stop
5051
51" options for pid52" option for kill
52syn keyword upstartOption file binary timeout53syn keyword upstartOption timeout signal
53" option for54" option for oom
54syn keyword upstartOption timeout55syn keyword upstartOption score never
55" option for respawn
56syn keyword upstartOption limit
57" options for console56" options for console
58syn keyword upstartOption logged output owner none57syn keyword upstartOption output owner
59" options for expect58" options for expect
60syn keyword upstartOption daemon fork stop59syn keyword upstartOption stop fork daemon none
6160" options for limit
62syn keyword upstartEvent startup stalled control-alt-delete kbdrequest starting started stopping stopped runlevel61syn keyword upstartOption unlimited core cpu data fsize memlock msgqueue nice
6362syn keyword upstartOption nofile nproc rss rtprio sigpending stack
64hi def link upstartComment Comment63
65hi def link upstartTodo Todo64" 'options' for start/stop on
66hi def link upstartString String65syn keyword upstartOption and or
66
67" Upstart itself and associated utilities
68syn keyword upstartEvent runlevel
69syn keyword upstartEvent started
70syn keyword upstartEvent starting
71syn keyword upstartEvent startup
72syn keyword upstartEvent stopped
73syn keyword upstartEvent stopping
74syn match upstartEvent /control-alt-delete/
75syn match upstartEvent /keyboard-request/
76syn match upstartEvent /power-status-changed/
77
78" D-Bus
79syn match upstartEvent /dbus-activation/
80
81" Display Manager (ie gdm)
82syn match upstartEvent /desktop-session-start/
83syn match upstartEvent /login-session-start/
84
85" mountall
86syn keyword upstartEvent filesystem
87syn keyword upstartEvent mounted
88syn keyword upstartEvent mounting
89syn match upstartEvent /\(\<local\>\|\<virtual\>\|\<remote\>\)-filesystems/
90syn match upstartEvent /all-swaps/
91
92" upstart-udev-bridge and ifup/down
93syn match upstartEvent /\<\i\{-1,}-device-\(\<added\>\|\<removed\>\|\<up\>\|\<down\>\)/
94
95" upstart-socket-bridge
96syn keyword upstartEvent socket
97
98hi def link upstartComment Comment
99hi def link upstartTodo Todo
100hi def link upstartString String
67hi def link upstartStatement Statement101hi def link upstartStatement Statement
68hi def link upstartOption Type102hi def link upstartOption Type
69hi def link upstartEvent Define103hi def link upstartEvent Define
70104
71let b:current_syntax = "upstart"105let b:current_syntax = "upstart"
72106
=== modified file 'dbus/Upstart.conf'
--- dbus/Upstart.conf 2009-07-02 17:46:41 +0000
+++ dbus/Upstart.conf 2011-10-14 11:09:18 +0000
@@ -9,12 +9,14 @@
9 <allow own="com.ubuntu.Upstart" />9 <allow own="com.ubuntu.Upstart" />
10 </policy>10 </policy>
1111
12 <!-- Permit the root user to invoke all of the methods on Upstart, its jobs12 <!-- Allow any user to invoke all of the methods on Upstart, its jobs
13 or their instances, and to get and set properties. -->13 or their instances, and to get and set properties - since Upstart
14 <policy user="root">14 isolates commands by user. -->
15 <policy context="default">
16 <allow send_destination="com.ubuntu.Upstart"
17 send_interface="org.freedesktop.DBus.Introspectable" />
15 <allow send_destination="com.ubuntu.Upstart"18 <allow send_destination="com.ubuntu.Upstart"
16 send_interface="org.freedesktop.DBus.Properties" />19 send_interface="org.freedesktop.DBus.Properties" />
17
18 <allow send_destination="com.ubuntu.Upstart"20 <allow send_destination="com.ubuntu.Upstart"
19 send_interface="com.ubuntu.Upstart0_6" />21 send_interface="com.ubuntu.Upstart0_6" />
20 <allow send_destination="com.ubuntu.Upstart"22 <allow send_destination="com.ubuntu.Upstart"
@@ -22,36 +24,4 @@
22 <allow send_destination="com.ubuntu.Upstart"24 <allow send_destination="com.ubuntu.Upstart"
23 send_interface="com.ubuntu.Upstart0_6.Instance" />25 send_interface="com.ubuntu.Upstart0_6.Instance" />
24 </policy>26 </policy>
25
26 <!-- Allow any user to introspect Upstart's interfaces, to obtain the
27 values of properties (but not set them) and to invoke selected
28 methods on Upstart and its jobs that are used to walk information. -->
29 <policy context="default">
30 <allow send_destination="com.ubuntu.Upstart"
31 send_interface="org.freedesktop.DBus.Introspectable" />
32
33 <allow send_destination="com.ubuntu.Upstart"
34 send_interface="org.freedesktop.DBus.Properties"
35 send_type="method_call" send_member="Get" />
36 <allow send_destination="com.ubuntu.Upstart"
37 send_interface="org.freedesktop.DBus.Properties"
38 send_type="method_call" send_member="GetAll" />
39
40 <allow send_destination="com.ubuntu.Upstart"
41 send_interface="com.ubuntu.Upstart0_6"
42 send_type="method_call" send_member="GetJobByName" />
43 <allow send_destination="com.ubuntu.Upstart"
44 send_interface="com.ubuntu.Upstart0_6"
45 send_type="method_call" send_member="GetAllJobs" />
46
47 <allow send_destination="com.ubuntu.Upstart"
48 send_interface="com.ubuntu.Upstart0_6.Job"
49 send_type="method_call" send_member="GetInstance" />
50 <allow send_destination="com.ubuntu.Upstart"
51 send_interface="com.ubuntu.Upstart0_6.Job"
52 send_type="method_call" send_member="GetInstanceByName" />
53 <allow send_destination="com.ubuntu.Upstart"
54 send_interface="com.ubuntu.Upstart0_6.Job"
55 send_type="method_call" send_member="GetAllInstances" />
56 </policy>
57</busconfig>27</busconfig>
5828
=== modified file 'dbus/com.ubuntu.Upstart.xml'
--- dbus/com.ubuntu.Upstart.xml 2009-07-03 16:08:10 +0000
+++ dbus/com.ubuntu.Upstart.xml 2011-10-14 11:09:18 +0000
@@ -49,6 +49,13 @@
49 <arg name="env" type="as" direction="in" />49 <arg name="env" type="as" direction="in" />
50 <arg name="wait" type="b" direction="in" />50 <arg name="wait" type="b" direction="in" />
51 </method>51 </method>
52 <method name="EmitEventWithFile">
53 <annotation name="com.netsplit.Nih.Method.Async" value="true" />
54 <arg name="name" type="s" direction="in" />
55 <arg name="env" type="as" direction="in" />
56 <arg name="wait" type="b" direction="in" />
57 <arg name="file" type="h" direction="in" />
58 </method>
5259
53 <!-- Basic information about Upstart -->60 <!-- Basic information about Upstart -->
54 <property name="version" type="s" access="read" />61 <property name="version" type="s" access="read" />
5562
=== modified file 'dbus/upstart.h'
--- dbus/upstart.h 2010-12-10 04:04:51 +0000
+++ dbus/upstart.h 2011-10-14 11:09:18 +0000
@@ -31,7 +31,7 @@
31# define DBUS_SERVICE_UPSTART "com.ubuntu.TestUpstart"31# define DBUS_SERVICE_UPSTART "com.ubuntu.TestUpstart"
32# else32# else
33# define DBUS_SERVICE_UPSTART "com.ubuntu.Upstart"33# define DBUS_SERVICE_UPSTART "com.ubuntu.Upstart"
34#endif34# endif
35#endif35#endif
3636
3737
3838
=== added directory 'extra'
=== added file 'extra/Makefile.am'
--- extra/Makefile.am 1970-01-01 00:00:00 +0000
+++ extra/Makefile.am 2011-10-14 11:09:18 +0000
@@ -0,0 +1,125 @@
1## Process this file with automake to produce Makefile.in
2
3AM_CFLAGS = \
4 $(NIH_CFLAGS) \
5 $(NIH_DBUS_CFLAGS) \
6 $(DBUS_CFLAGS) \
7 $(UDEV_CFLAGS)
8
9AM_CPPFLAGS = \
10 -DLOCALEDIR="\"$(localedir)\"" \
11 -DSBINDIR="\"$(sbindir)\"" \
12 -I$(top_builddir) -I$(top_srcdir) -iquote$(builddir) -iquote$(srcdir) \
13 -I$(top_srcdir)/intl
14
15
16initdir = $(sysconfdir)/init
17
18
19sbin_PROGRAMS = \
20 upstart-socket-bridge
21
22dist_init_DATA = \
23 conf/upstart-socket-bridge.conf
24
25dist_man_MANS = \
26 man/upstart-socket-bridge.8 \
27 man/socket-event.7
28
29upstart_socket_bridge_SOURCES = \
30 upstart-socket-bridge.c
31nodist_upstart_socket_bridge_SOURCES = \
32 $(com_ubuntu_Upstart_OUTPUTS) \
33 $(com_ubuntu_Upstart_Job_OUTPUTS)
34upstart_socket_bridge_LDADD = \
35 $(LTLIBINTL) \
36 $(NIH_LIBS) \
37 $(NIH_DBUS_LIBS) \
38 $(DBUS_LIBS)
39
40
41if HAVE_UDEV
42dist_init_DATA += \
43 conf/upstart-udev-bridge.conf
44
45dist_man_MANS += \
46 man/upstart-udev-bridge.8
47
48sbin_PROGRAMS += \
49 upstart-udev-bridge
50
51upstart_udev_bridge_SOURCES = \
52 upstart-udev-bridge.c
53nodist_upstart_udev_bridge_SOURCES = \
54 $(com_ubuntu_Upstart_OUTPUTS)
55upstart_udev_bridge_LDADD = \
56 $(LTLIBINTL) \
57 $(NIH_LIBS) \
58 $(NIH_DBUS_LIBS) \
59 $(DBUS_LIBS) \
60 $(UDEV_LIBS)
61
62install-data-hook:
63 src=`echo upstart-udev-bridge| sed '$(transform)'`.8; \
64 for symlink in \
65 net-device-added \
66 net-device-removed \
67 graphics-device-added \
68 drm-device-added; do \
69 inst=`echo $$symlink | sed '$(transform)'`.7; \
70 echo " ln -sf '$(man8dir)/$$src' '$(DESTDIR)$(man7dir)/$$inst'"; \
71 ln -sf "$(man8dir)/$$src" "$(DESTDIR)$(man7dir)/$$inst"; \
72 done
73
74else
75EXTRA_DIST = \
76 man/upstart-udev-bridge.8
77endif
78
79
80com_ubuntu_Upstart_OUTPUTS = \
81 com.ubuntu.Upstart.c \
82 com.ubuntu.Upstart.h
83
84com_ubuntu_Upstart_XML = \
85 ../dbus/com.ubuntu.Upstart.xml
86
87$(com_ubuntu_Upstart_OUTPUTS): $(com_ubuntu_Upstart_XML)
88 $(AM_V_GEN)$(NIH_DBUS_TOOL) \
89 --package=$(PACKAGE) \
90 --mode=proxy --prefix=upstart \
91 --default-interface=com.ubuntu.Upstart0_6 \
92 --output=$@ $<
93
94
95com_ubuntu_Upstart_Job_OUTPUTS = \
96 com.ubuntu.Upstart.Job.c \
97 com.ubuntu.Upstart.Job.h
98
99com_ubuntu_Upstart_Job_XML = \
100 ../dbus/com.ubuntu.Upstart.Job.xml
101
102$(com_ubuntu_Upstart_Job_OUTPUTS): $(com_ubuntu_Upstart_Job_XML)
103 $(AM_V_GEN)$(NIH_DBUS_TOOL) \
104 --package=$(PACKAGE) \
105 --mode=proxy --prefix=job_class \
106 --default-interface=com.ubuntu.Upstart0_6.Job \
107 --output=$@ $<
108
109
110# These have to be built sources because we can't compile object files
111# without the header file existing first
112BUILT_SOURCES = \
113 $(com_ubuntu_Upstart_OUTPUTS) \
114 $(com_ubuntu_Upstart_Job_OUTPUTS)
115
116CLEANFILES = \
117 $(com_ubuntu_Upstart_OUTPUTS) \
118 $(com_ubuntu_Upstart_Job_OUTPUTS)
119
120
121clean-local:
122 rm -f *.gcno *.gcda
123
124maintainer-clean-local:
125 rm -f *.gcov
0126
=== added directory 'extra/conf'
=== added file 'extra/conf/upstart-socket-bridge.conf'
--- extra/conf/upstart-socket-bridge.conf 1970-01-01 00:00:00 +0000
+++ extra/conf/upstart-socket-bridge.conf 2011-10-14 11:09:18 +0000
@@ -0,0 +1,16 @@
1# upstart-socket-bridge - Bridge socket events into upstart
2#
3# This helper daemon receives socket(7) events and
4# emits equivalent Upstart events.
5
6description "Bridge socket events into upstart"
7
8emits socket
9
10start on net-device-up IFACE=lo
11stop on runlevel [!2345]
12
13expect daemon
14respawn
15
16exec upstart-socket-bridge --daemon
017
=== added file 'extra/conf/upstart-udev-bridge.conf'
--- extra/conf/upstart-udev-bridge.conf 1970-01-01 00:00:00 +0000
+++ extra/conf/upstart-udev-bridge.conf 2011-10-14 11:09:18 +0000
@@ -0,0 +1,16 @@
1# upstart-udev-bridge - Bridge udev events into upstart
2#
3# This helper daemon receives udev events from the netlink socket and
4# emits equivalent Upstart events.
5
6description "Bridge udev events into upstart"
7
8emits *-device-*
9
10start on starting udev
11stop on stopped udev
12
13expect daemon
14respawn
15
16exec upstart-udev-bridge --daemon
017
=== added directory 'extra/man'
=== added file 'extra/man/socket-event.7'
--- extra/man/socket-event.7 1970-01-01 00:00:00 +0000
+++ extra/man/socket-event.7 2011-10-14 11:09:18 +0000
@@ -0,0 +1,92 @@
1.TH socket\-event 8 2011-03-08 upstart
2.\"
3.SH NAME
4socket \- event signalling that a socket connection has been made
5.\"
6.SH SYNOPSIS
7.B socket
8.BI PROTO\fR= PROTO
9.BI PORT\fR= PORT
10.BI ADDR\fR= ADDR
11
12.B socket
13.BI PROTO\fR= PROTO
14.BI PATH\fR= PATH
15.\"
16.SH DESCRIPTION
17
18The
19.B socket
20event is generated by the
21.BR upstart\-socket\-bridge (8)
22daemon when a socket connection is made whose details match the
23socket event condition and environment specified in a jobs
24.B start on
25or
26.B stop on
27stanza.
28
29When an incoming connection is detected, the file descriptor
30representing the socket is passed to the job in question to allow it to
31.BR accept (2)
32the connection. Additionally, the environment variable
33.B UPSTART_JOB
34will contain the name of the event ("socket") and the environment
35variable
36.B UPSTART_FDS
37will contain the number of the file descriptor corresponding to the
38listening socket.
39.\"
40.SH EXAMPLES
41.\"
42.SS Internet socket
43Start web server when first client connects from localhost:
44.RS
45.nf
46
47start on socket PROTO=inet PORT=80 ADDR=127.0.0.1
48.fi
49.RE
50.\"
51.SS Local socket
52.P
53.RS
54.nf
55
56start on socket PROTO=unix PATH=/var/run/.s.pgsql.1234
57.fi
58.FE
59.\"
60.SS Abstract socket
61.P
62
63.RS
64.nf
65
66start on socket PROTO=unix PATH=@/at/upstart/example
67.fi
68.FE
69.\"
70.SH AUTHOR
71Written by Scott James Remnant
72.RB < scott@netsplit.com >
73
74Manual page written by James Hunt
75.RB < james.hunt@ubuntu.com >
76.\"
77.SH BUGS
78Report bugs at
79.RB < https://launchpad.net/upstart/+bugs >
80.\"
81.SH COPYRIGHT
82Copyright \(co 2011 Canonical Ltd.
83.PP
84This is free software; see the source for copying conditions. There is NO
85warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
86.\"
87.SH SEE ALSO
88.BR init (5)
89.BR init (8)
90.BR socket (2)
91.BR socket (7)
92.BR upstart\-socket\-bridge (8)
093
=== added file 'extra/man/upstart-socket-bridge.8'
--- extra/man/upstart-socket-bridge.8 1970-01-01 00:00:00 +0000
+++ extra/man/upstart-socket-bridge.8 2011-10-14 11:09:18 +0000
@@ -0,0 +1,47 @@
1.TH upstart-socket-bridge 8 2011-03-08 upstart
2.\"
3.SH NAME
4upstart-socket-bridge \- Bridge between Upstart and sockets
5.\"
6.SH SYNOPSIS
7.B upstart-socket-bridge
8.RI [ OPTIONS ]...
9.\"
10.SH DESCRIPTION
11The
12.B upstart-socket-bridge
13queries the Upstart
14.BR init (8)
15daemon for all job configurations which
16.B start on
17or
18.B stop on
19the socket event. It then waits for an incoming connection on each
20specified
21.BR socket (7)
22and when detected emits the socket event (\fBsocket\-event\fP (7)),
23setting a number of environment variables for the job to query.
24.\"
25.SH AUTHOR
26Written by Scott James Remnant
27.RB < scott@netsplit.com >
28
29Manual page written by James Hunt
30.RB < james.hunt@ubuntu.com >
31.\"
32.SH BUGS
33Report bugs at
34.RB < https://launchpad.net/upstart/+bugs >
35.\"
36.SH COPYRIGHT
37Copyright \(co 2011 Canonical Ltd.
38.PP
39This is free software; see the source for copying conditions. There is NO
40warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
41.\"
42.SH SEE ALSO
43.BR init (5)
44.BR init (8)
45.BR socket (2)
46.BR socket (7)
47.BR socket\-event (7)
048
=== added file 'extra/man/upstart-udev-bridge.8'
--- extra/man/upstart-udev-bridge.8 1970-01-01 00:00:00 +0000
+++ extra/man/upstart-udev-bridge.8 2011-10-14 11:09:18 +0000
@@ -0,0 +1,57 @@
1.TH upstart\-udev\-bridge 8 2011-03-08 upstart
2.\"
3.SH NAME
4upstart\-udev\-bridge \- Bridge between Upstart and udev
5.\"
6.SH SYNOPSIS
7.B upstart\-udev\-bridge
8.RI [ OPTIONS ]...
9.\"
10.SH DESCRIPTION
11.B upstart\-udev\-bridge
12receives information about kernel uevents that
13.BR udev (8)
14has completed and creates
15.BR init (8)
16events for them.
17
18It emits events which match the pattern "\fIS\fP\-device\-\fIA\fP" where
19\(aqS\(aq is the udev \fIsubsystem\fP and \(aqA\(aq is the udev \fIaction\fP.
20See \fBudev\fP(7) and for further details.
21
22Assuming \fI/sys\fP is mounted, possible values for \fIsubsystem\fP for
23your system are viewable via \fI/sys/class/\fP.
24
25.\"
26.SH EXAMPLES
27
28.IP net\-device\-added
29Event emitted when a network device is added.
30.IP net\-device\-removed
31Event emitted when a network device is removed.
32.IP graphics\-card\-added
33Event emitted when a graphics device is available to the system.
34.\"
35.SH NOTES
36This is a temporary tool until
37.BR init (8)
38itself gains the functionality to read them directly; you should not
39rely on its behaviour.
40.\"
41.SH AUTHOR
42Written by Scott James Remnant
43.RB < scott@netsplit.com >
44.\"
45.SH BUGS
46Report bugs at
47.RB < https://launchpad.net/ubuntu/+source/upstart/+bugs >
48.\"
49.SH COPYRIGHT
50Copyright \(co 2009,2010,2011 Canonical Ltd.
51.PP
52This is free software; see the source for copying conditions. There is NO
53warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
54.SH SEE ALSO
55.BR init (5)
56.BR init (8)
57.BR udev (7)
058
=== added file 'extra/upstart-socket-bridge.c'
--- extra/upstart-socket-bridge.c 1970-01-01 00:00:00 +0000
+++ extra/upstart-socket-bridge.c 2011-10-14 11:09:18 +0000
@@ -0,0 +1,644 @@
1/* upstart
2 *
3 * Copyright © 2010 Canonical Ltd.
4 * Author: Scott James Remnant <scott@netsplit.com>.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2, as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20#ifdef HAVE_CONFIG_H
21# include <config.h>
22#endif /* HAVE_CONFIG_H */
23
24
25#include <sys/epoll.h>
26#include <sys/types.h>
27#include <sys/socket.h>
28#include <sys/un.h>
29
30#include <netinet/in.h>
31#include <arpa/inet.h>
32
33#include <errno.h>
34#include <stdlib.h>
35#include <string.h>
36#include <syslog.h>
37#include <unistd.h>
38
39#include <nih/macros.h>
40#include <nih/alloc.h>
41#include <nih/list.h>
42#include <nih/hash.h>
43#include <nih/string.h>
44#include <nih/io.h>
45#include <nih/option.h>
46#include <nih/main.h>
47#include <nih/logging.h>
48#include <nih/error.h>
49
50#include <nih-dbus/dbus_connection.h>
51#include <nih-dbus/dbus_proxy.h>
52
53#include "dbus/upstart.h"
54#include "com.ubuntu.Upstart.h"
55#include "com.ubuntu.Upstart.Job.h"
56
57
58/* Structure we use for tracking jobs */
59typedef struct job {
60 NihList entry;
61 char *path;
62 NihList sockets;
63} Job;
64
65/* Structure we use for tracking listening sockets */
66typedef struct socket {
67 NihList entry;
68
69 union {
70 struct sockaddr addr;
71 struct sockaddr_in sin_addr;
72 struct sockaddr_un sun_addr;
73 };
74 socklen_t addrlen;
75
76 int sock;
77} Socket;
78
79
80/* Prototypes for static functions */
81static void epoll_watcher (void *data, NihIoWatch *watch,
82 NihIoEvents events);
83static void upstart_job_added (void *data, NihDBusMessage *message,
84 const char *job);
85static void upstart_job_removed (void *data, NihDBusMessage *message,
86 const char *job);
87static void job_add_socket (Job *job, char **socket_info);
88static void socket_destroy (Socket *socket);
89static void upstart_disconnected (DBusConnection *connection);
90static void emit_event_reply (Socket *sock, NihDBusMessage *message);
91static void emit_event_error (Socket *sock, NihDBusMessage *message);
92
93
94/**
95 * daemonise:
96 *
97 * Set to TRUE if we should become a daemon, rather than just running
98 * in the foreground.
99 **/
100static int daemonise = FALSE;
101
102/**
103 * epoll_fd:
104 *
105 * Shared epoll file descriptor for listening on.
106 **/
107static int epoll_fd = -1;
108
109/**
110 * jobs:
111 *
112 * Jobs that we're monitoring.
113 **/
114static NihHash *jobs = NULL;
115
116/**
117 * upstart:
118 *
119 * Proxy to Upstart daemon.
120 **/
121static NihDBusProxy *upstart = NULL;
122
123
124/**
125 * options:
126 *
127 * Command-line options accepted by this program.
128 **/
129static NihOption options[] = {
130 { 0, "daemon", N_("Detach and run in the background"),
131 NULL, NULL, &daemonise, NULL },
132
133 NIH_OPTION_LAST
134};
135
136
137int
138main (int argc,
139 char *argv[])
140{
141 char ** args;
142 DBusConnection *connection;
143 char ** job_class_paths;
144 int ret;
145
146 nih_main_init (argv[0]);
147
148 nih_option_set_synopsis (_("Bridge socket events into upstart"));
149 nih_option_set_help (
150 _("By default, upstart-socket-bridge does not detach from the "
151 "console and remains in the foreground. Use the --daemon "
152 "option to have it detach."));
153
154 args = nih_option_parser (NULL, argc, argv, options, FALSE);
155 if (! args)
156 exit (1);
157
158 /* Create an epoll file descriptor for listening on; use this so
159 * we can do edge triggering rather than level.
160 */
161 epoll_fd = epoll_create1 (0);
162 if (epoll_fd < 0) {
163 nih_fatal ("%s: %s", _("Could not create epoll descriptor"),
164 strerror (errno));
165 exit (1);
166 }
167
168 NIH_MUST (nih_io_add_watch (NULL, epoll_fd, NIH_IO_READ,
169 epoll_watcher, NULL));
170
171 /* Allocate jobs hash table */
172 jobs = NIH_MUST (nih_hash_string_new (NULL, 0));
173
174 /* Initialise the connection to Upstart */
175 connection = NIH_SHOULD (nih_dbus_connect (DBUS_ADDRESS_UPSTART, upstart_disconnected));
176 if (! connection) {
177 NihError *err;
178
179 err = nih_error_get ();
180 nih_fatal ("%s: %s", _("Could not connect to Upstart"),
181 err->message);
182 nih_free (err);
183
184 exit (1);
185 }
186
187 upstart = NIH_SHOULD (nih_dbus_proxy_new (NULL, connection,
188 NULL, DBUS_PATH_UPSTART,
189 NULL, NULL));
190 if (! upstart) {
191 NihError *err;
192
193 err = nih_error_get ();
194 nih_fatal ("%s: %s", _("Could not create Upstart proxy"),
195 err->message);
196 nih_free (err);
197
198 exit (1);
199 }
200
201 /* Connect signals to be notified when jobs come and go */
202 if (! nih_dbus_proxy_connect (upstart, &upstart_com_ubuntu_Upstart0_6, "JobAdded",
203 (NihDBusSignalHandler)upstart_job_added, NULL)) {
204 NihError *err;
205
206 err = nih_error_get ();
207 nih_fatal ("%s: %s", _("Could not create JobAdded signal connection"),
208 err->message);
209 nih_free (err);
210
211 exit (1);
212 }
213
214 if (! nih_dbus_proxy_connect (upstart, &upstart_com_ubuntu_Upstart0_6, "JobRemoved",
215 (NihDBusSignalHandler)upstart_job_removed, NULL)) {
216 NihError *err;
217
218 err = nih_error_get ();
219 nih_fatal ("%s: %s", _("Could not create JobRemoved signal connection"),
220 err->message);
221 nih_free (err);
222
223 exit (1);
224 }
225
226 /* Request a list of all current jobs */
227 if (upstart_get_all_jobs_sync (NULL, upstart, &job_class_paths) < 0) {
228 NihError *err;
229
230 err = nih_error_get ();
231 nih_fatal ("%s: %s", _("Could not obtain job list"),
232 err->message);
233 nih_free (err);
234
235 exit (1);
236 }
237
238 for (char **job_class_path = job_class_paths;
239 job_class_path && *job_class_path; job_class_path++)
240 upstart_job_added (NULL, NULL, *job_class_path);
241
242 nih_free (job_class_paths);
243
244 /* Become daemon */
245 if (daemonise) {
246 if (nih_main_daemonise () < 0) {
247 NihError *err;
248
249 err = nih_error_get ();
250 nih_fatal ("%s: %s", _("Unable to become daemon"),
251 err->message);
252 nih_free (err);
253
254 exit (1);
255 }
256
257 /* Send all logging output to syslog */
258 openlog (program_name, LOG_PID, LOG_DAEMON);
259 nih_log_set_logger (nih_logger_syslog);
260 }
261
262 /* Handle TERM and INT signals gracefully */
263 nih_signal_set_handler (SIGTERM, nih_signal_handler);
264 NIH_MUST (nih_signal_add_handler (NULL, SIGTERM, nih_main_term_signal, NULL));
265
266 if (! daemonise) {
267 nih_signal_set_handler (SIGINT, nih_signal_handler);
268 NIH_MUST (nih_signal_add_handler (NULL, SIGINT, nih_main_term_signal, NULL));
269 }
270
271 ret = nih_main_loop ();
272
273 return ret;
274}
275
276
277static void
278epoll_watcher (void * data,
279 NihIoWatch *watch,
280 NihIoEvents events)
281{
282 struct epoll_event event[1024];
283 int num_events;
284
285 num_events = epoll_wait (epoll_fd, event, 1024, 0);
286 if (num_events < 0) {
287 nih_error ("%s: %s", _("Error from epoll"), strerror (errno));
288 return;
289 } else if (num_events == 0)
290 return;
291
292 for (int i = 0; i < num_events; i++) {
293 Socket *sock = (Socket *)event[i].data.ptr;
294 nih_local char **env = NULL;
295 size_t env_len = 0;
296 char *var;
297 DBusPendingCall *pending_call;
298
299 if (event[i].events & EPOLLIN)
300 nih_debug ("%p EPOLLIN", sock);
301 if (event[i].events & EPOLLERR)
302 nih_debug ("%p EPOLLERR", sock);
303 if (event[i].events & EPOLLHUP)
304 nih_debug ("%p EPOLLHUP", sock);
305
306 env = NIH_MUST (nih_str_array_new (NULL));
307
308 switch (sock->addr.sa_family) {
309 case AF_INET:
310 NIH_MUST (nih_str_array_add (&env, NULL, &env_len,
311 "PROTO=inet"));
312
313 var = NIH_MUST (nih_sprintf (NULL, "PORT=%d",
314 ntohs (sock->sin_addr.sin_port)));
315 NIH_MUST (nih_str_array_addp (&env, NULL, &env_len,
316 var));
317 nih_discard (var);
318
319 var = NIH_MUST (nih_sprintf (NULL, "ADDR=%s",
320 inet_ntoa (sock->sin_addr.sin_addr)));
321 NIH_MUST (nih_str_array_addp (&env, NULL, &env_len,
322 var));
323 nih_discard (var);
324 break;
325 case AF_UNIX:
326 NIH_MUST (nih_str_array_add (&env, NULL, &env_len,
327 "PROTO=unix"));
328
329 var = NIH_MUST (nih_sprintf (NULL, "PATH=%s",
330 sock->sun_addr.sun_path));
331 NIH_MUST (nih_str_array_addp (&env, NULL, &env_len,
332 var));
333 nih_discard (var);
334 break;
335 default:
336 nih_assert_not_reached ();
337 }
338
339 pending_call = NIH_SHOULD (upstart_emit_event_with_file (
340 upstart, "socket", env, TRUE,
341 sock->sock,
342 (UpstartEmitEventWithFileReply)emit_event_reply,
343 (NihDBusErrorHandler)emit_event_error,
344 sock,
345 NIH_DBUS_TIMEOUT_NEVER));
346 if (! pending_call) {
347 NihError *err;
348
349 err = nih_error_get ();
350 nih_warn ("%s: %s", _("Could not send socket event"),
351 err->message);
352 nih_free (err);
353 }
354
355 dbus_pending_call_unref (pending_call);
356
357 // might be EPOLLIN
358 // might be EPOLLERR
359 // might be EPOLLHUP
360 }
361}
362
363
364static void
365upstart_job_added (void * data,
366 NihDBusMessage *message,
367 const char * job_class_path)
368{
369 nih_local NihDBusProxy *job_class = NULL;
370 nih_local char ***start_on = NULL;
371 nih_local char ***stop_on = NULL;
372 Job *job;
373
374 nih_assert (job_class_path != NULL);
375
376 /* Obtain a proxy to the job */
377 job_class = nih_dbus_proxy_new (NULL, upstart->connection,
378 upstart->name, job_class_path,
379 NULL, NULL);
380 if (! job_class) {
381 NihError *err;
382
383 err = nih_error_get ();
384 nih_error ("Could not create proxy for job %s: %s",
385 job_class_path, err->message);
386 nih_free (err);
387
388 return;
389 }
390
391 job_class->auto_start = FALSE;
392
393 /* Obtain the start_on and stop_on properties of the job */
394 if (job_class_get_start_on_sync (NULL, job_class, &start_on) < 0) {
395 NihError *err;
396
397 err = nih_error_get ();
398 nih_error ("Could not obtain job start condition %s: %s",
399 job_class_path, err->message);
400 nih_free (err);
401
402 return;
403 }
404
405 if (job_class_get_stop_on_sync (NULL, job_class, &stop_on) < 0) {
406 NihError *err;
407
408 err = nih_error_get ();
409 nih_error ("Could not obtain job stop condition %s: %s",
410 job_class_path, err->message);
411 nih_free (err);
412
413 return;
414 }
415
416 /* Free any existing record for the job (should never happen,
417 * but worth being safe).
418 */
419 job = (Job *)nih_hash_lookup (jobs, job_class_path);
420 if (job)
421 nih_free (job);
422
423 /* Create new record for the job */
424 job = NIH_MUST (nih_new (NULL, Job));
425 job->path = NIH_MUST (nih_strdup (job, job_class_path));
426
427 nih_list_init (&job->entry);
428 nih_list_init (&job->sockets);
429
430 /* Find out whether this job listens for any socket events */
431 for (char ***event = start_on; event && *event && **event; event++)
432 if (! strcmp (**event, "socket"))
433 job_add_socket (job, *event);
434 for (char ***event = stop_on; event && *event && **event; event++)
435 if (! strcmp (**event, "socket"))
436 job_add_socket (job, *event);
437
438 /* If we didn't end up with any sockets, free the job and move on */
439 if (NIH_LIST_EMPTY (&job->sockets)) {
440 nih_free (job);
441 return;
442 }
443
444 nih_debug ("Job got added %s", job_class_path);
445
446 nih_alloc_set_destructor (job, nih_list_destroy);
447 nih_hash_add (jobs, &job->entry);
448}
449
450static void
451upstart_job_removed (void * data,
452 NihDBusMessage *message,
453 const char * job_path)
454{
455 Job *job;
456
457 nih_assert (job_path != NULL);
458
459 job = (Job *)nih_hash_lookup (jobs, job_path);
460 if (job) {
461 nih_debug ("Job went away %s", job_path);
462 nih_free (job);
463 }
464}
465
466
467static void
468job_add_socket (Job * job,
469 char **socket_info)
470{
471 Socket *sock;
472 nih_local char *error = NULL;
473 int components = 0;
474 struct epoll_event event;
475
476 nih_assert (job != NULL);
477 nih_assert (socket_info != NULL);
478 nih_assert (! strcmp(socket_info[0], "socket"));
479
480 sock = NIH_MUST (nih_new (job, Socket));
481 memset (sock, 0, sizeof (Socket));
482 sock->sock = -1;
483
484 nih_list_init (&sock->entry);
485
486 nih_debug ("Found socket");
487 for (char **env = socket_info + 1; env && *env; env++) {
488 char *val;
489 size_t name_len;
490
491 val = strchr (*env, '=');
492 if (! val) {
493 nih_warn ("Ignored socket event without variable name in %s",
494 job->path);
495 goto error;
496 }
497
498 name_len = val - *env;
499 val++;
500
501 if (! strncmp (*env, "PROTO", name_len)) {
502 if (! strcmp (val, "inet")) {
503 sock->addrlen = sizeof sock->sin_addr;
504 sock->sin_addr.sin_family = AF_INET;
505 sock->sin_addr.sin_addr.s_addr = INADDR_ANY;
506 components = 1;
507 } else if (! strcmp (val, "unix")) {
508 sock->addrlen = sizeof sock->sun_addr;
509 sock->sun_addr.sun_family = AF_UNIX;
510 components = 1;
511 } else {
512 nih_warn ("Ignored socket event with unknown PROTO=%s in %s",
513 val, job->path);
514 goto error;
515 }
516
517 } else if (! strncmp (*env, "PORT", name_len)
518 && (sock->sin_addr.sin_family == AF_INET)) {
519 sock->sin_addr.sin_port = htons (atoi (val));
520 components--;
521
522 } else if (! strncmp (*env, "ADDR", name_len)
523 && (sock->sin_addr.sin_family == AF_INET)) {
524 if (inet_aton (val, &(sock->sin_addr.sin_addr)) == 0) {
525 nih_warn ("Ignored socket event with invalid ADDR=%s in %s",
526 val, job->path);
527 goto error;
528 }
529
530 } else if (! strncmp (*env, "PATH", name_len)
531 && (sock->sun_addr.sun_family == AF_UNIX)) {
532 strncpy (sock->sun_addr.sun_path, val,
533 sizeof sock->sun_addr.sun_path);
534
535 if (sock->sun_addr.sun_path[0] == '@')
536 sock->sun_addr.sun_path[0] = '\0';
537
538 components--;
539
540 } else {
541 nih_warn ("Ignored socket event with unknown variable %.*s in %s",
542 (int)name_len, *env, job->path);
543 goto error;
544 }
545 }
546
547 /* Missing any required components? */
548 if (components) {
549 nih_warn ("Ignored incomplete socket event in %s",
550 job->path);
551 goto error;
552 }
553
554 /* Let's try and set this baby up */
555 sock->sock = socket (sock->addr.sa_family, SOCK_STREAM, 0);
556 if (sock->sock < 0) {
557 nih_warn ("Failed to create socket in %s: %s",
558 job->path, strerror (errno));
559 goto error;
560 }
561
562 int opt = 1;
563 if (setsockopt (sock->sock, SOL_SOCKET, SO_REUSEADDR,
564 &opt, sizeof opt) < 0) {
565 nih_warn ("Failed to set socket reuse in %s: %s",
566 job->path, strerror (errno));
567 goto error;
568 }
569
570 if (bind (sock->sock, &sock->addr, sock->addrlen) < 0) {
571 nih_warn ("Failed to bind socket in %s: %s",
572 job->path, strerror (errno));
573 goto error;
574 }
575
576 if (listen (sock->sock, SOMAXCONN) < 0) {
577 nih_warn ("Failed to listen on socket in %s: %s",
578 job->path, strerror (errno));
579 goto error;
580 }
581
582 /* We have a listening socket, now we want to be notified when someone
583 * connects; but we just want one notification, we don't want to get
584 * a DDoS of wake-ups while waiting for the service to start.
585 *
586 * The solution is to use epoll in edge-triggered mode, this will
587 * fire only on initial connection until a new one comes in.
588 */
589 event.events = EPOLLIN | EPOLLET;
590 event.data.ptr = sock;
591
592 if (epoll_ctl (epoll_fd, EPOLL_CTL_ADD, sock->sock, &event) < 0) {
593 nih_warn ("Failed to watch socket in %s: %s",
594 job->path, strerror (errno));
595 goto error;
596 }
597
598 /* Okay then, add to the job */
599 nih_alloc_set_destructor (sock, socket_destroy);
600 nih_list_add (&job->sockets, &sock->entry);
601
602 return;
603
604error:
605 if (sock->sock != -1)
606 close (sock->sock);
607 nih_free (sock);
608}
609
610static void
611socket_destroy (Socket *sock)
612{
613 epoll_ctl (epoll_fd, EPOLL_CTL_DEL, sock->sock, NULL);
614 close (sock->sock);
615
616 nih_list_destroy (&sock->entry);
617}
618
619
620static void
621upstart_disconnected (DBusConnection *connection)
622{
623 nih_fatal (_("Disconnected from Upstart"));
624 nih_main_loop_exit (1);
625}
626
627
628static void
629emit_event_reply (Socket * sock,
630 NihDBusMessage *message)
631{
632 nih_debug ("Event completed");
633}
634
635static void
636emit_event_error (Socket * sock,
637 NihDBusMessage *message)
638{
639 NihError *err;
640
641 err = nih_error_get ();
642 nih_warn ("%s: %s", _("Error emitting socket event"), err->message);
643 nih_free (err);
644}
0645
=== added file 'extra/upstart-udev-bridge.c'
--- extra/upstart-udev-bridge.c 1970-01-01 00:00:00 +0000
+++ extra/upstart-udev-bridge.c 2011-10-14 11:09:18 +0000
@@ -0,0 +1,310 @@
1/* upstart
2 *
3 * Copyright © 2009 Canonical Ltd.
4 * Author: Scott James Remnant <scott@netsplit.com>.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2, as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20#ifdef HAVE_CONFIG_H
21# include <config.h>
22#endif /* HAVE_CONFIG_H */
23
24
25#include <libudev.h>
26
27#include <stdlib.h>
28#include <string.h>
29#include <syslog.h>
30
31#include <nih/macros.h>
32#include <nih/alloc.h>
33#include <nih/string.h>
34#include <nih/io.h>
35#include <nih/option.h>
36#include <nih/main.h>
37#include <nih/logging.h>
38#include <nih/error.h>
39
40#include <nih-dbus/dbus_connection.h>
41#include <nih-dbus/dbus_proxy.h>
42
43#include "dbus/upstart.h"
44#include "com.ubuntu.Upstart.h"
45
46
47/* Prototypes for static functions */
48static void udev_monitor_watcher (struct udev_monitor *udev_monitor,
49 NihIoWatch *watch, NihIoEvents events);
50static void upstart_disconnected (DBusConnection *connection);
51static void emit_event_error (void *data, NihDBusMessage *message);
52
53
54/**
55 * daemonise:
56 *
57 * Set to TRUE if we should become a daemon, rather than just running
58 * in the foreground.
59 **/
60static int daemonise = FALSE;
61
62/**
63 * upstart:
64 *
65 * Proxy to Upstart daemon.
66 **/
67static NihDBusProxy *upstart = NULL;
68
69
70/**
71 * options:
72 *
73 * Command-line options accepted by this program.
74 **/
75static NihOption options[] = {
76 { 0, "daemon", N_("Detach and run in the background"),
77 NULL, NULL, &daemonise, NULL },
78
79 NIH_OPTION_LAST
80};
81
82
83int
84main (int argc,
85 char *argv[])
86{
87 char ** args;
88 DBusConnection * connection;
89 struct udev * udev;
90 struct udev_monitor *udev_monitor;
91 int ret;
92
93 nih_main_init (argv[0]);
94
95 nih_option_set_synopsis (_("Bridge udev events into upstart"));
96 nih_option_set_help (
97 _("By default, upstart-udev-bridge does not detach from the "
98 "console and remains in the foreground. Use the --daemon "
99 "option to have it detach."));
100
101 args = nih_option_parser (NULL, argc, argv, options, FALSE);
102 if (! args)
103 exit (1);
104
105 /* Initialise the connection to Upstart */
106 connection = NIH_SHOULD (nih_dbus_connect (DBUS_ADDRESS_UPSTART, upstart_disconnected));
107 if (! connection) {
108 NihError *err;
109
110 err = nih_error_get ();
111 nih_fatal ("%s: %s", _("Could not connect to Upstart"),
112 err->message);
113 nih_free (err);
114
115 exit (1);
116 }
117
118 upstart = NIH_SHOULD (nih_dbus_proxy_new (NULL, connection,
119 NULL, DBUS_PATH_UPSTART,
120 NULL, NULL));
121 if (! upstart) {
122 NihError *err;
123
124 err = nih_error_get ();
125 nih_fatal ("%s: %s", _("Could not create Upstart proxy"),
126 err->message);
127 nih_free (err);
128
129 exit (1);
130 }
131
132 /* Initialise the connection to udev */
133 nih_assert (udev = udev_new ());
134 nih_assert (udev_monitor = udev_monitor_new_from_netlink (udev, "udev"));
135 nih_assert (udev_monitor_enable_receiving (udev_monitor) == 0);
136 udev_monitor_set_receive_buffer_size(udev_monitor, 128*1024*1024);
137
138 NIH_MUST (nih_io_add_watch (NULL, udev_monitor_get_fd (udev_monitor),
139 NIH_IO_READ,
140 (NihIoWatcher)udev_monitor_watcher,
141 udev_monitor));
142
143 /* Become daemon */
144 if (daemonise) {
145 if (nih_main_daemonise () < 0) {
146 NihError *err;
147
148 err = nih_error_get ();
149 nih_fatal ("%s: %s", _("Unable to become daemon"),
150 err->message);
151 nih_free (err);
152
153 exit (1);
154 }
155
156 /* Send all logging output to syslog */
157 openlog (program_name, LOG_PID, LOG_DAEMON);
158 nih_log_set_logger (nih_logger_syslog);
159 }
160
161 /* Handle TERM and INT signals gracefully */
162 nih_signal_set_handler (SIGTERM, nih_signal_handler);
163 NIH_MUST (nih_signal_add_handler (NULL, SIGTERM, nih_main_term_signal, NULL));
164
165 if (! daemonise) {
166 nih_signal_set_handler (SIGINT, nih_signal_handler);
167 NIH_MUST (nih_signal_add_handler (NULL, SIGINT, nih_main_term_signal, NULL));
168 }
169
170 ret = nih_main_loop ();
171
172 return ret;
173}
174
175
176static void
177udev_monitor_watcher (struct udev_monitor *udev_monitor,
178 NihIoWatch * watch,
179 NihIoEvents events)
180{
181 struct udev_device * udev_device;
182 const char * subsystem;
183 const char * action;
184 const char * kernel;
185 const char * devpath;
186 const char * devname;
187 nih_local char * name = NULL;
188 nih_local char ** env = NULL;
189 size_t env_len = 0;
190 DBusPendingCall * pending_call;
191
192 udev_device = udev_monitor_receive_device (udev_monitor);
193 if (! udev_device)
194 return;
195
196 subsystem = udev_device_get_subsystem (udev_device);
197 action = udev_device_get_action (udev_device);
198 kernel = udev_device_get_sysname (udev_device);
199 devpath = udev_device_get_devpath (udev_device);
200 devname = udev_device_get_devnode (udev_device);
201
202 if (! strcmp (action, "add")) {
203 name = NIH_MUST (nih_sprintf (NULL, "%s-device-added",
204 subsystem));
205 } else if (! strcmp (action, "change")) {
206 name = NIH_MUST (nih_sprintf (NULL, "%s-device-changed",
207 subsystem));
208 } else if (! strcmp (action, "remove")) {
209 name = NIH_MUST (nih_sprintf (NULL, "%s-device-removed",
210 subsystem));
211 } else {
212 name = NIH_MUST (nih_sprintf (NULL, "%s-device-%s",
213 subsystem, action));
214 }
215
216 env = NIH_MUST (nih_str_array_new (NULL));
217
218 if (kernel) {
219 nih_local char *var = NULL;
220
221 var = NIH_MUST (nih_sprintf (NULL, "KERNEL=%s", kernel));
222 NIH_MUST (nih_str_array_addp (&env, NULL, &env_len, var));
223 }
224
225 if (devpath) {
226 nih_local char *var = NULL;
227
228 var = NIH_MUST (nih_sprintf (NULL, "DEVPATH=%s", devpath));
229 NIH_MUST (nih_str_array_addp (&env, NULL, &env_len, var));
230 }
231
232 if (devname) {
233 nih_local char *var = NULL;
234
235 var = NIH_MUST (nih_sprintf (NULL, "DEVNAME=%s", devname));
236 NIH_MUST (nih_str_array_addp (&env, NULL, &env_len, var));
237 }
238
239 if (subsystem) {
240 nih_local char *var = NULL;
241
242 var = NIH_MUST (nih_sprintf (NULL, "SUBSYSTEM=%s", subsystem));
243 NIH_MUST (nih_str_array_addp (&env, NULL, &env_len, var));
244 }
245
246 if (action) {
247 nih_local char *var = NULL;
248
249 var = NIH_MUST (nih_sprintf (NULL, "ACTION=%s", action));
250 NIH_MUST (nih_str_array_addp (&env, NULL, &env_len, var));
251 }
252
253 for (struct udev_list_entry *list_entry = udev_device_get_properties_list_entry (udev_device);
254 list_entry != NULL;
255 list_entry = udev_list_entry_get_next (list_entry)) {
256 const char * key;
257 nih_local char *var = NULL;
258
259 key = udev_list_entry_get_name (list_entry);
260 if (! strcmp (key, "DEVPATH"))
261 continue;
262 if (! strcmp (key, "DEVNAME"))
263 continue;
264 if (! strcmp (key, "SUBSYSTEM"))
265 continue;
266 if (! strcmp (key, "ACTION"))
267 continue;
268
269 var = NIH_MUST (nih_sprintf (NULL, "%s=%s", key,
270 udev_list_entry_get_value (list_entry)));
271 NIH_MUST (nih_str_array_addp (&env, NULL, &env_len, var));
272 }
273
274 nih_debug ("%s %s", name, devname);
275
276 pending_call = NIH_SHOULD (upstart_emit_event (upstart,
277 name, env, FALSE,
278 NULL, emit_event_error, NULL,
279 NIH_DBUS_TIMEOUT_NEVER));
280 if (! pending_call) {
281 NihError *err;
282
283 err = nih_error_get ();
284 nih_warn ("%s", err->message);
285 nih_free (err);
286 }
287
288 dbus_pending_call_unref (pending_call);
289
290 udev_device_unref (udev_device);
291}
292
293
294static void
295upstart_disconnected (DBusConnection *connection)
296{
297 nih_fatal (_("Disconnected from Upstart"));
298 nih_main_loop_exit (1);
299}
300
301static void
302emit_event_error (void * data,
303 NihDBusMessage *message)
304{
305 NihError *err;
306
307 err = nih_error_get ();
308 nih_warn ("%s", err->message);
309 nih_free (err);
310}
0311
=== modified file 'init/Makefile.am'
--- init/Makefile.am 2010-02-04 03:42:29 +0000
+++ init/Makefile.am 2011-10-14 11:09:18 +0000
@@ -40,6 +40,7 @@
40 system.c system.h \40 system.c system.h \
41 environ.c environ.h \41 environ.c environ.h \
42 process.c process.h \42 process.c process.h \
43 session.c session.h \
43 job_class.c job_class.h \44 job_class.c job_class.h \
44 job_process.c job_process.h \45 job_process.c job_process.h \
45 job.c job.h \46 job.c job.h \
@@ -158,6 +159,7 @@
158 system.o environ.o process.o \159 system.o environ.o process.o \
159 job_class.o job_process.o job.o event.o event_operator.o blocked.o \160 job_class.o job_process.o job.o event.o event_operator.o blocked.o \
160 parse_job.o parse_conf.o conf.o control.o \161 parse_job.o parse_conf.o conf.o control.o \
162 session.o \
161 com.ubuntu.Upstart.o \163 com.ubuntu.Upstart.o \
162 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \164 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
163 $(NIH_LIBS) \165 $(NIH_LIBS) \
@@ -169,6 +171,7 @@
169 system.o environ.o process.o \171 system.o environ.o process.o \
170 job_class.o job_process.o job.o event.o event_operator.o blocked.o \172 job_class.o job_process.o job.o event.o event_operator.o blocked.o \
171 parse_job.o parse_conf.o conf.o control.o \173 parse_job.o parse_conf.o conf.o control.o \
174 session.o \
172 com.ubuntu.Upstart.o \175 com.ubuntu.Upstart.o \
173 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \176 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
174 $(NIH_LIBS) \177 $(NIH_LIBS) \
@@ -180,6 +183,7 @@
180 system.o environ.o process.o \183 system.o environ.o process.o \
181 job_class.o job_process.o job.o event.o event_operator.o blocked.o \184 job_class.o job_process.o job.o event.o event_operator.o blocked.o \
182 parse_job.o parse_conf.o conf.o control.o \185 parse_job.o parse_conf.o conf.o control.o \
186 session.o \
183 com.ubuntu.Upstart.o \187 com.ubuntu.Upstart.o \
184 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \188 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
185 $(NIH_LIBS) \189 $(NIH_LIBS) \
@@ -191,6 +195,7 @@
191 system.o environ.o process.o \195 system.o environ.o process.o \
192 job_class.o job_process.o job.o event.o event_operator.o blocked.o \196 job_class.o job_process.o job.o event.o event_operator.o blocked.o \
193 parse_job.o parse_conf.o conf.o control.o \197 parse_job.o parse_conf.o conf.o control.o \
198 session.o \
194 com.ubuntu.Upstart.o \199 com.ubuntu.Upstart.o \
195 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \200 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
196 $(NIH_LIBS) \201 $(NIH_LIBS) \
@@ -202,6 +207,7 @@
202 system.o environ.o process.o \207 system.o environ.o process.o \
203 job_class.o job_process.o job.o event.o event_operator.o blocked.o \208 job_class.o job_process.o job.o event.o event_operator.o blocked.o \
204 parse_job.o parse_conf.o conf.o control.o \209 parse_job.o parse_conf.o conf.o control.o \
210 session.o \
205 com.ubuntu.Upstart.o \211 com.ubuntu.Upstart.o \
206 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \212 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
207 $(NIH_LIBS) \213 $(NIH_LIBS) \
@@ -213,6 +219,7 @@
213 system.o environ.o process.o \219 system.o environ.o process.o \
214 job_class.o job_process.o job.o event.o event_operator.o blocked.o \220 job_class.o job_process.o job.o event.o event_operator.o blocked.o \
215 parse_job.o parse_conf.o conf.o control.o \221 parse_job.o parse_conf.o conf.o control.o \
222 session.o \
216 com.ubuntu.Upstart.o \223 com.ubuntu.Upstart.o \
217 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \224 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
218 $(NIH_LIBS) \225 $(NIH_LIBS) \
@@ -224,6 +231,7 @@
224 system.o environ.o process.o \231 system.o environ.o process.o \
225 job_class.o job_process.o job.o event.o event_operator.o blocked.o \232 job_class.o job_process.o job.o event.o event_operator.o blocked.o \
226 parse_job.o parse_conf.o conf.o control.o \233 parse_job.o parse_conf.o conf.o control.o \
234 session.o \
227 com.ubuntu.Upstart.o \235 com.ubuntu.Upstart.o \
228 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \236 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
229 $(NIH_LIBS) \237 $(NIH_LIBS) \
@@ -235,6 +243,7 @@
235 system.o environ.o process.o \243 system.o environ.o process.o \
236 job_class.o job_process.o job.o event.o event_operator.o blocked.o \244 job_class.o job_process.o job.o event.o event_operator.o blocked.o \
237 parse_job.o parse_conf.o conf.o control.o \245 parse_job.o parse_conf.o conf.o control.o \
246 session.o \
238 com.ubuntu.Upstart.o \247 com.ubuntu.Upstart.o \
239 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \248 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
240 $(NIH_LIBS) \249 $(NIH_LIBS) \
@@ -246,6 +255,7 @@
246 system.o environ.o process.o \255 system.o environ.o process.o \
247 job_class.o job_process.o job.o event.o event_operator.o blocked.o \256 job_class.o job_process.o job.o event.o event_operator.o blocked.o \
248 parse_job.o parse_conf.o conf.o control.o \257 parse_job.o parse_conf.o conf.o control.o \
258 session.o \
249 com.ubuntu.Upstart.o \259 com.ubuntu.Upstart.o \
250 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \260 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
251 $(NIH_LIBS) \261 $(NIH_LIBS) \
@@ -257,6 +267,7 @@
257 system.o environ.o process.o \267 system.o environ.o process.o \
258 job_class.o job_process.o job.o event.o event_operator.o blocked.o \268 job_class.o job_process.o job.o event.o event_operator.o blocked.o \
259 parse_job.o parse_conf.o conf.o control.o \269 parse_job.o parse_conf.o conf.o control.o \
270 session.o \
260 com.ubuntu.Upstart.o \271 com.ubuntu.Upstart.o \
261 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \272 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
262 $(NIH_LIBS) \273 $(NIH_LIBS) \
@@ -268,6 +279,7 @@
268 system.o environ.o process.o \279 system.o environ.o process.o \
269 job_class.o job_process.o job.o event.o event_operator.o blocked.o \280 job_class.o job_process.o job.o event.o event_operator.o blocked.o \
270 parse_job.o parse_conf.o conf.o control.o \281 parse_job.o parse_conf.o conf.o control.o \
282 session.o \
271 com.ubuntu.Upstart.o \283 com.ubuntu.Upstart.o \
272 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \284 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
273 $(NIH_LIBS) \285 $(NIH_LIBS) \
274286
=== modified file 'init/conf.c'
--- init/conf.c 2011-03-15 18:44:09 +0000
+++ init/conf.c 2011-10-14 11:09:18 +0000
@@ -2,8 +2,7 @@
2 *2 *
3 * conf.c - configuration management3 * conf.c - configuration management
4 *4 *
5 * Copyright © 2011 Google Inc.5 * Copyright © 2009,2010,2011 Canonical Ltd.
6 * Copyright © 2009 Canonical Ltd.
7 * Author: Scott James Remnant <scott@netsplit.com>.6 * Author: Scott James Remnant <scott@netsplit.com>.
8 *7 *
9 * This program is free software; you can redistribute it and/or modify8 * This program is free software; you can redistribute it and/or modify
@@ -49,7 +48,7 @@
49#include "parse_conf.h"48#include "parse_conf.h"
50#include "conf.h"49#include "conf.h"
51#include "errors.h"50#include "errors.h"
5251#include "paths.h"
5352
54/* Prototypes for static functions */53/* Prototypes for static functions */
55static int conf_source_reload_file (ConfSource *source)54static int conf_source_reload_file (ConfSource *source)
@@ -71,9 +70,18 @@
71 struct stat *statbuf)70 struct stat *statbuf)
72 __attribute__ ((warn_unused_result));71 __attribute__ ((warn_unused_result));
7372
74static int conf_reload_path (ConfSource *source, const char *path)73static int conf_reload_path (ConfSource *source, const char *path,
75 __attribute__ ((warn_unused_result));74 const char *override_path)
7675 __attribute__ ((warn_unused_result));
76
77static inline int is_conf_file (const char *path)
78 __attribute__ ((warn_unused_result));
79
80static inline int is_conf_file_std (const char *path)
81 __attribute__ ((warn_unused_result));
82
83static inline int is_conf_file_override(const char *path)
84 __attribute__ ((warn_unused_result));
7785
78/**86/**
79 * conf_sources:87 * conf_sources:
@@ -86,6 +94,115 @@
8694
8795
88/**96/**
97 * is_conf_file_std:
98 * @path: path to check.
99 *
100 * Determine if specified path contains a legitimate
101 * configuration file name.
102 *
103 * Returns: TRUE if @path contains a valid configuration file name,
104 * else FALSE.
105 *
106 **/
107static inline int
108is_conf_file_std (const char *path)
109{
110 char *ptr = strrchr (path, '.');
111
112 if (ptr && IS_CONF_EXT_STD (ptr))
113 return TRUE;
114
115 return FALSE;
116}
117
118/**
119 * is_conf_file_override:
120 * @path: path to check.
121 *
122 * Determine if specified path contains a legitimate
123 * override file name.
124 *
125 * Returns: TRUE if @path contains a valid override file name,
126 * else FALSE.
127 *
128 **/
129static inline int
130is_conf_file_override (const char *path)
131{
132 char *ptr = strrchr (path, '.');
133
134 if (ptr && IS_CONF_EXT_OVERRIDE (ptr))
135 return TRUE;
136
137 return FALSE;
138}
139
140/**
141 * is_conf_file:
142 * @path: path to check.
143 *
144 * Determine if specified path contains a legitimate
145 * configuration file or override file name.
146 *
147 * Returns: TRUE if @path contains a valid configuration
148 * file or override file name, else FALSE.
149 *
150 **/
151static inline int
152is_conf_file (const char *path)
153{
154 char *ptr = strrchr (path, '.');
155
156 if (ptr && (ptr > path) && (ptr[-1] != '/') && IS_CONF_EXT (ptr))
157 return TRUE;
158
159 return FALSE;
160}
161
162/**
163 * Convert a configuration file name to an override file name and vice
164 * versa.
165 *
166 * For example, if @path is "foo.conf", this function will return
167 * "foo.override", whereas if @path is "foo.override", it will return
168 * "foo.conf".
169 *
170 * Note that this function should be static, but isn't to allow the
171 * tests to access it.
172 *
173 * @parent: parent of returned path,
174 * @path: path to a configuration file.
175 *
176 * Returns: newly allocated toggled path, or NULL on error.
177 **/
178char *
179toggle_conf_name (const void *parent,
180 const char *path)
181{
182 char *new_path;
183 char *ext;
184 char *new_ext;
185 size_t len;
186
187 ext = strrchr (path, '.');
188 if (!ext)
189 return NULL;
190
191 new_ext = IS_CONF_EXT_STD (ext)
192 ? CONF_EXT_OVERRIDE
193 : CONF_EXT_STD;
194
195 len = strlen (new_ext);
196
197 new_path = NIH_MUST (nih_strndup (parent, path, (ext - path) + len));
198
199 memcpy (new_path + (ext - path), new_ext, len);
200
201 return new_path;
202}
203
204
205/**
89 * conf_init:206 * conf_init:
90 *207 *
91 * Initialise the conf_sources list.208 * Initialise the conf_sources list.
@@ -147,6 +264,7 @@
147264
148 source->type = type;265 source->type = type;
149 source->watch = NULL;266 source->watch = NULL;
267 source->session = NULL;
150268
151 source->flag = FALSE;269 source->flag = FALSE;
152 source->files = nih_hash_string_new (source, 0);270 source->files = nih_hash_string_new (source, 0);
@@ -235,8 +353,8 @@
235 err = nih_error_get ();353 err = nih_error_get ();
236 if (err->number != ENOENT)354 if (err->number != ENOENT)
237 nih_error ("%s: %s: %s", source->path,355 nih_error ("%s: %s: %s", source->path,
238 _("Unable to load configuration"),356 _("Unable to load configuration"),
239 err->message);357 err->message);
240 nih_free (err);358 nih_free (err);
241 }359 }
242 }360 }
@@ -329,10 +447,16 @@
329conf_source_reload_file (ConfSource *source)447conf_source_reload_file (ConfSource *source)
330{448{
331 NihError *err = NULL;449 NihError *err = NULL;
450 nih_local char *override_path = NULL;
451
452 struct stat statbuf;
332453
333 nih_assert (source != NULL);454 nih_assert (source != NULL);
334 nih_assert (source->type == CONF_FILE);455 nih_assert (source->type == CONF_FILE);
335456
457 /* this function should only be called for standard
458 * configuration files.
459 */
336 if (! source->watch) {460 if (! source->watch) {
337 nih_local char *dpath = NULL;461 nih_local char *dpath = NULL;
338 char *dname;462 char *dname;
@@ -361,7 +485,7 @@
361 /* Parse the file itself. If this fails, then we can discard the485 /* Parse the file itself. If this fails, then we can discard the
362 * inotify error, since this one will be better.486 * inotify error, since this one will be better.
363 */487 */
364 if (conf_reload_path (source, source->path) < 0) {488 if (conf_reload_path (source, source->path, NULL) < 0) {
365 if (err)489 if (err)
366 nih_free (err);490 nih_free (err);
367491
@@ -382,6 +506,23 @@
382 nih_free (err);506 nih_free (err);
383 }507 }
384508
509 if (! is_conf_file_std (source->path))
510 return 0;
511
512 override_path = toggle_conf_name (NULL, source->path);
513
514 if (stat (override_path, &statbuf) != 0)
515 return 0;
516
517 nih_debug ("Updating configuration for %s from %s",
518 source->path, override_path);
519 if (conf_reload_path (source, source->path, override_path) < 0) {
520 if (err)
521 nih_free (err);
522
523 return -1;
524 }
525
385 return 0;526 return 0;
386}527}
387528
@@ -501,19 +642,18 @@
501 * @is_dir: TRUE of @path is a directory.642 * @is_dir: TRUE of @path is a directory.
502 *643 *
503 * This is the file filter used for the jobs directory, we only care644 * This is the file filter used for the jobs directory, we only care
504 * about paths with the ".conf" extension. Directories that645 * about paths with particular extensions (see IS_CONF_EXT).
505 * match the nih_file_ignore() function are also ignored.646 *
506 *647 * Directories that match the nih_file_ignore() function are also ignored.
507 * Returns: FALSE if @path ends in ".conf", or is the original source,648 *
508 * TRUE otherwise.649 * Returns: FALSE if @path ends in ".conf" or ".override",
650 * or is the original source, TRUE otherwise.
509 **/651 **/
510static int652static int
511conf_dir_filter (ConfSource *source,653conf_dir_filter (ConfSource *source,
512 const char *path,654 const char *path,
513 int is_dir)655 int is_dir)
514{656{
515 char *ptr;
516
517 nih_assert (source != NULL);657 nih_assert (source != NULL);
518 nih_assert (path != NULL);658 nih_assert (path != NULL);
519659
@@ -523,8 +663,7 @@
523 if (is_dir)663 if (is_dir)
524 return nih_file_ignore (NULL, path);664 return nih_file_ignore (NULL, path);
525665
526 ptr = strrchr (path, '.');666 if (is_conf_file (path))
527 if (ptr && (ptr > path) && (ptr[-1] != '/') && (! strcmp (ptr, ".conf")))
528 return FALSE;667 return FALSE;
529668
530 return TRUE;669 return TRUE;
@@ -546,29 +685,92 @@
546 * After checking that it was a regular file that was changed, we reload it;685 * After checking that it was a regular file that was changed, we reload it;
547 * we expect this to fail sometimes since the file may be only partially686 * we expect this to fail sometimes since the file may be only partially
548 * written.687 * written.
549 **/688 **/
550static void689static void
551conf_create_modify_handler (ConfSource *source,690conf_create_modify_handler (ConfSource *source,
552 NihWatch *watch,691 NihWatch *watch,
553 const char *path,692 const char *path,
554 struct stat *statbuf)693 struct stat *statbuf)
555{694{
695 ConfFile *file = NULL;
696 const char *error_path = path;
697 nih_local char *new_path = NULL;
698 int ret;
699
556 nih_assert (source != NULL);700 nih_assert (source != NULL);
557 nih_assert (watch != NULL);701 nih_assert (watch != NULL);
558 nih_assert (path != NULL);702 nih_assert (path != NULL);
559 nih_assert (statbuf != NULL);703 nih_assert (statbuf != NULL);
560704
705 /* note that symbolic links are ignored */
561 if (! S_ISREG (statbuf->st_mode))706 if (! S_ISREG (statbuf->st_mode))
562 return;707 return;
563708
564 if (conf_reload_path (source, path) < 0) {709 new_path = toggle_conf_name (NULL, path);
710 file = (ConfFile *)nih_hash_lookup (source->files, new_path);
711
712 if (is_conf_file_override (path)) {
713 if (! file) {
714 /* override file has no corresponding conf file */
715 nih_debug ("Ignoring orphan override file %s", path);
716 return;
717 }
718
719 /* reload conf file */
720 nih_debug ("Loading configuration file %s", new_path);
721 ret = conf_reload_path (source, new_path, NULL);
722 if (ret < 0) {
723 error_path = new_path;
724 goto error;
725 }
726
727 /* overlay override settings */
728 nih_debug ("Loading override file %s for %s", path, new_path);
729 ret = conf_reload_path (source, new_path, path);
730 if (ret < 0) {
731 error_path = path;
732 goto error;
733 }
734 } else {
735 nih_debug ("Loading configuration and override files for %s", path);
736
737 /* load conf file */
738 nih_debug ("Loading configuration file %s", path);
739 ret = conf_reload_path (source, path, NULL);
740 if (ret < 0) {
741 error_path = path;
742 goto error;
743 }
744
745 /* ensure we ignore directory changes (which won't have overrides. */
746 if (is_conf_file_std (path)) {
747 struct stat st;
748 if (stat (new_path, &st) == 0) {
749 /* overlay override settings */
750 nih_debug ("Loading override file %s for %s", new_path, path);
751 ret = conf_reload_path (source, path, new_path);
752 if (ret < 0) {
753 error_path = new_path;
754 goto error;
755 }
756 }
757
758 }
759 }
760
761 return;
762
763error:
764 {
565 NihError *err;765 NihError *err;
566766
567 err = nih_error_get ();767 err = nih_error_get ();
568 nih_error ("%s: %s: %s", path,768 nih_error ("%s: %s: %s", error_path,
569 _("Error while loading configuration file"),769 _("Error while loading configuration file"),
570 err->message);770 err->message);
571 nih_free (err);771 nih_free (err);
772 if (file)
773 nih_unref (file, source);
572 }774 }
573}775}
574776
@@ -585,13 +787,14 @@
585 *787 *
586 * We lookup the file in our hash table, and if we can find it, perform788 * We lookup the file in our hash table, and if we can find it, perform
587 * the usual deletion of it.789 * the usual deletion of it.
588 **/790 **/
589static void791static void
590conf_delete_handler (ConfSource *source,792conf_delete_handler (ConfSource *source,
591 NihWatch *watch,793 NihWatch *watch,
592 const char *path)794 const char *path)
593{795{
594 ConfFile *file;796 ConfFile *file;
797 nih_local char *new_path = NULL;
595798
596 nih_assert (source != NULL);799 nih_assert (source != NULL);
597 nih_assert (watch != NULL);800 nih_assert (watch != NULL);
@@ -603,7 +806,11 @@
603 * it's probably a directory or something, so just ignore it.806 * it's probably a directory or something, so just ignore it.
604 */807 */
605 file = (ConfFile *)nih_hash_lookup (source->files, path);808 file = (ConfFile *)nih_hash_lookup (source->files, path);
606 if (! file) {809 /* Note we have to be careful to consider deletion of directories too.
810 * This is handled implicitly by the override check which will return
811 * false if passed a directory in this case.
812 */
813 if (! file && ! is_conf_file_override (path)) {
607 if (! strcmp (watch->path, path)) {814 if (! strcmp (watch->path, path)) {
608 nih_warn ("%s: %s", source->path,815 nih_warn ("%s: %s", source->path,
609 _("Configuration directory deleted"));816 _("Configuration directory deleted"));
@@ -614,7 +821,30 @@
614 return;821 return;
615 }822 }
616823
617 nih_unref (file, source);824 /* non-override files (and directories) are the simple case, so handle
825 * them and leave.
826 */
827 if (! is_conf_file_override (path)) {
828 nih_unref (file, source);
829 return;
830 }
831
832 /* if an override file is deleted for which there is a corresponding
833 * conf file, reload the conf file to remove any modifications
834 * introduced by the override file.
835 */
836 new_path = toggle_conf_name (NULL, path);
837 file = (ConfFile *)nih_hash_lookup (source->files, new_path);
838
839 if (file) {
840 nih_debug ("Reloading configuration for %s on deletion of overide (%s)",
841 new_path, path);
842
843 if ( conf_reload_path (source, new_path, NULL) < 0 ) {
844 nih_warn ("%s: %s", new_path,
845 _("Unable to reload configuration after override deletion"));
846 }
847 }
618}848}
619849
620/**850/**
@@ -637,22 +867,61 @@
637 const char *path,867 const char *path,
638 struct stat *statbuf)868 struct stat *statbuf)
639{869{
870 ConfFile *file = NULL;
871 nih_local char *new_path = NULL;
872
640 nih_assert (source != NULL);873 nih_assert (source != NULL);
641 nih_assert (dirname != NULL);874 nih_assert (dirname != NULL);
642 nih_assert (path != NULL);875 nih_assert (path != NULL);
643 nih_assert (statbuf != NULL);876 nih_assert (statbuf != NULL);
644877
878 /* We assume that CONF_EXT_STD files are visited before
879 * CONF_EXT_OVERRIDE files. Happily, this assumption is currently
880 * valid since CONF_EXT_STD comes before CONF_EXT_OVERRIDE if ordered
881 * alphabetically.
882 *
883 * If this were ever to change (for example if we decided to
884 * rename the CONF_EXT_OVERRIDE files to end in ".abc", say), the logic
885 * in this function would be erroneous since it would never be possible when
886 * visiting an override file (before a conf file) to lookup a conf file
887 * in the hash, since the conf file would not yet have been seen and thus would
888 * not exist in the hash (yet).
889 */
890 nih_assert (CONF_EXT_STD[1] < CONF_EXT_OVERRIDE[1]);
891
645 if (! S_ISREG (statbuf->st_mode))892 if (! S_ISREG (statbuf->st_mode))
646 return 0;893 return 0;
647894
648 if (conf_reload_path (source, path) < 0) {895 if (is_conf_file_std (path)) {
649 NihError *err;896 if (conf_reload_path (source, path, NULL) < 0) {
650897 NihError *err;
651 err = nih_error_get ();898
652 nih_error ("%s: %s: %s", path,899 err = nih_error_get ();
653 _("Error while loading configuration file"),900 nih_error ("%s: %s: %s", path,
654 err->message);901 _("Error while loading configuration file"),
655 nih_free (err);902 err->message);
903 nih_free (err);
904 }
905 return 0;
906 }
907
908 new_path = toggle_conf_name (NULL, path);
909 file = (ConfFile *)nih_hash_lookup (source->files, new_path);
910
911 if (file) {
912 /* we're visiting an override file with an associated conf file that
913 * has already been loaded, so just overlay the override file. If
914 * there is no corresponding conf file, we ignore the override file.
915 */
916 if (conf_reload_path (source, new_path, path) < 0) {
917 NihError *err;
918
919 err = nih_error_get ();
920 nih_error ("%s: %s: %s", new_path,
921 _("Error while reloading configuration file"),
922 err->message);
923 nih_free (err);
924 }
656 }925 }
657926
658 return 0;927 return 0;
@@ -662,16 +931,20 @@
662/**931/**
663 * conf_reload_path:932 * conf_reload_path:
664 * @source: configuration source,933 * @source: configuration source,
665 * @path: path of file to be reloaded.934 * @path: path of conf file to be reloaded.
935 * @override_path: if not NULL and @path refers to a path associated with @source,
936 * overlay the contents of @path into the existing @source entry for
937 * @path. If FALSE, discard any existing knowledge of @path.
666 *938 *
667 * This function is used to parse the file at @path in the context of the939 * This function is used to parse the file at @path (or @override_path) in the
668 * given configuration @source. Necessary ConfFile structures are allocated940 * context of the given configuration @source. Necessary ConfFile structures
669 * and attached to @source as appropriate. CONF_FILE sources always have941 * are allocated and attached to @source as appropriate. CONF_FILE sources
670 * a single ConfFile when the file exists.942 * always have a single ConfFile when the file exists.
671 *943 *
672 * If the file has been parsed before, then the existing item is deleted and944 * If the file has been parsed before, then the existing item is deleted and
673 * freed if the file fails to load, or after the new item has been parsed.945 * freed if the file fails to load, or after the new item has been parsed.
674 * Items are not reused between reloads.946 * Items are only reused between reloads if @override_path is
947 * non-NULL.
675 *948 *
676 * Physical errors are returned, parse errors are not.949 * Physical errors are returned, parse errors are not.
677 *950 *
@@ -679,36 +952,47 @@
679 **/952 **/
680static int953static int
681conf_reload_path (ConfSource *source,954conf_reload_path (ConfSource *source,
682 const char *path)955 const char *path,
956 const char *override_path)
683{957{
684 ConfFile *file;958 ConfFile *file = NULL;
685 nih_local char *buf = NULL;959 nih_local char *buf = NULL;
686 const char *start, *end;960 const char *start, *end;
687 nih_local char *name = NULL;961 nih_local char *name = NULL;
688 size_t len, pos, lineno;962 size_t len, pos, lineno;
689 NihError *err = NULL;963 NihError *err = NULL;
964 const char *path_to_load;
690965
691 nih_assert (source != NULL);966 nih_assert (source != NULL);
692 nih_assert (path != NULL);967 nih_assert (path != NULL);
693968
694 /* Look up the old file in memory, and then free it. In cases969 path_to_load = (override_path ? override_path : path);
695 * of failure, we discard it anyway, so there's no particular reason970
971 /* If there is no corresponding override file, look up the old
972 * conf file in memory, and then free it. In cases of failure,
973 * we discard it anyway, so there's no particular reason
696 * to keep it around anymore.974 * to keep it around anymore.
975 *
976 * Note: if @override_path has been specified, do not
977 * free the file if found, since we want to _update_ the
978 * existing entry.
697 */979 */
698 file = (ConfFile *)nih_hash_lookup (source->files, path);980 file = (ConfFile *)nih_hash_lookup (source->files, path);
699 if (file)981 if (! override_path && file)
700 nih_unref (file, source);982 nih_unref (file, source);
701983
702 /* Read the file into memory for parsing, if this fails we don't984 /* Read the file into memory for parsing, if this fails we don't
703 * bother creating a new ConfFile structure for it and bail out985 * bother creating a new ConfFile structure for it and bail out
704 * now.986 * now.
705 */987 */
706 buf = nih_file_read (NULL, path, &len);988 buf = nih_file_read (NULL, path_to_load, &len);
707 if (! buf)989 if (! buf)
708 return -1;990 return -1;
709991
710 /* Parse the file, storing the item in a new ConfFile structure. */992 /* Create a new ConfFile structure (if no @override_path specified) */
711 file = NIH_MUST (conf_file_new (source, path));993 file = (ConfFile *)nih_hash_lookup (source->files, path);
994 if (! file)
995 file = NIH_MUST (conf_file_new (source, path));
712996
713 pos = 0;997 pos = 0;
714 lineno = 1;998 lineno = 1;
@@ -717,7 +1001,14 @@
717 case CONF_FILE:1001 case CONF_FILE:
718 case CONF_DIR:1002 case CONF_DIR:
719 /* Simple file of options; usually no item attached to it. */1003 /* Simple file of options; usually no item attached to it. */
720 nih_debug ("Loading configuration from %s", path);1004 if (override_path) {
1005 nih_debug ("Updating configuration for %s from %s",
1006 path, override_path);
1007 } else {
1008 nih_debug ("Loading configuration from %s %s",
1009 (source->type == CONF_DIR ? "directory" : "file"), path);
1010 }
1011
721 if (parse_conf (file, buf, len, &pos, &lineno) < 0)1012 if (parse_conf (file, buf, len, &pos, &lineno) < 0)
722 err = nih_error_get ();1013 err = nih_error_get ();
7231014
@@ -735,7 +1026,7 @@
735 start++;1026 start++;
7361027
737 end = strrchr (start, '.');1028 end = strrchr (start, '.');
738 if (end && (! strcmp (end, ".conf"))) {1029 if (end && IS_CONF_EXT (end)) {
739 name = NIH_MUST (nih_strndup (NULL, start, end - start));1030 name = NIH_MUST (nih_strndup (NULL, start, end - start));
740 } else {1031 } else {
741 name = NIH_MUST (nih_strdup (NULL, start));1032 name = NIH_MUST (nih_strdup (NULL, start));
@@ -744,8 +1035,16 @@
744 /* Create a new job item and parse the buffer to produce1035 /* Create a new job item and parse the buffer to produce
745 * the job definition.1036 * the job definition.
746 */1037 */
747 nih_debug ("Loading %s from %s", name, path);1038 if (override_path) {
748 file->job = parse_job (NULL, name, buf, len, &pos, &lineno);1039 nih_debug ("Updating %s (%s) with %s",
1040 name, path, override_path);
1041 } else {
1042 nih_debug ("Loading %s from %s", name, path);
1043 }
1044
1045 file->job = parse_job (NULL, source->session, file->job,
1046 name, buf, len, &pos, &lineno);
1047
749 if (file->job) {1048 if (file->job) {
750 job_class_consider (file->job);1049 job_class_consider (file->job);
751 } else {1050 } else {
@@ -779,7 +1078,7 @@
779 case PARSE_EXPECTED_OPERATOR:1078 case PARSE_EXPECTED_OPERATOR:
780 case PARSE_EXPECTED_VARIABLE:1079 case PARSE_EXPECTED_VARIABLE:
781 case PARSE_MISMATCHED_PARENS:1080 case PARSE_MISMATCHED_PARENS:
782 nih_error ("%s:%zi: %s", path, lineno, err->message);1081 nih_error ("%s:%zi: %s", path_to_load, lineno, err->message);
783 nih_free (err);1082 nih_free (err);
784 err = NULL;1083 err = NULL;
785 break;1084 break;
@@ -849,7 +1148,8 @@
8491148
850/**1149/**
851 * conf_select_job:1150 * conf_select_job:
852 * @name: name of job class to locate.1151 * @name: name of job class to locate,
1152 * @session: session class name belongs to.
853 *1153 *
854 * Select the best available class of a job named @name from the registered1154 * Select the best available class of a job named @name from the registered
855 * configuration sources.1155 * configuration sources.
@@ -857,7 +1157,7 @@
857 * Returns: Best available job class or NULL if none available.1157 * Returns: Best available job class or NULL if none available.
858 **/1158 **/
859JobClass *1159JobClass *
860conf_select_job (const char *name)1160conf_select_job (const char *name, const Session *session)
861{1161{
862 nih_assert (name != NULL);1162 nih_assert (name != NULL);
8631163
@@ -869,6 +1169,9 @@
869 if (source->type != CONF_JOB_DIR)1169 if (source->type != CONF_JOB_DIR)
870 continue;1170 continue;
8711171
1172 if (source->session != session)
1173 continue;
1174
872 NIH_HASH_FOREACH (source->files, file_iter) {1175 NIH_HASH_FOREACH (source->files, file_iter) {
873 ConfFile *file = (ConfFile *)file_iter;1176 ConfFile *file = (ConfFile *)file_iter;
8741177
@@ -882,3 +1185,149 @@
8821185
883 return NULL;1186 return NULL;
884}1187}
1188
1189#ifdef DEBUG
1190
1191size_t
1192debug_count_list_entries (const NihList *list)
1193{
1194 size_t i = 0;
1195 NIH_LIST_FOREACH (list, iter) {
1196 i++;
1197 }
1198 return i;
1199}
1200
1201size_t
1202debug_count_hash_entries (const NihHash *hash)
1203{
1204 size_t i = 0;
1205 NIH_HASH_FOREACH_SAFE (hash, iter) {
1206 i++;
1207 }
1208 return i;
1209}
1210
1211void
1212debug_show_job_class (const JobClass *job)
1213{
1214 int i;
1215 char **env = (char **)job->env;
1216 char **export = (char **)job->export;
1217
1218 nih_assert (job);
1219
1220 nih_debug ("JobClass %p: name='%s', path='%s', task=%d, "
1221 "respawn=%d, console=%x, deleted=%d, debug=%d",
1222 job, job->name, job->path, job->task,
1223 job->respawn, job->console, job->deleted, job->debug);
1224
1225 nih_debug ("\tstart_on=%p, stop_on=%p, emits=%p, process=%p",
1226 job->start_on, job->stop_on, job->emits, job->process);
1227
1228 nih_debug ("\tauthor='%s', description='%s'",
1229 job->author, job->description);
1230
1231 if (env && *env) {
1232 nih_debug ("\tenv:");
1233 i = 0;
1234 while ( *env ) {
1235 nih_debug ("\t\tenv[%d]='%s' (len=%u+1)",
1236 i, *env, strlen (*env));
1237 env++;
1238 ++i;
1239 }
1240 } else {
1241 nih_debug ("\tenv: none.");
1242 }
1243
1244
1245 if (export && *export) {
1246 nih_debug ("\texport:");
1247 i = 0;
1248 while ( *export ) {
1249 nih_debug ("\t\tenv[%d]='%s' (len=%u+1)",
1250 i, *export, strlen (*export));
1251 export++;
1252 ++i;
1253 }
1254 }
1255 else {
1256 nih_debug ("\texport: none");
1257 }
1258}
1259
1260void
1261debug_show_job_classes (void)
1262{
1263 nih_debug ("job_classes:");
1264
1265 NIH_HASH_FOREACH_SAFE (job_classes, iter) {
1266 JobClass *job = (JobClass *)iter;
1267 debug_show_job_class (job);
1268 }
1269}
1270
1271void
1272debug_show_event (const Event *event)
1273{
1274 nih_assert (event);
1275
1276 nih_debug ("Event %p: name='%s', progress=%x, failed=%d, "
1277 "blockers=%d, blocking=%p",
1278 event, event->name, event->progress, event->failed,
1279 event->blockers, (void *)&event->blocking);
1280}
1281
1282void
1283debug_show_conf_file (const ConfFile *file)
1284{
1285 nih_assert (file);
1286
1287 nih_debug ("ConfFile %p: path='%s', source=%p, flag=%x, job=%p",
1288 file, file->path, file->source, file->flag, file->job);
1289
1290 /* Some ConfFile objects won't have any JobClass details, for example,
1291 * the ConfFile object associated with "/etc/init.conf".
1292 */
1293 if (! file->job) {
1294 nih_debug ("ConfFile %p: job: no JobClass object.", file);
1295 return;
1296 }
1297
1298 nih_debug ("ConfFile %p: job:", file);
1299 debug_show_job_class (file->job);
1300}
1301
1302void
1303debug_show_conf_source (const ConfSource *source)
1304{
1305 nih_assert (source);
1306
1307 nih_debug ("ConfSource %p: path='%s', type=%x, flag=%x",
1308 source, source->path, source->type, source->flag);
1309
1310 nih_debug ("ConfSource %p files (%d):", source,
1311 debug_count_hash_entries (source->files));
1312
1313 NIH_HASH_FOREACH (source->files, file_iter) {
1314 ConfFile *file = (ConfFile *)file_iter;
1315 debug_show_conf_file (file);
1316 }
1317}
1318
1319void
1320debug_show_conf_sources (void)
1321{
1322 nih_assert (conf_sources);
1323
1324 nih_debug ("conf_sources:");
1325
1326 NIH_LIST_FOREACH (conf_sources, iter) {
1327 ConfSource *source = (ConfSource *)iter;
1328 debug_show_conf_source (source);
1329 }
1330}
1331
1332#endif /* DEBUG */
1333
8851334
=== modified file 'init/conf.h'
--- init/conf.h 2009-07-09 08:36:52 +0000
+++ init/conf.h 2011-10-14 11:09:18 +0000
@@ -1,6 +1,6 @@
1/* upstart1/* upstart
2 *2 *
3 * Copyright © 2009 Canonical Ltd.3 * Copyright © 2010,2011 Canonical Ltd.
4 * Author: Scott James Remnant <scott@netsplit.com>.4 * Author: Scott James Remnant <scott@netsplit.com>.
5 *5 *
6 * This program is free software; you can redistribute it and/or modify6 * This program is free software; you can redistribute it and/or modify
@@ -26,6 +26,7 @@
26#include <nih/list.h>26#include <nih/list.h>
27#include <nih/watch.h>27#include <nih/watch.h>
2828
29#include "session.h"
29#include "job_class.h"30#include "job_class.h"
3031
3132
@@ -47,6 +48,7 @@
47/**48/**
48 * ConfSource:49 * ConfSource:
49 * @entry: list header,50 * @entry: list header,
51 * @session: attached session,
50 * @path: path to source,52 * @path: path to source,
51 * @type: type of source,53 * @type: type of source,
52 * @watch: NihWatch structure for automatic change notification,54 * @watch: NihWatch structure for automatic change notification,
@@ -64,6 +66,7 @@
64 **/66 **/
65typedef struct conf_source {67typedef struct conf_source {
66 NihList entry;68 NihList entry;
69 Session * session;
67 char *path;70 char *path;
68 ConfSourceType type;71 ConfSourceType type;
6972
@@ -122,7 +125,47 @@
122125
123int conf_file_destroy (ConfFile *file);126int conf_file_destroy (ConfFile *file);
124127
125JobClass * conf_select_job (const char *name);128JobClass * conf_select_job (const char *name, const Session *session);
129
130char *toggle_conf_name (const void *parent, const char *path)
131 __attribute__ ((warn_unused_result, malloc));
132
133#ifdef DEBUG
134
135/* used for debugging only */
136
137size_t
138debug_count_hash_entries (const NihHash *hash);
139
140size_t
141debug_count_list_entries (const NihList *list)
142 __attribute__ ((unused));
143
144void
145debug_show_job_class (const JobClass *job)
146 __attribute__ ((unused));
147
148void
149debug_show_job_classes (void)
150 __attribute__ ((unused));
151
152void
153debug_show_event (const Event *event)
154 __attribute__ ((unused));
155
156void
157debug_show_conf_file(const ConfFile *file)
158 __attribute__ ((unused));
159
160void
161debug_show_conf_source(const ConfSource *source)
162 __attribute__ ((unused));
163
164void
165debug_show_conf_sources(void)
166 __attribute__ ((unused));
167
168#endif
126169
127NIH_END_EXTERN170NIH_END_EXTERN
128171
129172
=== modified file 'init/control.c'
--- init/control.c 2009-07-11 11:47:12 +0000
+++ init/control.c 2011-10-14 11:09:18 +0000
@@ -2,7 +2,7 @@
2 *2 *
3 * control.c - D-Bus connections, objects and methods3 * control.c - D-Bus connections, objects and methods
4 *4 *
5 * Copyright © 2009 Canonical Ltd.5 * Copyright © 2009-2011 Canonical Ltd.
6 * Author: Scott James Remnant <scott@netsplit.com>.6 * Author: Scott James Remnant <scott@netsplit.com>.
7 *7 *
8 * This program is free software; you can redistribute it and/or modify8 * This program is free software; you can redistribute it and/or modify
@@ -25,8 +25,10 @@
2525
26#include <dbus/dbus.h>26#include <dbus/dbus.h>
2727
28#include <fcntl.h>
28#include <stdio.h>29#include <stdio.h>
29#include <string.h>30#include <string.h>
31#include <unistd.h>
3032
31#include <nih/macros.h>33#include <nih/macros.h>
32#include <nih/alloc.h>34#include <nih/alloc.h>
@@ -46,6 +48,7 @@
46#include "dbus/upstart.h"48#include "dbus/upstart.h"
4749
48#include "environ.h"50#include "environ.h"
51#include "session.h"
49#include "job_class.h"52#include "job_class.h"
50#include "blocked.h"53#include "blocked.h"
51#include "conf.h"54#include "conf.h"
@@ -54,12 +57,19 @@
5457
55#include "com.ubuntu.Upstart.h"58#include "com.ubuntu.Upstart.h"
5659
57
58/* Prototypes for static functions */60/* Prototypes for static functions */
59static int control_server_connect (DBusServer *server, DBusConnection *conn);61static int control_server_connect (DBusServer *server, DBusConnection *conn);
60static void control_disconnected (DBusConnection *conn);62static void control_disconnected (DBusConnection *conn);
61static void control_register_all (DBusConnection *conn);63static void control_register_all (DBusConnection *conn);
6264
65/**
66 * use_session_bus:
67 *
68 * If TRUE, connect to the D-Bus session bus rather than the system bus.
69 *
70 * Used for testing.
71 **/
72int use_session_bus = FALSE;
6373
64/**74/**
65 * control_server_address:75 * control_server_address:
@@ -78,7 +88,7 @@
78/**88/**
79 * control_bus:89 * control_bus:
80 *90 *
81 * Open connection to D-Bus system bus. The connection may be opened with91 * Open connection to a D-Bus bus. The connection may be opened with
82 * control_bus_open() and if lost will become NULL.92 * control_bus_open() and if lost will become NULL.
83 **/93 **/
84DBusConnection *control_bus = NULL;94DBusConnection *control_bus = NULL;
@@ -86,7 +96,7 @@
86/**96/**
87 * control_conns:97 * control_conns:
88 *98 *
89 * Open control connections, including the connection to the D-Bus system99 * Open control connections, including the connection to a D-Bus
90 * bus and any private client connections.100 * bus and any private client connections.
91 **/101 **/
92NihList *control_conns = NULL;102NihList *control_conns = NULL;
@@ -190,8 +200,9 @@
190/**200/**
191 * control_bus_open:201 * control_bus_open:
192 *202 *
193 * Open a connection to the D-Bus system bus and store it in the control_bus203 * Open a connection to the appropriate D-Bus bus and store it in the
194 * global. The connection is handled automatically in the main loop.204 * control_bus global. The connection is handled automatically
205 * in the main loop.
195 *206 *
196 * Returns: zero on success, negative value on raised error.207 * Returns: zero on success, negative value on raised error.
197 **/208 **/
@@ -207,10 +218,13 @@
207218
208 control_init ();219 control_init ();
209220
221 control_handle_bus_type ();
222
210 /* Connect to the D-Bus System Bus and hook everything up into223 /* Connect to the D-Bus System Bus and hook everything up into
211 * our own main loop automatically.224 * our own main loop automatically.
212 */225 */
213 conn = nih_dbus_bus (DBUS_BUS_SYSTEM, control_disconnected);226 conn = nih_dbus_bus (use_session_bus ? DBUS_BUS_SESSION : DBUS_BUS_SYSTEM,
227 control_disconnected);
214 if (! conn)228 if (! conn)
215 return -1;229 return -1;
216230
@@ -382,7 +396,9 @@
382 const char *name,396 const char *name,
383 char **job)397 char **job)
384{398{
385 JobClass *class;399 Session *session;
400 JobClass *class = NULL;
401 JobClass *global_class = NULL;
386402
387 nih_assert (message != NULL);403 nih_assert (message != NULL);
388 nih_assert (name != NULL);404 nih_assert (name != NULL);
@@ -397,8 +413,30 @@
397 return -1;413 return -1;
398 }414 }
399415
400 /* Lookup the job and copy its path into the reply */416 /* Get the relevant session */
401 class = (JobClass *)nih_hash_lookup (job_classes, name);417 session = session_from_dbus (NULL, message);
418
419 /* Lookup the job */
420 class = (JobClass *)nih_hash_search (job_classes, name, NULL);
421
422 while (class && (class->session != session)) {
423
424 /* Found a match in the global session which may be used
425 * later if no matching user session job exists.
426 */
427 if ((! class->session) && (session && ! session->chroot))
428 global_class = class;
429
430 class = (JobClass *)nih_hash_search (job_classes, name,
431 &class->entry);
432 }
433
434 /* If no job with the given name exists in the appropriate
435 * session, look in the global namespace (aka the NULL session).
436 */
437 if (! class)
438 class = global_class;
439
402 if (! class) {440 if (! class) {
403 nih_dbus_error_raise_printf (441 nih_dbus_error_raise_printf (
404 DBUS_INTERFACE_UPSTART ".Error.UnknownJob",442 DBUS_INTERFACE_UPSTART ".Error.UnknownJob",
@@ -406,6 +444,7 @@
406 return -1;444 return -1;
407 }445 }
408446
447 /* Copy the path */
409 *job = nih_strdup (message, class->path);448 *job = nih_strdup (message, class->path);
410 if (! *job)449 if (! *job)
411 nih_return_system_error (-1);450 nih_return_system_error (-1);
@@ -432,6 +471,7 @@
432 NihDBusMessage *message,471 NihDBusMessage *message,
433 char ***jobs)472 char ***jobs)
434{473{
474 Session *session;
435 char **list;475 char **list;
436 size_t len;476 size_t len;
437477
@@ -445,9 +485,16 @@
445 if (! list)485 if (! list)
446 nih_return_system_error (-1);486 nih_return_system_error (-1);
447487
488 /* Get the relevant session */
489 session = session_from_dbus (NULL, message);
490
448 NIH_HASH_FOREACH (job_classes, iter) {491 NIH_HASH_FOREACH (job_classes, iter) {
449 JobClass *class = (JobClass *)iter;492 JobClass *class = (JobClass *)iter;
450493
494 if ((class->session || (session && session->chroot))
495 && (class->session != session))
496 continue;
497
451 if (! nih_str_array_add (&list, message, &len,498 if (! nih_str_array_add (&list, message, &len,
452 class->path)) {499 class->path)) {
453 nih_error_raise_system ();500 nih_error_raise_system ();
@@ -462,13 +509,24 @@
462}509}
463510
464511
512int
513control_emit_event (void *data,
514 NihDBusMessage *message,
515 const char *name,
516 char * const *env,
517 int wait)
518{
519 return control_emit_event_with_file (data, message, name, env, wait, -1);
520}
521
465/**522/**
466 * control_emit_event:523 * control_emit_event_with_file:
467 * @data: not used,524 * @data: not used,
468 * @message: D-Bus connection and message received,525 * @message: D-Bus connection and message received,
469 * @name: name of event to emit,526 * @name: name of event to emit,
470 * @env: environment of environment,527 * @env: environment of environment,
471 * @wait: whether to wait for event completion before returning.528 * @wait: whether to wait for event completion before returning,
529 * @file: file descriptor.
472 *530 *
473 * Implements the top half of the EmitEvent method of the com.ubuntu.Upstart531 * Implements the top half of the EmitEvent method of the com.ubuntu.Upstart
474 * interface, the bottom half may be found in event_finished().532 * interface, the bottom half may be found in event_finished().
@@ -488,11 +546,12 @@
488 * Returns: zero on success, negative value on raised error.546 * Returns: zero on success, negative value on raised error.
489 **/547 **/
490int548int
491control_emit_event (void *data,549control_emit_event_with_file (void *data,
492 NihDBusMessage *message,550 NihDBusMessage *message,
493 const char *name,551 const char *name,
494 char * const *env,552 char * const *env,
495 int wait)553 int wait,
554 int file)
496{555{
497 Event *event;556 Event *event;
498 Blocked *blocked;557 Blocked *blocked;
@@ -505,6 +564,7 @@
505 if (! strlen (name)) {564 if (! strlen (name)) {
506 nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,565 nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
507 _("Name may not be empty string"));566 _("Name may not be empty string"));
567 close (file);
508 return -1;568 return -1;
509 }569 }
510570
@@ -512,19 +572,36 @@
512 if (! environ_all_valid (env)) {572 if (! environ_all_valid (env)) {
513 nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,573 nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
514 _("Env must be KEY=VALUE pairs"));574 _("Env must be KEY=VALUE pairs"));
575 close (file);
515 return -1;576 return -1;
516 }577 }
517578
518 /* Make the event and block the message on it */579 /* Make the event and block the message on it */
519 event = event_new (NULL, name, (char **)env);580 event = event_new (NULL, name, (char **)env);
520 if (! event)581 if (! event) {
521 nih_return_system_error (-1);582 nih_error_raise_system ();
583 close (file);
584 return -1;
585 }
586
587 event->fd = file;
588 if (event->fd >= 0) {
589 long flags;
590
591 flags = fcntl (event->fd, F_GETFD);
592 flags &= ~FD_CLOEXEC;
593 fcntl (event->fd, F_SETFD, flags);
594 }
595
596 /* Obtain the session */
597 event->session = session_from_dbus (NULL, message);
522598
523 if (wait) {599 if (wait) {
524 blocked = blocked_new (event, BLOCKED_EMIT_METHOD, message);600 blocked = blocked_new (event, BLOCKED_EMIT_METHOD, message);
525 if (! blocked) {601 if (! blocked) {
526 nih_error_raise_system ();602 nih_error_raise_system ();
527 nih_free (event);603 nih_free (event);
604 close (file);
528 return -1;605 return -1;
529 }606 }
530607
@@ -669,3 +746,18 @@
669746
670 return 0;747 return 0;
671}748}
749
750/**
751 * control_handle_bus_type:
752 *
753 * Determine D-Bus bus type to connect to.
754 **/
755void
756control_handle_bus_type (void)
757{
758 if (getenv (USE_SESSION_BUS_ENV))
759 use_session_bus = TRUE;
760
761 if (use_session_bus)
762 nih_debug ("Using session bus");
763}
672764
=== modified file 'init/control.h'
--- init/control.h 2009-07-09 08:36:52 +0000
+++ init/control.h 2011-10-14 11:09:18 +0000
@@ -1,6 +1,6 @@
1/* upstart1/* upstart
2 *2 *
3 * Copyright © 2009 Canonical Ltd.3 * Copyright © 2009-2011 Canonical Ltd.
4 * Author: Scott James Remnant <scott@netsplit.com>.4 * Author: Scott James Remnant <scott@netsplit.com>.
5 *5 *
6 * This program is free software; you can redistribute it and/or modify6 * This program is free software; you can redistribute it and/or modify
@@ -27,6 +27,18 @@
27#include <nih-dbus/dbus_connection.h>27#include <nih-dbus/dbus_connection.h>
28#include <nih-dbus/dbus_message.h>28#include <nih-dbus/dbus_message.h>
2929
30/**
31 * USE_SESSION_BUS_ENV:
32 *
33 * If this environment variable is set to any value, connect to
34 * D-Bus session bus rather than the system bus.
35 *
36 * Used for testing.
37 **/
38#ifndef USE_SESSION_BUS_ENV
39#define USE_SESSION_BUS_ENV "UPSTART_USE_SESSION_BUS"
40#endif
41
3042
31NIH_BEGIN_EXTERN43NIH_BEGIN_EXTERN
3244
@@ -60,6 +72,10 @@
60 const char *name, char * const *env,72 const char *name, char * const *env,
61 int wait)73 int wait)
62 __attribute__ ((warn_unused_result));74 __attribute__ ((warn_unused_result));
75int control_emit_event_with_file (void *data, NihDBusMessage *message,
76 const char *name, char * const *env,
77 int wait, int file)
78 __attribute__ ((warn_unused_result));
6379
64int control_get_version (void *data, NihDBusMessage *message,80int control_get_version (void *data, NihDBusMessage *message,
65 char **version)81 char **version)
@@ -72,6 +88,8 @@
72 const char *log_priority)88 const char *log_priority)
73 __attribute__ ((warn_unused_result));89 __attribute__ ((warn_unused_result));
7490
91void control_handle_bus_type (void);
92
75NIH_END_EXTERN93NIH_END_EXTERN
7694
77#endif /* INIT_CONTROL_H */95#endif /* INIT_CONTROL_H */
7896
=== modified file 'init/environ.c'
--- init/environ.c 2011-03-16 22:42:48 +0000
+++ init/environ.c 2011-10-14 11:09:18 +0000
@@ -2,7 +2,6 @@
2 *2 *
3 * environ.c - environment table utilities3 * environ.c - environment table utilities
4 *4 *
5 * Copyright © 2011 Google Inc.
6 * Copyright © 2009 Canonical Ltd.5 * Copyright © 2009 Canonical Ltd.
7 * Author: Scott James Remnant <scott@netsplit.com>.6 * Author: Scott James Remnant <scott@netsplit.com>.
8 *7 *
98
=== modified file 'init/environ.h'
--- init/environ.h 2011-03-16 22:42:48 +0000
+++ init/environ.h 2011-10-14 11:09:18 +0000
@@ -1,6 +1,5 @@
1/* upstart1/* upstart
2 *2 *
3 * Copyright © 2011 Google Inc.
4 * Copyright © 2009 Canonical Ltd.3 * Copyright © 2009 Canonical Ltd.
5 * Author: Scott James Remnant <scott@netsplit.com>.4 * Author: Scott James Remnant <scott@netsplit.com>.
6 *5 *
76
=== modified file 'init/event.c'
--- init/event.c 2010-12-14 15:32:41 +0000
+++ init/event.c 2011-10-14 11:09:18 +0000
@@ -25,6 +25,7 @@
2525
2626
27#include <string.h>27#include <string.h>
28#include <unistd.h>
2829
29#include <nih/macros.h>30#include <nih/macros.h>
30#include <nih/alloc.h>31#include <nih/alloc.h>
@@ -123,6 +124,9 @@
123124
124 nih_list_init (&event->entry);125 nih_list_init (&event->entry);
125126
127 event->session = NULL;
128 event->fd = -1;
129
126 event->progress = EVENT_PENDING;130 event->progress = EVENT_PENDING;
127 event->failed = FALSE;131 event->failed = FALSE;
128132
@@ -293,6 +297,13 @@
293 NIH_HASH_FOREACH_SAFE (job_classes, iter) {297 NIH_HASH_FOREACH_SAFE (job_classes, iter) {
294 JobClass *class = (JobClass *)iter;298 JobClass *class = (JobClass *)iter;
295299
300 /* Only affect jobs within the same session as the event
301 * unless the event has no session, in which case do them
302 * all.
303 */
304 if (event->session && (class->session != event->session))
305 continue;
306
296 /* We stop first so that if an event is listed both as a307 /* We stop first so that if an event is listed both as a
297 * stop and start event, it causes an active running process308 * stop and start event, it causes an active running process
298 * to be killed, the stop script then the start script to be309 * to be killed, the stop script then the start script to be
@@ -393,8 +404,16 @@
393 job->start_env = env;404 job->start_env = env;
394 nih_ref (job->start_env, job);405 nih_ref (job->start_env, job);
395406
407 nih_discard (env);
408 env = NULL;
409
396 job_finished (job, FALSE);410 job_finished (job, FALSE);
397411
412 NIH_MUST (event_operator_fds (class->start_on, job,
413 &job->fds, &job->num_fds,
414 &job->start_env, &len,
415 "UPSTART_FDS"));
416
398 event_operator_events (job->class->start_on,417 event_operator_events (job->class->start_on,
399 job, &job->blocking);418 job, &job->blocking);
400419
@@ -459,6 +478,8 @@
459 nih_free (blocked);478 nih_free (blocked);
460 }479 }
461480
481 close (event->fd);
482
462 if (event->failed) {483 if (event->failed) {
463 char *name;484 char *name;
464485
@@ -470,6 +491,7 @@
470 failed = NIH_MUST (nih_sprintf (NULL, "%s/failed",491 failed = NIH_MUST (nih_sprintf (NULL, "%s/failed",
471 event->name));492 event->name));
472 new_event = NIH_MUST (event_new (NULL, failed, NULL));493 new_event = NIH_MUST (event_new (NULL, failed, NULL));
494 new_event->session = event->session;
473495
474 if (event->env)496 if (event->env)
475 new_event->env = NIH_MUST (nih_str_array_copy (497 new_event->env = NIH_MUST (nih_str_array_copy (
476498
=== modified file 'init/event.h'
--- init/event.h 2009-07-09 08:36:52 +0000
+++ init/event.h 2011-10-14 11:09:18 +0000
@@ -1,6 +1,6 @@
1/* upstart1/* upstart
2 *2 *
3 * Copyright © 2009 Canonical Ltd.3 * Copyright © 2010 Canonical Ltd.
4 * Author: Scott James Remnant <scott@netsplit.com>.4 * Author: Scott James Remnant <scott@netsplit.com>.
5 *5 *
6 * This program is free software; you can redistribute it and/or modify6 * This program is free software; you can redistribute it and/or modify
@@ -23,6 +23,8 @@
23#include <nih/macros.h>23#include <nih/macros.h>
24#include <nih/list.h>24#include <nih/list.h>
2525
26#include "session.h"
27
2628
27/**29/**
28 * EventProgress:30 * EventProgress:
@@ -40,6 +42,7 @@
40/**42/**
41 * Event:43 * Event:
42 * @entry: list header,44 * @entry: list header,
45 * @session: session the event is attached to,
43 * @name: string name of the event,46 * @name: string name of the event,
44 * @env: NULL-terminated array of environment variables,47 * @env: NULL-terminated array of environment variables,
45 * @progress: progress of event,48 * @progress: progress of event,
@@ -61,8 +64,10 @@
61typedef struct event {64typedef struct event {
62 NihList entry;65 NihList entry;
6366
67 Session * session;
64 char *name;68 char *name;
65 char **env;69 char **env;
70 int fd;
6671
67 EventProgress progress;72 EventProgress progress;
68 int failed;73 int failed;
6974
=== modified file 'init/event_operator.c'
--- init/event_operator.c 2010-11-19 14:34:51 +0000
+++ init/event_operator.c 2011-10-14 11:09:18 +0000
@@ -552,6 +552,65 @@
552 return *env;552 return *env;
553}553}
554554
555int *
556event_operator_fds (EventOperator *root,
557 const void *parent,
558 int **fds,
559 size_t *num_fds,
560 char ***env,
561 size_t *len,
562 const char *key)
563{
564 nih_local char *evlist = NULL;
565
566 nih_assert (root != NULL);
567 nih_assert (fds != NULL);
568 nih_assert (num_fds != NULL);
569 nih_assert (env != NULL);
570 nih_assert (len != NULL);
571 nih_assert (key != NULL);
572
573 /* Initialise the event list variable with the name given. */
574 evlist = nih_sprintf (NULL, "%s=", key);
575 if (! evlist)
576 return NULL;
577
578 *num_fds = 0;
579 NIH_TREE_FOREACH_FULL (&root->node, iter,
580 (NihTreeFilter)event_operator_filter, NULL) {
581 EventOperator *oper = (EventOperator *)iter;
582
583 if (oper->type != EVENT_MATCH)
584 continue;
585
586 nih_assert (oper->event != NULL);
587
588 if (oper->event->fd >= 0) {
589 *fds = nih_realloc (*fds, parent, sizeof (int) * (*num_fds + 1));
590 if (! *fds)
591 return NULL;
592
593 (*fds)[(*num_fds)++] = oper->event->fd;
594
595 if (evlist[strlen (evlist) - 1] != '=') {
596 if (! nih_strcat_sprintf (&evlist, NULL, " %d",
597 oper->event->fd))
598 return NULL;
599 } else {
600 if (! nih_strcat_sprintf (&evlist, NULL, "%d",
601 oper->event->fd))
602 return NULL;
603 }
604 }
605 }
606
607 if (*num_fds)
608 if (! environ_add (env, parent, len, TRUE, evlist))
609 return NULL;
610
611 return (void *)1;
612}
613
555/**614/**
556 * event_operator_events:615 * event_operator_events:
557 * @root: operator tree to collect from,616 * @root: operator tree to collect from,
558617
=== modified file 'init/event_operator.h'
--- init/event_operator.h 2009-06-23 09:29:35 +0000
+++ init/event_operator.h 2011-10-14 11:09:18 +0000
@@ -95,6 +95,14 @@
95char ** event_operator_environment (EventOperator *root, char ***env,95char ** event_operator_environment (EventOperator *root, char ***env,
96 const void *parent, size_t *len,96 const void *parent, size_t *len,
97 const char *key);97 const char *key);
98int *
99event_operator_fds (EventOperator *root,
100 const void *parent,
101 int **fds,
102 size_t *num_fds,
103 char ***env,
104 size_t *len,
105 const char *key);
98void event_operator_events (EventOperator *root,106void event_operator_events (EventOperator *root,
99 const void *parent, NihList *list);107 const void *parent, NihList *list);
100108
101109
=== modified file 'init/job.c'
--- init/job.c 2010-12-14 15:32:41 +0000
+++ init/job.c 2011-10-14 11:09:18 +0000
@@ -2,7 +2,7 @@
2 *2 *
3 * job.c - core state machine of tasks and services3 * job.c - core state machine of tasks and services
4 *4 *
5 * Copyright © 2010 Canonical Ltd.5 * Copyright © 2010,2011 Canonical Ltd.
6 * Author: Scott James Remnant <scott@netsplit.com>.6 * Author: Scott James Remnant <scott@netsplit.com>.
7 *7 *
8 * This program is free software; you can redistribute it and/or modify8 * This program is free software; you can redistribute it and/or modify
@@ -47,6 +47,7 @@
47#include "events.h"47#include "events.h"
48#include "environ.h"48#include "environ.h"
49#include "process.h"49#include "process.h"
50#include "session.h"
50#include "job_class.h"51#include "job_class.h"
51#include "job.h"52#include "job.h"
52#include "job_process.h"53#include "job_process.h"
@@ -99,8 +100,14 @@
99100
100 job->class = class;101 job->class = class;
101102
102 job->path = nih_dbus_path (job, DBUS_PATH_UPSTART, "jobs",103 if (job->class->session && job->class->session->chroot) {
103 class->name, job->name, NULL);104 /* JobClass already contains a valid D-Bus path prefix for the job */
105 job->path = nih_dbus_path (job, class->path, job->name, NULL);
106 } else {
107 job->path = nih_dbus_path (job, DBUS_PATH_UPSTART, "jobs",
108 class->name, job->name, NULL);
109 }
110
104 if (! job->path)111 if (! job->path)
105 goto error;112 goto error;
106113
@@ -118,6 +125,9 @@
118 goto error;125 goto error;
119 }126 }
120127
128 job->fds = NULL;
129 job->num_fds = 0;
130
121 job->pid = nih_alloc (job, sizeof (pid_t) * PROCESS_LAST);131 job->pid = nih_alloc (job, sizeof (pid_t) * PROCESS_LAST);
122 if (! job->pid)132 if (! job->pid)
123 goto error;133 goto error;
@@ -906,6 +916,7 @@
906 }916 }
907917
908 event = NIH_MUST (event_new (NULL, name, env));918 event = NIH_MUST (event_new (NULL, name, env));
919 event->session = job->class->session;
909920
910 if (block) {921 if (block) {
911 Blocked *blocked;922 Blocked *blocked;
@@ -1102,11 +1113,22 @@
1102 NihDBusMessage *message,1113 NihDBusMessage *message,
1103 int wait)1114 int wait)
1104{1115{
1116 Session *session;
1105 Blocked *blocked = NULL;1117 Blocked *blocked = NULL;
11061118
1107 nih_assert (job != NULL);1119 nih_assert (job != NULL);
1108 nih_assert (message != NULL);1120 nih_assert (message != NULL);
11091121
1122 /* Don't permit out-of-session modification */
1123 session = session_from_dbus (NULL, message);
1124 if (session != job->class->session) {
1125 nih_dbus_error_raise_printf (
1126 DBUS_INTERFACE_UPSTART ".Error.PermissionDenied",
1127 _("You do not have permission to modify job: %s"),
1128 job_name (job));
1129 return -1;
1130 }
1131
1110 if (job->goal == JOB_START) {1132 if (job->goal == JOB_START) {
1111 nih_dbus_error_raise_printf (1133 nih_dbus_error_raise_printf (
1112 DBUS_INTERFACE_UPSTART ".Error.AlreadyStarted",1134 DBUS_INTERFACE_UPSTART ".Error.AlreadyStarted",
@@ -1166,11 +1188,22 @@
1166 NihDBusMessage *message,1188 NihDBusMessage *message,
1167 int wait)1189 int wait)
1168{1190{
1191 Session *session;
1169 Blocked *blocked = NULL;1192 Blocked *blocked = NULL;
11701193
1171 nih_assert (job != NULL);1194 nih_assert (job != NULL);
1172 nih_assert (message != NULL);1195 nih_assert (message != NULL);
11731196
1197 /* Don't permit out-of-session modification */
1198 session = session_from_dbus (NULL, message);
1199 if (session != job->class->session) {
1200 nih_dbus_error_raise_printf (
1201 DBUS_INTERFACE_UPSTART ".Error.PermissionDenied",
1202 _("You do not have permission to modify job: %s"),
1203 job_name (job));
1204 return -1;
1205 }
1206
1174 if (job->goal == JOB_STOP) {1207 if (job->goal == JOB_STOP) {
1175 nih_dbus_error_raise_printf (1208 nih_dbus_error_raise_printf (
1176 DBUS_INTERFACE_UPSTART ".Error.AlreadyStopped",1209 DBUS_INTERFACE_UPSTART ".Error.AlreadyStopped",
@@ -1231,11 +1264,22 @@
1231 NihDBusMessage *message,1264 NihDBusMessage *message,
1232 int wait)1265 int wait)
1233{1266{
1267 Session *session;
1234 Blocked *blocked = NULL;1268 Blocked *blocked = NULL;
12351269
1236 nih_assert (job != NULL);1270 nih_assert (job != NULL);
1237 nih_assert (message != NULL);1271 nih_assert (message != NULL);
12381272
1273 /* Don't permit out-of-session modification */
1274 session = session_from_dbus (NULL, message);
1275 if (session != job->class->session) {
1276 nih_dbus_error_raise_printf (
1277 DBUS_INTERFACE_UPSTART ".Error.PermissionDenied",
1278 _("You do not have permission to modify job: %s"),
1279 job_name (job));
1280 return -1;
1281 }
1282
1239 if (job->goal == JOB_STOP) {1283 if (job->goal == JOB_STOP) {
1240 nih_dbus_error_raise_printf (1284 nih_dbus_error_raise_printf (
1241 DBUS_INTERFACE_UPSTART ".Error.AlreadyStopped",1285 DBUS_INTERFACE_UPSTART ".Error.AlreadyStopped",
12421286
=== modified file 'init/job.h'
--- init/job.h 2009-07-03 16:38:02 +0000
+++ init/job.h 2011-10-14 11:09:18 +0000
@@ -1,6 +1,6 @@
1/* upstart1/* upstart
2 *2 *
3 * Copyright © 2009 Canonical Ltd.3 * Copyright © 2010 Canonical Ltd.
4 * Author: Scott James Remnant <scott@netsplit.com>.4 * Author: Scott James Remnant <scott@netsplit.com>.
5 *5 *
6 * This program is free software; you can redistribute it and/or modify6 * This program is free software; you can redistribute it and/or modify
@@ -134,6 +134,9 @@
134 char **stop_env;134 char **stop_env;
135 EventOperator *stop_on;135 EventOperator *stop_on;
136136
137 int *fds;
138 size_t num_fds;
139
137 pid_t *pid;140 pid_t *pid;
138 Event *blocker;141 Event *blocker;
139 NihList blocking;142 NihList blocking;
140143
=== modified file 'init/job_class.c'
--- init/job_class.c 2011-05-12 20:42:28 +0000
+++ init/job_class.c 2011-10-14 11:09:18 +0000
@@ -2,7 +2,7 @@
2 *2 *
3 * job_class.c - job class definition handling3 * job_class.c - job class definition handling
4 *4 *
5 * Copyright © 2010 Canonical Ltd.5 * Copyright © 2011 Canonical Ltd.
6 * Author: Scott James Remnant <scott@netsplit.com>.6 * Author: Scott James Remnant <scott@netsplit.com>.
7 *7 *
8 * This program is free software; you can redistribute it and/or modify8 * This program is free software; you can redistribute it and/or modify
@@ -45,6 +45,7 @@
4545
46#include "environ.h"46#include "environ.h"
47#include "process.h"47#include "process.h"
48#include "session.h"
48#include "job_class.h"49#include "job_class.h"
49#include "job.h"50#include "job.h"
50#include "event_operator.h"51#include "event_operator.h"
@@ -56,51 +57,9 @@
56#include "com.ubuntu.Upstart.Job.h"57#include "com.ubuntu.Upstart.Job.h"
5758
5859
59/**
60 * JOB_DEFAULT_KILL_TIMEOUT:
61 *
62 * The default length of time to wait after sending a process the TERM
63 * signal before sending the KILL signal if it hasn't terminated.
64 **/
65#define JOB_DEFAULT_KILL_TIMEOUT 5
66
67/**
68 * JOB_DEFAULT_RESPAWN_LIMIT:
69 *
70 * The default number of times in JOB_DEFAULT_RESPAWN_INTERVAL seconds that
71 * we permit a process to respawn before stoping it
72 **/
73#define JOB_DEFAULT_RESPAWN_LIMIT 10
74
75/**
76 * JOB_DEFAULT_RESPAWN_INTERVAL:
77 *
78 * The default number of seconds before resetting the respawn timer.
79 **/
80#define JOB_DEFAULT_RESPAWN_INTERVAL 5
81
82/**
83 * JOB_DEFAULT_UMASK:
84 *
85 * The default file creation mark for processes.
86 **/
87#define JOB_DEFAULT_UMASK 022
88
89/**
90 * JOB_DEFAULT_ENVIRONMENT:
91 *
92 * Environment variables to always copy from our own environment, these
93 * can be overriden in the job definition or by events since they have the
94 * lowest priority.
95 **/
96#define JOB_DEFAULT_ENVIRONMENT \
97 "PATH", \
98 "TERM"
99
100
101/* Prototypes for static functions */60/* Prototypes for static functions */
102static void job_class_add (JobClass *class);61static void job_class_add (JobClass *class);
103static int job_class_remove (JobClass *class);62static int job_class_remove (JobClass *class, const Session *session);
10463
10564
106/**65/**
@@ -128,13 +87,15 @@
12887
129/**88/**
130 * job_class_new:89 * job_class_new:
90 *
131 * @parent: parent for new job class,91 * @parent: parent for new job class,
132 * @name: name of new job class.92 * @name: name of new job class,
93 * @session: session.
133 *94 *
134 * Allocates and returns a new JobClass structure with the @name given.95 * Allocates and returns a new JobClass structure with the given @name
135 * It will not be automatically added to the job classes table, it is up96 * and @session. It will not be automatically added to the job classes
136 * to the caller to ensure this is done using job_class_register() once97 * table, it is up to the caller to ensure this is done using
137 * the class has been set up.98 * job_class_register() once the class has been set up.
138 *99 *
139 * If @parent is not NULL, it should be a pointer to another object which100 * If @parent is not NULL, it should be a pointer to another object which
140 * will be used as a parent for the returned job class. When all parents101 * will be used as a parent for the returned job class. When all parents
@@ -145,7 +106,8 @@
145 **/106 **/
146JobClass *107JobClass *
147job_class_new (const void *parent,108job_class_new (const void *parent,
148 const char *name)109 const char *name,
110 Session *session)
149{111{
150 JobClass *class;112 JobClass *class;
151 int i;113 int i;
@@ -165,8 +127,41 @@
165 if (! class->name)127 if (! class->name)
166 goto error;128 goto error;
167129
168 class->path = nih_dbus_path (class, DBUS_PATH_UPSTART, "jobs",130 class->session = session;
169 class->name, NULL);131 if (class->session
132 && class->session->chroot
133 && class->session->user) {
134 nih_local char *uid = NULL;
135
136 uid = nih_sprintf (NULL, "%d", class->session->user);
137 if (! uid)
138 goto error;
139
140 class->path = nih_dbus_path (class, DBUS_PATH_UPSTART, "jobs",
141 session->chroot, uid,
142 class->name, NULL);
143
144 } else if (class->session
145 && class->session->chroot) {
146 class->path = nih_dbus_path (class, DBUS_PATH_UPSTART, "jobs",
147 session->chroot,
148 class->name, NULL);
149
150 } else if (class->session
151 && class->session->user) {
152 nih_local char *uid = NULL;
153
154 uid = nih_sprintf (NULL, "%d", class->session->user);
155 if (! uid)
156 goto error;
157
158 class->path = nih_dbus_path (class, DBUS_PATH_UPSTART, "jobs",
159 uid, class->name, NULL);
160
161 } else {
162 class->path = nih_dbus_path (class, DBUS_PATH_UPSTART, "jobs",
163 class->name, NULL);
164 }
170 if (! class->path)165 if (! class->path)
171 goto error;166 goto error;
172167
@@ -212,8 +207,8 @@
212 class->console = CONSOLE_NONE;207 class->console = CONSOLE_NONE;
213208
214 class->umask = JOB_DEFAULT_UMASK;209 class->umask = JOB_DEFAULT_UMASK;
215 class->nice = 0;210 class->nice = JOB_DEFAULT_NICE;
216 class->oom_score_adj = 0;211 class->oom_score_adj = JOB_DEFAULT_OOM_SCORE_ADJ;
217212
218 for (i = 0; i < RLIMIT_NLIMITS; i++)213 for (i = 0; i < RLIMIT_NLIMITS; i++)
219 class->limits[i] = NULL;214 class->limits[i] = NULL;
@@ -245,19 +240,27 @@
245int240int
246job_class_consider (JobClass *class)241job_class_consider (JobClass *class)
247{242{
248 JobClass *registered, *best;243 JobClass *registered = NULL, *best = NULL;
249244
250 nih_assert (class != NULL);245 nih_assert (class != NULL);
251246
252 job_class_init ();247 job_class_init ();
253248
254 best = conf_select_job (class->name);249 best = conf_select_job (class->name, class->session);
255 nih_assert (best != NULL);250 nih_assert (best != NULL);
256251 nih_assert (best->session == class->session);
257 registered = (JobClass *)nih_hash_lookup (job_classes, class->name);252
253 registered = (JobClass *)nih_hash_search (job_classes, class->name, NULL);
254
255 /* If we found an entry, ensure we only consider the appropriate session */
256 while (registered && registered->session != class->session)
257 {
258 registered = (JobClass *)nih_hash_search (job_classes, class->name, &registered->entry);
259 }
260
258 if (registered != best) {261 if (registered != best) {
259 if (registered)262 if (registered)
260 if (! job_class_remove (registered))263 if (! job_class_remove (registered, class->session))
261 return FALSE;264 return FALSE;
262265
263 job_class_add (best);266 job_class_add (best);
@@ -282,18 +285,25 @@
282int285int
283job_class_reconsider (JobClass *class)286job_class_reconsider (JobClass *class)
284{287{
285 JobClass *registered, *best;288 JobClass *registered = NULL, *best = NULL;
286289
287 nih_assert (class != NULL);290 nih_assert (class != NULL);
288291
289 job_class_init ();292 job_class_init ();
290293
291 best = conf_select_job (class->name);294 best = conf_select_job (class->name, class->session);
292295
293 registered = (JobClass *)nih_hash_lookup (job_classes, class->name);296 registered = (JobClass *)nih_hash_search (job_classes, class->name, NULL);
297
298 /* If we found an entry, ensure we only consider the appropriate session */
299 while (registered && registered->session != class->session)
300 {
301 registered = (JobClass *)nih_hash_search (job_classes, class->name, &registered->entry);
302 }
303
294 if (registered == class) {304 if (registered == class) {
295 if (class != best) {305 if (class != best) {
296 if (! job_class_remove (class))306 if (! job_class_remove (class, class->session))
297 return FALSE;307 return FALSE;
298308
299 job_class_add (best);309 job_class_add (best);
@@ -334,19 +344,24 @@
334344
335/**345/**
336 * job_class_remove:346 * job_class_remove:
337 * @class: class to remove.347 * @class: class to remove,
348 * @session: Session of @class.
338 *349 *
339 * Removes @class from the hash table and unregisters it from all current350 * Removes @class from the hash table and unregisters it from all current
340 * D-Bus connections.351 * D-Bus connections.
341 *352 *
342 * Returns: TRUE if class could be unregistered, FALSE if there are353 * Returns: TRUE if class could be unregistered, FALSE if there are
343 * active instances that prevent unregistration.354 * active instances that prevent unregistration, or if @session
355 * does not match the session associated with @class.
344 **/356 **/
345static int357static int
346job_class_remove (JobClass *class)358job_class_remove (JobClass *class, const Session *session)
347{359{
348 nih_assert (class != NULL);360 nih_assert (class != NULL);
349361
362 if (class->session != session)
363 return FALSE;
364
350 control_init ();365 control_init ();
351366
352 /* Return if we have any active instances */367 /* Return if we have any active instances */
@@ -696,6 +711,7 @@
696 char * const *env,711 char * const *env,
697 int wait)712 int wait)
698{713{
714 Session *session;
699 Blocked *blocked = NULL;715 Blocked *blocked = NULL;
700 Job *job;716 Job *job;
701 nih_local char **start_env = NULL;717 nih_local char **start_env = NULL;
@@ -706,6 +722,16 @@
706 nih_assert (message != NULL);722 nih_assert (message != NULL);
707 nih_assert (env != NULL);723 nih_assert (env != NULL);
708724
725 /* Don't permit out-of-session modification */
726 session = session_from_dbus (NULL, message);
727 if (session != class->session) {
728 nih_dbus_error_raise_printf (
729 DBUS_INTERFACE_UPSTART ".Error.PermissionDenied",
730 _("You do not have permission to modify job: %s"),
731 class->name);
732 return -1;
733 }
734
709 /* Verify that the environment is valid */735 /* Verify that the environment is valid */
710 if (! environ_all_valid (env)) {736 if (! environ_all_valid (env)) {
711 nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,737 nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
@@ -815,6 +841,7 @@
815 char * const *env,841 char * const *env,
816 int wait)842 int wait)
817{843{
844 Session *session;
818 Blocked *blocked = NULL;845 Blocked *blocked = NULL;
819 Job *job;846 Job *job;
820 nih_local char **stop_env = NULL;847 nih_local char **stop_env = NULL;
@@ -825,6 +852,16 @@
825 nih_assert (message != NULL);852 nih_assert (message != NULL);
826 nih_assert (env != NULL);853 nih_assert (env != NULL);
827854
855 /* Don't permit out-of-session modification */
856 session = session_from_dbus (NULL, message);
857 if (session != class->session) {
858 nih_dbus_error_raise_printf (
859 DBUS_INTERFACE_UPSTART ".Error.PermissionDenied",
860 _("You do not have permission to modify job: %s"),
861 class->name);
862 return -1;
863 }
864
828 /* Verify that the environment is valid */865 /* Verify that the environment is valid */
829 if (! environ_all_valid (env)) {866 if (! environ_all_valid (env)) {
830 nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,867 nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
@@ -939,6 +976,7 @@
939 char * const *env,976 char * const *env,
940 int wait)977 int wait)
941{978{
979 Session *session;
942 Blocked *blocked = NULL;980 Blocked *blocked = NULL;
943 Job *job;981 Job *job;
944 nih_local char **restart_env = NULL;982 nih_local char **restart_env = NULL;
@@ -949,6 +987,16 @@
949 nih_assert (message != NULL);987 nih_assert (message != NULL);
950 nih_assert (env != NULL);988 nih_assert (env != NULL);
951989
990 /* Don't permit out-of-session modification */
991 session = session_from_dbus (NULL, message);
992 if (session != class->session) {
993 nih_dbus_error_raise_printf (
994 DBUS_INTERFACE_UPSTART ".Error.PermissionDenied",
995 _("You do not have permission to modify job: %s"),
996 class->name);
997 return -1;
998 }
999
952 /* Verify that the environment is valid */1000 /* Verify that the environment is valid */
953 if (! environ_all_valid (env)) {1001 if (! environ_all_valid (env)) {
954 nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,1002 nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
9551003
=== modified file 'init/job_class.h'
--- init/job_class.h 2011-05-12 20:42:28 +0000
+++ init/job_class.h 2011-10-14 11:09:18 +0000
@@ -1,6 +1,6 @@
1/* upstart1/* upstart
2 *2 *
3 * Copyright © 2010 Canonical Ltd.3 * Copyright © 2011 Canonical Ltd.
4 * Author: Scott James Remnant <scott@netsplit.com>.4 * Author: Scott James Remnant <scott@netsplit.com>.
5 *5 *
6 * This program is free software; you can redistribute it and/or modify6 * This program is free software; you can redistribute it and/or modify
@@ -35,6 +35,7 @@
3535
36#include "process.h"36#include "process.h"
37#include "event_operator.h"37#include "event_operator.h"
38#include "session.h"
3839
3940
40/**41/**
@@ -67,10 +68,67 @@
6768
6869
69/**70/**
71 * JOB_DEFAULT_KILL_TIMEOUT:
72 *
73 * The default length of time to wait after sending a process the TERM
74 * signal before sending the KILL signal if it hasn't terminated.
75 **/
76#define JOB_DEFAULT_KILL_TIMEOUT 5
77
78/**
79 * JOB_DEFAULT_RESPAWN_LIMIT:
80 *
81 * The default number of times in JOB_DEFAULT_RESPAWN_INTERVAL seconds that
82 * we permit a process to respawn before stoping it
83 **/
84#define JOB_DEFAULT_RESPAWN_LIMIT 10
85
86/**
87 * JOB_DEFAULT_RESPAWN_INTERVAL:
88 *
89 * The default number of seconds before resetting the respawn timer.
90 **/
91#define JOB_DEFAULT_RESPAWN_INTERVAL 5
92
93/**
94 * JOB_DEFAULT_UMASK:
95 *
96 * The default file creation mark for processes.
97 **/
98#define JOB_DEFAULT_UMASK 022
99
100/**
101 * JOB_DEFAULT_NICE:
102 *
103 * The default nice level for processes.
104 **/
105#define JOB_DEFAULT_NICE 0
106
107/**
108 * JOB_DEFAULT_OOM_SCORE_ADJ:
109 *
110 * The default OOM score adjustment for processes.
111 **/
112#define JOB_DEFAULT_OOM_SCORE_ADJ 0
113
114/**
115 * JOB_DEFAULT_ENVIRONMENT:
116 *
117 * Environment variables to always copy from our own environment, these
118 * can be overriden in the job definition or by events since they have the
119 * lowest priority.
120 **/
121#define JOB_DEFAULT_ENVIRONMENT \
122 "PATH", \
123 "TERM"
124
125
126/**
70 * JobClass:127 * JobClass:
71 * @entry: list header,128 * @entry: list header,
72 * @name: unique name,129 * @name: unique name,
73 * @path: path of D-Bus object,130 * @path: path of D-Bus object,
131 * @session: attached session,
74 * @instance: pattern to uniquely identify multiple instances,132 * @instance: pattern to uniquely identify multiple instances,
75 * @instances: hash table of active instances,133 * @instances: hash table of active instances,
76 * @description: description; intended for humans,134 * @description: description; intended for humans,
@@ -110,6 +168,7 @@
110168
111 char *name;169 char *name;
112 char *path;170 char *path;
171 Session * session;
113172
114 char *instance;173 char *instance;
115 NihHash *instances;174 NihHash *instances;
@@ -161,7 +220,8 @@
161void job_class_init (void);220void job_class_init (void);
162221
163JobClass * job_class_new (const void *parent,222JobClass * job_class_new (const void *parent,
164 const char *name)223 const char *name,
224 Session *session)
165 __attribute__ ((warn_unused_result, malloc));225 __attribute__ ((warn_unused_result, malloc));
166226
167int job_class_consider (JobClass *class);227int job_class_consider (JobClass *class);
168228
=== modified file 'init/job_process.c'
--- init/job_process.c 2011-05-12 20:42:28 +0000
+++ init/job_process.c 2011-10-14 11:09:18 +0000
@@ -2,7 +2,6 @@
2 *2 *
3 * job_process.c - job process handling3 * job_process.c - job process handling
4 *4 *
5 * Copyright © 2011 Google Inc.
6 * Copyright © 2011 Canonical Ltd.5 * Copyright © 2011 Canonical Ltd.
7 * Author: Scott James Remnant <scott@netsplit.com>.6 * Author: Scott James Remnant <scott@netsplit.com>.
8 *7 *
@@ -41,6 +40,7 @@
41#include <unistd.h>40#include <unistd.h>
42#include <utmp.h>41#include <utmp.h>
43#include <utmpx.h>42#include <utmpx.h>
43#include <pwd.h>
4444
45#include <nih/macros.h>45#include <nih/macros.h>
46#include <nih/alloc.h>46#include <nih/alloc.h>
@@ -373,14 +373,20 @@
373 int trace,373 int trace,
374 int script_fd)374 int script_fd)
375{375{
376 sigset_t child_set, orig_set;376 sigset_t child_set, orig_set;
377 pid_t pid;377 pid_t pid;
378 int i, fds[2];378 int i, fds[2];
379 char filename[PATH_MAX];379 char filename[PATH_MAX];
380 FILE *fd;380 FILE *fd;
381 int user_job = FALSE;
382 nih_local char *user_dir = NULL;
383
381384
382 nih_assert (class != NULL);385 nih_assert (class != NULL);
383386
387 if (class && class->session && class->session->user)
388 user_job = TRUE;
389
384 /* Create a pipe to communicate with the child process until it390 /* Create a pipe to communicate with the child process until it
385 * execs so we know whether that was successful or an error occurred.391 * execs so we know whether that was successful or an error occurred.
386 */392 */
@@ -439,6 +445,8 @@
439 close (fds[0]);445 close (fds[0]);
440 if (fds[1] == JOB_PROCESS_SCRIPT_FD) {446 if (fds[1] == JOB_PROCESS_SCRIPT_FD) {
441 int tmp = dup2 (fds[1], fds[0]);447 int tmp = dup2 (fds[1], fds[0]);
448 if (tmp < 0)
449 job_process_error_abort (fds[1], JOB_PROCESS_ERROR_DUP, 0);
442 close (fds[1]);450 close (fds[1]);
443 fds[1] = tmp;451 fds[1] = tmp;
444 }452 }
@@ -447,7 +455,7 @@
447 /* Move the script fd to special fd 9; the only gotcha is if that455 /* Move the script fd to special fd 9; the only gotcha is if that
448 * would be our error descriptor, but that's handled above.456 * would be our error descriptor, but that's handled above.
449 */457 */
450 if (script_fd != -1) {458 if ((script_fd != -1) && (script_fd != JOB_PROCESS_SCRIPT_FD)) {
451 int tmp = dup2 (script_fd, JOB_PROCESS_SCRIPT_FD);459 int tmp = dup2 (script_fd, JOB_PROCESS_SCRIPT_FD);
452 if (tmp < 0)460 if (tmp < 0)
453 job_process_error_abort (fds[1], JOB_PROCESS_ERROR_DUP, 0);461 job_process_error_abort (fds[1], JOB_PROCESS_ERROR_DUP, 0);
@@ -460,6 +468,84 @@
460 */468 */
461 setsid ();469 setsid ();
462470
471 /* Set the process environment from the function paramters. */
472 environ = (char **)env;
473
474 /* Handle unprivileged user job by dropping privileges to
475 * their level as soon as possible to avoid privilege
476 * escalations when we set resource limits.
477 */
478 if (user_job) {
479 uid_t uid = class->session->user;
480 struct passwd *pw = NULL;
481
482 /* D-Bus does not expose a public API call to allow
483 * us to query a users primary group.
484 * _dbus_user_info_fill_uid () seems to exist for this
485 * purpose, but is a "secret" API. It is unclear why
486 * D-Bus neglects the gid when it allows the uid
487 * to be queried directly.
488 *
489 * Our only recourse is to disallow user sessions in a
490 * chroot and assume that all other user sessions
491 * originate from the local system. In this way, we can
492 * bypass D-Bus and use getpwuid ().
493 */
494
495 if (class->session->chroot) {
496 /* We cannot determine the group id of the user
497 * session in the chroot via D-Bus, so disallow
498 * all jobs in such an environment.
499 */
500 nih_return_error (-1, EPERM, "user jobs not supported in chroots");
501 }
502
503 pw = getpwuid (uid);
504
505 if (!pw)
506 nih_return_system_error (-1);
507
508 nih_assert (pw->pw_uid == uid);
509
510 if (! pw->pw_dir) {
511 nih_local char *message = NIH_MUST (nih_sprintf (NULL,
512 "no home directory for user with uid %d",
513 uid));
514
515 nih_return_error (-1, ENOENT, message);
516
517 }
518
519 /* Note we don't use NIH_MUST since this could result in a
520 * DOS for a (low priority) user job in low-memory scenarios.
521 */
522 user_dir = nih_strdup (NULL, pw->pw_dir);
523
524 if (!user_dir)
525 nih_return_no_memory_error (-1);
526
527 /* Ensure the file associated with fd 9
528 * (/proc/self/fd/9) is owned by the user we're about to
529 * become to avoid EPERM.
530 */
531 if (script_fd != -1 && fchown (script_fd, pw->pw_uid, pw->pw_gid) < 0) {
532 nih_error_raise_system ();
533 job_process_error_abort (fds[1], JOB_PROCESS_ERROR_CHOWN, 0);
534 }
535
536 if (pw->pw_gid && setgid (pw->pw_gid) < 0) {
537 nih_error_raise_system ();
538 job_process_error_abort (fds[1], JOB_PROCESS_ERROR_SETGID, 0);
539 }
540
541 if (pw->pw_uid && setuid (pw->pw_uid) < 0) {
542 nih_error_raise_system ();
543 job_process_error_abort (fds[1], JOB_PROCESS_ERROR_SETUID, 0);
544 }
545
546
547 }
548
463 /* Set the standard file descriptors to an output of our chosing;549 /* Set the standard file descriptors to an output of our chosing;
464 * any other open descriptor must be intended for the child, or have550 * any other open descriptor must be intended for the child, or have
465 * the FD_CLOEXEC flag so it's automatically closed when we exec()551 * the FD_CLOEXEC flag so it's automatically closed when we exec()
@@ -480,6 +566,7 @@
480 job_process_error_abort (fds[1], JOB_PROCESS_ERROR_CONSOLE, 0);566 job_process_error_abort (fds[1], JOB_PROCESS_ERROR_CONSOLE, 0);
481 }567 }
482568
569
483 /* Set resource limits for the process, skipping over any that570 /* Set resource limits for the process, skipping over any that
484 * aren't set in the job class such that they inherit from571 * aren't set in the job class such that they inherit from
485 * ourselves (and we inherit from kernel defaults).572 * ourselves (and we inherit from kernel defaults).
@@ -495,9 +582,6 @@
495 }582 }
496 }583 }
497584
498 /* Set the process environment from the function paramters. */
499 environ = (char **)env;
500
501 /* Set the file mode creation mask; this is one of the few operations585 /* Set the file mode creation mask; this is one of the few operations
502 * that can never fail.586 * that can never fail.
503 */587 */
@@ -513,13 +597,13 @@
513597
514 /* Adjust the process OOM killer priority.598 /* Adjust the process OOM killer priority.
515 */599 */
516 if (class->oom_score_adj) {600 if (class->oom_score_adj != JOB_DEFAULT_OOM_SCORE_ADJ) {
517 int oom_value;601 int oom_value;
518 snprintf (filename, sizeof (filename),602 snprintf (filename, sizeof (filename),
519 "/proc/%d/oom_score_adj", getpid ());603 "/proc/%d/oom_score_adj", getpid ());
520 oom_value = class->oom_score_adj;604 oom_value = class->oom_score_adj;
521 fd = fopen (filename, "w");605 fd = fopen (filename, "w");
522 if ((! fd) && (errno == EACCES)) {606 if ((! fd) && (errno == ENOENT)) {
523 snprintf (filename, sizeof (filename),607 snprintf (filename, sizeof (filename),
524 "/proc/%d/oom_adj", getpid ());608 "/proc/%d/oom_adj", getpid ());
525 oom_value = (class->oom_score_adj609 oom_value = (class->oom_score_adj
@@ -539,6 +623,16 @@
539 }623 }
540 }624 }
541625
626 /* Handle changing a chroot session job prior to dealing with
627 * the 'chroot' stanza.
628 */
629 if (class->session && class->session->chroot) {
630 if (chroot (class->session->chroot) < 0) {
631 nih_error_raise_system ();
632 job_process_error_abort (fds[1], JOB_PROCESS_ERROR_CHROOT, 0);
633 }
634 }
635
542 /* Change the root directory, confining path resolution within it;636 /* Change the root directory, confining path resolution within it;
543 * we do this before the working directory call so that is always637 * we do this before the working directory call so that is always
544 * relative to the new root.638 * relative to the new root.
@@ -555,12 +649,11 @@
555 * configured in the job, or to the root directory of the filesystem649 * configured in the job, or to the root directory of the filesystem
556 * (or at least relative to the chroot).650 * (or at least relative to the chroot).
557 */651 */
558 if (chdir (class->chdir ? class->chdir : "/") < 0) {652 if (chdir (class->chdir ? class->chdir : user_job ? user_dir : "/") < 0) {
559 nih_error_raise_system ();653 nih_error_raise_system ();
560 job_process_error_abort (fds[1], JOB_PROCESS_ERROR_CHDIR, 0);654 job_process_error_abort (fds[1], JOB_PROCESS_ERROR_CHDIR, 0);
561 }655 }
562656
563
564 /* Reset all the signal handlers back to their default handling so657 /* Reset all the signal handlers back to their default handling so
565 * the child isn't unexpectedly ignoring any, and so we won't658 * the child isn't unexpectedly ignoring any, and so we won't
566 * surprisingly handle them before we've exec()d the new process.659 * surprisingly handle them before we've exec()d the new process.
@@ -787,6 +880,21 @@
787 err, _("unable to execute: %s"),880 err, _("unable to execute: %s"),
788 strerror (err->errnum)));881 strerror (err->errnum)));
789 break;882 break;
883 case JOB_PROCESS_ERROR_SETUID:
884 err->error.message = NIH_MUST (nih_sprintf (
885 err, _("unable to setuid: %s"),
886 strerror (err->errnum)));
887 break;
888 case JOB_PROCESS_ERROR_SETGID:
889 err->error.message = NIH_MUST (nih_sprintf (
890 err, _("unable to setgid: %s"),
891 strerror (err->errnum)));
892 break;
893 case JOB_PROCESS_ERROR_CHOWN:
894 err->error.message = NIH_MUST (nih_sprintf (
895 err, _("unable to chown: %s"),
896 strerror (err->errnum)));
897 break;
790 default:898 default:
791 nih_assert_not_reached ();899 nih_assert_not_reached ();
792 }900 }
793901
=== modified file 'init/job_process.h'
--- init/job_process.h 2011-05-12 19:21:16 +0000
+++ init/job_process.h 2011-10-14 11:09:18 +0000
@@ -1,7 +1,6 @@
1/* upstart1/* upstart
2 *2 *
3 * Copyright © 2011 Google Inc.3 * Copyright © 2009,2010,2011 Canonical Ltd.
4 * Copyright © 2009 Canonical Ltd.
5 * Author: Scott James Remnant <scott@netsplit.com>.4 * Author: Scott James Remnant <scott@netsplit.com>.
6 *5 *
7 * This program is free software; you can redistribute it and/or modify6 * This program is free software; you can redistribute it and/or modify
@@ -57,7 +56,10 @@
57 JOB_PROCESS_ERROR_CHROOT,56 JOB_PROCESS_ERROR_CHROOT,
58 JOB_PROCESS_ERROR_CHDIR,57 JOB_PROCESS_ERROR_CHDIR,
59 JOB_PROCESS_ERROR_PTRACE,58 JOB_PROCESS_ERROR_PTRACE,
60 JOB_PROCESS_ERROR_EXEC59 JOB_PROCESS_ERROR_EXEC,
60 JOB_PROCESS_ERROR_SETUID,
61 JOB_PROCESS_ERROR_SETGID,
62 JOB_PROCESS_ERROR_CHOWN
61} JobProcessErrorType;63} JobProcessErrorType;
6264
63/**65/**
6466
=== modified file 'init/main.c'
--- init/main.c 2011-05-30 00:06:07 +0000
+++ init/main.c 2011-10-14 11:09:18 +0000
@@ -1,7 +1,6 @@
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches