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