Merge lp:~jamesodhunt/upstart/upstart-shutdown into lp:upstart
- upstart-shutdown
- Merge into trunk
Status: | Merged |
---|---|
Merged at revision: | 1433 |
Proposed branch: | lp:~jamesodhunt/upstart/upstart-shutdown |
Merge into: | lp:upstart |
Diff against target: |
2291 lines (+1581/-107) (has conflicts) 22 files modified
ChangeLog (+77/-0) dbus/com.ubuntu.Upstart.xml (+2/-0) init/Makefile.am (+17/-15) init/conf.c (+11/-0) init/conf.h (+1/-0) init/control.c (+51/-3) init/control.h (+1/-0) init/events.h (+7/-0) init/job_class.c (+30/-0) init/job_class.h (+3/-0) init/job_process.c (+60/-1) init/job_process.h (+4/-1) init/main.c (+25/-21) init/man/init.8 (+19/-2) init/man/session-end.7 (+34/-0) init/man/startup.7 (+8/-1) init/quiesce.c (+248/-0) init/quiesce.h (+76/-0) init/session.c (+12/-0) init/session.h (+1/-0) util/initctl.c (+1/-1) util/tests/test_initctl.c (+893/-62) Text conflict in ChangeLog Text conflict in init/job_process.c |
To merge this branch: | bzr merge lp:~jamesodhunt/upstart/upstart-shutdown |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Stéphane Graber (community) | Approve | ||
Upstart Reviewers | Pending | ||
Review via email: mp+148676@code.launchpad.net |
Commit message
Description of the change
This branch provides the Session Init shutdown facility.
= Session Init Shutdown as Result of Impending System Shutdown =
Sending SIGTERM to a Session Init is indicative of a system shutdown. In this scenario the Session Init will emit the 'session-end' event and immediately request all jobs stop.
The Session Init will (attempt) to wait for up to the maximum kill_timeout value specified in any running jobs .conf file (5 seconds by default) before they are forcibly killed (although note that system policy may not allow the Session Init to wait as long as it wishes).
= Session Init Shutdown as Result of Logout Request =
The branch also introduces an 'EndSession' D-Bus method which is designed to be called when the user wishes their session to be ended due to a 'logout' request.
In this scenario, the Session Init will emit the 'session-end' event and wait for up to 5 seconds for *new* jobs to react to this event. If no new jobs start or after 5 seconds, the final shutdown phase is entered where all running jobs are requested to stop and after the maximum kill_timeout value specified in any running jobs .conf file is reached (5 seconds by default), the Session Init will exit.
Preview Diff
1 | === modified file 'ChangeLog' |
2 | --- ChangeLog 2013-02-08 16:55:25 +0000 |
3 | +++ ChangeLog 2013-02-15 11:31:39 +0000 |
4 | @@ -1,3 +1,4 @@ |
5 | +<<<<<<< TREE |
6 | 2013-02-08 James Hunt <james.hunt@ubuntu.com> |
7 | |
8 | * init/job_process.c: job_process_run(): Copy parent environment if |
9 | @@ -5,6 +6,82 @@ |
10 | * init/main.c: Added 'inherit-env' command-line option. |
11 | * init/man/init.8: Documented --inherit-env. |
12 | |
13 | +======= |
14 | +2013-02-15 James Hunt <james.hunt@ubuntu.com> |
15 | + |
16 | + * util/tests/test_initctl.c: |
17 | + - timed_waitpid(): Back off if no status change. |
18 | + - test_quiesce(): |
19 | + - Set XDG_RUNTIME_DIR to a temporary value. |
20 | + - Remove stale session files. |
21 | + - test_job_env(): Remove stale session files. |
22 | + |
23 | +2013-02-14 James Hunt <james.hunt@ubuntu.com> |
24 | + |
25 | + * util/tests/test_initctl.c: |
26 | + - wait_for_upstart(): Functional replacement of WAIT_FOR_UPSTART() |
27 | + macro. Now accepts @user. |
28 | + - set_upstart_session(): Poll to ensure we give Upstart time to |
29 | + initialise and write the session file. |
30 | + - _start_upstart(): Extra @user parameter. |
31 | + |
32 | +2013-02-14 James Hunt <james.hunt@ubuntu.com> |
33 | + |
34 | + * init/Makefile.am: Added quiesce.o, now required by control.o. |
35 | + * init/main.c: main(): |
36 | + - SIGHUP+SIGUSR1 handling now applies however you run init (since |
37 | + it should react to these signals when run as a Session Init). |
38 | + - Qualified sessions message to avoid confusion. |
39 | + * util/initctl.c: upstart_open(): Better handling for user_mode. |
40 | + * util/tests/test_initctl.c: |
41 | + - WAIT_FOR_UPSTART(): Made session-aware. |
42 | + - KILL_UPSTART(): Reset user mode flag (taken from STOP_UPSTART()). |
43 | + - set_upstart_session(): New function. |
44 | + - self_pipe_write(): New Function. |
45 | + - self_pipe_setup(): New Function. |
46 | + - timed_waitpid(): New function. |
47 | + - _start_upstart(): |
48 | + - Signal handling and extra checks. |
49 | + - Discard init output (unless UPSTART_TEST_VERBOSE set) |
50 | + for saner logs. |
51 | + - test_list_sessions(): |
52 | + - Removed need for a dbus-daemon. |
53 | + - Added required initctl reset. |
54 | + - test_quiesce(): Tests for Session Init shutdown (both |
55 | + system-initiated and end-session request). |
56 | + - test_usage(): Added extra checks and tidyup. |
57 | + - main(): Added call to test_quiesce(). |
58 | + |
59 | +2013-02-08 James Hunt <james.hunt@ubuntu.com> |
60 | + |
61 | + * dbus/com.ubuntu.Upstart.xml: Added 'EndSession' method. |
62 | + * init/Makefile.am: Updated for quiesce.[ch]. |
63 | + * init/conf.c: conf_destroy(): Cleanup function. |
64 | + * init/conf.h: Prototype. |
65 | + * init/control.c: control_end_session(): 'EndSession' implemenation. |
66 | + * init/control.h: Include. |
67 | + * init/events.h: Added SESSION_END_EVENT. |
68 | + * init/job_class.c: job_class_max_kill_timeout(): New function. |
69 | + * init/job_class.h: Prototype. |
70 | + * init/job_process.c: |
71 | + - Added disable_respawn to disallow respawns. |
72 | + - job_process_jobs_running(): New function. |
73 | + - job_process_stop_all(): New function. |
74 | + - job_process_terminated(): Honours disable_respawn. |
75 | + * init/job_process.h: Prototypes. |
76 | + * init/main.c: |
77 | + - Typos. |
78 | + - term_handler(): Quiesce rather than re-exec on receipt of SIGTERM |
79 | + when running as a Session Init. |
80 | + - main(): Make quiesce() handle cleanup. |
81 | + * init/man/init.8: Update for Session Init SIGTERM handling. |
82 | + * init/man/startup.7: Update for Session Init. |
83 | + * init/session.c: session_destroy(): New function. |
84 | + * init/session.h: Prototype. |
85 | + * init/man/session-end.7: New man page. |
86 | + * init/quiesce.[ch]: New files. |
87 | + |
88 | +>>>>>>> MERGE-SOURCE |
89 | 2013-02-02 James Hunt <james.hunt@ubuntu.com> |
90 | |
91 | * util/initctl.c: Remove ability to specify explicitly job and/or job |
92 | |
93 | === modified file 'dbus/com.ubuntu.Upstart.xml' |
94 | --- dbus/com.ubuntu.Upstart.xml 2013-01-25 20:08:49 +0000 |
95 | +++ dbus/com.ubuntu.Upstart.xml 2013-02-15 11:31:39 +0000 |
96 | @@ -103,6 +103,8 @@ |
97 | <method name="NotifyDiskWriteable"> |
98 | </method> |
99 | |
100 | + <method name="EndSession"/> |
101 | + |
102 | <!-- Basic information about Upstart --> |
103 | <property name="version" type="s" access="read" /> |
104 | <property name="log_priority" type="s" access="readwrite" /> |
105 | |
106 | === modified file 'init/Makefile.am' |
107 | --- init/Makefile.am 2013-01-21 16:39:28 +0000 |
108 | +++ init/Makefile.am 2013-02-15 11:31:39 +0000 |
109 | @@ -31,7 +31,8 @@ |
110 | man/keyboard-request.7 \ |
111 | man/power-status-changed.7 \ |
112 | man/upstart.7 \ |
113 | - man/inittab.5 |
114 | + man/inittab.5 \ |
115 | + man/session-end.7 |
116 | |
117 | |
118 | sbin_PROGRAMS = init |
119 | @@ -57,6 +58,7 @@ |
120 | conf.c conf.h \ |
121 | control.c control.h \ |
122 | xdg.c xdg.h \ |
123 | + quiesce.c quiesce.h \ |
124 | errors.h |
125 | nodist_init_SOURCES = \ |
126 | $(com_ubuntu_Upstart_OUTPUTS) \ |
127 | @@ -176,7 +178,7 @@ |
128 | test_process_LDADD = \ |
129 | system.o environ.o process.o \ |
130 | job_class.o job_process.o job.o event.o event_operator.o blocked.o \ |
131 | - parse_job.o parse_conf.o conf.o control.o \ |
132 | + parse_job.o parse_conf.o conf.o control.o quiesce.o \ |
133 | session.o log.o state.o xdg.o \ |
134 | com.ubuntu.Upstart.o \ |
135 | com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \ |
136 | @@ -190,7 +192,7 @@ |
137 | test_job_class_LDADD = \ |
138 | system.o environ.o process.o \ |
139 | job_class.o job_process.o job.o event.o event_operator.o blocked.o \ |
140 | - parse_job.o parse_conf.o conf.o control.o \ |
141 | + parse_job.o parse_conf.o conf.o control.o quiesce.o \ |
142 | session.o log.o state.o xdg.o \ |
143 | com.ubuntu.Upstart.o \ |
144 | com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \ |
145 | @@ -204,7 +206,7 @@ |
146 | test_job_process_LDADD = \ |
147 | system.o environ.o process.o \ |
148 | job_class.o job_process.o job.o event.o event_operator.o blocked.o \ |
149 | - parse_job.o parse_conf.o conf.o control.o \ |
150 | + parse_job.o parse_conf.o conf.o control.o quiesce.o \ |
151 | session.o log.o state.o xdg.o \ |
152 | com.ubuntu.Upstart.o \ |
153 | com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \ |
154 | @@ -218,7 +220,7 @@ |
155 | test_job_LDADD = \ |
156 | system.o environ.o process.o \ |
157 | job_class.o job_process.o job.o event.o event_operator.o blocked.o \ |
158 | - parse_job.o parse_conf.o conf.o control.o \ |
159 | + parse_job.o parse_conf.o conf.o control.o quiesce.o \ |
160 | session.o log.o state.o xdg.o \ |
161 | com.ubuntu.Upstart.o \ |
162 | com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \ |
163 | @@ -232,7 +234,7 @@ |
164 | test_log_LDADD = \ |
165 | system.o environ.o process.o \ |
166 | job_class.o job_process.o job.o event.o event_operator.o blocked.o \ |
167 | - parse_job.o parse_conf.o conf.o control.o \ |
168 | + parse_job.o parse_conf.o conf.o control.o quiesce.o \ |
169 | session.o log.o state.o xdg.o \ |
170 | com.ubuntu.Upstart.o \ |
171 | com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \ |
172 | @@ -246,7 +248,7 @@ |
173 | test_state_LDADD = \ |
174 | system.o environ.o process.o \ |
175 | job_class.o job_process.o job.o event.o event_operator.o blocked.o \ |
176 | - parse_job.o parse_conf.o conf.o control.o \ |
177 | + parse_job.o parse_conf.o conf.o control.o quiesce.o \ |
178 | session.o log.o state.o xdg.o \ |
179 | com.ubuntu.Upstart.o \ |
180 | com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \ |
181 | @@ -260,7 +262,7 @@ |
182 | test_event_LDADD = \ |
183 | system.o environ.o process.o \ |
184 | job_class.o job_process.o job.o event.o event_operator.o blocked.o \ |
185 | - parse_job.o parse_conf.o conf.o control.o \ |
186 | + parse_job.o parse_conf.o conf.o control.o quiesce.o \ |
187 | session.o log.o state.o xdg.o \ |
188 | com.ubuntu.Upstart.o \ |
189 | com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \ |
190 | @@ -274,7 +276,7 @@ |
191 | test_event_operator_LDADD = \ |
192 | system.o environ.o process.o \ |
193 | job_class.o job_process.o job.o event.o event_operator.o blocked.o \ |
194 | - parse_job.o parse_conf.o conf.o control.o \ |
195 | + parse_job.o parse_conf.o conf.o control.o quiesce.o \ |
196 | session.o log.o state.o xdg.o \ |
197 | com.ubuntu.Upstart.o \ |
198 | com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \ |
199 | @@ -288,7 +290,7 @@ |
200 | test_blocked_LDADD = \ |
201 | system.o environ.o process.o \ |
202 | job_class.o job_process.o job.o event.o event_operator.o blocked.o \ |
203 | - parse_job.o parse_conf.o conf.o control.o \ |
204 | + parse_job.o parse_conf.o conf.o control.o quiesce.o \ |
205 | session.o log.o state.o xdg.o \ |
206 | com.ubuntu.Upstart.o \ |
207 | com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \ |
208 | @@ -302,7 +304,7 @@ |
209 | test_parse_job_LDADD = \ |
210 | system.o environ.o process.o \ |
211 | job_class.o job_process.o job.o event.o event_operator.o blocked.o \ |
212 | - parse_job.o parse_conf.o conf.o control.o \ |
213 | + parse_job.o parse_conf.o conf.o control.o quiesce.o \ |
214 | session.o log.o state.o xdg.o \ |
215 | com.ubuntu.Upstart.o \ |
216 | com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \ |
217 | @@ -316,7 +318,7 @@ |
218 | test_parse_conf_LDADD = \ |
219 | system.o environ.o process.o \ |
220 | job_class.o job_process.o job.o event.o event_operator.o blocked.o \ |
221 | - parse_job.o parse_conf.o conf.o control.o \ |
222 | + parse_job.o parse_conf.o conf.o control.o quiesce.o \ |
223 | session.o log.o state.o xdg.o \ |
224 | com.ubuntu.Upstart.o \ |
225 | com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \ |
226 | @@ -330,7 +332,7 @@ |
227 | test_conf_LDADD = \ |
228 | system.o environ.o process.o \ |
229 | job_class.o job_process.o job.o event.o event_operator.o blocked.o \ |
230 | - parse_job.o parse_conf.o conf.o control.o \ |
231 | + parse_job.o parse_conf.o conf.o control.o quiesce.o \ |
232 | session.o log.o state.o xdg.o \ |
233 | com.ubuntu.Upstart.o \ |
234 | com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \ |
235 | @@ -344,7 +346,7 @@ |
236 | test_conf_static_LDADD = \ |
237 | system.o environ.o process.o \ |
238 | job_class.o job_process.o job.o event.o event_operator.o blocked.o \ |
239 | - parse_job.o parse_conf.o control.o \ |
240 | + parse_job.o parse_conf.o control.o quiesce.o \ |
241 | session.o log.o state.o xdg.o \ |
242 | com.ubuntu.Upstart.o \ |
243 | com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \ |
244 | @@ -365,7 +367,7 @@ |
245 | test_control_LDADD = \ |
246 | system.o environ.o process.o \ |
247 | job_class.o job_process.o job.o event.o event_operator.o blocked.o \ |
248 | - parse_job.o parse_conf.o conf.o control.o \ |
249 | + parse_job.o parse_conf.o conf.o control.o quiesce.o \ |
250 | session.o log.o state.o xdg.o \ |
251 | com.ubuntu.Upstart.o \ |
252 | com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \ |
253 | |
254 | === modified file 'init/conf.c' |
255 | --- init/conf.c 2013-01-08 16:15:46 +0000 |
256 | +++ init/conf.c 2013-02-15 11:31:39 +0000 |
257 | @@ -321,6 +321,17 @@ |
258 | conf_sources = NIH_MUST (nih_list_new (NULL)); |
259 | } |
260 | |
261 | +/** |
262 | + * conf_destroy: |
263 | + * |
264 | + * Clear: the conf_sources list. |
265 | + **/ |
266 | +void |
267 | +conf_destroy (void) |
268 | +{ |
269 | + if (conf_sources) |
270 | + nih_free (conf_sources); |
271 | +} |
272 | |
273 | /** |
274 | * conf_source_new: |
275 | |
276 | === modified file 'init/conf.h' |
277 | --- init/conf.h 2012-12-19 12:46:46 +0000 |
278 | +++ init/conf.h 2013-02-15 11:31:39 +0000 |
279 | @@ -112,6 +112,7 @@ |
280 | |
281 | |
282 | void conf_init (void); |
283 | +void conf_destroy (void); |
284 | |
285 | ConfSource *conf_source_new (const void *parent, const char *path, |
286 | ConfSourceType type) |
287 | |
288 | === modified file 'init/control.c' |
289 | --- init/control.c 2013-01-31 17:23:55 +0000 |
290 | +++ init/control.c 2013-02-15 11:31:39 +0000 |
291 | @@ -57,6 +57,7 @@ |
292 | #include "errors.h" |
293 | #include "state.h" |
294 | #include "event.h" |
295 | +#include "events.h" |
296 | #include "paths.h" |
297 | #include "xdg.h" |
298 | |
299 | @@ -115,9 +116,9 @@ |
300 | NihList *control_conns = NULL; |
301 | |
302 | /* External definitions */ |
303 | -extern int user_mode; |
304 | - |
305 | -extern char *session_file; |
306 | +extern int user_mode; |
307 | +extern int disable_respawn; |
308 | +extern char *session_file; |
309 | |
310 | /** |
311 | * control_init: |
312 | @@ -1744,3 +1745,50 @@ |
313 | if (session_file) |
314 | (void)unlink (session_file); |
315 | } |
316 | + |
317 | +/** |
318 | + * control_session_end: |
319 | + * |
320 | + * @data: not used, |
321 | + * @message: D-Bus connection and message received. |
322 | + * |
323 | + * Implements the EndSession method of the com.ubuntu.Upstart |
324 | + * interface. |
325 | + * |
326 | + * Called to request that Upstart stop all jobs and exit. Only |
327 | + * appropriate when running as a Session Init and user wishes to |
328 | + * 'logout'. |
329 | + * |
330 | + * Returns: zero on success, negative value on raised error. |
331 | + **/ |
332 | +int |
333 | +control_end_session (void *data, |
334 | + NihDBusMessage *message) |
335 | +{ |
336 | + Session *session; |
337 | + |
338 | + nih_assert (message); |
339 | + |
340 | + /* Not supported at the system level */ |
341 | + if (getpid () == 1) |
342 | + return 0; |
343 | + |
344 | + if (! control_check_permission (message)) { |
345 | + nih_dbus_error_raise_printf ( |
346 | + DBUS_INTERFACE_UPSTART ".Error.PermissionDenied", |
347 | + _("You do not have permission to end session")); |
348 | + return -1; |
349 | + } |
350 | + |
351 | + /* Get the relevant session */ |
352 | + session = session_from_dbus (NULL, message); |
353 | + |
354 | + if (session && session->chroot) { |
355 | + nih_warn (_("Ignoring session end request from chroot session")); |
356 | + return 0; |
357 | + } |
358 | + |
359 | + quiesce (QUIESCE_REQUESTER_SESSION); |
360 | + |
361 | + return 0; |
362 | +} |
363 | |
364 | === modified file 'init/control.h' |
365 | --- init/control.h 2013-01-31 17:23:55 +0000 |
366 | +++ init/control.h 2013-02-15 11:31:39 +0000 |
367 | @@ -31,6 +31,7 @@ |
368 | #include <json.h> |
369 | |
370 | #include "event.h" |
371 | +#include "quiesce.h" |
372 | |
373 | /** |
374 | * USE_SESSION_BUS_ENV: |
375 | |
376 | === modified file 'init/events.h' |
377 | --- init/events.h 2009-06-23 09:29:35 +0000 |
378 | +++ init/events.h 2013-02-15 11:31:39 +0000 |
379 | @@ -31,6 +31,13 @@ |
380 | #define STARTUP_EVENT "debug" |
381 | #endif |
382 | |
383 | +/** |
384 | + * SESSION_END_EVENT: |
385 | + * |
386 | + * Name of the event Upstart emits to denote a Session Init |
387 | + * is shutting down. |
388 | + **/ |
389 | +#define SESSION_END_EVENT "session-end" |
390 | |
391 | /** |
392 | * CTRLALTDEL_EVENT: |
393 | |
394 | === modified file 'init/job_class.c' |
395 | --- init/job_class.c 2013-01-31 17:23:55 +0000 |
396 | +++ init/job_class.c 2013-02-15 11:31:39 +0000 |
397 | @@ -2344,3 +2344,33 @@ |
398 | |
399 | return class; |
400 | } |
401 | + |
402 | +/** |
403 | + * job_class_max_kill_timeout: |
404 | + * |
405 | + * Determine maximum kill timeout for all running jobs. |
406 | + * |
407 | + * Returns: Maximum kill timeout (seconds). |
408 | + **/ |
409 | +time_t |
410 | +job_class_max_kill_timeout (void) |
411 | +{ |
412 | + time_t kill_timeout = JOB_DEFAULT_KILL_TIMEOUT; |
413 | + |
414 | + job_class_init (); |
415 | + |
416 | + NIH_HASH_FOREACH (job_classes, iter) { |
417 | + JobClass *class = (JobClass *)iter; |
418 | + |
419 | + NIH_HASH_FOREACH (class->instances, job_iter) { |
420 | + Job *job = (Job *)job_iter; |
421 | + |
422 | + if (job->class->kill_timeout > kill_timeout) { |
423 | + kill_timeout = job->class->kill_timeout; |
424 | + break; |
425 | + } |
426 | + } |
427 | + } |
428 | + |
429 | + return kill_timeout; |
430 | +} |
431 | |
432 | === modified file 'init/job_class.h' |
433 | --- init/job_class.h 2013-01-25 20:08:49 +0000 |
434 | +++ init/job_class.h 2013-02-15 11:31:39 +0000 |
435 | @@ -359,6 +359,9 @@ |
436 | JobClass * job_class_find (const Session *session, const char *name) |
437 | __attribute__ ((warn_unused_result)); |
438 | |
439 | +time_t job_class_max_kill_timeout (void) |
440 | + __attribute__ ((warn_unused_result)); |
441 | + |
442 | NIH_END_EXTERN |
443 | |
444 | #endif /* INIT_JOB_CLASS_H */ |
445 | |
446 | === modified file 'init/job_process.c' |
447 | --- init/job_process.c 2013-02-14 02:54:10 +0000 |
448 | +++ init/job_process.c 2013-02-15 11:31:39 +0000 |
449 | @@ -99,6 +99,13 @@ |
450 | **/ |
451 | char *log_dir = NULL; |
452 | |
453 | +/** |
454 | + * disable_respawn: |
455 | + * |
456 | + * If TRUE, disallow respawning. |
457 | + **/ |
458 | +int disable_respawn = FALSE; |
459 | + |
460 | /* Prototypes for static functions */ |
461 | static void job_process_error_abort (int fd, JobProcessErrorType type, |
462 | int arg) |
463 | @@ -136,8 +143,14 @@ |
464 | static void job_process_trace_fork (Job *job, ProcessType process); |
465 | static void job_process_trace_exec (Job *job, ProcessType process); |
466 | |
467 | +<<<<<<< TREE |
468 | extern int user_mode; |
469 | +======= |
470 | +>>>>>>> MERGE-SOURCE |
471 | extern char *control_server_address; |
472 | +extern int user_mode; |
473 | +extern int session_end; |
474 | +extern time_t quiesce_phase_time; |
475 | |
476 | /** |
477 | * job_process_run: |
478 | @@ -1231,6 +1244,52 @@ |
479 | } |
480 | |
481 | /** |
482 | + * job_process_jobs_running: |
483 | + * |
484 | + * Determine if any jobs are running. |
485 | + * |
486 | + * Returns: TRUE if jobs are still running, else FALSE. |
487 | + **/ |
488 | +int |
489 | +job_process_jobs_running (void) |
490 | +{ |
491 | + job_class_init (); |
492 | + |
493 | + NIH_HASH_FOREACH (job_classes, iter) { |
494 | + JobClass *class = (JobClass *)iter; |
495 | + |
496 | + NIH_HASH_FOREACH (class->instances, job_iter) |
497 | + return TRUE; |
498 | + } |
499 | + |
500 | + return FALSE; |
501 | +} |
502 | + |
503 | + |
504 | +/** |
505 | + * job_process_stop_all: |
506 | + * |
507 | + * Stop all running jobs. |
508 | + **/ |
509 | +void |
510 | +job_process_stop_all (void) |
511 | +{ |
512 | + job_class_init (); |
513 | + |
514 | + NIH_HASH_FOREACH (job_classes, iter) { |
515 | + JobClass *class = (JobClass *)iter; |
516 | + |
517 | + /* Note that instances get killed in a random order */ |
518 | + NIH_HASH_FOREACH (class->instances, job_iter) { |
519 | + Job *job = (Job *)job_iter; |
520 | + |
521 | + /* Request job instance stops */ |
522 | + job_change_goal (job, JOB_STOP); |
523 | + } |
524 | + } |
525 | +} |
526 | + |
527 | +/** |
528 | * job_process_set_kill_timer: |
529 | * @job: job to set kill timer for, |
530 | * @process: process to be killed, |
531 | @@ -1559,7 +1618,7 @@ |
532 | * that's a simple matter of doing nothing. Check |
533 | * the job isn't running away first though. |
534 | */ |
535 | - if (failed && job->class->respawn) { |
536 | + if (failed && job->class->respawn && ! disable_respawn) { |
537 | if (job_process_catch_runaway (job)) { |
538 | nih_warn (_("%s respawning too fast, stopped"), |
539 | job_name (job)); |
540 | |
541 | === modified file 'init/job_process.h' |
542 | --- init/job_process.h 2012-11-26 19:30:41 +0000 |
543 | +++ init/job_process.h 2013-02-15 11:31:39 +0000 |
544 | @@ -63,7 +63,6 @@ |
545 | #define JOB_PROCESS_LOG_FILE_EXT ".log" |
546 | #endif |
547 | |
548 | - |
549 | /** |
550 | * JobProcessErrorType: |
551 | * |
552 | @@ -151,6 +150,10 @@ |
553 | |
554 | void job_process_adj_kill_timer (Job *job, time_t due); |
555 | |
556 | +int job_process_jobs_running (void); |
557 | + |
558 | +void job_process_stop_all (void); |
559 | + |
560 | NIH_END_EXTERN |
561 | |
562 | #endif /* INIT_JOB_PROCESS_H */ |
563 | |
564 | === modified file 'init/main.c' |
565 | --- init/main.c 2013-02-14 13:36:06 +0000 |
566 | +++ init/main.c 2013-02-15 11:31:39 +0000 |
567 | @@ -425,19 +425,20 @@ |
568 | nih_signal_set_handler (SIGPWR, nih_signal_handler); |
569 | NIH_MUST (nih_signal_add_handler (NULL, SIGPWR, pwr_handler, NULL)); |
570 | |
571 | - /* SIGHUP instructs us to re-load our configuration */ |
572 | - nih_signal_set_handler (SIGHUP, nih_signal_handler); |
573 | - NIH_MUST (nih_signal_add_handler (NULL, SIGHUP, hup_handler, NULL)); |
574 | - |
575 | - /* SIGUSR1 instructs us to reconnect to D-Bus */ |
576 | - nih_signal_set_handler (SIGUSR1, nih_signal_handler); |
577 | - NIH_MUST (nih_signal_add_handler (NULL, SIGUSR1, usr1_handler, NULL)); |
578 | - |
579 | } |
580 | |
581 | - /* SIGTERM instructs us to re-exec ourselves; this should be the |
582 | - * last in the list to ensure that all other signals are handled |
583 | - * before a SIGTERM. |
584 | + /* SIGHUP instructs us to re-load our configuration */ |
585 | + nih_signal_set_handler (SIGHUP, nih_signal_handler); |
586 | + NIH_MUST (nih_signal_add_handler (NULL, SIGHUP, hup_handler, NULL)); |
587 | + |
588 | + /* SIGUSR1 instructs us to reconnect to D-Bus */ |
589 | + nih_signal_set_handler (SIGUSR1, nih_signal_handler); |
590 | + NIH_MUST (nih_signal_add_handler (NULL, SIGUSR1, usr1_handler, NULL)); |
591 | + |
592 | + /* SIGTERM instructs us to re-exec ourselves when running as PID |
593 | + * 1, or to exit when running as a Session Init; this signal should |
594 | + * be the last in the list to ensure that all other signals are |
595 | + * handled before a SIGTERM. |
596 | */ |
597 | nih_signal_set_handler (SIGTERM, nih_signal_handler); |
598 | NIH_MUST (nih_signal_add_handler (NULL, SIGTERM, term_handler, NULL)); |
599 | @@ -634,7 +635,7 @@ |
600 | } |
601 | |
602 | if (disable_sessions) |
603 | - nih_debug ("Sessions disabled"); |
604 | + nih_debug ("Chroot Sessions disabled"); |
605 | |
606 | /* Set us as the child subreaper. |
607 | * This ensures that even when init doesn't run as PID 1, it'll always be |
608 | @@ -656,8 +657,6 @@ |
609 | nih_main_loop_interrupt (); |
610 | ret = nih_main_loop (); |
611 | |
612 | - control_cleanup (); |
613 | - |
614 | return ret; |
615 | } |
616 | |
617 | @@ -805,7 +804,8 @@ |
618 | * @signal: signal caught. |
619 | * |
620 | * This is called when we receive the TERM signal, which instructs us |
621 | - * to reexec ourselves. |
622 | + * to reexec ourselves when running as PID 1, or to perform a controlled |
623 | + * exit when running as a Session Init. |
624 | **/ |
625 | static void |
626 | term_handler (void *data, |
627 | @@ -814,8 +814,12 @@ |
628 | nih_assert (args_copy[0] != NULL); |
629 | nih_assert (signal != NULL); |
630 | |
631 | + if (user_mode) { |
632 | + quiesce (QUIESCE_REQUESTER_SYSTEM); |
633 | + return; |
634 | + } |
635 | + |
636 | nih_warn (_("Re-executing %s"), args_copy[0]); |
637 | - |
638 | stateful_reexec (); |
639 | } |
640 | |
641 | @@ -826,7 +830,7 @@ |
642 | * @data: unused, |
643 | * @signal: signal that called this handler. |
644 | * |
645 | - * Handle having recieved the SIGINT signal, sent to us when somebody |
646 | + * Handle having received the SIGINT signal, sent to us when somebody |
647 | * presses Ctrl-Alt-Delete on the console. We just generate a |
648 | * ctrlaltdel event. |
649 | **/ |
650 | @@ -842,7 +846,7 @@ |
651 | * @data: unused, |
652 | * @signal: signal that called this handler. |
653 | * |
654 | - * Handle having recieved the SIGWINCH signal, sent to us when somebody |
655 | + * Handle having received the SIGWINCH signal, sent to us when somebody |
656 | * presses Alt-UpArrow on the console. We just generate a |
657 | * kbdrequest event. |
658 | **/ |
659 | @@ -858,7 +862,7 @@ |
660 | * @data: unused, |
661 | * @signal: signal that called this handler. |
662 | * |
663 | - * Handle having recieved the SIGPWR signal, sent to us when powstatd |
664 | + * Handle having received the SIGPWR signal, sent to us when powstatd |
665 | * changes the /etc/powerstatus file. We just generate a |
666 | * power-status-changed event and jobs read the file. |
667 | **/ |
668 | @@ -874,7 +878,7 @@ |
669 | * @data: unused, |
670 | * @signal: signal that called this handler. |
671 | * |
672 | - * Handle having recieved the SIGHUP signal, which we use to instruct us to |
673 | + * Handle having received the SIGHUP signal, which we use to instruct us to |
674 | * reload our configuration. |
675 | **/ |
676 | static void |
677 | @@ -890,7 +894,7 @@ |
678 | * @data: unused, |
679 | * @signal: signal that called this handler. |
680 | * |
681 | - * Handle having recieved the SIGUSR signal, which we use to instruct us to |
682 | + * Handle having received the SIGUSR signal, which we use to instruct us to |
683 | * reconnect to D-Bus. |
684 | **/ |
685 | static void |
686 | |
687 | === modified file 'init/man/init.8' |
688 | --- init/man/init.8 2013-02-08 16:55:25 +0000 |
689 | +++ init/man/init.8 2013-02-15 11:31:39 +0000 |
690 | @@ -149,8 +149,25 @@ |
691 | and pass all arguments to that. See that manual page for further |
692 | details. However, if the |
693 | .B \-\-user |
694 | -option is specified, it will read alternative configuration files and |
695 | -manage the individual user session in a similar fashion. |
696 | +option is specified, it will run as a |
697 | +.B Session Init |
698 | +and read alternative configuration files and manage the individual user |
699 | +session in a similar fashion. |
700 | + |
701 | +Sending a Session Init a |
702 | +.I SIGTERM |
703 | +signal is taken as a request to shutdown due to an impending system |
704 | +shutdown. In this scenario, the |
705 | +Session Init will emit the |
706 | +.B session\-end |
707 | +event and request all running jobs stop. It will attempt to honour jobs |
708 | +.B kill timeout |
709 | +values (see |
710 | +.BR init (5) |
711 | +for further details). Note however that system policy will prevail: if |
712 | +jobs request timeout values longer than the system policy allows for |
713 | +complete system shutdown, it will not be possible to honour them before |
714 | +the Session Init is killed by the system. |
715 | .\" |
716 | .SH ENVIRONMENT VARIABLES |
717 | |
718 | |
719 | === added file 'init/man/session-end.7' |
720 | --- init/man/session-end.7 1970-01-01 00:00:00 +0000 |
721 | +++ init/man/session-end.7 2013-02-15 11:31:39 +0000 |
722 | @@ -0,0 +1,34 @@ |
723 | +.TH session\-end 7 2013-02-08 "Upstart" |
724 | +.\" |
725 | +.SH NAME |
726 | +session\-end \- event signalling session shutdown |
727 | +.\" |
728 | +.SH SYNOPSIS |
729 | +.B session\-end |
730 | +.BI TYPE\fR= TYPE |
731 | +.\" |
732 | +.SH DESCRIPTION |
733 | +The |
734 | +.B session\-end |
735 | +event is generated by the Upstart |
736 | +.BR init (8) |
737 | +daemon when running as a Session Init (where its pid is not 1) when |
738 | +requested to stop. |
739 | + |
740 | +The |
741 | +.B TYPE |
742 | +environment variable will be set to either |
743 | +.I shutdown |
744 | +when the Session Init has received the |
745 | +.I SIGTERM |
746 | +signal, or |
747 | +.I logout |
748 | +when the Session Init has processed the |
749 | +.B com.ubuntu.Upstart0_6.EndSession() |
750 | +D\-Bus method call. |
751 | + |
752 | +.\" |
753 | +.SH SEE ALSO |
754 | +.BR startup (7) |
755 | +.BR init (5) |
756 | +.BR init (8) |
757 | |
758 | === modified file 'init/man/startup.7' |
759 | --- init/man/startup.7 2009-07-09 12:26:11 +0000 |
760 | +++ init/man/startup.7 2013-02-15 11:31:39 +0000 |
761 | @@ -27,12 +27,17 @@ |
762 | .BR runlevel (7) |
763 | event. See that page for a more detailed explanation of this process. |
764 | |
765 | +This event is emitted when running both as pid 1 and as a Session Init. |
766 | + |
767 | Paradoxically there is currently no corresponding Upstart-native event |
768 | signifying that the system is to be shutdown, only the System V compatible |
769 | .B runlevel 0 |
770 | and |
771 | .B runlevel 6 |
772 | -events provide this functionality. |
773 | +events provide this functionality. However, when running as a Session |
774 | +Init, the |
775 | +.BR session\-end |
776 | +event performs this function. |
777 | .\" |
778 | .SH EXAMPLE |
779 | A service with no other dependencies run on startup might use: |
780 | @@ -45,4 +50,6 @@ |
781 | .\" |
782 | .SH SEE ALSO |
783 | .BR runlevel (7) |
784 | +.BR session\-end (7) |
785 | +.BR init (5) |
786 | .BR init (8) |
787 | |
788 | === added file 'init/quiesce.c' |
789 | --- init/quiesce.c 1970-01-01 00:00:00 +0000 |
790 | +++ init/quiesce.c 2013-02-15 11:31:39 +0000 |
791 | @@ -0,0 +1,248 @@ |
792 | +/* upstart |
793 | + * |
794 | + * quiesce.c - shutdown handling. |
795 | + * |
796 | + * Copyright © 2013 Canonical Ltd. |
797 | + * Author: James Hunt <james.hunt@canonical.com> |
798 | + * |
799 | + * This program is free software; you can redistribute it and/or modify |
800 | + * it under the terms of the GNU General Public License version 2, as |
801 | + * published by the Free Software Foundation. |
802 | + * |
803 | + * This program is distributed in the hope that it will be useful, |
804 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
805 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
806 | + * GNU General Public License for more details. |
807 | + * |
808 | + * You should have received a copy of the GNU General Public License along |
809 | + * with this program; if not, write to the Free Software Foundation, Inc., |
810 | + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
811 | + */ |
812 | + |
813 | +#ifdef HAVE_CONFIG_H |
814 | +# include <config.h> |
815 | +#endif /* HAVE_CONFIG_H */ |
816 | + |
817 | +#include "quiesce.h" |
818 | +#include "events.h" |
819 | +#include "environ.h" |
820 | +#include "conf.h" |
821 | +#include "job_process.h" |
822 | +#include "control.h" |
823 | + |
824 | +#include <nih/main.h> |
825 | + |
826 | +/** |
827 | + * quiesce_requester: |
828 | + * |
829 | + * Where the quiesce request originated. This determines |
830 | + * the shutdown behaviour. |
831 | + **/ |
832 | +static QuiesceRequester quiesce_requester = QUIESCE_REQUESTER_INVALID; |
833 | + |
834 | +/** |
835 | + * quiesce_phase: |
836 | + * |
837 | + * Current phase of shutdown. |
838 | + **/ |
839 | +static QuiescePhase quiesce_phase = QUIESCE_PHASE_NOT_QUIESCED; |
840 | + |
841 | +/** |
842 | + * max_kill_timeout: |
843 | + * |
844 | + * Maxiumum kill_timout value calculated from all running jobs used to |
845 | + * determine how long to wait before exiting. |
846 | + **/ |
847 | +static time_t max_kill_timeout = 0; |
848 | + |
849 | +/** |
850 | + * quiesce_phase_time: |
851 | + * |
852 | + * Time that a particular phase started. |
853 | + **/ |
854 | +static time_t quiesce_phase_time = 0; |
855 | + |
856 | +/* External definitions */ |
857 | +extern int disable_respawn; |
858 | + |
859 | +/** |
860 | + * quiesce: |
861 | + * |
862 | + * @requester: where the quiesce request originated. |
863 | + * |
864 | + * Commence Session Init shutdown. |
865 | + **/ |
866 | +void |
867 | +quiesce (QuiesceRequester requester) |
868 | +{ |
869 | + nih_local char **env = NULL; |
870 | + const char *reason; |
871 | + |
872 | + job_class_init (); |
873 | + |
874 | + /* Quiesce already in progress */ |
875 | + if (quiesce_phase != QUIESCE_PHASE_NOT_QUIESCED) |
876 | + return; |
877 | + |
878 | + quiesce_requester = requester; |
879 | + |
880 | + /* System shutdown skips the wait phase to ensure all running |
881 | + * jobs get signalled. |
882 | + * |
883 | + * Note that jobs which choose to start on SESSION_END_EVENT may |
884 | + * not complete (or even start), but no guarantee is possible in |
885 | + * the system shutdown scenario since Session Inits must not |
886 | + * hold up the system. |
887 | + */ |
888 | + quiesce_phase = (requester == QUIESCE_REQUESTER_SYSTEM) |
889 | + ? QUIESCE_PHASE_KILL |
890 | + : QUIESCE_PHASE_WAIT; |
891 | + |
892 | + reason = (requester == QUIESCE_REQUESTER_SESSION) |
893 | + ? _("logout") : _("shutdown"); |
894 | + |
895 | + nih_info (_("Quiescing due to %s request"), reason); |
896 | + |
897 | + quiesce_phase_time = time (NULL); |
898 | + |
899 | + /* Stop existing jobs from respawning */ |
900 | + disable_respawn = TRUE; |
901 | + |
902 | + /* Signal that the session is ending. This may start new jobs. |
903 | + * |
904 | + * Note that the event doesn't actually get emitted until the |
905 | + * next time the main loop gets a chance to run. |
906 | + */ |
907 | + env = NIH_MUST (nih_str_array_new (NULL)); |
908 | + |
909 | + NIH_MUST (environ_set (&env, NULL, NULL, TRUE, |
910 | + "TYPE=%s", reason)); |
911 | + |
912 | + NIH_MUST (event_new (NULL, SESSION_END_EVENT, env)); |
913 | + |
914 | + if (requester == QUIESCE_REQUESTER_SYSTEM) { |
915 | + /* We'll attempt to wait for this long, but system |
916 | + * policy may prevent it such that we just get killed |
917 | + * and job processes reparented to PID 1. |
918 | + */ |
919 | + max_kill_timeout = job_class_max_kill_timeout (); |
920 | + |
921 | + job_process_stop_all (); |
922 | + } |
923 | + |
924 | + /* Check every second to see if all jobs have finished. If so, |
925 | + * we can exit early. |
926 | + */ |
927 | + NIH_MUST (nih_timer_add_periodic (NULL, 1, |
928 | + (NihTimerCb)quiesce_wait_callback, NULL)); |
929 | +} |
930 | + |
931 | +/** |
932 | + * quiesce_wait_callback: |
933 | + * |
934 | + * @data: not used, |
935 | + * @timer: timer that caused us to be called. |
936 | + * |
937 | + * Callback used to check if all jobs have finished and if so |
938 | + * finalise Session Init shutdown. |
939 | + **/ |
940 | +void |
941 | +quiesce_wait_callback (void *data, NihTimer *timer) |
942 | +{ |
943 | + time_t now; |
944 | + |
945 | + nih_assert (timer); |
946 | + nih_assert (quiesce_phase_time); |
947 | + |
948 | + now = time (NULL); |
949 | + |
950 | + nih_assert (quiesce_requester != QUIESCE_REQUESTER_INVALID); |
951 | + |
952 | + if (quiesce_requester == QUIESCE_REQUESTER_SYSTEM) { |
953 | + nih_assert (quiesce_phase == QUIESCE_PHASE_KILL); |
954 | + |
955 | + if ((now - quiesce_phase_time) > max_kill_timeout) |
956 | + goto out; |
957 | + |
958 | + } else if (quiesce_phase == QUIESCE_PHASE_WAIT) { |
959 | + |
960 | + if ((now - quiesce_phase_time) > QUIESCE_DEFAULT_JOB_RUNTIME) { |
961 | + quiesce_phase = QUIESCE_PHASE_KILL; |
962 | + |
963 | + /* reset for new phase */ |
964 | + quiesce_phase_time = time (NULL); |
965 | + |
966 | + max_kill_timeout = job_class_max_kill_timeout (); |
967 | + job_process_stop_all (); |
968 | + } |
969 | + } else if (quiesce_phase == QUIESCE_PHASE_KILL) { |
970 | + |
971 | + if ((now - quiesce_phase_time) > max_kill_timeout) |
972 | + goto out; |
973 | + } else { |
974 | + nih_assert_not_reached (); |
975 | + } |
976 | + |
977 | + if (! job_process_jobs_running ()) |
978 | + goto out; |
979 | + |
980 | + return; |
981 | + |
982 | +out: |
983 | + quiesce_show_slow_jobs (); |
984 | + |
985 | + /* Note that we might skip the kill phase for the session |
986 | + * requestor if no jobs are actually running at this point. |
987 | + */ |
988 | + quiesce_phase = QUIESCE_PHASE_CLEANUP; |
989 | + quiesce_finalise (); |
990 | + |
991 | + /* Deregister */ |
992 | + nih_free (timer); |
993 | +} |
994 | + |
995 | +/** |
996 | + * quiesce_show_slow_jobs: |
997 | + * |
998 | + * List jobs that are still running after their expected end time. |
999 | + **/ |
1000 | +void |
1001 | +quiesce_show_slow_jobs (void) |
1002 | +{ |
1003 | + job_class_init (); |
1004 | + |
1005 | + NIH_HASH_FOREACH (job_classes, iter) { |
1006 | + JobClass *class = (JobClass *)iter; |
1007 | + |
1008 | + /* Note that instances get killed in a random order */ |
1009 | + NIH_HASH_FOREACH (class->instances, job_iter) { |
1010 | + nih_local const char *name = NULL; |
1011 | + Job *job; |
1012 | + |
1013 | + job = (Job *)job_iter; |
1014 | + |
1015 | + name = job_name (job); |
1016 | + |
1017 | + nih_message ("job %s failed to stop", name); |
1018 | + } |
1019 | + } |
1020 | +} |
1021 | + |
1022 | + |
1023 | +/** |
1024 | + * quiesce_finalise: |
1025 | + * |
1026 | + * Perform final shutdown operations. |
1027 | + **/ |
1028 | +void |
1029 | +quiesce_finalise (void) |
1030 | +{ |
1031 | + nih_assert (quiesce_phase == QUIESCE_PHASE_CLEANUP); |
1032 | + |
1033 | + /* Cleanup */ |
1034 | + conf_destroy (); |
1035 | + session_destroy (); |
1036 | + control_cleanup (); |
1037 | + |
1038 | + nih_main_loop_exit (0); |
1039 | +} |
1040 | |
1041 | === added file 'init/quiesce.h' |
1042 | --- init/quiesce.h 1970-01-01 00:00:00 +0000 |
1043 | +++ init/quiesce.h 2013-02-15 11:31:39 +0000 |
1044 | @@ -0,0 +1,76 @@ |
1045 | +/* upstart |
1046 | + * |
1047 | + * Copyright © 2013 Canonical Ltd. |
1048 | + * Author: James Hunt <james.hunt@canonical.com> |
1049 | + * |
1050 | + * This program is free software; you can redistribute it and/or modify |
1051 | + * it under the terms of the GNU General Public License version 2, as |
1052 | + * published by the Free Software Foundation. |
1053 | + * |
1054 | + * This program is distributed in the hope that it will be useful, |
1055 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1056 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1057 | + * GNU General Public License for more details. |
1058 | + * |
1059 | + * You should have received a copy of the GNU General Public License along |
1060 | + * with this program; if not, write to the Free Software Foundation, Inc., |
1061 | + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
1062 | + */ |
1063 | + |
1064 | +#ifndef INIT_QUIESCE_H |
1065 | +#define INIT_QUIESCE_H |
1066 | + |
1067 | +#include <nih/timer.h> |
1068 | + |
1069 | +/** |
1070 | + * QUIESCE_DEFAULT_JOB_RUNTIME: |
1071 | + * |
1072 | + * The default maximum length of time to wait after emitting the |
1073 | + * SESSION_END_EVENT event before stopping all jobs. |
1074 | + **/ |
1075 | +#define QUIESCE_DEFAULT_JOB_RUNTIME 5 |
1076 | + |
1077 | +/** |
1078 | + * QuiesceRequester: |
1079 | + * |
1080 | + * Reason for Session Init wishing to shutdown; either the Session Init |
1081 | + * has been notified the system is being shutdown, or the session has |
1082 | + * requested it be ended (for example due to a user logout request). |
1083 | + **/ |
1084 | +typedef enum quiesce_requester { |
1085 | + QUIESCE_REQUESTER_INVALID = -1, |
1086 | + QUIESCE_REQUESTER_SYSTEM = 0, |
1087 | + QUIESCE_REQUESTER_SESSION, |
1088 | +} QuiesceRequester; |
1089 | + |
1090 | +/** |
1091 | + * QuiescePhase: |
1092 | + * |
1093 | + * Phase 0: No quiesce operation in progress. |
1094 | + * |
1095 | + * Phase 1: Wait: Period between SESSION_END_EVENT being emitted and |
1096 | + * QUIESCE_DEFAULT_JOB_RUNTIME being reached. |
1097 | + * |
1098 | + * Phase 2: Kill: Period between QUIESCE_DEFAULT_JOB_RUNTIME being |
1099 | + * reached and kill signal being sent to all jobs. |
1100 | + * |
1101 | + * Phase 3: Cleanup: Period between all jobs having ended |
1102 | + * (either naturally or by induction) and final exit. |
1103 | + **/ |
1104 | +typedef enum quiesce_phase { |
1105 | + QUIESCE_PHASE_NOT_QUIESCED, |
1106 | + QUIESCE_PHASE_WAIT, |
1107 | + QUIESCE_PHASE_KILL, |
1108 | + QUIESCE_PHASE_CLEANUP, |
1109 | +} QuiescePhase; |
1110 | + |
1111 | +NIH_BEGIN_EXTERN |
1112 | + |
1113 | +void quiesce (QuiesceRequester requester); |
1114 | +void quiesce_wait_callback (void *data, NihTimer *timer); |
1115 | +void quiesce_show_slow_jobs (void); |
1116 | +void quiesce_finalise (void); |
1117 | + |
1118 | +NIH_END_EXTERN |
1119 | + |
1120 | +#endif /* INIT_QUIESCE_H */ |
1121 | |
1122 | === modified file 'init/session.c' |
1123 | --- init/session.c 2013-01-25 09:01:00 +0000 |
1124 | +++ init/session.c 2013-02-15 11:31:39 +0000 |
1125 | @@ -89,6 +89,18 @@ |
1126 | sessions = NIH_MUST (nih_list_new (NULL)); |
1127 | } |
1128 | |
1129 | +/** |
1130 | + * session_destroy: |
1131 | + * |
1132 | + * Clean up the sessions list. |
1133 | + **/ |
1134 | +void |
1135 | +session_destroy (void) |
1136 | +{ |
1137 | + if (sessions) |
1138 | + nih_free (sessions); |
1139 | +} |
1140 | + |
1141 | |
1142 | /** |
1143 | * session_new: |
1144 | |
1145 | === modified file 'init/session.h' |
1146 | --- init/session.h 2013-01-25 09:01:00 +0000 |
1147 | +++ init/session.h 2013-02-15 11:31:39 +0000 |
1148 | @@ -78,6 +78,7 @@ |
1149 | extern NihList *sessions; |
1150 | |
1151 | void session_init (void); |
1152 | +void session_destroy (void); |
1153 | |
1154 | Session * session_new (const void *parent, const char *chroot) |
1155 | __attribute__ ((malloc, warn_unused_result)); |
1156 | |
1157 | === modified file 'util/initctl.c' |
1158 | --- util/initctl.c 2013-02-02 16:09:52 +0000 |
1159 | +++ util/initctl.c 2013-02-15 11:31:39 +0000 |
1160 | @@ -372,7 +372,7 @@ |
1161 | |
1162 | dbus_connection_set_exit_on_disconnect (connection, FALSE); |
1163 | } else { |
1164 | - if (dest_name) { |
1165 | + if (dest_name && ! user_mode) { |
1166 | fprintf (stderr, _("%s: --dest given without --system\n"), |
1167 | program_name); |
1168 | nih_main_suggest_help (); |
1169 | |
1170 | === modified file 'util/tests/test_initctl.c' |
1171 | --- util/tests/test_initctl.c 2013-02-02 16:09:52 +0000 |
1172 | +++ util/tests/test_initctl.c 2013-02-15 11:31:39 +0000 |
1173 | @@ -32,6 +32,7 @@ |
1174 | #include <regex.h> |
1175 | #include <sys/types.h> |
1176 | #include <sys/stat.h> |
1177 | +#include <ctype.h> |
1178 | |
1179 | #include <nih-dbus/dbus_error.h> |
1180 | #include <nih-dbus/dbus_connection.h> |
1181 | @@ -50,6 +51,9 @@ |
1182 | |
1183 | #include "dbus/upstart.h" |
1184 | |
1185 | +#include "com.ubuntu.Upstart.h" |
1186 | + |
1187 | + |
1188 | #ifndef UPSTART_BINARY |
1189 | #error unable to find init binary as UPSTART_BINARY not defined |
1190 | #endif /* UPSTART_BINARY */ |
1191 | @@ -60,6 +64,24 @@ |
1192 | |
1193 | #define BUFFER_SIZE 1024 |
1194 | |
1195 | +/** |
1196 | + * TEST_QUIESCE_WAIT_PHASE: |
1197 | + * |
1198 | + * Maximum time we expect upstart to wait in the QUIESCE_PHASE_WAIT |
1199 | + * phase. |
1200 | + **/ |
1201 | +#define TEST_EXIT_TIME 5 |
1202 | + |
1203 | +/** |
1204 | + * TEST_QUIESCE_KILL_PHASE: |
1205 | + * |
1206 | + * Maximum time we expect upstart to wait in the QUIESCE_PHASE_KILL |
1207 | + * phase. |
1208 | + **/ |
1209 | +#define TEST_QUIESCE_KILL_PHASE 5 |
1210 | + |
1211 | +#define TEST_QUIESCE_TOTAL_WAIT_TIME (TEST_EXIT_TIME + TEST_QUIESCE_KILL_PHASE) |
1212 | + |
1213 | /* A 'reasonable' path, but which also contains a marker at the end so |
1214 | * we know when we're looking at a PATH these tests have set. |
1215 | */ |
1216 | @@ -68,53 +90,66 @@ |
1217 | /* Default value for TERM if not already set */ |
1218 | #define TEST_INITCTL_DEFAULT_TERM "linux" |
1219 | |
1220 | +int |
1221 | +set_upstart_session (void); |
1222 | + |
1223 | /** |
1224 | - * WAIT_FOR_UPSTART: |
1225 | + * wait_for_upstart: |
1226 | + * |
1227 | + * @user: TRUE if waiting for a Session Init (which uses a private bus |
1228 | + * rather than the session bus), else FALSE. |
1229 | * |
1230 | * Wait for Upstart to appear on D-Bus denoting its completion of |
1231 | * initialisation. Wait time is somewhat arbitrary (but more |
1232 | * than adequate!). |
1233 | **/ |
1234 | -#define WAIT_FOR_UPSTART() \ |
1235 | -{ \ |
1236 | - nih_local NihDBusProxy *upstart = NULL; \ |
1237 | - DBusConnection *connection; \ |
1238 | - char *address; \ |
1239 | - NihError *err; \ |
1240 | - int running = FALSE; \ |
1241 | - \ |
1242 | - /* XXX: arbitrary value */ \ |
1243 | - int attempts = 10; \ |
1244 | - \ |
1245 | - address = getenv ("DBUS_SESSION_BUS_ADDRESS"); \ |
1246 | - TEST_TRUE (address); \ |
1247 | - \ |
1248 | - while (attempts) { \ |
1249 | - attempts--; \ |
1250 | - sleep (1); \ |
1251 | - connection = nih_dbus_connect (address, NULL); \ |
1252 | - \ |
1253 | - if (! connection) { \ |
1254 | - err = nih_error_get (); \ |
1255 | - nih_free (err); \ |
1256 | - continue; \ |
1257 | - } \ |
1258 | - \ |
1259 | - upstart = nih_dbus_proxy_new (NULL, connection, \ |
1260 | - NULL, \ |
1261 | - DBUS_PATH_UPSTART, \ |
1262 | - NULL, NULL); \ |
1263 | - \ |
1264 | - if (! upstart) { \ |
1265 | - err = nih_error_get (); \ |
1266 | - nih_free (err); \ |
1267 | - dbus_connection_unref (connection); \ |
1268 | - } else { \ |
1269 | - running = TRUE; \ |
1270 | - break; \ |
1271 | - } \ |
1272 | - } \ |
1273 | - TEST_EQ (running, TRUE); \ |
1274 | +void |
1275 | +wait_for_upstart (int user) |
1276 | +{ |
1277 | + nih_local NihDBusProxy *upstart = NULL; |
1278 | + DBusConnection *connection; |
1279 | + char *address; |
1280 | + NihError *err; |
1281 | + int running = FALSE; |
1282 | + |
1283 | + /* XXX: arbitrary value */ |
1284 | + int attempts = 10; |
1285 | + |
1286 | + if (user) { |
1287 | + set_upstart_session (); |
1288 | + address = getenv ("UPSTART_SESSION"); |
1289 | + } else { |
1290 | + address = getenv ("DBUS_SESSION_BUS_ADDRESS"); |
1291 | + } |
1292 | + |
1293 | + TEST_TRUE (address); |
1294 | + |
1295 | + while (attempts) { |
1296 | + attempts--; |
1297 | + sleep (1); |
1298 | + connection = nih_dbus_connect (address, NULL); |
1299 | + |
1300 | + if (! connection) { |
1301 | + err = nih_error_get (); |
1302 | + nih_free (err); |
1303 | + continue; |
1304 | + } |
1305 | + |
1306 | + upstart = nih_dbus_proxy_new (NULL, connection, |
1307 | + NULL, |
1308 | + DBUS_PATH_UPSTART, |
1309 | + NULL, NULL); |
1310 | + |
1311 | + if (! upstart) { |
1312 | + err = nih_error_get (); |
1313 | + nih_free (err); |
1314 | + dbus_connection_unref (connection); |
1315 | + } else { |
1316 | + running = TRUE; |
1317 | + break; |
1318 | + } |
1319 | + } |
1320 | + TEST_EQ (running, TRUE); |
1321 | } |
1322 | |
1323 | /** |
1324 | @@ -150,6 +185,10 @@ |
1325 | TEST_TRUE (WIFSIGNALED (status)); \ |
1326 | TEST_TRUE (WTERMSIG (status) == signo); \ |
1327 | } \ |
1328 | + /* reset since a subsequent start could specify a different \ |
1329 | + * user_mode value. \ |
1330 | + */ \ |
1331 | + test_user_mode = FALSE; \ |
1332 | } |
1333 | |
1334 | /** |
1335 | @@ -160,11 +199,7 @@ |
1336 | * Stop upstart process @pid. |
1337 | **/ |
1338 | #define STOP_UPSTART(pid) \ |
1339 | - KILL_UPSTART (pid, SIGKILL, TRUE); \ |
1340 | - /* reset since a subsequent start could specify a different \ |
1341 | - * user_mode value. \ |
1342 | - */ \ |
1343 | - test_user_mode = FALSE |
1344 | + KILL_UPSTART (pid, SIGKILL, TRUE) |
1345 | |
1346 | /** |
1347 | * REEXEC_UPSTART: |
1348 | @@ -175,7 +210,7 @@ |
1349 | **/ |
1350 | #define REEXEC_UPSTART(pid) \ |
1351 | KILL_UPSTART (pid, SIGTERM, FALSE); \ |
1352 | - WAIT_FOR_UPSTART () |
1353 | + wait_for_upstart (FALSE) |
1354 | |
1355 | /** |
1356 | * RUN_COMMAND: |
1357 | @@ -475,6 +510,204 @@ |
1358 | int test_user_mode = FALSE; |
1359 | |
1360 | /** |
1361 | + * set_upstart_session: |
1362 | + * |
1363 | + * Attempt to "enter" an Upstart session by setting UPSTART_SESSION to |
1364 | + * the value of the currently running session. |
1365 | + * |
1366 | + * It is only legitimate to call this function if you have previously |
1367 | + * started a Session Init process. |
1368 | + * |
1369 | + * Limitations: Assumes that at most 1 session is running. |
1370 | + * |
1371 | + * Returns: TRUE if it was possible to enter the currently running |
1372 | + * Upstart session, else FALSE. |
1373 | + **/ |
1374 | +int |
1375 | +set_upstart_session (void) |
1376 | +{ |
1377 | + char *value; |
1378 | + nih_local char *cmd = NULL; |
1379 | + nih_local char **output = NULL; |
1380 | + size_t lines = 0; |
1381 | + int got = FALSE; |
1382 | + int i; |
1383 | + |
1384 | + /* XXX: arbitrary value */ |
1385 | + int loops = 5; |
1386 | + |
1387 | + /* list-sessions relies on this */ |
1388 | + if (! getenv ("XDG_RUNTIME_DIR")) |
1389 | + return FALSE; |
1390 | + |
1391 | + cmd = nih_sprintf (NULL, "%s list-sessions 2>&1", INITCTL_BINARY); |
1392 | + TEST_NE_P (cmd, NULL); |
1393 | + |
1394 | + /* We expect the list-sessions command to return a valid session |
1395 | + * within a reasonable period of time. |
1396 | + */ |
1397 | + for (i = 0; i < loops; i++) { |
1398 | + sleep (1); |
1399 | + |
1400 | + RUN_COMMAND (NULL, cmd, &output, &lines); |
1401 | + if (lines != 1) |
1402 | + continue; |
1403 | + |
1404 | + /* No pid in output */ |
1405 | + if (! isdigit(output[0][0])) |
1406 | + continue; |
1407 | + |
1408 | + /* look for separator between pid and value of |
1409 | + * UPSTART_SESSION. |
1410 | + */ |
1411 | + value = strstr (output[0], " "); |
1412 | + if (! value) |
1413 | + continue; |
1414 | + |
1415 | + /* jump over space */ |
1416 | + value += 1; |
1417 | + if (! value) |
1418 | + continue; |
1419 | + |
1420 | + /* No socket address */ |
1421 | + if (strstr (value, "unix:abstract") == value) { |
1422 | + got = TRUE; |
1423 | + break; |
1424 | + } |
1425 | + } |
1426 | + |
1427 | + if (got != TRUE) |
1428 | + return FALSE; |
1429 | + |
1430 | + assert0 (setenv ("UPSTART_SESSION", value, 1)); |
1431 | + |
1432 | + return TRUE; |
1433 | +} |
1434 | + |
1435 | +/** |
1436 | + * selfpipe: |
1437 | + * |
1438 | + * Used to allow a timed process wait. |
1439 | + **/ |
1440 | +int selfpipe[2] = { -1, -1 }; |
1441 | + |
1442 | +void |
1443 | +selfpipe_write (int n) |
1444 | +{ |
1445 | + assert (selfpipe[1] != -1); |
1446 | + |
1447 | + (void)write (selfpipe[1], "", 1); |
1448 | +} |
1449 | + |
1450 | +/** |
1451 | + * selfpipe_setup: |
1452 | + * |
1453 | + * Arrange for SIGCHLD to write to selfpipe such that we can select(2) |
1454 | + * on child process status changes. |
1455 | + **/ |
1456 | +void |
1457 | +selfpipe_setup (void) |
1458 | +{ |
1459 | + static struct sigaction act; |
1460 | + int read_flags; |
1461 | + int write_flags; |
1462 | + |
1463 | + assert (selfpipe[0] == -1); |
1464 | + |
1465 | + assert (! pipe (selfpipe)); |
1466 | + |
1467 | + /* Set non-blocking */ |
1468 | + read_flags = fcntl (selfpipe[0], F_GETFL); |
1469 | + write_flags = fcntl (selfpipe[1], F_GETFL); |
1470 | + |
1471 | + read_flags |= O_NONBLOCK; |
1472 | + write_flags |= O_NONBLOCK; |
1473 | + |
1474 | + assert (fcntl (selfpipe[0], F_SETFL, read_flags) == 0); |
1475 | + assert (fcntl (selfpipe[1], F_SETFL, write_flags) == 0); |
1476 | + |
1477 | + /* Don't leak */ |
1478 | + assert (fcntl (selfpipe[0], F_SETFD, FD_CLOEXEC) == 0); |
1479 | + assert (fcntl (selfpipe[1], F_SETFD, FD_CLOEXEC) == 0); |
1480 | + |
1481 | + memset (&act, 0, sizeof (act)); |
1482 | + |
1483 | + /* register SIGCHLD handler which will cause pipe write when child |
1484 | + * changes state. |
1485 | + */ |
1486 | + act.sa_handler = selfpipe_write; |
1487 | + |
1488 | + sigaction (SIGCHLD, &act, NULL); |
1489 | +} |
1490 | + |
1491 | +/** |
1492 | + * timed_waitpid: |
1493 | + * |
1494 | + * @pid: pid to wait for, |
1495 | + * @timeout: seconds to wait for @pid to change state. |
1496 | + * |
1497 | + * Simplified waitpid(2) with timeout using a pipe to allow select(2) |
1498 | + * with timeout to be used to wait for process state change. |
1499 | + **/ |
1500 | +pid_t |
1501 | +timed_waitpid (pid_t pid, time_t timeout) |
1502 | +{ |
1503 | + static char buffer[1]; |
1504 | + fd_set read_fds; |
1505 | + struct timeval tv; |
1506 | + int status; |
1507 | + int nfds; |
1508 | + int ret; |
1509 | + pid_t ret2; |
1510 | + |
1511 | + assert (pid); |
1512 | + assert (timeout); |
1513 | + |
1514 | + if (selfpipe[0] == -1) |
1515 | + selfpipe_setup (); |
1516 | + |
1517 | + FD_ZERO (&read_fds); |
1518 | + FD_SET (selfpipe[0], &read_fds); |
1519 | + |
1520 | + nfds = 1 + selfpipe[0]; |
1521 | + |
1522 | + tv.tv_sec = timeout; |
1523 | + tv.tv_usec = 0; |
1524 | + |
1525 | + /* wait for some activity */ |
1526 | + ret = select (nfds, &read_fds, NULL, NULL, &tv); |
1527 | + |
1528 | + if (! ret) |
1529 | + /* timed out */ |
1530 | + return 0; |
1531 | + |
1532 | + /* discard any data written to pipe */ |
1533 | + while (read (selfpipe[0], buffer, sizeof (buffer)) > 0) |
1534 | + ; |
1535 | + |
1536 | + while (TRUE) { |
1537 | + /* wait for status change or error */ |
1538 | + ret2 = waitpid (pid, &status, WNOHANG); |
1539 | + |
1540 | + if (ret2 < 0) |
1541 | + return -1; |
1542 | + |
1543 | + if (! ret2) |
1544 | + /* give child a chance to change state */ |
1545 | + sleep (1); |
1546 | + |
1547 | + if (ret2) { |
1548 | + if (WIFEXITED (status)) |
1549 | + return ret2; |
1550 | + |
1551 | + /* unexpected status change */ |
1552 | + return -1; |
1553 | + } |
1554 | + } |
1555 | +} |
1556 | + |
1557 | + |
1558 | +/** |
1559 | * get_initctl(): |
1560 | * |
1561 | * Determine a suitable initctl command-line for testing purposes. |
1562 | @@ -504,6 +737,8 @@ |
1563 | * _start_upstart: |
1564 | * |
1565 | * @pid: PID of running instance, |
1566 | + * @user: TRUE if upstart will run in User Session mode (FALSE to |
1567 | + * use the users D-Bus session bus), |
1568 | * @args: optional list of arguments to specify. |
1569 | * |
1570 | * Start an instance of Upstart. |
1571 | @@ -511,9 +746,10 @@ |
1572 | * If the instance fails to start, abort(3) is called. |
1573 | **/ |
1574 | void |
1575 | -_start_upstart (pid_t *pid, char * const *args) |
1576 | +_start_upstart (pid_t *pid, int user, char * const *args) |
1577 | { |
1578 | nih_local char **argv = NULL; |
1579 | + sigset_t child_set, orig_set; |
1580 | |
1581 | assert (pid); |
1582 | |
1583 | @@ -525,12 +761,29 @@ |
1584 | if (args) |
1585 | NIH_MUST (nih_str_array_append (&argv, NULL, NULL, args)); |
1586 | |
1587 | + sigfillset (&child_set); |
1588 | + sigprocmask (SIG_BLOCK, &child_set, &orig_set); |
1589 | + |
1590 | TEST_NE (*pid = fork (), -1); |
1591 | |
1592 | - if (*pid == 0) |
1593 | - execv (argv[0], argv); |
1594 | - |
1595 | - WAIT_FOR_UPSTART (); |
1596 | + if (! *pid) { |
1597 | + int fd; |
1598 | + nih_signal_reset (); |
1599 | + sigprocmask (SIG_SETMASK, &orig_set, NULL); |
1600 | + |
1601 | + if (! getenv ("UPSTART_TEST_VERBOSE")) { |
1602 | + fd = open ("/dev/null", O_RDWR); |
1603 | + assert (fd >= 0); |
1604 | + assert (dup2 (fd, STDIN_FILENO) != -1); |
1605 | + assert (dup2 (fd, STDOUT_FILENO) != -1); |
1606 | + assert (dup2 (fd, STDERR_FILENO) != -1); |
1607 | + } |
1608 | + |
1609 | + assert (execv (argv[0], argv) != -1); |
1610 | + } |
1611 | + |
1612 | + sigprocmask (SIG_SETMASK, &orig_set, NULL); |
1613 | + wait_for_upstart (user); |
1614 | } |
1615 | |
1616 | /** |
1617 | @@ -588,7 +841,7 @@ |
1618 | if (extra) |
1619 | NIH_MUST (nih_str_array_append (&args, NULL, NULL, extra)); |
1620 | |
1621 | - _start_upstart (pid, args); |
1622 | + _start_upstart (pid, user, args); |
1623 | } |
1624 | |
1625 | /** |
1626 | @@ -11782,9 +12035,7 @@ |
1627 | char dirname[PATH_MAX]; |
1628 | char confdir[PATH_MAX]; |
1629 | nih_local char *cmd = NULL; |
1630 | - nih_local char **args = NULL; |
1631 | pid_t upstart_pid = 0; |
1632 | - pid_t dbus_pid = 0; |
1633 | char **output; |
1634 | size_t lines; |
1635 | struct stat statbuf; |
1636 | @@ -11839,12 +12090,10 @@ |
1637 | TEST_EQ (setenv ("UPSTART_CONFDIR", confdir, 1), 0); |
1638 | TEST_EQ (setenv ("XDG_RUNTIME_DIR", dirname, 1), 0); |
1639 | |
1640 | - args = NIH_MUST (nih_str_array_new (NULL)); |
1641 | - NIH_MUST (nih_str_array_add (&args, NULL, NULL, "--user")); |
1642 | + /* Reset initctl global from previous tests */ |
1643 | + dest_name = NULL; |
1644 | |
1645 | - /* Start to create session file */ |
1646 | - TEST_DBUS (dbus_pid); |
1647 | - start_upstart_common (&upstart_pid, FALSE, NULL, NULL, args); |
1648 | + start_upstart_common (&upstart_pid, TRUE, NULL, NULL, NULL); |
1649 | |
1650 | session_file = nih_sprintf (NULL, "%s/upstart/sessions/%d.session", |
1651 | dirname, (int)upstart_pid); |
1652 | @@ -11877,7 +12126,6 @@ |
1653 | nih_free (output); |
1654 | |
1655 | STOP_UPSTART (upstart_pid); |
1656 | - TEST_DBUS_END (dbus_pid); |
1657 | |
1658 | /* Upstart cannot yet be instructed to shutdown cleanly, so for |
1659 | * now we have to remove the session file manually. |
1660 | @@ -11908,6 +12156,571 @@ |
1661 | } |
1662 | |
1663 | void |
1664 | +test_quiesce (void) |
1665 | +{ |
1666 | + char confdir[PATH_MAX]; |
1667 | + char logdir[PATH_MAX]; |
1668 | + char sessiondir[PATH_MAX]; |
1669 | + nih_local char *cmd = NULL; |
1670 | + pid_t upstart_pid = 0; |
1671 | + nih_local char *logfile = NULL; |
1672 | + FILE *file; |
1673 | + char **output; |
1674 | + size_t lines; |
1675 | + nih_local NihDBusProxy *upstart = NULL; |
1676 | + nih_local char *orig_xdg_runtime_dir = NULL; |
1677 | + nih_local char *session_file = NULL; |
1678 | + |
1679 | + TEST_GROUP ("Session Init quiesce"); |
1680 | + |
1681 | + TEST_FILENAME (confdir); |
1682 | + TEST_EQ (mkdir (confdir, 0755), 0); |
1683 | + |
1684 | + TEST_FILENAME (logdir); |
1685 | + TEST_EQ (mkdir (logdir, 0755), 0); |
1686 | + |
1687 | + TEST_FILENAME (sessiondir); |
1688 | + TEST_EQ (mkdir (sessiondir, 0755), 0); |
1689 | + |
1690 | + /* Take care to avoid disrupting users environment by saving and |
1691 | + * restoring this variable (assuming the tests all pass...). |
1692 | + */ |
1693 | + orig_xdg_runtime_dir = getenv ("XDG_RUNTIME_DIR"); |
1694 | + if (orig_xdg_runtime_dir) |
1695 | + orig_xdg_runtime_dir = NIH_MUST (nih_strdup (NULL, orig_xdg_runtime_dir)); |
1696 | + |
1697 | + /* Use the "secret" interface */ |
1698 | + TEST_EQ (setenv ("UPSTART_CONFDIR", confdir, 1), 0); |
1699 | + TEST_EQ (setenv ("UPSTART_LOGDIR", logdir, 1), 0); |
1700 | + TEST_EQ (setenv ("XDG_RUNTIME_DIR", sessiondir, 1), 0); |
1701 | + |
1702 | + /* Reset initctl global from previous tests */ |
1703 | + dest_name = NULL; |
1704 | + |
1705 | + /*******************************************************************/ |
1706 | + TEST_FEATURE ("system shutdown: no jobs"); |
1707 | + |
1708 | + start_upstart_common (&upstart_pid, TRUE, confdir, logdir, NULL); |
1709 | + |
1710 | + /* Should be running */ |
1711 | + assert0 (kill (upstart_pid, 0)); |
1712 | + |
1713 | + /* Trigger shutdown */ |
1714 | + assert0 (kill (upstart_pid, SIGTERM)); |
1715 | + |
1716 | + /* Force reset */ |
1717 | + test_user_mode = FALSE; |
1718 | + |
1719 | + TEST_EQ (timed_waitpid (upstart_pid, TEST_QUIESCE_KILL_PHASE), upstart_pid); |
1720 | + |
1721 | + /* Should not now be running */ |
1722 | + TEST_EQ (kill (upstart_pid, 0), -1); |
1723 | + |
1724 | + session_file = NIH_MUST (nih_sprintf (NULL, "%s/upstart/sessions/%d.session", |
1725 | + sessiondir, (int)upstart_pid)); |
1726 | + unlink (session_file); |
1727 | + |
1728 | + /*******************************************************************/ |
1729 | + TEST_FEATURE ("system shutdown: one long-running job"); |
1730 | + |
1731 | + CREATE_FILE (confdir, "long-running.conf", |
1732 | + "exec sleep 999"); |
1733 | + |
1734 | + start_upstart_common (&upstart_pid, TRUE, confdir, logdir, NULL); |
1735 | + |
1736 | + /* Should be running */ |
1737 | + assert0 (kill (upstart_pid, 0)); |
1738 | + |
1739 | + cmd = nih_sprintf (NULL, "%s start %s 2>&1", |
1740 | + get_initctl (), "long-running"); |
1741 | + TEST_NE_P (cmd, NULL); |
1742 | + |
1743 | + RUN_COMMAND (NULL, cmd, &output, &lines); |
1744 | + TEST_EQ (lines, 1); |
1745 | + nih_free (output); |
1746 | + |
1747 | + /* Trigger shutdown */ |
1748 | + assert0 (kill (upstart_pid, SIGTERM)); |
1749 | + |
1750 | + /* Force reset */ |
1751 | + test_user_mode = FALSE; |
1752 | + |
1753 | + TEST_EQ (timed_waitpid (upstart_pid, TEST_QUIESCE_KILL_PHASE), upstart_pid); |
1754 | + |
1755 | + /* Should not now be running */ |
1756 | + TEST_EQ (kill (upstart_pid, 0), -1); |
1757 | + |
1758 | + session_file = NIH_MUST (nih_sprintf (NULL, "%s/upstart/sessions/%d.session", |
1759 | + sessiondir, (int)upstart_pid)); |
1760 | + unlink (session_file); |
1761 | + |
1762 | + DELETE_FILE (confdir, "long-running.conf"); |
1763 | + |
1764 | + /*******************************************************************/ |
1765 | + TEST_FEATURE ("system shutdown: one long-running job which ignores SIGTERM"); |
1766 | + |
1767 | + CREATE_FILE (confdir, "long-running-term.conf", |
1768 | + "script\n" |
1769 | + " trap '' TERM\n" |
1770 | + " sleep 999\n" |
1771 | + "end script"); |
1772 | + |
1773 | + start_upstart_common (&upstart_pid, TRUE, confdir, logdir, NULL); |
1774 | + |
1775 | + /* Should be running */ |
1776 | + assert0 (kill (upstart_pid, 0)); |
1777 | + |
1778 | + cmd = nih_sprintf (NULL, "%s start %s 2>&1", |
1779 | + get_initctl (), "long-running-term"); |
1780 | + TEST_NE_P (cmd, NULL); |
1781 | + |
1782 | + RUN_COMMAND (NULL, cmd, &output, &lines); |
1783 | + TEST_EQ (lines, 1); |
1784 | + nih_free (output); |
1785 | + |
1786 | + /* Trigger shutdown */ |
1787 | + assert0 (kill (upstart_pid, SIGTERM)); |
1788 | + |
1789 | + /* Force reset */ |
1790 | + test_user_mode = FALSE; |
1791 | + |
1792 | + TEST_EQ (timed_waitpid (upstart_pid, TEST_QUIESCE_KILL_PHASE), upstart_pid); |
1793 | + |
1794 | + /* Should not now be running */ |
1795 | + TEST_EQ (kill (upstart_pid, 0), -1); |
1796 | + |
1797 | + session_file = NIH_MUST (nih_sprintf (NULL, "%s/upstart/sessions/%d.session", |
1798 | + sessiondir, (int)upstart_pid)); |
1799 | + unlink (session_file); |
1800 | + |
1801 | + DELETE_FILE (confdir, "long-running-term.conf"); |
1802 | + |
1803 | + /*******************************************************************/ |
1804 | + TEST_FEATURE ("system shutdown: one job which starts on session-end"); |
1805 | + |
1806 | + CREATE_FILE (confdir, "session-end.conf", |
1807 | + "start on session-end\n" |
1808 | + "\n" |
1809 | + "script\n" |
1810 | + " echo hello\n" |
1811 | + " sleep 999\n" |
1812 | + "end script"); |
1813 | + |
1814 | + start_upstart_common (&upstart_pid, TRUE, confdir, logdir, NULL); |
1815 | + |
1816 | + /* Should be running */ |
1817 | + assert0 (kill (upstart_pid, 0)); |
1818 | + |
1819 | + /* Trigger shutdown */ |
1820 | + assert0 (kill (upstart_pid, SIGTERM)); |
1821 | + |
1822 | + /* Force reset */ |
1823 | + test_user_mode = FALSE; |
1824 | + |
1825 | + TEST_EQ (timed_waitpid (upstart_pid, TEST_QUIESCE_KILL_PHASE), upstart_pid); |
1826 | + |
1827 | + /* Should not now be running */ |
1828 | + TEST_EQ (kill (upstart_pid, 0), -1); |
1829 | + |
1830 | + logfile = NIH_MUST (nih_sprintf (NULL, "%s/%s", |
1831 | + logdir, |
1832 | + "session-end.log")); |
1833 | + |
1834 | + file = fopen (logfile, "r"); |
1835 | + TEST_NE_P (file, NULL); |
1836 | + TEST_FILE_EQ (file, "hello\r\n"); |
1837 | + TEST_FILE_END (file); |
1838 | + TEST_EQ (fclose (file), 0); |
1839 | + assert0 (unlink (logfile)); |
1840 | + |
1841 | + session_file = NIH_MUST (nih_sprintf (NULL, "%s/upstart/sessions/%d.session", |
1842 | + sessiondir, (int)upstart_pid)); |
1843 | + unlink (session_file); |
1844 | + |
1845 | + DELETE_FILE (confdir, "session-end.conf"); |
1846 | + |
1847 | + /*******************************************************************/ |
1848 | + TEST_FEATURE ("system shutdown: one job which starts on session-end and ignores SIGTERM"); |
1849 | + |
1850 | + CREATE_FILE (confdir, "session-end-term.conf", |
1851 | + "start on session-end\n" |
1852 | + "\n" |
1853 | + "script\n" |
1854 | + " trap '' TERM\n" |
1855 | + " echo hello\n" |
1856 | + " sleep 999\n" |
1857 | + "end script"); |
1858 | + |
1859 | + start_upstart_common (&upstart_pid, TRUE, confdir, logdir, NULL); |
1860 | + |
1861 | + /* Should be running */ |
1862 | + assert0 (kill (upstart_pid, 0)); |
1863 | + |
1864 | + /* Trigger shutdown */ |
1865 | + assert0 (kill (upstart_pid, SIGTERM)); |
1866 | + |
1867 | + /* Force reset */ |
1868 | + test_user_mode = FALSE; |
1869 | + |
1870 | + TEST_EQ (timed_waitpid (upstart_pid, TEST_QUIESCE_KILL_PHASE), upstart_pid); |
1871 | + |
1872 | + /* Should not now be running */ |
1873 | + TEST_EQ (kill (upstart_pid, 0), -1); |
1874 | + |
1875 | + logfile = NIH_MUST (nih_sprintf (NULL, "%s/%s", |
1876 | + logdir, |
1877 | + "session-end-term.log")); |
1878 | + |
1879 | + file = fopen (logfile, "r"); |
1880 | + TEST_NE_P (file, NULL); |
1881 | + TEST_FILE_EQ (file, "hello\r\n"); |
1882 | + TEST_FILE_END (file); |
1883 | + TEST_EQ (fclose (file), 0); |
1884 | + assert0 (unlink (logfile)); |
1885 | + |
1886 | + session_file = NIH_MUST (nih_sprintf (NULL, "%s/upstart/sessions/%d.session", |
1887 | + sessiondir, (int)upstart_pid)); |
1888 | + unlink (session_file); |
1889 | + |
1890 | + DELETE_FILE (confdir, "session-end-term.conf"); |
1891 | + |
1892 | + /*******************************************************************/ |
1893 | + TEST_FEATURE ("system shutdown: 2 jobs " |
1894 | + "(1 long-running job which ignores SIGTERM, " |
1895 | + "1 which starts on session-end and ignores SIGTERM)"); |
1896 | + |
1897 | + CREATE_FILE (confdir, "long-running-term.conf", |
1898 | + "script\n" |
1899 | + " trap '' TERM\n" |
1900 | + " sleep 999\n" |
1901 | + "end script"); |
1902 | + |
1903 | + CREATE_FILE (confdir, "session-end-term.conf", |
1904 | + "start on session-end\n" |
1905 | + "\n" |
1906 | + "script\n" |
1907 | + " trap '' TERM\n" |
1908 | + " sleep 999\n" |
1909 | + "end script"); |
1910 | + |
1911 | + |
1912 | + start_upstart_common (&upstart_pid, TRUE, confdir, logdir, NULL); |
1913 | + |
1914 | + /* Should be running */ |
1915 | + assert0 (kill (upstart_pid, 0)); |
1916 | + |
1917 | + cmd = nih_sprintf (NULL, "%s start %s 2>&1", |
1918 | + get_initctl (), "long-running-term"); |
1919 | + TEST_NE_P (cmd, NULL); |
1920 | + |
1921 | + RUN_COMMAND (NULL, cmd, &output, &lines); |
1922 | + TEST_EQ (lines, 1); |
1923 | + nih_free (output); |
1924 | + |
1925 | + /* Trigger shutdown */ |
1926 | + assert0 (kill (upstart_pid, SIGTERM)); |
1927 | + |
1928 | + /* Force reset */ |
1929 | + test_user_mode = FALSE; |
1930 | + |
1931 | + TEST_EQ (timed_waitpid (upstart_pid, TEST_QUIESCE_KILL_PHASE), upstart_pid); |
1932 | + |
1933 | + /* Should not now be running */ |
1934 | + TEST_EQ (kill (upstart_pid, 0), -1); |
1935 | + |
1936 | + session_file = NIH_MUST (nih_sprintf (NULL, "%s/upstart/sessions/%d.session", |
1937 | + sessiondir, (int)upstart_pid)); |
1938 | + unlink (session_file); |
1939 | + |
1940 | + DELETE_FILE (confdir, "long-running-term.conf"); |
1941 | + DELETE_FILE (confdir, "session-end-term.conf"); |
1942 | + |
1943 | + /*******************************************************************/ |
1944 | + TEST_FEATURE ("session shutdown: no jobs"); |
1945 | + |
1946 | + start_upstart_common (&upstart_pid, TRUE, confdir, logdir, NULL); |
1947 | + |
1948 | + /* Further required initctl global resets. Shudder. */ |
1949 | + user_mode = TRUE; |
1950 | + use_dbus = -1; |
1951 | + dbus_bus_type = DBUS_BUS_SESSION; |
1952 | + dbus_bus_type = -1; |
1953 | + |
1954 | + upstart = upstart_open (NULL); |
1955 | + TEST_NE_P (upstart, NULL); |
1956 | + |
1957 | + /* Should be running */ |
1958 | + assert0 (kill (upstart_pid, 0)); |
1959 | + |
1960 | + /* Force reset */ |
1961 | + test_user_mode = FALSE; |
1962 | + |
1963 | + /* Trigger session shutdown */ |
1964 | + assert0 (upstart_end_session_sync (NULL, upstart)); |
1965 | + |
1966 | + /* no jobs, so Session Init should shutdown "immediately" */ |
1967 | + TEST_EQ (timed_waitpid (upstart_pid, TEST_QUIESCE_KILL_PHASE), upstart_pid); |
1968 | + |
1969 | + /* Should not now be running */ |
1970 | + TEST_EQ (kill (upstart_pid, 0), -1); |
1971 | + |
1972 | + session_file = NIH_MUST (nih_sprintf (NULL, "%s/upstart/sessions/%d.session", |
1973 | + sessiondir, (int)upstart_pid)); |
1974 | + unlink (session_file); |
1975 | + |
1976 | + /*******************************************************************/ |
1977 | + TEST_FEATURE ("session shutdown: one long-running job"); |
1978 | + |
1979 | + CREATE_FILE (confdir, "long-running.conf", |
1980 | + "exec sleep 999"); |
1981 | + |
1982 | + start_upstart_common (&upstart_pid, TRUE, confdir, logdir, NULL); |
1983 | + |
1984 | + cmd = nih_sprintf (NULL, "%s start %s 2>&1", |
1985 | + get_initctl (), "long-running"); |
1986 | + TEST_NE_P (cmd, NULL); |
1987 | + |
1988 | + RUN_COMMAND (NULL, cmd, &output, &lines); |
1989 | + TEST_EQ (lines, 1); |
1990 | + nih_free (output); |
1991 | + |
1992 | + upstart = upstart_open (NULL); |
1993 | + TEST_NE_P (upstart, NULL); |
1994 | + |
1995 | + /* Should be running */ |
1996 | + assert0 (kill (upstart_pid, 0)); |
1997 | + |
1998 | + /* Force reset */ |
1999 | + test_user_mode = FALSE; |
2000 | + |
2001 | + /* Trigger session shutdown */ |
2002 | + assert0 (upstart_end_session_sync (NULL, upstart)); |
2003 | + |
2004 | + TEST_EQ (timed_waitpid (upstart_pid, TEST_QUIESCE_KILL_PHASE), upstart_pid); |
2005 | + |
2006 | + /* Should not now be running */ |
2007 | + TEST_EQ (kill (upstart_pid, 0), -1); |
2008 | + |
2009 | + session_file = NIH_MUST (nih_sprintf (NULL, "%s/upstart/sessions/%d.session", |
2010 | + sessiondir, (int)upstart_pid)); |
2011 | + unlink (session_file); |
2012 | + |
2013 | + DELETE_FILE (confdir, "long-running.conf"); |
2014 | + |
2015 | + /*******************************************************************/ |
2016 | + TEST_FEATURE ("session shutdown: one long-running job which ignores SIGTERM"); |
2017 | + |
2018 | + CREATE_FILE (confdir, "long-running-term.conf", |
2019 | + "script\n" |
2020 | + " trap '' TERM\n" |
2021 | + " sleep 999\n" |
2022 | + "end script"); |
2023 | + |
2024 | + start_upstart_common (&upstart_pid, TRUE, confdir, logdir, NULL); |
2025 | + |
2026 | + cmd = nih_sprintf (NULL, "%s start %s 2>&1", |
2027 | + get_initctl (), "long-running"); |
2028 | + TEST_NE_P (cmd, NULL); |
2029 | + |
2030 | + RUN_COMMAND (NULL, cmd, &output, &lines); |
2031 | + TEST_EQ (lines, 1); |
2032 | + nih_free (output); |
2033 | + |
2034 | + upstart = upstart_open (NULL); |
2035 | + TEST_NE_P (upstart, NULL); |
2036 | + |
2037 | + /* Should be running */ |
2038 | + assert0 (kill (upstart_pid, 0)); |
2039 | + |
2040 | + /* Force reset */ |
2041 | + test_user_mode = FALSE; |
2042 | + |
2043 | + /* Trigger session shutdown */ |
2044 | + assert0 (upstart_end_session_sync (NULL, upstart)); |
2045 | + |
2046 | + TEST_EQ (timed_waitpid (upstart_pid, TEST_QUIESCE_KILL_PHASE), upstart_pid); |
2047 | + |
2048 | + /* Should not now be running */ |
2049 | + TEST_EQ (kill (upstart_pid, 0), -1); |
2050 | + |
2051 | + session_file = NIH_MUST (nih_sprintf (NULL, "%s/upstart/sessions/%d.session", |
2052 | + sessiondir, (int)upstart_pid)); |
2053 | + unlink (session_file); |
2054 | + |
2055 | + DELETE_FILE (confdir, "long-running-term.conf"); |
2056 | + |
2057 | + /*******************************************************************/ |
2058 | + TEST_FEATURE ("session shutdown: one job which starts on session-end"); |
2059 | + |
2060 | + CREATE_FILE (confdir, "session-end.conf", |
2061 | + "start on session-end\n" |
2062 | + "\n" |
2063 | + "script\n" |
2064 | + " echo hello\n" |
2065 | + " sleep 999\n" |
2066 | + "end script"); |
2067 | + |
2068 | + start_upstart_common (&upstart_pid, TRUE, confdir, logdir, NULL); |
2069 | + |
2070 | + upstart = upstart_open (NULL); |
2071 | + TEST_NE_P (upstart, NULL); |
2072 | + |
2073 | + /* Should be running */ |
2074 | + assert0 (kill (upstart_pid, 0)); |
2075 | + |
2076 | + /* Force reset */ |
2077 | + test_user_mode = FALSE; |
2078 | + |
2079 | + /* Trigger session shutdown */ |
2080 | + assert0 (upstart_end_session_sync (NULL, upstart)); |
2081 | + |
2082 | + TEST_EQ (timed_waitpid (upstart_pid, TEST_QUIESCE_KILL_PHASE), upstart_pid); |
2083 | + |
2084 | + /* Should not now be running */ |
2085 | + TEST_EQ (kill (upstart_pid, 0), -1); |
2086 | + |
2087 | + logfile = NIH_MUST (nih_sprintf (NULL, "%s/%s", |
2088 | + logdir, |
2089 | + "session-end.log")); |
2090 | + |
2091 | + file = fopen (logfile, "r"); |
2092 | + TEST_NE_P (file, NULL); |
2093 | + TEST_FILE_EQ (file, "hello\r\n"); |
2094 | + TEST_FILE_END (file); |
2095 | + TEST_EQ (fclose (file), 0); |
2096 | + assert0 (unlink (logfile)); |
2097 | + |
2098 | + session_file = NIH_MUST (nih_sprintf (NULL, "%s/upstart/sessions/%d.session", |
2099 | + sessiondir, (int)upstart_pid)); |
2100 | + unlink (session_file); |
2101 | + |
2102 | + DELETE_FILE (confdir, "session-end.conf"); |
2103 | + |
2104 | + /*******************************************************************/ |
2105 | + TEST_FEATURE ("session shutdown: one job which starts on session-end"); |
2106 | + |
2107 | + CREATE_FILE (confdir, "session-end-term.conf", |
2108 | + "start on session-end\n" |
2109 | + "\n" |
2110 | + "script\n" |
2111 | + " trap '' TERM\n" |
2112 | + " echo hello\n" |
2113 | + " sleep 999\n" |
2114 | + "end script"); |
2115 | + |
2116 | + start_upstart_common (&upstart_pid, TRUE, confdir, logdir, NULL); |
2117 | + |
2118 | + upstart = upstart_open (NULL); |
2119 | + TEST_NE_P (upstart, NULL); |
2120 | + |
2121 | + /* Should be running */ |
2122 | + assert0 (kill (upstart_pid, 0)); |
2123 | + |
2124 | + /* Force reset */ |
2125 | + test_user_mode = FALSE; |
2126 | + |
2127 | + /* Trigger session shutdown */ |
2128 | + assert0 (upstart_end_session_sync (NULL, upstart)); |
2129 | + |
2130 | + TEST_EQ (timed_waitpid (upstart_pid, TEST_QUIESCE_KILL_PHASE), upstart_pid); |
2131 | + |
2132 | + /* Should not now be running */ |
2133 | + TEST_EQ (kill (upstart_pid, 0), -1); |
2134 | + |
2135 | + logfile = NIH_MUST (nih_sprintf (NULL, "%s/%s", |
2136 | + logdir, |
2137 | + "session-end-term.log")); |
2138 | + |
2139 | + file = fopen (logfile, "r"); |
2140 | + TEST_NE_P (file, NULL); |
2141 | + TEST_FILE_EQ (file, "hello\r\n"); |
2142 | + TEST_FILE_END (file); |
2143 | + TEST_EQ (fclose (file), 0); |
2144 | + assert0 (unlink (logfile)); |
2145 | + |
2146 | + session_file = NIH_MUST (nih_sprintf (NULL, "%s/upstart/sessions/%d.session", |
2147 | + sessiondir, (int)upstart_pid)); |
2148 | + unlink (session_file); |
2149 | + |
2150 | + DELETE_FILE (confdir, "session-end-term.conf"); |
2151 | + |
2152 | + /*******************************************************************/ |
2153 | + TEST_FEATURE ("session shutdown: 2 jobs " |
2154 | + "(1 long-running job which ignores SIGTERM, " |
2155 | + "1 which starts on session-end and ignores SIGTERM)"); |
2156 | + |
2157 | + CREATE_FILE (confdir, "long-running-term.conf", |
2158 | + "script\n" |
2159 | + " trap '' TERM\n" |
2160 | + " sleep 999\n" |
2161 | + "end script"); |
2162 | + |
2163 | + CREATE_FILE (confdir, "session-end-term.conf", |
2164 | + "start on session-end\n" |
2165 | + "\n" |
2166 | + "script\n" |
2167 | + " trap '' TERM\n" |
2168 | + " sleep 999\n" |
2169 | + "end script"); |
2170 | + |
2171 | + start_upstart_common (&upstart_pid, TRUE, confdir, logdir, NULL); |
2172 | + |
2173 | + cmd = nih_sprintf (NULL, "%s start %s 2>&1", |
2174 | + get_initctl (), "long-running-term"); |
2175 | + TEST_NE_P (cmd, NULL); |
2176 | + |
2177 | + RUN_COMMAND (NULL, cmd, &output, &lines); |
2178 | + TEST_EQ (lines, 1); |
2179 | + nih_free (output); |
2180 | + |
2181 | + upstart = upstart_open (NULL); |
2182 | + TEST_NE_P (upstart, NULL); |
2183 | + |
2184 | + /* Should be running */ |
2185 | + assert0 (kill (upstart_pid, 0)); |
2186 | + |
2187 | + /* Force reset */ |
2188 | + test_user_mode = FALSE; |
2189 | + |
2190 | + /* Trigger session shutdown */ |
2191 | + assert0 (upstart_end_session_sync (NULL, upstart)); |
2192 | + |
2193 | + TEST_EQ (timed_waitpid (upstart_pid, TEST_QUIESCE_TOTAL_WAIT_TIME), upstart_pid); |
2194 | + |
2195 | + /* Should not now be running */ |
2196 | + TEST_EQ (kill (upstart_pid, 0), -1); |
2197 | + |
2198 | + session_file = NIH_MUST (nih_sprintf (NULL, "%s/upstart/sessions/%d.session", |
2199 | + sessiondir, (int)upstart_pid)); |
2200 | + unlink (session_file); |
2201 | + |
2202 | + DELETE_FILE (confdir, "long-running-term.conf"); |
2203 | + DELETE_FILE (confdir, "session-end-term.conf"); |
2204 | + |
2205 | + /*******************************************************************/ |
2206 | + assert0 (unsetenv ("UPSTART_CONFDIR")); |
2207 | + assert0 (unsetenv ("UPSTART_LOGDIR")); |
2208 | + |
2209 | + if (orig_xdg_runtime_dir) { |
2210 | + /* restore */ |
2211 | + setenv ("XDG_RUNTIME_DIR", orig_xdg_runtime_dir, 1); |
2212 | + } else { |
2213 | + assert0 (unsetenv ("XDG_RUNTIME_DIR")); |
2214 | + } |
2215 | + |
2216 | + TEST_EQ (rmdir (logdir), 0); |
2217 | + TEST_EQ (rmdir (confdir), 0); |
2218 | + |
2219 | + session_file = NIH_MUST (nih_sprintf (NULL, "%s/upstart/sessions", sessiondir)); |
2220 | + TEST_EQ (rmdir (session_file), 0); |
2221 | + session_file = NIH_MUST (nih_sprintf (NULL, "%s/upstart", sessiondir)); |
2222 | + TEST_EQ (rmdir (session_file), 0); |
2223 | + TEST_EQ (rmdir (sessiondir), 0); |
2224 | + |
2225 | + /*******************************************************************/ |
2226 | +} |
2227 | + |
2228 | +void |
2229 | test_show_config (void) |
2230 | { |
2231 | char dirname[PATH_MAX]; |
2232 | @@ -15570,6 +16383,9 @@ |
2233 | out = tmpfile (); |
2234 | err = tmpfile (); |
2235 | |
2236 | + TEST_NE_P (out, NULL); |
2237 | + TEST_NE_P (err, NULL); |
2238 | + |
2239 | TEST_DIVERT_STDOUT (out) { |
2240 | TEST_DIVERT_STDERR (err) { |
2241 | ret = status_action (&command, args); |
2242 | @@ -15588,12 +16404,16 @@ |
2243 | TEST_FILE_END (err); |
2244 | TEST_FILE_RESET (err); |
2245 | |
2246 | + assert0 (fclose (out)); |
2247 | + assert0 (fclose (err)); |
2248 | + |
2249 | DELETE_FILE (dirname, "foo.conf"); |
2250 | |
2251 | - |
2252 | STOP_UPSTART (upstart_pid); |
2253 | TEST_EQ (unsetenv ("UPSTART_CONFDIR"), 0); |
2254 | TEST_DBUS_END (dbus_pid); |
2255 | + |
2256 | + assert0 (rmdir (dirname)); |
2257 | } |
2258 | |
2259 | void |
2260 | @@ -16525,6 +17345,7 @@ |
2261 | nih_local char *orig_xdg_runtime_dir = NULL; |
2262 | nih_local char *cmd = NULL; |
2263 | char **output; |
2264 | + nih_local char *session_file = NULL; |
2265 | |
2266 | TEST_GROUP ("job process table commands"); |
2267 | |
2268 | @@ -16589,6 +17410,15 @@ |
2269 | assert0 (unsetenv ("UPSTART_LOGDIR")); |
2270 | assert0 (unsetenv ("UPSTART_SESSION")); |
2271 | |
2272 | + session_file = NIH_MUST (nih_sprintf (NULL, "%s/upstart/sessions/%d.session", |
2273 | + runtimedir, (int)upstart_pid)); |
2274 | + unlink (session_file); |
2275 | + session_file = NIH_MUST (nih_sprintf (NULL, "%s/upstart/sessions", runtimedir)); |
2276 | + TEST_EQ (rmdir (session_file), 0); |
2277 | + session_file = NIH_MUST (nih_sprintf (NULL, "%s/upstart", runtimedir)); |
2278 | + TEST_EQ (rmdir (session_file), 0); |
2279 | + TEST_EQ (rmdir (runtimedir), 0); |
2280 | + |
2281 | if (orig_xdg_runtime_dir) { |
2282 | /* restore */ |
2283 | setenv ("XDG_RUNTIME_DIR", orig_xdg_runtime_dir, 1); |
2284 | @@ -16675,6 +17505,7 @@ |
2285 | test_job_env (); |
2286 | test_reexec (); |
2287 | test_list_sessions (); |
2288 | + test_quiesce (); |
2289 | |
2290 | if (in_chroot () && !dbus_configured ()) { |
2291 | fprintf(stderr, "\n\n" |
I'm using this code in my PPA and I can confirm that session logout works with it. In my case I'm not using the POSIX signals to trigger a shutdown but calling EndSession directly over DBus.
I haven't spent any particular time testing the timeouts and the shutdown signal as in my case everything is part of gnome-session and so is stopping when it does. However I had a quick look and I clearly see the signal being emitted, so that part looks good too.