Merge lp:~jamesodhunt/upstart/async-fix-job-new-destructor into lp:upstart

Proposed by James Hunt on 2014-05-22
Status: Superseded
Proposed branch: lp:~jamesodhunt/upstart/async-fix-job-new-destructor
Merge into: lp:upstart
Diff against target: 4221 lines (+1656/-571)
17 files modified
doc/states.dot (+50/-15)
init/Makefile.am (+1/-0)
init/job.c (+327/-63)
init/job.h (+106/-37)
init/job_class.c (+2/-2)
init/job_process.c (+599/-170)
init/job_process.h (+40/-3)
init/log.c (+2/-2)
init/state.c (+2/-2)
init/state.h (+1/-1)
init/tests/test_event.c (+2/-2)
init/tests/test_job.c (+140/-25)
init/tests/test_job_process.c (+202/-244)
init/tests/test_util.c (+2/-1)
test/test_util_common.c (+91/-1)
test/test_util_common.h (+88/-2)
util/tests/test_initctl.c (+1/-1)
To merge this branch: bzr merge lp:~jamesodhunt/upstart/async-fix-job-new-destructor
Reviewer Review Type Date Requested Status
Dimitri John Ledkov 2014-05-22 Pending
Review via email: mp+220641@code.launchpad.net

This proposal has been superseded by a proposal from 2014-05-22.

To post a comment you must log in.

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'doc/states.dot'
2--- doc/states.dot 2014-03-05 11:17:37 +0000
3+++ doc/states.dot 2014-05-22 13:31:23 +0000
4@@ -20,44 +20,79 @@
5 */
6
7 digraph {
8- rankdir=LR;
9 edge [fontsize=10];
10
11 waiting [shape=diamond];
12 starting [label="starting\n(emit starting)"];
13+ security_spawning [label="security-spawning"];
14 security [label="security"];
15+ pre_starting [label="pre-starting"];
16 pre_start [label="pre-start"];
17+ spawning [label="spawning"];
18 spawned [label="spawned\n(wait for pid)"];
19+ post_starting [label="post-starting"];
20 post_start [label="post-start"];
21 emit_started [shape=rectangle,label="emit started"];
22 running [shape=diamond];
23+ pre_stopping [label="pre-stopping"];
24 pre_stop [label="pre-stop"];
25 stopping [label="stopping\n(emit stopping)"];
26 killed [label="killed\n(wait for SIGCHLD)"];
27+ post_stopping [label="post-stopping"];
28 post_stop [label="post-stop"];
29 emit_stopped [shape=rectangle,label="emit stopped"];
30
31- waiting -> starting [color=green];
32- starting -> security [color=green];
33- security -> pre_start [color=green];
34+ constraint=false;
35+ waiting -> starting [color=green,weight=10];
36+
37+ starting -> security_spawning [color=green,weight=10];
38+ starting -> stopping [color=red];
39+
40+ security_spawning -> security [color=green,weight=10];
41+ security_spawning -> stopping [color=red];
42+
43+ security -> pre_starting [color=green,weight=10];
44 security -> stopping [color=red];
45- starting -> stopping [color=red];
46- pre_start -> spawned [color=green];
47+
48+ pre_starting -> pre_start [color=green,weight=10];
49+ pre_starting -> stopping [color=red];
50+
51+ pre_start -> spawning [color=green,weight=10];
52 pre_start -> stopping [color=red];
53- spawned -> post_start [color=green];
54+
55+ spawning -> spawned [color=green,weight=10];
56+ spawning -> stopping [color=red];
57+
58+ spawned -> post_starting [color=green,weight=10];
59 spawned -> stopping [color=red];
60- post_start -> emit_started -> running [color=green];
61+
62+ post_starting -> post_start [color=green,weight=10];
63+ post_starting -> stopping [color=red];
64+
65+ post_start -> emit_started -> running [color=green,weight=10];
66 post_start -> stopping [color=red];
67- running -> pre_stop [color=red,label="pid > 0"];
68- running -> stopping [color=red,label="pid == 0"];
69- running -> stopping [color=green,label="respawn"];
70+
71+ running -> pre_stopping [color=red,fontcolor=red,label="pid > 0",weight=10];
72+ running -> stopping [color=red,fontcolor=red,label="pid == 0"];
73+ running -> stopping [color=green,fontcolor=darkgreen,label="respawn"];
74+
75+ pre_stopping -> pre_stop [color=green,weight=10];
76+ pre_stopping -> pre_stop [color=red,weight=10];
77+
78 pre_stop -> running [color=green];
79- pre_stop -> stopping [color=red];
80+ pre_stop -> stopping [color=red,weight=10];
81+
82 stopping -> killed [color=green];
83 stopping -> killed [color=red];
84- killed -> post_stop [color=green];
85- killed -> post_stop [color=red];
86+
87+ killed -> post_stopping [color=green];
88+ killed -> post_stopping [color=red];
89+
90+ post_stopping -> post_stop [color=green,weight=10];
91+ post_stopping -> post_stop [color=red];
92+
93 post_stop -> starting [color=green];
94- post_stop -> emit_stopped [color=red];
95+ post_stop -> emit_stopped [color=red,weight=10];
96+
97 emit_stopped -> waiting [color=red];
98 }
99
100=== removed file 'doc/states.png'
101Binary files doc/states.png 2014-03-05 11:17:37 +0000 and doc/states.png 1970-01-01 00:00:00 +0000 differ
102=== modified file 'init/Makefile.am'
103--- init/Makefile.am 2013-11-12 14:00:36 +0000
104+++ init/Makefile.am 2014-05-22 13:31:23 +0000
105@@ -265,6 +265,7 @@
106 session.o log.o state.o xdg.o apparmor.o \
107 com.ubuntu.Upstart.o \
108 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
109+ $(top_builddir)/test/libtest_util_common.a \
110 $(NIH_LIBS) \
111 $(NIH_DBUS_LIBS) \
112 $(DBUS_LIBS) \
113
114=== modified file 'init/job.c'
115--- init/job.c 2014-05-07 16:34:44 +0000
116+++ init/job.c 2014-05-22 13:31:23 +0000
117@@ -70,14 +70,6 @@
118 __attribute__ ((warn_unused_result));
119
120 static const char *
121-job_state_enum_to_str (JobState state)
122- __attribute__ ((warn_unused_result));
123-
124-static JobState
125-job_state_str_to_enum (const char *state)
126- __attribute__ ((warn_unused_result));
127-
128-static const char *
129 job_trace_state_enum_to_str (TraceState state)
130 __attribute__ ((warn_unused_result));
131
132@@ -93,6 +85,31 @@
133 job_deserialise_kill_timer (json_object *json)
134 __attribute__ ((warn_unused_result));
135
136+int
137+job_destroy (Job *job)
138+{
139+ int i;
140+
141+ nih_assert (job);
142+
143+ /* Free any associated NihIo's to avoid the handlers getting
144+ * called potentially after the job has been freed.
145+ */
146+ if (job->process_data) {
147+ for (i = 0; i < PROCESS_LAST; i++) {
148+ if (job->process_data[i]) {
149+ nih_free (job->process_data[i]);
150+
151+ job->process_data[i] = NULL;
152+ }
153+ }
154+ }
155+ nih_list_destroy (&job->entry);
156+
157+ return 0;
158+}
159+
160+
161 /**
162 * job_new:
163 * @class: class of job,
164@@ -125,7 +142,10 @@
165
166 nih_list_init (&job->entry);
167
168- nih_alloc_set_destructor (job, nih_list_destroy);
169+ /* Ensure unset before destructor could possibly be called */
170+ job->process_data = NULL;
171+
172+ nih_alloc_set_destructor (job, job_destroy);
173
174 job->name = nih_strdup (job, name);
175 if (! job->name)
176@@ -207,6 +227,24 @@
177 job_register (job, conn, TRUE);
178 }
179
180+ /* Since some job processes can run in parallel, we must ensure
181+ * that the asynchronous-spawning of such job processes is
182+ * handled by providing a handler for each pid.
183+ *
184+ * Strictly, this is only necessary for certain combinations of
185+ * job processes (such as PROCESS_MAIN and PROCESS_POST_START),
186+ * however for consistency with other entities (such as Log), we
187+ * create a slot for all job processes since there is minimal
188+ * overhead (a single pointer) for those job processes tha
189+ * cannot run in parallel with others.
190+ */
191+ job->process_data = nih_alloc (job, sizeof (JobProcessData *) * PROCESS_LAST);
192+ if (! job->process_data)
193+ goto error;
194+
195+ for (i = 0; i < PROCESS_LAST; i++)
196+ job->process_data[i] = NULL;
197+
198 return job;
199
200 error:
201@@ -398,64 +436,78 @@
202 job->blocker = job_emit_event (job);
203
204 break;
205- case JOB_SECURITY:
206+ case JOB_SECURITY_SPAWNING:
207 nih_assert (job->goal == JOB_START);
208 nih_assert (old_state == JOB_STARTING);
209
210 if (job->class->process[PROCESS_SECURITY]
211 && apparmor_available()) {
212- if (job_process_run (job, PROCESS_SECURITY) < 0) {
213- job_failed (job, PROCESS_SECURITY, -1);
214- job_change_goal (job, JOB_STOP);
215- state = job_next_state (job);
216- }
217- } else {
218+ job_process_start (job, PROCESS_SECURITY);
219+ }
220+ state = job_next_state (job);
221+ break;
222+ case JOB_SECURITY:
223+ nih_assert (job->goal == JOB_START);
224+ nih_assert (old_state == JOB_SECURITY_SPAWNING);
225+
226+ if (! (job->class->process[PROCESS_SECURITY]
227+ && apparmor_available())) {
228 state = job_next_state (job);
229 }
230-
231 break;
232- case JOB_PRE_START:
233+ case JOB_PRE_STARTING:
234 nih_assert (job->goal == JOB_START);
235 nih_assert (old_state == JOB_SECURITY);
236-
237+ /* spawn pre-start asynchronously, child
238+ * watcher asynchronously will change goal to
239+ * stop if spawning fails */
240 if (job->class->process[PROCESS_PRE_START]) {
241- if (job_process_run (job, PROCESS_PRE_START) < 0) {
242- job_failed (job, PROCESS_PRE_START, -1);
243- job_change_goal (job, JOB_STOP);
244- state = job_next_state (job);
245- }
246- } else {
247- state = job_next_state (job);
248- }
249+ job_process_start (job, PROCESS_PRE_START);
250+ }
251+ state = job_next_state (job);
252+ break;
253+ case JOB_PRE_START:
254+ nih_assert (job->goal == JOB_START);
255+ nih_assert (old_state == JOB_PRE_STARTING);
256
257+ /* if no pre-start process, go to next
258+ * state. otherwise async child watcher will
259+ * trigger us to go to the next state */
260+ if (! job->class->process[PROCESS_PRE_START])
261+ state = job_next_state (job);
262 break;
263- case JOB_SPAWNED:
264+ case JOB_SPAWNING:
265 nih_assert (job->goal == JOB_START);
266 nih_assert (old_state == JOB_PRE_START);
267
268 if (job->class->process[PROCESS_MAIN]) {
269- if (job_process_run (job, PROCESS_MAIN) < 0) {
270- job_failed (job, PROCESS_MAIN, -1);
271- job_change_goal (job, JOB_STOP);
272- state = job_next_state (job);
273- } else if (job->class->expect == EXPECT_NONE)
274- state = job_next_state (job);
275- } else {
276- state = job_next_state (job);
277- }
278-
279- break;
280- case JOB_POST_START:
281+ job_process_start (job, PROCESS_MAIN);
282+ }
283+ state = job_next_state (job);
284+ break;
285+ case JOB_SPAWNED:
286+ nih_assert (job->goal == JOB_START);
287+ nih_assert (old_state == JOB_SPAWNING);
288+ if (! job->class->process[PROCESS_MAIN]) {
289+ state = job_next_state (job);
290+ }
291+ break;
292+ case JOB_POST_STARTING:
293 nih_assert (job->goal == JOB_START);
294 nih_assert (old_state == JOB_SPAWNED);
295
296 if (job->class->process[PROCESS_POST_START]) {
297- if (job_process_run (job, PROCESS_POST_START) < 0)
298- state = job_next_state (job);
299- } else {
300+ job_process_start (job, PROCESS_POST_START);
301+ }
302+ state = job_next_state (job);
303+ break;
304+ case JOB_POST_START:
305+ nih_assert (job->goal == JOB_START);
306+ nih_assert (old_state == JOB_POST_STARTING);
307+
308+ if (! job->class->process[PROCESS_POST_START]) {
309 state = job_next_state (job);
310 }
311-
312 break;
313 case JOB_RUNNING:
314 nih_assert (job->goal == JOB_START);
315@@ -482,20 +534,26 @@
316 }
317
318 break;
319- case JOB_PRE_STOP:
320+ case JOB_PRE_STOPPING:
321 nih_assert (job->goal == JOB_STOP);
322 nih_assert (old_state == JOB_RUNNING);
323
324 if (job->class->process[PROCESS_PRE_STOP]) {
325- if (job_process_run (job, PROCESS_PRE_STOP) < 0)
326- state = job_next_state (job);
327- } else {
328- state = job_next_state (job);
329+ job_process_start (job, PROCESS_PRE_STOP);
330 }
331+ state = job_next_state (job);
332+ break;
333+ case JOB_PRE_STOP:
334+ nih_assert (job->goal == JOB_STOP);
335+ nih_assert (old_state == JOB_PRE_STOPPING);
336
337+ if (! job->class->process[PROCESS_PRE_STOP]) {
338+ state = job_next_state (job);
339+ }
340 break;
341 case JOB_STOPPING:
342 nih_assert ((old_state == JOB_STARTING)
343+ || (old_state == JOB_PRE_STARTING)
344 || (old_state == JOB_PRE_START)
345 || (old_state == JOB_SECURITY)
346 || (old_state == JOB_SPAWNED)
347@@ -508,7 +566,6 @@
348 break;
349 case JOB_KILLED:
350 nih_assert (old_state == JOB_STOPPING);
351-
352 if (job->class->process[PROCESS_MAIN]
353 && (job->pid[PROCESS_MAIN] > 0)) {
354 job_process_kill (job, PROCESS_MAIN);
355@@ -517,19 +574,20 @@
356 }
357
358 break;
359- case JOB_POST_STOP:
360+ case JOB_POST_STOPPING:
361 nih_assert (old_state == JOB_KILLED);
362
363 if (job->class->process[PROCESS_POST_STOP]) {
364- if (job_process_run (job, PROCESS_POST_STOP) < 0) {
365- job_failed (job, PROCESS_POST_STOP, -1);
366- job_change_goal (job, JOB_STOP);
367- state = job_next_state (job);
368- }
369- } else {
370- state = job_next_state (job);
371+ job_process_start (job, PROCESS_POST_STOP);
372 }
373+ state = job_next_state (job);
374+ break;
375+ case JOB_POST_STOP:
376+ nih_assert (old_state == JOB_POST_STOPPING);
377
378+ if (! job->class->process[PROCESS_POST_STOP]) {
379+ state = job_next_state (job);
380+ }
381 break;
382 case JOB_WAITING:
383 nih_assert (job->goal == JOB_STOP);
384@@ -617,6 +675,15 @@
385 case JOB_STOP:
386 return JOB_STOPPING;
387 case JOB_START:
388+ return JOB_SECURITY_SPAWNING;
389+ default:
390+ nih_assert_not_reached ();
391+ }
392+ case JOB_SECURITY_SPAWNING:
393+ switch (job->goal) {
394+ case JOB_STOP:
395+ return JOB_STOPPING;
396+ case JOB_START:
397 return JOB_SECURITY;
398 default:
399 nih_assert_not_reached ();
400@@ -626,6 +693,15 @@
401 case JOB_STOP:
402 return JOB_STOPPING;
403 case JOB_START:
404+ return JOB_PRE_STARTING;
405+ default:
406+ nih_assert_not_reached ();
407+ }
408+ case JOB_PRE_STARTING:
409+ switch (job->goal) {
410+ case JOB_STOP:
411+ return JOB_STOPPING;
412+ case JOB_START:
413 return JOB_PRE_START;
414 default:
415 nih_assert_not_reached ();
416@@ -635,6 +711,15 @@
417 case JOB_STOP:
418 return JOB_STOPPING;
419 case JOB_START:
420+ return JOB_SPAWNING;
421+ default:
422+ nih_assert_not_reached ();
423+ }
424+ case JOB_SPAWNING:
425+ switch (job->goal) {
426+ case JOB_STOP:
427+ return JOB_STOPPING;
428+ case JOB_START:
429 return JOB_SPAWNED;
430 default:
431 nih_assert_not_reached ();
432@@ -644,6 +729,15 @@
433 case JOB_STOP:
434 return JOB_STOPPING;
435 case JOB_START:
436+ return JOB_POST_STARTING;
437+ default:
438+ nih_assert_not_reached ();
439+ }
440+ case JOB_POST_STARTING:
441+ switch (job->goal) {
442+ case JOB_STOP:
443+ return JOB_STOPPING;
444+ case JOB_START:
445 return JOB_POST_START;
446 default:
447 nih_assert_not_reached ();
448@@ -665,7 +759,7 @@
449 case JOB_STOP:
450 if (job->class->process[PROCESS_MAIN]
451 && (job->pid[PROCESS_MAIN] > 0)) {
452- return JOB_PRE_STOP;
453+ return JOB_PRE_STOPPING;
454 } else {
455 return JOB_STOPPING;
456 }
457@@ -674,6 +768,15 @@
458 default:
459 nih_assert_not_reached ();
460 }
461+ case JOB_PRE_STOPPING:
462+ switch (job->goal) {
463+ case JOB_STOP:
464+ return JOB_PRE_STOP;
465+ case JOB_START:
466+ return JOB_PRE_STOP;
467+ default:
468+ nih_assert_not_reached ();
469+ }
470 case JOB_PRE_STOP:
471 switch (job->goal) {
472 case JOB_STOP:
473@@ -698,6 +801,15 @@
474 case JOB_KILLED:
475 switch (job->goal) {
476 case JOB_STOP:
477+ return JOB_POST_STOPPING;
478+ case JOB_START:
479+ return JOB_POST_STOPPING;
480+ default:
481+ nih_assert_not_reached ();
482+ }
483+ case JOB_POST_STOPPING:
484+ switch (job->goal) {
485+ case JOB_STOP:
486 return JOB_POST_STOP;
487 case JOB_START:
488 return JOB_POST_STOP;
489@@ -870,8 +982,8 @@
490
491
492 /**
493- * job_emit_event:
494- * @job: job generating the event.
495+ * job_emit_event_with_state:
496+ * @job: job generating the event,
497 *
498 * Called from a state change because it believes an event should be
499 * emitted. Constructs the event with the right arguments and environment
500@@ -1100,22 +1212,34 @@
501 return N_("waiting");
502 case JOB_STARTING:
503 return N_("starting");
504+ case JOB_SECURITY_SPAWNING:
505+ return N_("security-spawning");
506 case JOB_SECURITY:
507 return N_("security");
508+ case JOB_PRE_STARTING:
509+ return N_("pre-starting");
510 case JOB_PRE_START:
511 return N_("pre-start");
512+ case JOB_SPAWNING:
513+ return N_("spawning");
514 case JOB_SPAWNED:
515 return N_("spawned");
516+ case JOB_POST_STARTING:
517+ return N_("post-starting");
518 case JOB_POST_START:
519 return N_("post-start");
520 case JOB_RUNNING:
521 return N_("running");
522+ case JOB_PRE_STOPPING:
523+ return N_("pre-stopping");
524 case JOB_PRE_STOP:
525 return N_("pre-stop");
526 case JOB_STOPPING:
527 return N_("stopping");
528 case JOB_KILLED:
529 return N_("killed");
530+ case JOB_POST_STOPPING:
531+ return N_("post-stopping");
532 case JOB_POST_STOP:
533 return N_("post-stop");
534 default:
535@@ -1140,22 +1264,34 @@
536 return JOB_WAITING;
537 } else if (! strcmp (state, "starting")) {
538 return JOB_STARTING;
539+ } else if (! strcmp (state, "security-spawning")) {
540+ return JOB_SECURITY_SPAWNING;
541 } else if (! strcmp (state, "security")) {
542 return JOB_SECURITY;
543+ } else if (! strcmp (state, "pre-starting")) {
544+ return JOB_PRE_STARTING;
545 } else if (! strcmp (state, "pre-start")) {
546 return JOB_PRE_START;
547+ } else if (! strcmp (state, "spawning")) {
548+ return JOB_SPAWNING;
549 } else if (! strcmp (state, "spawned")) {
550 return JOB_SPAWNED;
551+ } else if (! strcmp (state, "post-starting")) {
552+ return JOB_POST_STARTING;
553 } else if (! strcmp (state, "post-start")) {
554 return JOB_POST_START;
555 } else if (! strcmp (state, "running")) {
556 return JOB_RUNNING;
557+ } else if (! strcmp (state, "pre-stopping")) {
558+ return JOB_PRE_STOPPING;
559 } else if (! strcmp (state, "pre-stop")) {
560 return JOB_PRE_STOP;
561 } else if (! strcmp (state, "stopping")) {
562 return JOB_STOPPING;
563 } else if (! strcmp (state, "killed")) {
564 return JOB_KILLED;
565+ } else if (! strcmp (state, "post-stopping")) {
566+ return JOB_POST_STOPPING;
567 } else if (! strcmp (state, "post-stop")) {
568 return JOB_POST_STOP;
569 } else {
570@@ -1626,6 +1762,7 @@
571 json_object *json_pid;
572 json_object *json_fds;
573 json_object *json_logs;
574+ json_object *json_handler_data;
575
576 nih_assert (job);
577
578@@ -1771,6 +1908,33 @@
579
580 json_object_object_add (json, "log", json_logs);
581
582+ json_handler_data = json_object_new_array ();
583+
584+ if (! json_handler_data)
585+ return json;
586+
587+ for (int process = 0; process < PROCESS_LAST; process++) {
588+ json_object *json_data = NULL;
589+
590+ /* Only bother serialising if the process data hasn't
591+ * been handled yet.
592+ */
593+ if (job->process_data[process] && job->process_data[process]->valid) {
594+
595+ json_data = job_process_data_serialise (job,
596+ job->process_data[process]);
597+
598+ if (! json_data)
599+ goto error;
600+
601+ }
602+
603+ if (json_object_array_add (json_handler_data, json_data) < 0)
604+ goto error;
605+ }
606+
607+ json_object_object_add (json, "process_data", json_handler_data);
608+
609 return json;
610
611 error:
612@@ -1834,6 +1998,7 @@
613 json_object *json_fds;
614 json_object *json_pid;
615 json_object *json_logs;
616+ json_object *json_process_data;
617 json_object *json_stop_on = NULL;
618 size_t len;
619 int ret;
620@@ -2062,6 +2227,38 @@
621 }
622 }
623
624+
625+ if (json_object_object_get_ex (json, "process_data", &json_process_data)) {
626+ if (! state_check_json_type (json_process_data, array))
627+ goto error;
628+
629+ for (int process = 0; process < PROCESS_LAST; process++) {
630+ json_object *json_data = NULL;
631+
632+ json_data = json_object_array_get_idx (json_process_data, process);
633+
634+ if (json_data) {
635+ /* NULL if there was no process_data for this job process, or we failed to
636+ * deserialise it; either way, this should be non-fatal.
637+ */
638+ job->process_data[process] =
639+ job_process_data_deserialise (job->process_data, job, json_data);
640+
641+ if (! job->process_data[process])
642+ goto error;
643+
644+ /* Recreate watch */
645+ if (job->process_data[process]->valid) {
646+ job_register_child_handler (job->process_data[process],
647+ job->process_data[process]->job_process_fd,
648+ job->process_data[process]);
649+ }
650+ } else {
651+ job->process_data[process] = NULL;
652+ }
653+ }
654+ }
655+
656 return job;
657
658 error:
659@@ -2163,19 +2360,25 @@
660 *
661 * Returns: string representation of @state, or NULL if not known.
662 **/
663-static const char *
664+const char *
665 job_state_enum_to_str (JobState state)
666 {
667 state_enum_to_str (JOB_WAITING, state);
668 state_enum_to_str (JOB_STARTING, state);
669+ state_enum_to_str (JOB_SECURITY_SPAWNING, state);
670 state_enum_to_str (JOB_SECURITY, state);
671+ state_enum_to_str (JOB_PRE_STARTING, state);
672 state_enum_to_str (JOB_PRE_START, state);
673+ state_enum_to_str (JOB_SPAWNING, state);
674 state_enum_to_str (JOB_SPAWNED, state);
675+ state_enum_to_str (JOB_POST_STARTING, state);
676 state_enum_to_str (JOB_POST_START, state);
677 state_enum_to_str (JOB_RUNNING, state);
678+ state_enum_to_str (JOB_PRE_STOPPING, state);
679 state_enum_to_str (JOB_PRE_STOP, state);
680 state_enum_to_str (JOB_STOPPING, state);
681 state_enum_to_str (JOB_KILLED, state);
682+ state_enum_to_str (JOB_POST_STOPPING, state);
683 state_enum_to_str (JOB_POST_STOP, state);
684
685 return NULL;
686@@ -2190,19 +2393,25 @@
687 *
688 * Returns: JobState representation of @state, or -1 if not known.
689 **/
690-static JobState
691+JobState
692 job_state_str_to_enum (const char *state)
693 {
694 state_str_to_enum (JOB_WAITING, state);
695 state_str_to_enum (JOB_STARTING, state);
696+ state_str_to_enum (JOB_SECURITY_SPAWNING, state);
697 state_str_to_enum (JOB_SECURITY, state);
698+ state_str_to_enum (JOB_PRE_STARTING, state);
699 state_str_to_enum (JOB_PRE_START, state);
700+ state_str_to_enum (JOB_SPAWNING, state);
701 state_str_to_enum (JOB_SPAWNED, state);
702+ state_str_to_enum (JOB_POST_STARTING, state);
703 state_str_to_enum (JOB_POST_START, state);
704 state_str_to_enum (JOB_RUNNING, state);
705+ state_str_to_enum (JOB_PRE_STOPPING, state);
706 state_str_to_enum (JOB_PRE_STOP, state);
707 state_str_to_enum (JOB_STOPPING, state);
708 state_str_to_enum (JOB_KILLED, state);
709+ state_str_to_enum (JOB_POST_STOPPING, state);
710 state_str_to_enum (JOB_POST_STOP, state);
711
712 return -1;
713@@ -2358,3 +2567,58 @@
714 error:
715 return NULL;
716 }
717+
718+/**
719+ * job_child_error_handler:
720+ *
721+ * @job: job,
722+ * @process: process that failed to start.
723+ *
724+ * JobProcessErrorHandler that deals with errors resulting from
725+ * a failure to start a job process.
726+ **/
727+void
728+job_child_error_handler (Job *job, ProcessType process)
729+{
730+ nih_assert (job);
731+ nih_assert (process > PROCESS_INVALID);
732+ nih_assert (process < PROCESS_LAST);
733+
734+ job->pid[process] = 0;
735+
736+ switch (process) {
737+ case PROCESS_SECURITY:
738+ job_failed (job, PROCESS_SECURITY, -1);
739+ job_change_goal (job, JOB_STOP);
740+ break;
741+
742+ case PROCESS_PRE_START:
743+ job_failed (job, PROCESS_PRE_START, -1);
744+ job_change_goal (job, JOB_STOP);
745+ job_change_state (job, job_next_state (job));
746+ break;
747+
748+ case PROCESS_MAIN:
749+ job_failed (job, PROCESS_MAIN, -1);
750+ job_change_goal (job, JOB_STOP);
751+ job_change_state (job, job_next_state (job));
752+ break;
753+
754+ case PROCESS_POST_START:
755+ job_change_state (job, job_next_state (job));
756+ break;
757+
758+ case PROCESS_PRE_STOP:
759+ job_change_state (job, job_next_state (job));
760+ break;
761+
762+ case PROCESS_POST_STOP:
763+ job_failed (job, PROCESS_POST_STOP, -1);
764+ job_change_goal (job, JOB_STOP);
765+ job_change_state (job, job_next_state (job));
766+ break;
767+
768+ default:
769+ nih_assert_not_reached ();
770+ }
771+}
772
773=== modified file 'init/job.h'
774--- init/job.h 2013-07-22 01:24:26 +0000
775+++ init/job.h 2014-05-22 13:31:23 +0000
776@@ -1,6 +1,6 @@
777 /* upstart
778 *
779- * Copyright © 2010 Canonical Ltd.
780+ * Copyright 2010 Canonical Ltd.
781 * Author: Scott James Remnant <scott@netsplit.com>.
782 *
783 * This program is free software; you can redistribute it and/or modify
784@@ -66,14 +66,20 @@
785 typedef enum job_state {
786 JOB_WAITING,
787 JOB_STARTING,
788+ JOB_SECURITY_SPAWNING,
789 JOB_SECURITY,
790+ JOB_PRE_STARTING,
791 JOB_PRE_START,
792+ JOB_SPAWNING,
793 JOB_SPAWNED,
794+ JOB_POST_STARTING,
795 JOB_POST_START,
796 JOB_RUNNING,
797+ JOB_PRE_STOPPING,
798 JOB_PRE_STOP,
799 JOB_STOPPING,
800 JOB_KILLED,
801+ JOB_POST_STOPPING,
802 JOB_POST_STOP
803 } JobState;
804
805@@ -91,6 +97,7 @@
806 TRACE_NORMAL
807 } TraceState;
808
809+typedef struct job_process_data JobProcessData;
810
811 /**
812 * Job:
813@@ -119,49 +126,102 @@
814 * @respawn_count: number of respawns since @respawn_time,
815 * @trace_forks: number of forks traced,
816 * @trace_state: state of trace,
817- * @log: pointer to array of log objects for handling job output.
818+ * @log: pointer to array of log objects for handling job output,
819+ * @process_data: transitory async job process metadata.
820 *
821 * This structure holds the state of an active job instance being tracked
822 * by the init daemon, the configuration details of the job are available
823 * from the @class member.
824 **/
825 typedef struct job {
826- NihList entry;
827-
828- char *name;
829- JobClass *class;
830- char *path;
831-
832- JobGoal goal;
833- JobState state;
834- char **env;
835-
836- char **start_env;
837- char **stop_env;
838- EventOperator *stop_on;
839-
840- int *fds;
841- size_t num_fds;
842-
843- pid_t *pid;
844- Event *blocker;
845- NihList blocking;
846-
847- NihTimer *kill_timer;
848- ProcessType kill_process;
849-
850- int failed;
851- ProcessType failed_process;
852- int exit_status;
853-
854- time_t respawn_time;
855- int respawn_count;
856-
857- int trace_forks;
858- TraceState trace_state;
859- Log **log;
860+ NihList entry;
861+
862+ char *name;
863+ JobClass *class;
864+ char *path;
865+
866+ JobGoal goal;
867+ JobState state;
868+ char **env;
869+
870+ char **start_env;
871+ char **stop_env;
872+ EventOperator *stop_on;
873+
874+ int *fds;
875+ size_t num_fds;
876+
877+ pid_t *pid;
878+ Event *blocker;
879+ NihList blocking;
880+
881+ NihTimer *kill_timer;
882+ ProcessType kill_process;
883+
884+ int failed;
885+ ProcessType failed_process;
886+ int exit_status;
887+
888+ time_t respawn_time;
889+ int respawn_count;
890+
891+ int trace_forks;
892+ TraceState trace_state;
893+ Log **log;
894+ JobProcessData **process_data;
895+
896 } Job;
897
898+/**
899+ * JobProcessData:
900+ *
901+ * @job: job,
902+ * @process: job process to run,
903+ * @script: optional script that job should run with,
904+ * @shell_fd: file descriptor attached to child that @script should be
905+ * written to (or -1 when @script is NULL),
906+ * @job_process_fd: open readable file descriptor attached to the child
907+ * process used to detect child setup errors,
908+ * @status: exit status or signal in higher byte (iff
909+ * job_process_terminated() ran before the job_register_child_handler()
910+ * handlers),
911+ * @valid: FALSE once the data has been handled, else TRUE.
912+ *
913+ * Used to keep track of asynchronously started job processes.
914+ **/
915+typedef struct job_process_data {
916+ Job *job;
917+ ProcessType process;
918+ char *script;
919+ int shell_fd;
920+ int job_process_fd;
921+ int status;
922+ int valid;
923+} JobProcessData;
924+
925+/**
926+ * job_register_child_handler:
927+ *
928+ * @_parent: parent pointer,
929+ * @_fd: file descriptor to monitor,
930+ * @_data: data to pass to nih_io_reopen().
931+ *
932+ * Register a watcher to monitor the job process child error file
933+ * descriptor @_fd.
934+ **/
935+#define job_register_child_handler(_parent, _fd, _data) \
936+ while (! nih_io_reopen (_parent, _fd, NIH_IO_STREAM, \
937+ (NihIoReader)job_process_child_reader, \
938+ (NihIoCloseHandler)job_process_close_handler, \
939+ NULL, \
940+ _data)) { \
941+ NihError *err; \
942+ err = nih_error_get (); \
943+ if (err->number != ENOMEM) \
944+ nih_assert_not_reached (); \
945+ nih_free (err); \
946+ }
947+
948
949 NIH_BEGIN_EXTERN
950
951@@ -179,7 +239,6 @@
952
953 Event *job_emit_event (Job *job);
954
955-
956 const char *job_name (Job *job);
957
958 const char *job_goal_name (JobGoal goal)
959@@ -228,6 +287,16 @@
960 const char *job_name)
961 __attribute__ ((warn_unused_result));
962
963+const char *
964+job_state_enum_to_str (JobState state)
965+ __attribute__ ((warn_unused_result));
966+
967+JobState
968+job_state_str_to_enum (const char *state)
969+ __attribute__ ((warn_unused_result));
970+
971+void job_child_error_handler (Job *job, ProcessType process);
972+
973 NIH_END_EXTERN
974
975 #endif /* INIT_JOB_H */
976
977=== modified file 'init/job_class.c'
978--- init/job_class.c 2014-05-07 16:34:44 +0000
979+++ init/job_class.c 2014-05-22 13:31:23 +0000
980@@ -2584,14 +2584,14 @@
981 if (fd < 0)
982 continue;
983
984- if (state_toggle_cloexec (fd, FALSE) < 0)
985+ if (state_modify_cloexec (fd, FALSE) < 0)
986 goto error;
987
988 fd = log->fd;
989 if (fd < 0)
990 continue;
991
992- if (state_toggle_cloexec (fd, FALSE) < 0)
993+ if (state_modify_cloexec (fd, FALSE) < 0)
994 goto error;
995 }
996 }
997
998=== modified file 'init/job_process.c'
999--- init/job_process.c 2014-01-31 23:45:02 +0000
1000+++ init/job_process.c 2014-05-22 13:31:23 +0000
1001@@ -111,8 +111,6 @@
1002 static void job_process_error_abort (int fd, JobProcessErrorType type,
1003 int arg)
1004 __attribute__ ((noreturn));
1005-static int job_process_error_read (int fd)
1006- __attribute__ ((warn_unused_result));
1007 static void job_process_remap_fd (int *fd, int reserved_fd, int error_fd);
1008
1009 /**
1010@@ -134,7 +132,7 @@
1011 /* Prototypes for static functions */
1012 static void job_process_kill_timer (Job *job, NihTimer *timer);
1013 static void job_process_terminated (Job *job, ProcessType process,
1014- int status);
1015+ int status, int state_only);
1016 static int job_process_catch_runaway (Job *job);
1017 static void job_process_stopped (Job *job, ProcessType process);
1018 static void job_process_trace_new (Job *job, ProcessType process);
1019@@ -149,8 +147,10 @@
1020 extern int session_end;
1021 extern time_t quiesce_phase_time;
1022
1023+
1024 /**
1025- * job_process_run:
1026+ * job_process_start:
1027+ *
1028 * @job: job context for process to be run in,
1029 * @process: job process to run.
1030 *
1031@@ -174,27 +174,33 @@
1032 * In either case the shell is run with the -e option so that commands will
1033 * fail if their exit status is not checked.
1034 *
1035- * This function will block until the job_process_spawn() call succeeds or
1036- * a non-temporary error occurs (such as file not found). It is up to the
1037- * called to decide whether non-temporary errors are a reason to change the
1038- * job state or not.
1039+ * This function will only block on temporary job_process_spawn_with_fd() error
1040+ * (for example fork() failure): in normal operation it returns as soon as
1041+ * the fork() was successful, registering an NihIo which provides
1042+ * asynchronous handling of the child setup stage. The specified error
1043+ * handler will be called should child setup fail.
1044 *
1045- * Returns: zero on success, negative value on non-temporary error.
1046+ * It is up to the caller to decide whether non-temporary errors are a reason
1047+ * to change the job state or not.
1048 **/
1049-int
1050-job_process_run (Job *job,
1051- ProcessType process)
1052+void
1053+job_process_start (Job *job,
1054+ ProcessType process)
1055 {
1056- Process *proc;
1057- nih_local char **argv = NULL;
1058- nih_local char **env = NULL;
1059- nih_local char *script = NULL;
1060- char **e;
1061- size_t argc, envc;
1062- int fds[2] = { -1, -1 };
1063- int error = FALSE, trace = FALSE, shell = FALSE;
1064+ Process *proc;
1065+ nih_local char **argv = NULL;
1066+ nih_local char **env = NULL;
1067+ nih_local char *script = NULL;
1068+ char **e;
1069+ size_t argc, envc;
1070+ int fds[2] = { -1, -1 };
1071+ int trace = FALSE, shell = FALSE;
1072+ int job_process_fd = -1;
1073+ JobProcessData *process_data = NULL;
1074
1075- nih_assert (job != NULL);
1076+ nih_assert (job);
1077+ nih_assert (process > PROCESS_INVALID);
1078+ nih_assert (process < PROCESS_LAST);
1079
1080 proc = job->class->process[process];
1081 nih_assert (proc != NULL);
1082@@ -304,35 +310,14 @@
1083 trace = TRUE;
1084
1085 /* Spawn the process, repeat until fork() works */
1086- while ((job->pid[process] = job_process_spawn (job, argv, env,
1087- trace, fds[0], process)) < 0) {
1088+ while ((job->pid[process] = job_process_spawn_with_fd (job, argv, env,
1089+ trace, fds[0], process, &job_process_fd)) < 0) {
1090 NihError *err;
1091
1092 err = nih_error_get ();
1093- if (err->number == JOB_PROCESS_ERROR) {
1094- /* Non-temporary error condition, we're not going
1095- * to be able to spawn this process. Clean up after
1096- * ourselves before returning.
1097- */
1098- if (shell) {
1099- close (fds[0]);
1100- close (fds[1]);
1101- }
1102-
1103- job->pid[process] = 0;
1104-
1105- /* Return non-temporary error condition */
1106- nih_warn (_("Failed to spawn %s %s process: %s"),
1107- job_name (job), process_name (process),
1108- err->message);
1109- nih_free (err);
1110- return -1;
1111- } else if (! error)
1112- nih_warn ("%s: %s", _("Temporary process spawn error"),
1113- err->message);
1114+ nih_warn ("%s: %s", _("Temporary process spawn error"),
1115+ err->message);
1116 nih_free (err);
1117-
1118- error = TRUE;
1119 }
1120
1121 nih_info (_("%s %s process (%d)"),
1122@@ -341,51 +326,50 @@
1123 job->trace_forks = 0;
1124 job->trace_state = trace ? TRACE_NEW : TRACE_NONE;
1125
1126- /* Feed the script to the child process */
1127 if (shell) {
1128- NihIo *io;
1129-
1130 /* Clean up and close the reading end (we don't need it) */
1131 close (fds[0]);
1132-
1133- /* Put the entire script into an NihIo send buffer and
1134- * then mark it for closure so that the shell gets EOF
1135- * and the structure gets cleaned up automatically.
1136- */
1137- while (! (io = nih_io_reopen (job, fds[1], NIH_IO_STREAM,
1138- NULL, NULL, NULL, NULL))) {
1139- NihError *err;
1140-
1141- err = nih_error_get ();
1142- if (err->number != ENOMEM)
1143- nih_assert_not_reached ();
1144- nih_free (err);
1145- }
1146-
1147- /* We're feeding using a pipe, which has a file descriptor
1148- * on the child end even though it open()s it again using
1149- * a path. Instruct the shell to close this extra fd and
1150- * not to leak it.
1151- */
1152- NIH_ZERO (nih_io_printf (io, "exec %d<&-\n",
1153- JOB_PROCESS_SCRIPT_FD));
1154-
1155- NIH_ZERO (nih_io_write (io, script, strlen (script)));
1156- nih_io_shutdown (io);
1157- }
1158-
1159- return 0;
1160+ }
1161+
1162+ /* At this stage, a child process has been spawned, but may not
1163+ * yet have been setup appropriately. This operation is handled
1164+ * asynchronously since some setup operations may block,
1165+ * and even though they are running in a new child process, they could
1166+ * still block PID 1 since the latter needs to wait until the
1167+ * child is fully setup and the appropriate program has been
1168+ * exec'd before marking the job as running.
1169+ *
1170+ * This is now achieved by creating an NihIo and registering
1171+ * appropriate handlers such that notification of successful
1172+ * child setup and child error scenarios are handled
1173+ * automatically.
1174+ *
1175+ * job_process_child_reader() handles updating the jobs state.
1176+ */
1177+ process_data = job->process_data[process] =
1178+ NIH_MUST (job_process_data_new
1179+ (job->process_data, job, process, job_process_fd));
1180+
1181+ if (shell) {
1182+ process_data->shell_fd = fds[1];
1183+ process_data->script = script;
1184+ nih_ref (script, process_data);
1185+ }
1186+
1187+ /* Set up a handler to monitor the child fd asynchronously */
1188+ job_register_child_handler (job->process_data[process],
1189+ job_process_fd, process_data);
1190 }
1191
1192-
1193 /**
1194- * job_process_spawn:
1195+ * job_process_spawn_with_fd:
1196 * @job: job of process to be spawned,
1197 * @argv: NULL-terminated list of arguments for the process,
1198 * @env: NULL-terminated list of environment variables for the process,
1199 * @trace: whether to trace this process,
1200 * @script_fd: script file descriptor,
1201- * @process: job process to spawn.
1202+ * @process: job process to spawn,
1203+ * @job_process_fd: readable child setup pipe file descriptor.
1204 *
1205 * This function spawns a new process using the class details in @job to set up
1206 * the environment for it; the process is always a session and process group
1207@@ -406,26 +390,30 @@
1208 *
1209 * This function only spawns the process, it is up to the caller to ensure
1210 * that the information is saved into the job and that the process is watched,
1211- * etc.
1212+ * etc. Also, it is up to the caller to monitor @job_process_fd to
1213+ * ensure the child setup was successful; data available to read
1214+ * indicates a failure to setup the child environment (represented by a
1215+ * JOB_PROCESS_ERROR error) whereas if the descriptor is simply
1216+ * closed setup was successful and the caller can then mark the job
1217+ * process as started.
1218 *
1219 * Spawning a process may fail for temporary reasons, usually due to a failure
1220- * of the fork() syscall or communication with the child; or more permanent
1221- * reasons such as a failure to setup the child environment. These latter
1222- * are always represented by a JOB_PROCESS_ERROR error.
1223+ * of the fork() syscall.
1224 *
1225 * Returns: process id of new process on success, -1 on raised error
1226 **/
1227 pid_t
1228-job_process_spawn (Job *job,
1229+job_process_spawn_with_fd (Job *job,
1230 char * const argv[],
1231 char * const *env,
1232 int trace,
1233 int script_fd,
1234- ProcessType process)
1235+ ProcessType process,
1236+ int *job_process_fd)
1237 {
1238 sigset_t child_set, orig_set;
1239 pid_t pid;
1240- int i, fds[2];
1241+ int i, fds[2] = { -1, -1 };
1242 int pty_master = -1;
1243 int pty_slave = -1;
1244 char pts_name[PATH_MAX];
1245@@ -438,7 +426,6 @@
1246 struct passwd *pwd = NULL;
1247 struct group *grp = NULL;
1248
1249-
1250 nih_assert (job != NULL);
1251 nih_assert (job->class != NULL);
1252 nih_assert (job->log != NULL);
1253@@ -478,7 +465,7 @@
1254 nih_free (err);
1255 close (fds[0]);
1256 close (fds[1]);
1257- nih_return_no_memory_error(-1);
1258+ nih_return_no_memory_error (-1);
1259 }
1260
1261 pty_master = posix_openpt (O_RDWR | O_NOCTTY);
1262@@ -538,23 +525,10 @@
1263 sigprocmask (SIG_SETMASK, &orig_set, NULL);
1264 close (fds[1]);
1265
1266- /* Read error from the pipe, return if one is raised */
1267- if (job_process_error_read (fds[0]) < 0) {
1268- if (class->console == CONSOLE_LOG) {
1269- /* Ensure the pty_master watch gets
1270- * removed and the fd closed.
1271- */
1272- nih_free (job->log[process]);
1273- job->log[process] = NULL;
1274- }
1275- close (fds[0]);
1276- return -1;
1277- }
1278-
1279- /* Note that pts_master is closed automatically in the parent when the
1280- * log object is destroyed.
1281- */
1282- close (fds[0]);
1283+ *job_process_fd = fds[0];
1284+
1285+ nih_io_set_cloexec (*job_process_fd);
1286+
1287 return pid;
1288 } else if (pid < 0) {
1289 nih_error_raise_system ();
1290@@ -923,6 +897,10 @@
1291 * call exec below.
1292 */
1293 if (class->debug) {
1294+ /* Since we have not exec'd at this point, we will still
1295+ * have a copy of the parents fds open. As such, re-exec
1296+ * will not work.
1297+ */
1298 close (fds[1]);
1299 raise (SIGSTOP);
1300 }
1301@@ -985,9 +963,11 @@
1302 exit (255);
1303 }
1304
1305+
1306 /**
1307- * job_process_error_read:
1308- * @fd: reading end of pipe.
1309+ * job_process_error_handler:
1310+ * @buf: data read from child process,
1311+ * @len: length of data read as @wire_err.
1312 *
1313 * Read from the reading end of the pipe specified by @fd, if we receive
1314 * data then the child raised a process error which we reconstruct and raise
1315@@ -996,30 +976,26 @@
1316 * The reconstructed error will be of JOB_PROCESS_ERROR type, the human-
1317 * readable message is generated according to the type of process error
1318 * and argument passed along with it.
1319- *
1320- * Returns: zero if no error was found, or negative value on raised error.
1321 **/
1322-static int
1323-job_process_error_read (int fd)
1324+void
1325+job_process_error_handler (const char *buf, size_t len)
1326 {
1327- JobProcessWireError wire_err;
1328- ssize_t len;
1329- JobProcessError *err;
1330- const char *res;
1331+ JobProcessWireError *wire_err;
1332+ JobProcessError *err;
1333+ const char *res;
1334+
1335+ wire_err = (JobProcessWireError *)buf;
1336+
1337+ nih_assert (wire_err);
1338
1339 /* Read the error from the pipe; a zero read indicates that the
1340 * exec succeeded so we return success, otherwise if we don't receive
1341 * a JobProcessWireError structure, we return a temporary error so we
1342 * try again.
1343 */
1344- len = read (fd, &wire_err, sizeof (wire_err));
1345- if (len == 0) {
1346- return 0;
1347- } else if (len < 0) {
1348- nih_return_system_error (-1);
1349- } else if (len != sizeof (wire_err)) {
1350+ if (len != sizeof (JobProcessWireError)) {
1351 errno = EILSEQ;
1352- nih_return_system_error (-1);
1353+ nih_return_system_error ();
1354 }
1355
1356 /* Construct a JobProcessError to be raised containing information
1357@@ -1028,9 +1004,9 @@
1358 */
1359 err = NIH_MUST (nih_new (NULL, JobProcessError));
1360
1361- err->type = wire_err.type;
1362- err->arg = wire_err.arg;
1363- err->errnum = wire_err.errnum;
1364+ err->type = wire_err->type;
1365+ err->arg = wire_err->arg;
1366+ err->errnum = wire_err->errnum;
1367
1368 err->error.number = JOB_PROCESS_ERROR;
1369
1370@@ -1218,7 +1194,6 @@
1371 }
1372
1373 nih_error_raise_error (&err->error);
1374- return -1;
1375 }
1376
1377
1378@@ -1332,6 +1307,7 @@
1379 {
1380 nih_assert (job);
1381 nih_assert (timeout);
1382+ nih_assert (job->kill_timer == NULL);
1383
1384 job->kill_process = process;
1385 job->kill_timer = NIH_MUST (nih_timer_add_timeout (
1386@@ -1462,7 +1438,7 @@
1387 job_name (job), process_name (process), pid);
1388 }
1389
1390- job_process_terminated (job, process, status);
1391+ job_process_terminated (job, process, status, FALSE);
1392 break;
1393 case NIH_CHILD_KILLED:
1394 case NIH_CHILD_DUMPED:
1395@@ -1483,7 +1459,7 @@
1396 }
1397
1398 status <<= 8;
1399- job_process_terminated (job, process, status);
1400+ job_process_terminated (job, process, status, FALSE);
1401 break;
1402 case NIH_CHILD_STOPPED:
1403 /* Child was stopped by a signal, make sure it was SIGSTOP
1404@@ -1560,7 +1536,8 @@
1405 * job_process_terminated:
1406 * @job: job that changed,
1407 * @process: specific process,
1408- * @status: exit status or signal in higher byte.
1409+ * @status: exit status or signal in higher byte,
1410+ * @state_only: if TRUE, only update the jobs state (not its goal).
1411 *
1412 * This function is called whenever a @process attached to @job terminates,
1413 * @status should contain the exit status in the lower byte or signal in
1414@@ -1572,7 +1549,8 @@
1415 static void
1416 job_process_terminated (Job *job,
1417 ProcessType process,
1418- int status)
1419+ int status,
1420+ int state_only)
1421 {
1422 int failed = FALSE, stop = FALSE, state = TRUE;
1423 struct utmpx *utmptr;
1424@@ -1580,6 +1558,36 @@
1425
1426 nih_assert (job != NULL);
1427
1428+ if (job->state == JOB_SECURITY_SPAWNING ||
1429+ job->state == JOB_PRE_STARTING ||
1430+ job->state == JOB_SPAWNING ||
1431+ job->state == JOB_POST_STARTING ||
1432+ job->state == JOB_PRE_STOPPING ||
1433+ job->state == JOB_POST_STOPPING) {
1434+ /* A child process has been spawned by
1435+ * job_process_spawn(), but we have not yet received
1436+ * confirmation of whether the child setup phase was
1437+ * successful or not.
1438+ *
1439+ * The fact that we are in this function means the child
1440+ * setup actually failed, however we handle that
1441+ * by waiting for the handlers registered by
1442+ * job_register_child_handler() to be called to deal
1443+ * with this error.
1444+ */
1445+ nih_assert (job->process_data);
1446+ nih_assert (job->process_data[process]);
1447+
1448+ /* Add the child data for the *second* call to this
1449+ * function when the child pipe has been closed.
1450+ */
1451+ job->process_data[process]->status = status;
1452+
1453+ job->state = job_next_state (job);
1454+
1455+ return;
1456+ }
1457+
1458 switch (process) {
1459 case PROCESS_MAIN:
1460 nih_assert ((job->state == JOB_RUNNING)
1461@@ -1701,7 +1709,7 @@
1462 }
1463 break;
1464 case PROCESS_POST_START:
1465- nih_assert (job->state == JOB_POST_START);
1466+ nih_assert (job->state == JOB_POST_START || job->state == JOB_RUNNING);
1467
1468 /* We always want to change the state when the post-start
1469 * script terminates; if the main process is running, we'll
1470@@ -1750,7 +1758,7 @@
1471 job->kill_process = PROCESS_INVALID;
1472 }
1473
1474- if (job->class->console == CONSOLE_LOG && job->log[process]) {
1475+ if (job->class->console == CONSOLE_LOG && job->log[process] && ! state_only) {
1476 int ret;
1477
1478 /* It is imperative that we free the log at this stage to ensure
1479@@ -1776,40 +1784,49 @@
1480 job->log[process] = NULL;
1481 }
1482
1483- /* Find existing utmp entry for the process pid */
1484- setutxent();
1485- while ((utmptr = getutxent()) != NULL) {
1486- if (utmptr->ut_pid == job->pid[process]) {
1487- /* set type and clean ut_user, ut_host,
1488- * ut_time as described in utmp(5)
1489- */
1490- utmptr->ut_type = DEAD_PROCESS;
1491- memset(utmptr->ut_user, 0, UT_NAMESIZE);
1492- memset(utmptr->ut_host, 0, UT_HOSTSIZE);
1493- utmptr->ut_time = 0;
1494- /* Update existing utmp file. */
1495- pututxline(utmptr);
1496-
1497- /* set ut_time for log */
1498- gettimeofday(&tv, NULL);
1499- utmptr->ut_tv.tv_sec = tv.tv_sec;
1500- utmptr->ut_tv.tv_usec = tv.tv_usec;
1501- /* Write wtmp entry */
1502- updwtmpx (_PATH_WTMP, utmptr);
1503-
1504- break;
1505+ if (! state_only) {
1506+ /* Find existing utmp entry for the process pid */
1507+ setutxent();
1508+ while ((utmptr = getutxent()) != NULL) {
1509+ if (utmptr->ut_pid == job->pid[process]) {
1510+ /* set type and clean ut_user, ut_host,
1511+ * ut_time as described in utmp(5)
1512+ */
1513+ utmptr->ut_type = DEAD_PROCESS;
1514+ memset(utmptr->ut_user, 0, UT_NAMESIZE);
1515+ memset(utmptr->ut_host, 0, UT_HOSTSIZE);
1516+ utmptr->ut_time = 0;
1517+ /* Update existing utmp file. */
1518+ pututxline(utmptr);
1519+
1520+ /* set ut_time for log */
1521+ gettimeofday(&tv, NULL);
1522+ utmptr->ut_tv.tv_sec = tv.tv_sec;
1523+ utmptr->ut_tv.tv_usec = tv.tv_usec;
1524+ /* Write wtmp entry */
1525+ updwtmpx (_PATH_WTMP, utmptr);
1526+
1527+ break;
1528+ }
1529 }
1530+ endutxent();
1531+
1532+ /* Clear the process pid field */
1533+ job->pid[process] = 0;
1534 }
1535- endutxent();
1536-
1537- /* Clear the process pid field */
1538- job->pid[process] = 0;
1539-
1540
1541 /* Mark the job as failed */
1542 if (failed)
1543 job_failed (job, process, status);
1544
1545+ /* Cancel goal transition if the job state only should be
1546+ * changed.
1547+ */
1548+ if (state_only && stop) {
1549+ stop = 0;
1550+ nih_assert (! failed);
1551+ }
1552+
1553 /* Change the goal to stop; normally this doesn't have any
1554 * side-effects, except when we're in the RUNNING state when it'll
1555 * change the state as well. We obviously don't want to change the
1556@@ -1887,7 +1904,7 @@
1557 /* Any process can stop on a signal, but we only care about the
1558 * main process when the state is still spawned.
1559 */
1560- if ((process != PROCESS_MAIN) || (job->state != JOB_SPAWNED))
1561+ if ((process != PROCESS_MAIN) || ((job->state != JOB_SPAWNING) && job->state != JOB_SPAWNED))
1562 return;
1563
1564 /* Send SIGCONT back and change the state to the next one, if this
1565@@ -1916,14 +1933,16 @@
1566 ProcessType process)
1567 {
1568 nih_assert (job != NULL);
1569+
1570 nih_assert ((job->trace_state == TRACE_NEW)
1571 || (job->trace_state == TRACE_NEW_CHILD));
1572
1573 /* Any process can get us to trace them, but we only care about the
1574 * main process when the state is still spawned.
1575 */
1576- if ((process != PROCESS_MAIN) || (job->state != JOB_SPAWNED))
1577+ if ((process != PROCESS_MAIN) || ((job->state != JOB_SPAWNING) && (job->state != JOB_SPAWNED))) {
1578 return;
1579+ }
1580
1581 /* Set options so that we are notified when the process forks, and
1582 * get a different kind of notification when it execs to a plain
1583@@ -1973,7 +1992,7 @@
1584 /* Any process can get us to trace them, but we only care about the
1585 * main process when the state is still spawned.
1586 */
1587- if ((process != PROCESS_MAIN) || (job->state != JOB_SPAWNED))
1588+ if ((process != PROCESS_MAIN) || ((job->state != JOB_SPAWNING) && (job->state != JOB_SPAWNED)))
1589 return;
1590
1591 /* We need to fork at least twice unless we're expecting a
1592@@ -2018,7 +2037,7 @@
1593 /* Any process can get us to trace them, but we only care about the
1594 * main process when the state is still spawned.
1595 */
1596- if ((process != PROCESS_MAIN) || (job->state != JOB_SPAWNED)
1597+ if ((process != PROCESS_MAIN) || ((job->state != JOB_SPAWNING) && (job->state != JOB_SPAWNED))
1598 || (job->trace_state != TRACE_NORMAL))
1599 return;
1600
1601@@ -2053,9 +2072,10 @@
1602 /* Any process can get us to trace them, but we only care about the
1603 * main process when the state is still spawned.
1604 */
1605- if ((process != PROCESS_MAIN) || (job->state != JOB_SPAWNED)
1606- || (job->trace_state != TRACE_NORMAL))
1607+ if ((process != PROCESS_MAIN) || ((job->state != JOB_SPAWNING) && (job->state != JOB_SPAWNED))
1608+ || (job->trace_state != TRACE_NORMAL)) {
1609 return;
1610+ }
1611
1612 /* Obtain the child process id from the ptrace event. */
1613 if (ptrace (PTRACE_GETEVENTMSG, job->pid[process], NULL, &data) < 0) {
1614@@ -2121,7 +2141,7 @@
1615 /* Any process can get us to trace them, but we only care about the
1616 * main process when the state is still spawned and we're tracing it.
1617 */
1618- if ((process != PROCESS_MAIN) || (job->state != JOB_SPAWNED)
1619+ if ((process != PROCESS_MAIN) || ((job->state != JOB_SPAWNING) && job->state != JOB_SPAWNED)
1620 || (job->trace_state != TRACE_NORMAL))
1621 return;
1622
1623@@ -2176,7 +2196,6 @@
1624 if (job->pid[i] == pid) {
1625 if (process)
1626 *process = i;
1627-
1628 return job;
1629 }
1630 }
1631@@ -2315,16 +2334,426 @@
1632
1633 nih_assert (fd);
1634 nih_assert (reserved_fd);
1635- nih_assert (error_fd);
1636+ nih_assert (error_fd >= 0);
1637
1638- if (*fd != reserved_fd)
1639+ if (*fd != reserved_fd) {
1640+ /* fd does not need remapping */
1641 return;
1642+ }
1643
1644 new = dup (*fd);
1645 if (new < 0) {
1646 nih_error_raise_system ();
1647 job_process_error_abort (error_fd, JOB_PROCESS_ERROR_DUP, 0);
1648 }
1649+
1650 close (*fd);
1651 *fd = new;
1652 }
1653+
1654+
1655+/**
1656+ * job_process_child_reader:
1657+ *
1658+ * @process_data: JobProcessHandlerData structure,
1659+ * @io: NihIo with data to be read,
1660+ * @buf: buffer data is available in,
1661+ * @len: bytes in @buf.
1662+ *
1663+ * Called automatically when an error occurred setting up the child process.
1664+ **/
1665+void
1666+job_process_child_reader (JobProcessData *process_data,
1667+ NihIo *io,
1668+ const char *buf,
1669+ size_t len)
1670+{
1671+ Job *job;
1672+ ProcessType process;
1673+ NihError *err;
1674+
1675+ /* The job is in the process of being killed which must mean all
1676+ * the job pids are dead. Hence, there is no point in attempting
1677+ * to talk to them.
1678+ */
1679+ if (! process_data)
1680+ return;
1681+ if (! process_data->valid)
1682+ return;
1683+
1684+ nih_assert (io);
1685+ nih_assert (buf);
1686+
1687+ job = process_data->job;
1688+ process = process_data->process;
1689+
1690+ /* Construct the NIH error from the data received from
1691+ * the child.
1692+ */
1693+ job_process_error_handler (buf, len);
1694+
1695+ err = nih_error_get ();
1696+
1697+ nih_assert (err->number == JOB_PROCESS_ERROR);
1698+
1699+ /* Non-temporary error condition */
1700+ nih_warn (_("Failed to spawn %s %s process: %s"),
1701+ job_name (job), process_name (process),
1702+ err->message);
1703+ nih_free (err);
1704+
1705+ /* Non-temporary error condition, we're not going
1706+ * to be able to spawn this job.
1707+ */
1708+ if (process_data->shell_fd != -1) {
1709+ close (process_data->shell_fd);
1710+
1711+ /* Invalidate */
1712+ process_data->shell_fd = -1;
1713+ }
1714+
1715+ if (job && job->class->console == CONSOLE_LOG && job->log[process]) {
1716+ /* Ensure the pty_master watch gets
1717+ * removed and the fd closed.
1718+ */
1719+ nih_free (job->log[process]);
1720+ job->log[process] = NULL;
1721+ }
1722+
1723+ /* Now call the handler registered via job_process_start()
1724+ * to deal with the error condition.
1725+ */
1726+ job_child_error_handler (job, process);
1727+
1728+ /* Note that pts_master is closed automatically in the parent
1729+ * when the log object is destroyed.
1730+ */
1731+
1732+ nih_io_shutdown (io);
1733+
1734+ /* Invalidate */
1735+ process_data->job_process_fd = -1;
1736+ process_data->valid = FALSE;
1737+}
1738+
1739+/**
1740+ * @process_data: JobProcessData,
1741+ * @io: NihIo.
1742+ *
1743+ * NihIoCloseHandler called when job process starts successfully.
1744+ **/
1745+void
1746+job_process_close_handler (JobProcessData *process_data,
1747+ NihIo *io)
1748+{
1749+ Job *job;
1750+ ProcessType process;
1751+ int status;
1752+
1753+ /* The job is in the process of being killed which must mean all
1754+ * the job pids are dead. Hence, there is no point in attempting
1755+ * to talk to them.
1756+ */
1757+ if (! process_data)
1758+ return;
1759+
1760+ nih_assert (io);
1761+
1762+ job = process_data->job;
1763+ process = process_data->process;
1764+ status = process_data->status;
1765+
1766+ /* Ensure the job process error fd is closed before attempting
1767+ * to handle any scripts.
1768+ */
1769+ nih_free (io);
1770+
1771+ /* invalidate */
1772+ process_data->job_process_fd = -1;
1773+ process_data->valid = FALSE;
1774+
1775+ job_process_run_bottom (process_data);
1776+
1777+ if (job && job->state == JOB_SPAWNED) {
1778+ if (job->class->expect == EXPECT_NONE) {
1779+ nih_assert (process == PROCESS_MAIN);
1780+ job_change_state (job, job_next_state (job));
1781+ }
1782+ }
1783+
1784+ /* Don't change the jobs goal yet as the process may not have
1785+ * actually terminted (and hence will have
1786+ * job_process_terminated() called on it again later).
1787+ */
1788+ switch (job->state) {
1789+ /* FIXME: BUG: incomplete list of states!!!! */
1790+ case JOB_SECURITY_SPAWNING:
1791+ case JOB_PRE_STARTING:
1792+ case JOB_SPAWNING:
1793+ case JOB_POST_STARTING:
1794+ case JOB_PRE_STOPPING:
1795+ case JOB_POST_STOPPING:
1796+ job_process_terminated (job, process, status, TRUE);
1797+ break;
1798+
1799+ default:
1800+ /* NOP */
1801+ break;
1802+ }
1803+}
1804+
1805+
1806+/**
1807+ * job_process_run_bottom:
1808+ *
1809+ * @process_data: JobProcessData.
1810+ *
1811+ * Perform final job process setup.
1812+ **/
1813+void
1814+job_process_run_bottom (JobProcessData *process_data)
1815+{
1816+ Job *job;
1817+ //JobState state;
1818+ char *script;
1819+ int shell_fd;
1820+
1821+ nih_assert (process_data);
1822+
1823+ job = process_data->job;
1824+ shell_fd = process_data->shell_fd;
1825+ script = process_data->script;
1826+ //state = process_data->state;
1827+
1828+ /* Handle job process containing a script section by sending the
1829+ * script to the child shell.
1830+ */
1831+ if (script && shell_fd != -1) {
1832+ NihIo *io;
1833+
1834+
1835+ /* Put the entire script into an NihIo send buffer and
1836+ * then mark it for closure so that the shell gets EOF
1837+ * and the structure gets cleaned up automatically.
1838+ */
1839+ while (! (io = nih_io_reopen (job, shell_fd, NIH_IO_STREAM,
1840+ NULL, NULL, NULL, NULL))) {
1841+ NihError *err;
1842+
1843+ err = nih_error_get ();
1844+
1845+ if (err->number != ENOMEM)
1846+ nih_assert_not_reached ();
1847+ nih_free (err);
1848+ }
1849+
1850+ /* We're feeding using a pipe, which has a file descriptor
1851+ * on the child end even though it open()s it again using
1852+ * a path. Instruct the shell to close this extra fd and
1853+ * not to leak it.
1854+ */
1855+ NIH_ZERO (nih_io_printf (io, "exec %d<&-\n",
1856+ JOB_PROCESS_SCRIPT_FD));
1857+
1858+ NIH_ZERO (nih_io_write (io, script, strlen (script)));
1859+
1860+ /* We're only using the io for writing, so clear the
1861+ * default flag.
1862+ */
1863+ io->watch->events &= ~NIH_IO_READ;
1864+
1865+ nih_io_shutdown (io);
1866+
1867+ /* Invalidate now that we've sent the script to the
1868+ * child.
1869+ */
1870+ process_data->shell_fd = -1;
1871+ process_data->valid = FALSE;
1872+ }
1873+
1874+ /* Success, so change the job state */
1875+ //job->state = state;
1876+ //job->state = job_next_state (job);
1877+
1878+ NIH_LIST_FOREACH (control_conns, iter) {
1879+ NihListEntry *entry = (NihListEntry *)iter;
1880+ DBusConnection *conn = (DBusConnection *)entry->data;
1881+
1882+ NIH_ZERO (job_emit_state_changed (
1883+ conn, job->path,
1884+ job_state_name (job->state)));
1885+ }
1886+}
1887+
1888+
1889+/**
1890+ * job_process_data_new:
1891+ *
1892+ * @parent: parent pointer,
1893+ * @job: job,
1894+ * @process: currently-running job process,
1895+ * @job_process_fd: error file descriptor connected to job process used
1896+ * to signal successful job process setup.
1897+ *
1898+ * Create a new job process data object to record meta-data for an
1899+ * asynchronously-started job process. The lifetime of such objects is
1900+ * limited to the time taken for the job process to fail or indicate
1901+ * successful startup (both scenarios are handled by @job_process_fd).
1902+ *
1903+ * Returns: Newly-allocated JobProcess on success, or NULL on
1904+ * insufficient memory.
1905+ **/
1906+JobProcessData *
1907+job_process_data_new (void *parent,
1908+ Job *job,
1909+ ProcessType process,
1910+ int job_process_fd)
1911+{
1912+ JobProcessData *process_data;
1913+
1914+ nih_assert (job);
1915+ nih_assert (job_process_fd != -1);
1916+
1917+ process_data = NIH_MUST (nih_new (parent, JobProcessData));
1918+ if (! process_data)
1919+ return NULL;
1920+
1921+ process_data->process = process;
1922+ process_data->job_process_fd = job_process_fd;
1923+
1924+ process_data->script = NULL;
1925+ process_data->shell_fd = -1;
1926+ process_data->valid = TRUE;
1927+
1928+ process_data->job = job;
1929+ process_data->status = 0;
1930+
1931+ return process_data;
1932+}
1933+
1934+/**
1935+ * job_process_data_serialise:
1936+ *
1937+ * @job: job,
1938+ * @process_data: job process data.
1939+ *
1940+ * Returns: JSON-serialised JobProcessData object, or NULL on error.
1941+ **/
1942+json_object *
1943+job_process_data_serialise (const Job *job, const JobProcessData *process_data)
1944+{
1945+ json_object *json;
1946+
1947+ nih_assert (job);
1948+
1949+ json = json_object_new_object ();
1950+ if (! json)
1951+ return NULL;
1952+
1953+ /* Job has no "in-flight" process */
1954+ if (! process_data)
1955+ return json;
1956+
1957+ /* XXX: Note that Job is not serialised; it's not necessary
1958+ * since the JobProcessData itself is serialised within its Job
1959+ * and the job pointer can be reinstated on deserialisation.
1960+ */
1961+
1962+ if (! state_set_json_enum_var (json,
1963+ process_type_enum_to_str,
1964+ "process", process_data->process))
1965+ goto error;
1966+
1967+ if (! state_set_json_string_var_from_obj (json, process_data, script))
1968+ goto error;
1969+
1970+ if (process_data->shell_fd != -1 && process_data->valid) {
1971+
1972+ /* Clear the cloexec flag to ensure the descriptors
1973+ * remains open across the re-exec.
1974+ */
1975+ if (state_modify_cloexec (process_data->shell_fd, FALSE) < 0)
1976+ goto error;
1977+
1978+ if (state_modify_cloexec (process_data->job_process_fd, FALSE) < 0)
1979+ goto error;
1980+ }
1981+
1982+ if (! state_set_json_int_var_from_obj (json, process_data, shell_fd))
1983+ goto error;
1984+
1985+ if (! state_set_json_int_var_from_obj (json, process_data, valid))
1986+ goto error;
1987+
1988+ if (! state_set_json_int_var_from_obj (json, process_data, job_process_fd))
1989+ goto error;
1990+
1991+ return json;
1992+
1993+error:
1994+ json_object_put (json);
1995+ return NULL;
1996+}
1997+
1998+/**
1999+ * job_process_data_deserialise:
2000+ *
2001+ * @parent: parent pointer,
2002+ * @job: job,
2003+ * @json: JSON-serialised JobProcessData object to deserialise.
2004+ *
2005+ * Returns: JobProcessData object, or NULL on error.
2006+ **/
2007+JobProcessData *
2008+job_process_data_deserialise (void *parent, Job *job, json_object *json)
2009+{
2010+ JobProcessData *process_data = NULL;
2011+ ProcessType process;
2012+ int job_process_fd;
2013+
2014+ nih_assert (job);
2015+ nih_assert (json);
2016+
2017+ if (! state_check_json_type (json, object))
2018+ return NULL;
2019+
2020+ if (! state_get_json_enum_var (json,
2021+ process_type_str_to_enum,
2022+ "process", process))
2023+ return NULL;
2024+
2025+ if (! state_get_json_int_var (json, "job_process_fd", job_process_fd))
2026+ return NULL;
2027+
2028+ process_data = job_process_data_new (parent, job, process, job_process_fd);
2029+ if (! process_data)
2030+ return NULL;
2031+
2032+ if (! state_get_json_string_var_to_obj (json, process_data, script))
2033+ goto error;
2034+
2035+ if (! state_get_json_int_var_to_obj (json, process_data, shell_fd))
2036+ goto error;
2037+
2038+ if (! state_get_json_int_var_to_obj (json, process_data, valid))
2039+ goto error;
2040+
2041+ if (process_data->shell_fd != -1 && process_data->valid) {
2042+ /* Reset the cloexec flag to ensure the descriptors
2043+ * are not leaked to any child processes.
2044+ */
2045+ if (state_modify_cloexec (process_data->shell_fd, TRUE) < 0)
2046+ goto error;
2047+
2048+ if (state_modify_cloexec (process_data->job_process_fd, TRUE) < 0)
2049+ goto error;
2050+ }
2051+
2052+ return process_data;
2053+
2054+error:
2055+ if (process_data)
2056+ nih_free (process_data);
2057+
2058+ return NULL;
2059+}
2060
2061=== modified file 'init/job_process.h'
2062--- init/job_process.h 2013-05-15 13:21:54 +0000
2063+++ init/job_process.h 2014-05-22 13:31:23 +0000
2064@@ -125,15 +125,38 @@
2065 } JobProcessError;
2066
2067
2068+/**
2069+ * JobProcessErrorHandler:
2070+ *
2071+ * @job: job,
2072+ * @state: required state job is attempting to achieve,
2073+ * @process: job process that failed.
2074+ *
2075+ * Function that is called when a job process @process fails to start.
2076+ **/
2077+typedef void (*JobProcessErrorHandler) (Job *job, JobState state, ProcessType process);
2078+
2079 NIH_BEGIN_EXTERN
2080
2081-int job_process_run (Job *job, ProcessType process);
2082+void job_process_start (Job *job, ProcessType process);
2083+void job_process_run_bottom (JobProcessData *handler_data);
2084+
2085+void job_process_child_reader (JobProcessData *handler_data, NihIo *io,
2086+ const char *buf, size_t len);
2087+
2088+void job_process_close_handler (JobProcessData *handler_data, NihIo *io);
2089
2090 pid_t job_process_spawn (Job *job, char * const argv[],
2091 char * const *env, int trace, int script_fd,
2092 ProcessType process)
2093 __attribute__ ((warn_unused_result));
2094
2095+pid_t job_process_spawn_with_fd (Job *job, char * const argv[],
2096+ char * const *env, int trace, int script_fd,
2097+ ProcessType process, int *job_process_fd)
2098+ __attribute__ ((warn_unused_result));
2099+
2100+
2101 void job_process_kill (Job *job, ProcessType process);
2102
2103 void job_process_handler (void *ptr, pid_t pid,
2104@@ -145,8 +168,8 @@
2105 __attribute__ ((warn_unused_result));
2106
2107 void job_process_set_kill_timer (Job *job,
2108- ProcessType process,
2109- time_t timeout);
2110+ ProcessType process,
2111+ time_t timeout);
2112
2113 void job_process_adj_kill_timer (Job *job, time_t due);
2114
2115@@ -154,6 +177,20 @@
2116
2117 void job_process_stop_all (void);
2118
2119+JobProcessData *
2120+job_process_data_new (void *parent, Job *job, ProcessType process, int job_process_fd)
2121+ __attribute__ ((warn_unused_result));
2122+
2123+json_object *
2124+job_process_data_serialise (const Job *job, const JobProcessData *handler_data)
2125+ __attribute__ ((warn_unused_result));
2126+
2127+JobProcessData *
2128+job_process_data_deserialise (void *parent, Job *job, json_object *json)
2129+ __attribute__ ((warn_unused_result));
2130+
2131+void job_process_error_handler (const char *buf, size_t len);
2132+
2133 NIH_END_EXTERN
2134
2135 #endif /* INIT_JOB_PROCESS_H */
2136
2137=== modified file 'init/log.c'
2138--- init/log.c 2014-05-07 16:34:44 +0000
2139+++ init/log.c 2014-05-22 13:31:23 +0000
2140@@ -974,7 +974,7 @@
2141 nih_assert (io_watch_fd != -1);
2142
2143 /* re-apply CLOEXEC flag to stop job fd being leaked to children */
2144- if (state_toggle_cloexec (io_watch_fd, TRUE) < 0)
2145+ if (state_modify_cloexec (io_watch_fd, TRUE) < 0)
2146 return NULL;
2147
2148 if (! state_get_json_int_var (json, "uid", uid))
2149@@ -993,7 +993,7 @@
2150 * we would never close the fd.
2151 */
2152 if (log->fd != -1)
2153- (void)state_toggle_cloexec (log->fd, TRUE);
2154+ (void)state_modify_cloexec (log->fd, TRUE);
2155
2156 log->unflushed = nih_io_buffer_new (log);
2157 if (! log->unflushed)
2158
2159=== modified file 'init/state.c'
2160--- init/state.c 2014-05-07 16:34:44 +0000
2161+++ init/state.c 2014-05-22 13:31:23 +0000
2162@@ -532,7 +532,7 @@
2163
2164
2165 /**
2166- * state_toggle_cloexec:
2167+ * state_modify_cloexec:
2168 *
2169 * @fd: file descriptor,
2170 * @set: set close-on-exec flag if TRUE, clear if FALSE.
2171@@ -542,7 +542,7 @@
2172 * Returns: 0 on success, -1 on error.
2173 **/
2174 int
2175-state_toggle_cloexec (int fd, int set)
2176+state_modify_cloexec (int fd, int set)
2177 {
2178 long flags;
2179 int ret;
2180
2181=== modified file 'init/state.h'
2182--- init/state.h 2013-06-04 16:51:55 +0000
2183+++ init/state.h 2014-05-22 13:31:23 +0000
2184@@ -1144,7 +1144,7 @@
2185 int state_from_string (const char *state)
2186 __attribute__ ((warn_unused_result));
2187
2188-int state_toggle_cloexec (int fd, int set);
2189+int state_modify_cloexec (int fd, int set);
2190
2191 json_object *
2192 state_serialise_str_array (char ** const array)
2193
2194=== modified file 'init/tests/test_event.c'
2195--- init/tests/test_event.c 2013-01-31 17:23:55 +0000
2196+++ init/tests/test_event.c 2014-05-22 13:31:23 +0000
2197@@ -300,7 +300,7 @@
2198 job = (Job *)nih_hash_lookup (class->instances, "");
2199
2200 TEST_EQ (job->goal, JOB_START);
2201- TEST_EQ (job->state, JOB_RUNNING);
2202+ TEST_EQ (job->state, JOB_SPAWNED);
2203 TEST_GT (job->pid[PROCESS_MAIN], 0);
2204
2205 waitpid (job->pid[PROCESS_MAIN], NULL, 0);
2206@@ -1739,7 +1739,7 @@
2207 job = (Job *)nih_hash_lookup (class->instances, "");
2208
2209 TEST_EQ (job->goal, JOB_START);
2210- TEST_EQ (job->state, JOB_RUNNING);
2211+ TEST_EQ (job->state, JOB_SPAWNED);
2212 TEST_GT (job->pid[PROCESS_MAIN], 0);
2213
2214 waitpid (job->pid[PROCESS_MAIN], NULL, 0);
2215
2216=== modified file 'init/tests/test_job.c'
2217--- init/tests/test_job.c 2013-11-18 16:38:32 +0000
2218+++ init/tests/test_job.c 2014-05-22 13:31:23 +0000
2219@@ -60,7 +60,15 @@
2220 #include "conf.h"
2221 #include "control.h"
2222 #include "state.h"
2223+#include "test_util_common.h"
2224
2225+void
2226+job_quit_with_state (void *data, NihMainLoopFunc *loop)
2227+{
2228+ Job *job;
2229+ job = (Job *)data;
2230+ nih_main_loop_exit (job->state);
2231+}
2232
2233 char *argv0;
2234
2235@@ -165,6 +173,12 @@
2236 TEST_EQ_P (job->log[i], NULL);
2237 }
2238
2239+ TEST_NE_P (job->process_data, NULL);
2240+ TEST_ALLOC_SIZE (job->log, sizeof (JobProcessData *) * PROCESS_LAST);
2241+ for (i = 0; i < PROCESS_LAST; i++) {
2242+ TEST_EQ_P (job->process_data[i], NULL);
2243+ }
2244+
2245 event_operator_reset (job->stop_on);
2246
2247 nih_free (job);
2248@@ -701,6 +715,10 @@
2249 char *path, *job_path = NULL, *state;
2250 int status;
2251
2252+ nih_error_init ();
2253+ nih_main_loop_init ();
2254+ event_init ();
2255+
2256 TEST_FUNCTION ("job_change_state");
2257 program_name = "test";
2258 output = tmpfile ();
2259@@ -1059,7 +1077,7 @@
2260 job->failed_process = PROCESS_INVALID;
2261 job->exit_status = 0;
2262
2263- job_change_state (job, JOB_PRE_START);
2264+ job_change_state (job, JOB_PRE_STARTING);
2265
2266 TEST_EQ (job->goal, JOB_START);
2267 TEST_EQ (job->state, JOB_PRE_START);
2268@@ -1110,6 +1128,7 @@
2269 blocked = blocked_new (job, BLOCKED_EVENT, cause);
2270 event_block (cause);
2271 nih_list_add (&job->blocking, &blocked->entry);
2272+ TEST_NE_P (nih_main_loop_add_func (job, job_quit_with_state, job), NULL);
2273 }
2274
2275 job->goal = JOB_START;
2276@@ -1125,7 +1144,8 @@
2277 job->failed_process = PROCESS_INVALID;
2278 job->exit_status = 0;
2279
2280- job_change_state (job, JOB_PRE_START);
2281+ job_change_state (job, JOB_PRE_STARTING);
2282+ while (nih_main_loop () < JOB_RUNNING) {}
2283
2284 TEST_EQ (job->goal, JOB_START);
2285 TEST_EQ (job->state, JOB_RUNNING);
2286@@ -1184,6 +1204,7 @@
2287 blocked = blocked_new (job, BLOCKED_EVENT, cause);
2288 event_block (cause);
2289 nih_list_add (&job->blocking, &blocked->entry);
2290+ TEST_NE_P (nih_main_loop_add_func (job, job_quit_with_state, job), NULL);
2291 }
2292
2293 job->goal = JOB_START;
2294@@ -1200,12 +1221,14 @@
2295 job->exit_status = 0;
2296
2297 TEST_DIVERT_STDERR (output) {
2298- job_change_state (job, JOB_PRE_START);
2299+ job_change_state (job, JOB_PRE_STARTING);
2300+ while (nih_main_loop() < JOB_STOPPING) {}
2301 }
2302 rewind (output);
2303
2304 TEST_EQ (job->goal, JOB_STOP);
2305 TEST_EQ (job->state, JOB_STOPPING);
2306+ TEST_FALSE (job->process_data[PROCESS_PRE_START]->valid);
2307 TEST_EQ (job->pid[PROCESS_PRE_START], 0);
2308
2309 TEST_EQ (cause->blockers, 0);
2310@@ -1269,6 +1292,7 @@
2311 blocked = blocked_new (job, BLOCKED_EVENT, cause);
2312 event_block (cause);
2313 nih_list_add (&job->blocking, &blocked->entry);
2314+ TEST_NE_P (nih_main_loop_add_func (job, job_quit_with_state, job), NULL);
2315 }
2316
2317 job->goal = JOB_START;
2318@@ -1284,7 +1308,8 @@
2319 job->failed_process = PROCESS_INVALID;
2320 job->exit_status = 0;
2321
2322- job_change_state (job, JOB_SPAWNED);
2323+ job_change_state (job, JOB_SPAWNING);
2324+ while (nih_main_loop() < JOB_RUNNING) {}
2325
2326 TEST_EQ (job->goal, JOB_START);
2327 TEST_EQ (job->state, JOB_RUNNING);
2328@@ -1337,6 +1362,7 @@
2329 blocked = blocked_new (job, BLOCKED_EVENT, cause);
2330 event_block (cause);
2331 nih_list_add (&job->blocking, &blocked->entry);
2332+ TEST_NE_P (nih_main_loop_add_func (job, job_quit_with_state, job), NULL);
2333 }
2334
2335 job->goal = JOB_START;
2336@@ -1352,7 +1378,8 @@
2337 job->failed_process = PROCESS_INVALID;
2338 job->exit_status = 0;
2339
2340- job_change_state (job, JOB_SPAWNED);
2341+ job_change_state (job, JOB_SPAWNING);
2342+ while (nih_main_loop() < JOB_RUNNING) {}
2343
2344 TEST_EQ (job->goal, JOB_START);
2345 TEST_EQ (job->state, JOB_RUNNING);
2346@@ -1417,6 +1444,7 @@
2347 blocked = blocked_new (job, BLOCKED_EVENT, cause);
2348 event_block (cause);
2349 nih_list_add (&job->blocking, &blocked->entry);
2350+ TEST_NE_P (nih_main_loop_add_func (job, job_quit_with_state, job), NULL);
2351 }
2352
2353 job->goal = JOB_START;
2354@@ -1432,7 +1460,8 @@
2355 job->failed_process = PROCESS_INVALID;
2356 job->exit_status = 0;
2357
2358- job_change_state (job, JOB_SPAWNED);
2359+ job_change_state (job, JOB_SPAWNING);
2360+ while (nih_main_loop() < JOB_RUNNING) {}
2361
2362 TEST_EQ (job->goal, JOB_START);
2363 TEST_EQ (job->state, JOB_RUNNING);
2364@@ -1507,7 +1536,7 @@
2365 job->failed_process = PROCESS_INVALID;
2366 job->exit_status = 0;
2367
2368- job_change_state (job, JOB_SPAWNED);
2369+ job_change_state (job, JOB_SPAWNING);
2370
2371 TEST_EQ (job->goal, JOB_START);
2372 TEST_EQ (job->state, JOB_RUNNING);
2373@@ -1556,6 +1585,7 @@
2374 blocked = blocked_new (job, BLOCKED_EVENT, cause);
2375 event_block (cause);
2376 nih_list_add (&job->blocking, &blocked->entry);
2377+ TEST_NE_P (nih_main_loop_add_func (job, job_quit_with_state, job), NULL);
2378 }
2379
2380 job->goal = JOB_START;
2381@@ -1572,12 +1602,14 @@
2382 job->exit_status = 0;
2383
2384 TEST_DIVERT_STDERR (output) {
2385- job_change_state (job, JOB_SPAWNED);
2386+ job_change_state (job, JOB_SPAWNING);
2387+ while (nih_main_loop() < JOB_STOPPING) {}
2388 }
2389 rewind (output);
2390
2391 TEST_EQ (job->goal, JOB_STOP);
2392 TEST_EQ (job->state, JOB_STOPPING);
2393+ TEST_FALSE (job->process_data[PROCESS_MAIN]->valid);
2394 TEST_EQ (job->pid[PROCESS_MAIN], 0);
2395
2396 TEST_EQ (cause->blockers, 0);
2397@@ -1658,7 +1690,7 @@
2398 job->failed_process = PROCESS_INVALID;
2399 job->exit_status = 0;
2400
2401- job_change_state (job, JOB_SPAWNED);
2402+ job_change_state (job, JOB_SPAWNING);
2403
2404 TEST_EQ (job->goal, JOB_START);
2405 TEST_EQ (job->state, JOB_SPAWNED);
2406@@ -1727,7 +1759,7 @@
2407 job->failed_process = PROCESS_INVALID;
2408 job->exit_status = 0;
2409
2410- job_change_state (job, JOB_POST_START);
2411+ job_change_state (job, JOB_POST_STARTING);
2412
2413 TEST_EQ (job->goal, JOB_START);
2414 TEST_EQ (job->state, JOB_POST_START);
2415@@ -1794,7 +1826,7 @@
2416 job->failed_process = PROCESS_INVALID;
2417 job->exit_status = 0;
2418
2419- job_change_state (job, JOB_POST_START);
2420+ job_change_state (job, JOB_POST_STARTING);
2421
2422 TEST_EQ (job->goal, JOB_START);
2423 TEST_EQ (job->state, JOB_RUNNING);
2424@@ -1842,6 +1874,7 @@
2425 blocked = blocked_new (job, BLOCKED_EVENT, cause);
2426 event_block (cause);
2427 nih_list_add (&job->blocking, &blocked->entry);
2428+ TEST_NE_P (nih_main_loop_add_func (job, job_quit_with_state, job), NULL);
2429 }
2430
2431 job->goal = JOB_START;
2432@@ -1858,7 +1891,8 @@
2433 job->exit_status = 0;
2434
2435 TEST_DIVERT_STDERR (output) {
2436- job_change_state (job, JOB_POST_START);
2437+ job_change_state (job, JOB_POST_STARTING);
2438+ while (nih_main_loop () < JOB_RUNNING) { }
2439 }
2440 rewind (output);
2441
2442@@ -2058,7 +2092,7 @@
2443 job->failed_process = PROCESS_INVALID;
2444 job->exit_status = 0;
2445
2446- job_change_state (job, JOB_PRE_STOP);
2447+ job_change_state (job, JOB_PRE_STOPPING);
2448
2449 TEST_EQ (job->goal, JOB_STOP);
2450 TEST_EQ (job->state, JOB_PRE_STOP);
2451@@ -2125,7 +2159,7 @@
2452 job->failed_process = PROCESS_INVALID;
2453 job->exit_status = 0;
2454
2455- job_change_state (job, JOB_PRE_STOP);
2456+ job_change_state (job, JOB_PRE_STOPPING);
2457
2458 TEST_EQ (job->goal, JOB_STOP);
2459 TEST_EQ (job->state, JOB_STOPPING);
2460@@ -2198,7 +2232,7 @@
2461 job->failed_process = PROCESS_INVALID;
2462 job->exit_status = 0;
2463
2464- job_change_state (job, JOB_PRE_STOP);
2465+ job_change_state (job, JOB_PRE_STOPPING);
2466
2467 TEST_EQ (job->goal, JOB_STOP);
2468 TEST_EQ (job->state, JOB_STOPPING);
2469@@ -2283,7 +2317,7 @@
2470 job->failed_process = PROCESS_INVALID;
2471 job->exit_status = 0;
2472
2473- job_change_state (job, JOB_PRE_STOP);
2474+ job_change_state (job, JOB_PRE_STOPPING);
2475
2476 TEST_EQ (job->goal, JOB_STOP);
2477 TEST_EQ (job->state, JOB_STOPPING);
2478@@ -2348,6 +2382,7 @@
2479 blocked = blocked_new (job, BLOCKED_EVENT, cause);
2480 event_block (cause);
2481 nih_list_add (&job->blocking, &blocked->entry);
2482+ TEST_NE_P (nih_main_loop_add_func (job, job_quit_with_state, job), NULL);
2483 }
2484
2485 job->goal = JOB_STOP;
2486@@ -2364,7 +2399,8 @@
2487 job->exit_status = 0;
2488
2489 TEST_DIVERT_STDERR (output) {
2490- job_change_state (job, JOB_PRE_STOP);
2491+ job_change_state (job, JOB_PRE_STOPPING);
2492+ while (nih_main_loop () < JOB_STOPPING) {}
2493 }
2494 rewind (output);
2495
2496@@ -3100,7 +3136,7 @@
2497 job->failed_process = PROCESS_INVALID;
2498 job->exit_status = 0;
2499
2500- job_change_state (job, JOB_POST_STOP);
2501+ job_change_state (job, JOB_POST_STOPPING);
2502
2503 TEST_EQ (job->goal, JOB_STOP);
2504 TEST_EQ (job->state, JOB_POST_STOP);
2505@@ -3168,7 +3204,7 @@
2506
2507 TEST_FREE_TAG (job);
2508
2509- job_change_state (job, JOB_POST_STOP);
2510+ job_change_state (job, JOB_POST_STOPPING);
2511
2512 TEST_FREE (job);
2513
2514@@ -3228,7 +3264,8 @@
2515 TEST_FREE_TAG (job);
2516
2517 TEST_DIVERT_STDERR (output) {
2518- job_change_state (job, JOB_POST_STOP);
2519+ job_change_state (job, JOB_POST_STOPPING);
2520+ TEST_WATCH_LOOP ();
2521 }
2522 rewind (output);
2523
2524@@ -4000,22 +4037,31 @@
2525
2526
2527 /* Check that the next state if we're starting a starting job is
2528+ * sec-spawning.
2529+ */
2530+ TEST_FEATURE ("with starting job and a goal of start");
2531+ job->goal = JOB_START;
2532+ job->state = JOB_STARTING;
2533+
2534+ TEST_EQ (job_next_state (job), JOB_SECURITY_SPAWNING);
2535+
2536+ /* Check that the next state if we're starting a sec-spawning job is
2537 * security.
2538 */
2539 TEST_FEATURE ("with starting job and a goal of start");
2540 job->goal = JOB_START;
2541- job->state = JOB_STARTING;
2542+ job->state = JOB_SECURITY_SPAWNING;
2543
2544 TEST_EQ (job_next_state (job), JOB_SECURITY);
2545
2546 /* Check that the next state if we're starting a security job is
2547- * pre-start.
2548+ * pre-starting.
2549 */
2550 TEST_FEATURE ("with security job and a goal of start");
2551 job->goal = JOB_START;
2552 job->state = JOB_SECURITY;
2553
2554- TEST_EQ (job_next_state (job), JOB_PRE_START);
2555+ TEST_EQ (job_next_state (job), JOB_PRE_STARTING);
2556
2557 /* Check that the next state if we're stopping an security job is
2558 * stopping.
2559@@ -4026,6 +4072,25 @@
2560
2561 TEST_EQ (job_next_state (job), JOB_STOPPING);
2562
2563+ /* Check that the next state if we're starting a pre-starting job is
2564+ * pre-start.
2565+ */
2566+ TEST_FEATURE ("with pre-stating job and a goal of start");
2567+ job->goal = JOB_START;
2568+ job->state = JOB_PRE_STARTING;
2569+
2570+ TEST_EQ (job_next_state (job), JOB_PRE_START);
2571+
2572+ /* Check that the next state if we're stopping a pre-starting job is
2573+ * stopping.
2574+ */
2575+ TEST_FEATURE ("with pre-starting job and a goal of stop");
2576+ job->goal = JOB_STOP;
2577+ job->state = JOB_PRE_STARTING;
2578+
2579+ TEST_EQ (job_next_state (job), JOB_STOPPING);
2580+
2581+
2582 /* Check that the next state if we're stopping a pre-start job is
2583 * stopping.
2584 */
2585@@ -4043,6 +4108,15 @@
2586 job->goal = JOB_START;
2587 job->state = JOB_PRE_START;
2588
2589+ TEST_EQ (job_next_state (job), JOB_SPAWNING);
2590+
2591+ /* Check that the next state if we're starting a spawning job is
2592+ * spawned.
2593+ */
2594+ TEST_FEATURE ("with pre-start job and a goal of start");
2595+ job->goal = JOB_START;
2596+ job->state = JOB_SPAWNING;
2597+
2598 TEST_EQ (job_next_state (job), JOB_SPAWNED);
2599
2600
2601@@ -4057,11 +4131,21 @@
2602
2603
2604 /* Check that the next state if we're starting a spawned job is
2605+ * post-starting.
2606+ */
2607+ TEST_FEATURE ("with spawned job and a goal of start");
2608+ job->goal = JOB_START;
2609+ job->state = JOB_SPAWNED;
2610+
2611+ TEST_EQ (job_next_state (job), JOB_POST_STARTING);
2612+
2613+
2614+ /* Check that the next state if we're starting a post-staring job is
2615 * post-start.
2616 */
2617- TEST_FEATURE ("with spawned job and a goal of start");
2618+ TEST_FEATURE ("with post-starting job and a goal of start");
2619 job->goal = JOB_START;
2620- job->state = JOB_SPAWNED;
2621+ job->state = JOB_POST_STARTING;
2622
2623 TEST_EQ (job_next_state (job), JOB_POST_START);
2624
2625@@ -4106,6 +4190,17 @@
2626 job->state = JOB_RUNNING;
2627 job->pid[PROCESS_MAIN] = 1;
2628
2629+ TEST_EQ (job_next_state (job), JOB_PRE_STOPPING);
2630+
2631+ /* Check that the next state if we're stopping a job with pre-stop is
2632+ * pre-stop. This is the "normal" stop process, as called from the
2633+ * goal change event.
2634+ */
2635+ TEST_FEATURE ("with pre-stopping job and a goal of stop");
2636+ job->goal = JOB_STOP;
2637+ job->state = JOB_PRE_STOPPING;
2638+ job->pid[PROCESS_MAIN] = 1;
2639+
2640 TEST_EQ (job_next_state (job), JOB_PRE_STOP);
2641
2642
2643@@ -4193,6 +4288,16 @@
2644 job->goal = JOB_START;
2645 job->state = JOB_KILLED;
2646
2647+ TEST_EQ (job_next_state (job), JOB_POST_STOPPING);
2648+
2649+
2650+ /* Check that the next state if we're starting a post-stopping
2651+ * job is post-stop.
2652+ */
2653+ TEST_FEATURE ("with post-stopping job and a goal of start");
2654+ job->goal = JOB_START;
2655+ job->state = JOB_POST_STOPPING;
2656+
2657 TEST_EQ (job_next_state (job), JOB_POST_STOP);
2658
2659
2660@@ -4203,6 +4308,16 @@
2661 job->goal = JOB_STOP;
2662 job->state = JOB_KILLED;
2663
2664+ TEST_EQ (job_next_state (job), JOB_POST_STOPPING);
2665+
2666+
2667+ /* Check that the next state if we're stopping a post-stopping
2668+ * job is post-stop.
2669+ */
2670+ TEST_FEATURE ("with post-stopping job and a goal of stop");
2671+ job->goal = JOB_STOP;
2672+ job->state = JOB_POST_STOPPING;
2673+
2674 TEST_EQ (job_next_state (job), JOB_POST_STOP);
2675
2676
2677
2678=== modified file 'init/tests/test_job_process.c'
2679--- init/tests/test_job_process.c 2013-11-11 10:13:08 +0000
2680+++ init/tests/test_job_process.c 2014-05-22 13:31:23 +0000
2681@@ -1,3 +1,6 @@
2682+/*
2683+ * FIXME: test_job_process has been left behind
2684+ */
2685 /* upstart
2686 *
2687 * test_job_process.c - test suite for init/job_process.c
2688@@ -147,33 +150,6 @@
2689 static int get_available_pty_count (void) __attribute__((unused));
2690 static void close_all_files (void);
2691
2692-/**
2693- * fd_valid:
2694- * @fd: file descriptor.
2695- *
2696- * Return 1 if @fd is valid, else 0.
2697- **/
2698-static int
2699-fd_valid (int fd)
2700-{
2701- int flags = 0;
2702-
2703- if (fd < 0)
2704- return 0;
2705-
2706- errno = 0;
2707- flags = fcntl (fd, F_GETFL);
2708-
2709- if (flags < 0)
2710- return 0;
2711-
2712- /* redundant really */
2713- if (errno == EBADF)
2714- return 0;
2715-
2716- return 1;
2717-}
2718-
2719 static void
2720 child (enum child_tests test,
2721 const char *filename)
2722@@ -409,7 +385,7 @@
2723 * (Such tests are handled in the bundled test_user_sessions.sh script).
2724 */
2725 void
2726-test_run (void)
2727+test_start (void)
2728 {
2729 char dirname[PATH_MAX];
2730 JobClass *class = NULL;
2731@@ -418,7 +394,7 @@
2732 struct stat statbuf;
2733 char filename[PATH_MAX], buf[80];
2734 char function[PATH_MAX];
2735- int ret = -1, status, first;
2736+ int status;
2737 siginfo_t info;
2738 char filebuf[1024];
2739 struct passwd *pwd;
2740@@ -433,7 +409,7 @@
2741 log_unflushed_init ();
2742 job_class_init ();
2743
2744- TEST_FUNCTION ("job_process_run");
2745+ TEST_FUNCTION ("job_process_start");
2746
2747 TEST_FILENAME (filename);
2748 program_name = "test";
2749@@ -467,8 +443,7 @@
2750 job->state = JOB_SPAWNED;
2751 }
2752
2753- ret = job_process_run (job, PROCESS_MAIN);
2754- TEST_EQ (ret, 0);
2755+ job_process_start (job, PROCESS_MAIN);
2756
2757 TEST_NE (job->pid[PROCESS_MAIN], 0);
2758
2759@@ -502,8 +477,7 @@
2760 job->state = JOB_SPAWNED;
2761 }
2762
2763- ret = job_process_run (job, PROCESS_MAIN);
2764- TEST_EQ (ret, 0);
2765+ job_process_start (job, PROCESS_MAIN);
2766
2767 TEST_NE (job->pid[PROCESS_MAIN], 0);
2768
2769@@ -544,8 +518,7 @@
2770 job->state = JOB_SPAWNED;
2771 }
2772
2773- ret = job_process_run (job, PROCESS_MAIN);
2774- TEST_EQ (ret, 0);
2775+ job_process_start (job, PROCESS_MAIN);
2776
2777 TEST_NE (job->pid[PROCESS_MAIN], 0);
2778
2779@@ -584,8 +557,7 @@
2780 job->state = JOB_SPAWNED;
2781 }
2782
2783- ret = job_process_run (job, PROCESS_MAIN);
2784- TEST_EQ (ret, 0);
2785+ job_process_start (job, PROCESS_MAIN);
2786
2787 TEST_NE (job->pid[PROCESS_MAIN], 0);
2788
2789@@ -625,8 +597,7 @@
2790 job->state = JOB_SPAWNED;
2791 }
2792
2793- ret = job_process_run (job, PROCESS_MAIN);
2794- TEST_EQ (ret, 0);
2795+ job_process_start (job, PROCESS_MAIN);
2796
2797 TEST_NE (job->pid[PROCESS_MAIN], 0);
2798
2799@@ -672,8 +643,7 @@
2800 "CRACKLE=FIZZ"));
2801 }
2802
2803- ret = job_process_run (job, PROCESS_MAIN);
2804- TEST_EQ (ret, 0);
2805+ job_process_start (job, PROCESS_MAIN);
2806
2807 TEST_NE (job->pid[PROCESS_MAIN], 0);
2808
2809@@ -728,8 +698,7 @@
2810 "CRACKLE=FIZZ"));
2811 }
2812
2813- ret = job_process_run (job, PROCESS_MAIN);
2814- TEST_EQ (ret, 0);
2815+ job_process_start (job, PROCESS_MAIN);
2816
2817 TEST_NE (job->pid[PROCESS_MAIN], 0);
2818
2819@@ -785,8 +754,7 @@
2820 "CRACKLE=FIZZ"));
2821 }
2822
2823- ret = job_process_run (job, PROCESS_PRE_STOP);
2824- TEST_EQ (ret, 0);
2825+ job_process_start (job, PROCESS_PRE_STOP);
2826
2827 TEST_NE (job->pid[PROCESS_PRE_STOP], 0);
2828
2829@@ -843,8 +811,7 @@
2830 "CRACKLE=FIZZ"));
2831 }
2832
2833- ret = job_process_run (job, PROCESS_POST_STOP);
2834- TEST_EQ (ret, 0);
2835+ job_process_start (job, PROCESS_POST_STOP);
2836
2837 TEST_NE (job->pid[PROCESS_POST_STOP], 0);
2838
2839@@ -894,36 +861,11 @@
2840 job->state = JOB_SPAWNED;
2841 }
2842
2843- ret = job_process_run (job, PROCESS_MAIN);
2844- TEST_EQ (ret, 0);
2845+ job_process_start (job, PROCESS_MAIN);
2846
2847 TEST_NE (job->pid[PROCESS_MAIN], 0);
2848
2849- /* Loop until we've fed all of the data. */
2850- first = TRUE;
2851- for (;;) {
2852- fd_set readfds, writefds, exceptfds;
2853- int nfds;
2854-
2855- nfds = 0;
2856- FD_ZERO (&readfds);
2857- FD_ZERO (&writefds);
2858- FD_ZERO (&exceptfds);
2859-
2860- nih_io_select_fds (&nfds, &readfds,
2861- &writefds, &exceptfds);
2862- if (! nfds) {
2863- if (first)
2864- TEST_FAILED ("expected to have "
2865- "data to feed.");
2866- break;
2867- }
2868- first = FALSE;
2869-
2870- select (nfds, &readfds, &writefds, &exceptfds, NULL);
2871-
2872- nih_io_handle_fds (&readfds, &writefds, &exceptfds);
2873- }
2874+ TEST_WATCH_LOOP ();
2875
2876 waitpid (job->pid[PROCESS_MAIN], &status, 0);
2877 TEST_TRUE (WIFEXITED (status));
2878@@ -962,8 +904,7 @@
2879 job->trace_state = TRACE_NORMAL;
2880 }
2881
2882- ret = job_process_run (job, PROCESS_MAIN);
2883- TEST_EQ (ret, 0);
2884+ job_process_start (job, PROCESS_MAIN);
2885
2886 TEST_EQ (job->trace_forks, 0);
2887 TEST_EQ (job->trace_state, TRACE_NONE);
2888@@ -1002,8 +943,7 @@
2889 job->trace_state = TRACE_NORMAL;
2890 }
2891
2892- ret = job_process_run (job, PROCESS_PRE_START);
2893- TEST_EQ (ret, 0);
2894+ job_process_start (job, PROCESS_PRE_START);
2895
2896 TEST_EQ (job->trace_forks, 0);
2897 TEST_EQ (job->trace_state, TRACE_NONE);
2898@@ -1044,8 +984,7 @@
2899 job->trace_state = TRACE_NORMAL;
2900 }
2901
2902- ret = job_process_run (job, PROCESS_MAIN);
2903- TEST_EQ (ret, 0);
2904+ job_process_start (job, PROCESS_MAIN);
2905
2906 TEST_EQ (job->trace_forks, 0);
2907 TEST_EQ (job->trace_state, TRACE_NEW);
2908@@ -1095,8 +1034,7 @@
2909 job->trace_state = TRACE_NORMAL;
2910 }
2911
2912- ret = job_process_run (job, PROCESS_MAIN);
2913- TEST_EQ (ret, 0);
2914+ job_process_start (job, PROCESS_MAIN);
2915
2916 TEST_EQ (job->trace_forks, 0);
2917 TEST_EQ (job->trace_state, TRACE_NEW);
2918@@ -1122,7 +1060,7 @@
2919 }
2920
2921 /* Check that if we try and run a command that doesn't exist,
2922- * job_process_run() raises a ProcessError and the command doesn't
2923+ * job_process_start() raises a ProcessError and the command doesn't
2924 * have any stored process id for it.
2925 */
2926 TEST_FEATURE ("with no such file");
2927@@ -1144,11 +1082,12 @@
2928 }
2929
2930 TEST_DIVERT_STDERR (output) {
2931- ret = job_process_run (job, PROCESS_MAIN);
2932+ job_process_start (job, PROCESS_MAIN);
2933+ TEST_WATCH_LOOP ();
2934+ event_poll ();
2935 }
2936 rewind (output);
2937- TEST_LT (ret, 0);
2938-
2939+
2940 TEST_EQ (job->pid[PROCESS_MAIN], 0);
2941
2942 TEST_FILE_EQ (output, ("test: Failed to spawn test (foo) main "
2943@@ -1195,8 +1134,7 @@
2944 job->goal = JOB_START;
2945 job->state = JOB_SPAWNED;
2946
2947- ret = job_process_run (job, PROCESS_MAIN);
2948- TEST_EQ (ret, 0);
2949+ job_process_start (job, PROCESS_MAIN);
2950
2951 TEST_NE (job->pid[PROCESS_MAIN], 0);
2952
2953@@ -1263,8 +1201,7 @@
2954 job->goal = JOB_START;
2955 job->state = JOB_SPAWNED;
2956
2957- ret = job_process_run (job, PROCESS_MAIN);
2958- TEST_EQ (ret, 0);
2959+ job_process_start (job, PROCESS_MAIN);
2960
2961 TEST_NE (job->pid[PROCESS_MAIN], 0);
2962
2963@@ -1331,8 +1268,7 @@
2964 job->goal = JOB_START;
2965 job->state = JOB_SPAWNED;
2966
2967- ret = job_process_run (job, PROCESS_MAIN);
2968- TEST_EQ (ret, 0);
2969+ job_process_start (job, PROCESS_MAIN);
2970
2971 TEST_NE (job->pid[PROCESS_MAIN], 0);
2972
2973@@ -1399,8 +1335,7 @@
2974 job->goal = JOB_START;
2975 job->state = JOB_SPAWNED;
2976
2977- ret = job_process_run (job, PROCESS_MAIN);
2978- TEST_EQ (ret, 0);
2979+ job_process_start (job, PROCESS_MAIN);
2980
2981 TEST_NE (job->pid[PROCESS_MAIN], 0);
2982
2983@@ -1462,8 +1397,7 @@
2984 job->goal = JOB_START;
2985 job->state = JOB_SPAWNED;
2986
2987- ret = job_process_run (job, PROCESS_MAIN);
2988- TEST_EQ (ret, 0);
2989+ job_process_start (job, PROCESS_MAIN);
2990
2991 TEST_NE (job->pid[PROCESS_MAIN], 0);
2992
2993@@ -1499,8 +1433,7 @@
2994 job->goal = JOB_START;
2995 job->state = JOB_SPAWNED;
2996
2997- ret = job_process_run (job, PROCESS_MAIN);
2998- TEST_EQ (ret, 0);
2999+ job_process_start (job, PROCESS_MAIN);
3000
3001 TEST_NE (job->pid[PROCESS_MAIN], 0);
3002
3003@@ -1536,8 +1469,7 @@
3004 job->goal = JOB_START;
3005 job->state = JOB_SPAWNED;
3006
3007- ret = job_process_run (job, PROCESS_MAIN);
3008- TEST_EQ (ret, 0);
3009+ job_process_start (job, PROCESS_MAIN);
3010
3011 TEST_NE (job->pid[PROCESS_MAIN], 0);
3012
3013@@ -1583,11 +1515,13 @@
3014 job->goal = JOB_START;
3015 job->state = JOB_SPAWNED;
3016
3017- ret = job_process_run (job, PROCESS_MAIN);
3018- TEST_EQ (ret, 0);
3019+ job_process_start (job, PROCESS_MAIN);
3020
3021 TEST_NE (job->pid[PROCESS_MAIN], 0);
3022
3023+ /* XXX: call 0: async process setup */
3024+ TEST_WATCH_UPDATE ();
3025+
3026 /* XXX: call 1: wait for script write to child shell */
3027 TEST_WATCH_UPDATE ();
3028
3029@@ -1613,10 +1547,10 @@
3030
3031 /* Note we can't use TEST_ALLOC_FAIL() for this test since on
3032 * the ENOMEM loop all we could do is discard the error and
3033- * continue since job_process_run() calls job_process_spawn()
3034+ * continue since job_process_start() calls job_process_spawn()
3035 * repeatedly until it works, but the alloc fails in log_new()
3036 * invoked by job_process_spawn() such that when we've left
3037- * job_process_run(), it's too late.
3038+ * job_process_start(), it's too late.
3039 *
3040 * However, we test this scenario in test_spawn() so all is not
3041 * lost.
3042@@ -1637,8 +1571,7 @@
3043 job->goal = JOB_START;
3044 job->state = JOB_SPAWNED;
3045
3046- ret = job_process_run (job, PROCESS_MAIN);
3047- TEST_EQ (ret, 0);
3048+ job_process_start (job, PROCESS_MAIN);
3049
3050 TEST_NE (job->pid[PROCESS_MAIN], 0);
3051
3052@@ -1695,11 +1628,13 @@
3053 job->goal = JOB_START;
3054 job->state = JOB_SPAWNED;
3055
3056- ret = job_process_run (job, PROCESS_MAIN);
3057- TEST_EQ (ret, 0);
3058+ job_process_start (job, PROCESS_MAIN);
3059
3060 TEST_NE (job->pid[PROCESS_MAIN], 0);
3061
3062+ /* wait for process to setup */
3063+ TEST_WATCH_UPDATE ();
3064+
3065 /* wait for read from pty allowing logger to write to log file */
3066 TEST_WATCH_UPDATE ();
3067
3068@@ -1779,11 +1714,13 @@
3069 job->goal = JOB_START;
3070 job->state = JOB_SPAWNED;
3071
3072- ret = job_process_run (job, PROCESS_MAIN);
3073- TEST_EQ (ret, 0);
3074+ job_process_start (job, PROCESS_MAIN);
3075
3076 TEST_NE (job->pid[PROCESS_MAIN], 0);
3077
3078+ /* wait for process to setup */
3079+ TEST_WATCH_UPDATE ();
3080+
3081 /* wait for read from pty allowing logger to write to log file */
3082 TEST_WATCH_UPDATE ();
3083
3084@@ -1861,10 +1798,10 @@
3085
3086 /* Note we can't use TEST_ALLOC_FAIL() for this test since on
3087 * the ENOMEM loop all we could do is discard the error and
3088- * continue since job_process_run() calls job_process_spawn()
3089+ * continue since job_process_start() calls job_process_spawn()
3090 * repeatedly until it works, but the alloc fails in log_new()
3091 * invoked by job_process_spawn() such that when we've left
3092- * job_process_run(), it's too late.
3093+ * job_process_start(), it's too late.
3094 *
3095 * However, we test this scenario in test_spawn() so all is not
3096 * lost.
3097@@ -1885,11 +1822,13 @@
3098 job->goal = JOB_START;
3099 job->state = JOB_SPAWNED;
3100
3101- ret = job_process_run (job, PROCESS_MAIN);
3102- TEST_EQ (ret, 0);
3103+ job_process_start (job, PROCESS_MAIN);
3104
3105 TEST_NE (job->pid[PROCESS_MAIN], 0);
3106
3107+ /* wait for process to setup */
3108+ TEST_WATCH_UPDATE ();
3109+
3110 /* XXX: call 1: wait for script write to child shell */
3111 TEST_WATCH_UPDATE ();
3112
3113@@ -1948,11 +1887,13 @@
3114 job->goal = JOB_START;
3115 job->state = JOB_SPAWNED;
3116
3117- ret = job_process_run (job, PROCESS_MAIN);
3118- TEST_EQ (ret, 0);
3119+ job_process_start (job, PROCESS_MAIN);
3120
3121 TEST_NE (job->pid[PROCESS_MAIN], 0);
3122
3123+ /* wait for process to setup */
3124+ TEST_WATCH_UPDATE ();
3125+
3126 /* wait for read from pty allowing logger to write to log file */
3127 TEST_WATCH_UPDATE ();
3128
3129@@ -2017,11 +1958,13 @@
3130 job->goal = JOB_START;
3131 job->state = JOB_SPAWNED;
3132
3133- ret = job_process_run (job, PROCESS_MAIN);
3134- TEST_EQ (ret, 0);
3135+ job_process_start (job, PROCESS_MAIN);
3136
3137 TEST_NE (job->pid[PROCESS_MAIN], 0);
3138
3139+ /* wait for process to setup */
3140+ TEST_WATCH_UPDATE ();
3141+
3142 /* XXX: call 1: wait for script write to child shell */
3143 TEST_WATCH_UPDATE ();
3144
3145@@ -2064,10 +2007,10 @@
3146
3147 /* Note we can't use TEST_ALLOC_FAIL() for this test since on
3148 * the ENOMEM loop all we could do is discard the error and
3149- * continue since job_process_run() calls job_process_spawn()
3150+ * continue since job_process_start() calls job_process_spawn()
3151 * repeatedly until it works, but the alloc fails in log_new()
3152 * invoked by job_process_spawn() such that when we've left
3153- * job_process_run(), it's too late.
3154+ * job_process_start(), it's too late.
3155 *
3156 * However, we test this scenario in test_spawn() so all is not
3157 * lost.
3158@@ -2088,8 +2031,7 @@
3159 job->goal = JOB_START;
3160 job->state = JOB_SPAWNED;
3161
3162- ret = job_process_run (job, PROCESS_MAIN);
3163- TEST_EQ (ret, 0);
3164+ job_process_start (job, PROCESS_MAIN);
3165
3166 TEST_NE (job->pid[PROCESS_MAIN], 0);
3167
3168@@ -2135,7 +2077,7 @@
3169 * XXX: TEST_WATCH_UPDATE() *TWICE* to ensure select(2) is
3170 * XXX: called twice.
3171 *
3172- * This is required since job_process_run() uses an NihIo object
3173+ * This is required since job_process_start() uses an NihIo object
3174 * to squirt the script to the shell sub-process and this
3175 * triggers select to return when the data is written to the shell.
3176 * However, we don't care about that directly - we care more about
3177@@ -2144,7 +2086,7 @@
3178 * written.
3179 *
3180 * Note that the 2nd call to TEST_WATCH_UPDATE would not be
3181- * required should job_process_run() simple invoke write(2) to
3182+ * required should job_process_start() simple invoke write(2) to
3183 * send the data.
3184 */
3185
3186@@ -2165,11 +2107,13 @@
3187 job->goal = JOB_START;
3188 job->state = JOB_SPAWNED;
3189
3190- ret = job_process_run (job, PROCESS_MAIN);
3191- TEST_EQ (ret, 0);
3192+ job_process_start (job, PROCESS_MAIN);
3193
3194 TEST_NE (job->pid[PROCESS_MAIN], 0);
3195
3196+ /* wait for process to setup */
3197+ TEST_WATCH_UPDATE ();
3198+
3199 /* XXX: call 1: wait for script write to child shell */
3200 TEST_WATCH_UPDATE ();
3201
3202@@ -2227,8 +2171,7 @@
3203 job->goal = JOB_START;
3204 job->state = JOB_SPAWNED;
3205
3206- ret = job_process_run (job, PROCESS_MAIN);
3207- TEST_EQ (ret, 0);
3208+ job_process_start (job, PROCESS_MAIN);
3209
3210 TEST_NE (job->pid[PROCESS_MAIN], 0);
3211
3212@@ -2287,8 +2230,7 @@
3213 job->goal = JOB_START;
3214 job->state = JOB_SPAWNED;
3215
3216- ret = job_process_run (job, PROCESS_MAIN);
3217- TEST_EQ (ret, 0);
3218+ job_process_start (job, PROCESS_MAIN);
3219
3220 TEST_NE (job->pid[PROCESS_MAIN], 0);
3221
3222@@ -2352,8 +2294,7 @@
3223 job->goal = JOB_START;
3224 job->state = JOB_SPAWNED;
3225
3226- ret = job_process_run (job, PROCESS_MAIN);
3227- TEST_EQ (ret, 0);
3228+ job_process_start (job, PROCESS_MAIN);
3229
3230 TEST_NE (job->pid[PROCESS_MAIN], 0);
3231
3232@@ -2414,12 +2355,12 @@
3233 job->goal = JOB_START;
3234 job->state = JOB_SPAWNED;
3235
3236- ret = job_process_run (job, PROCESS_MAIN);
3237- TEST_EQ (ret, 0);
3238+ job_process_start (job, PROCESS_MAIN);
3239
3240 TEST_NE (job->pid[PROCESS_MAIN], 0);
3241
3242 TEST_WATCH_UPDATE ();
3243+ TEST_WATCH_UPDATE ();
3244 waitpid (job->pid[PROCESS_MAIN], &status, 0);
3245 TEST_TRUE (WIFEXITED (status));
3246 TEST_EQ (WEXITSTATUS (status), 0);
3247@@ -2474,8 +2415,7 @@
3248 job->goal = JOB_START;
3249 job->state = JOB_SPAWNED;
3250
3251- ret = job_process_run (job, PROCESS_MAIN);
3252- TEST_EQ (ret, 0);
3253+ job_process_start (job, PROCESS_MAIN);
3254
3255 TEST_NE (job->pid[PROCESS_MAIN], 0);
3256
3257@@ -2537,8 +2477,7 @@
3258 job->goal = JOB_START;
3259 job->state = JOB_SPAWNED;
3260
3261- ret = job_process_run (job, PROCESS_MAIN);
3262- TEST_EQ (ret, 0);
3263+ job_process_start (job, PROCESS_MAIN);
3264
3265 TEST_NE (job->pid[PROCESS_MAIN], 0);
3266
3267@@ -2597,12 +2536,12 @@
3268 job->goal = JOB_START;
3269 job->state = JOB_SPAWNED;
3270
3271- ret = job_process_run (job, PROCESS_MAIN);
3272- TEST_EQ (ret, 0);
3273+ job_process_start (job, PROCESS_MAIN);
3274
3275 TEST_NE (job->pid[PROCESS_MAIN], 0);
3276
3277 TEST_WATCH_UPDATE ();
3278+ TEST_WATCH_UPDATE ();
3279
3280 waitpid (job->pid[PROCESS_MAIN], &status, 0);
3281 TEST_TRUE (WIFEXITED (status));
3282@@ -2659,8 +2598,7 @@
3283 job->goal = JOB_START;
3284 job->state = JOB_SPAWNED;
3285
3286- ret = job_process_run (job, PROCESS_MAIN);
3287- TEST_EQ (ret, 0);
3288+ job_process_start (job, PROCESS_MAIN);
3289
3290 TEST_NE (job->pid[PROCESS_MAIN], 0);
3291
3292@@ -2725,8 +2663,7 @@
3293 job->goal = JOB_START;
3294 job->state = JOB_SPAWNED;
3295
3296- ret = job_process_run (job, PROCESS_MAIN);
3297- TEST_EQ (ret, 0);
3298+ job_process_start (job, PROCESS_MAIN);
3299
3300 TEST_NE (job->pid[PROCESS_MAIN], 0);
3301
3302@@ -2787,12 +2724,12 @@
3303 job->goal = JOB_START;
3304 job->state = JOB_SPAWNED;
3305
3306- ret = job_process_run (job, PROCESS_MAIN);
3307- TEST_EQ (ret, 0);
3308+ job_process_start (job, PROCESS_MAIN);
3309
3310 TEST_NE (job->pid[PROCESS_MAIN], 0);
3311
3312 TEST_WATCH_UPDATE ();
3313+ TEST_WATCH_UPDATE ();
3314
3315 waitpid (job->pid[PROCESS_MAIN], &status, 0);
3316 TEST_TRUE (WIFEXITED (status));
3317@@ -2851,8 +2788,7 @@
3318 job->goal = JOB_START;
3319 job->state = JOB_SPAWNED;
3320
3321- ret = job_process_run (job, PROCESS_MAIN);
3322- TEST_EQ (ret, 0);
3323+ job_process_start (job, PROCESS_MAIN);
3324
3325 TEST_NE (job->pid[PROCESS_MAIN], 0);
3326
3327@@ -2913,8 +2849,7 @@
3328 job->goal = JOB_START;
3329 job->state = JOB_SPAWNED;
3330
3331- ret = job_process_run (job, PROCESS_MAIN);
3332- TEST_EQ (ret, 0);
3333+ job_process_start (job, PROCESS_MAIN);
3334
3335 TEST_NE (job->pid[PROCESS_MAIN], 0);
3336
3337@@ -2973,8 +2908,7 @@
3338 job->goal = JOB_START;
3339 job->state = JOB_SPAWNED;
3340
3341- ret = job_process_run (job, PROCESS_MAIN);
3342- TEST_EQ (ret, 0);
3343+ job_process_start (job, PROCESS_MAIN);
3344
3345 TEST_NE (job->pid[PROCESS_MAIN], 0);
3346
3347@@ -3037,8 +2971,7 @@
3348 job->goal = JOB_START;
3349 job->state = JOB_SPAWNED;
3350
3351- ret = job_process_run (job, PROCESS_MAIN);
3352- TEST_EQ (ret, 0);
3353+ job_process_start (job, PROCESS_MAIN);
3354
3355 TEST_NE (job->pid[PROCESS_MAIN], 0);
3356
3357@@ -3112,8 +3045,9 @@
3358 output = tmpfile ();
3359 TEST_NE_P (output, NULL);
3360 TEST_DIVERT_STDERR (output) {
3361- ret = job_process_run (job, PROCESS_MAIN);
3362- TEST_LT (ret, 0);
3363+ job_process_start (job, PROCESS_MAIN);
3364+ TEST_WATCH_UPDATE ();
3365+ event_poll ();
3366 }
3367 fclose (output);
3368
3369@@ -3161,8 +3095,8 @@
3370 job->goal = JOB_START;
3371 job->state = JOB_SPAWNED;
3372
3373- ret = job_process_run (job, PROCESS_MAIN);
3374- TEST_LT (ret, 0);
3375+ job_process_start (job, PROCESS_MAIN);
3376+ TEST_WATCH_UPDATE ();
3377
3378 /* We don't expect a logfile to be written since there is no
3379 * accompanying shell to write the error.
3380@@ -3173,10 +3107,10 @@
3381 job->goal = JOB_STOP;
3382 job->state = JOB_POST_STOP;
3383
3384- ret = job_process_run (job, PROCESS_POST_STOP);
3385- TEST_EQ (ret, 0);
3386+ job_process_start (job, PROCESS_POST_STOP);
3387
3388 TEST_NE (job->pid[PROCESS_POST_STOP], 0);
3389+ TEST_WATCH_UPDATE ();
3390
3391 /* Flush the io so that the shell on the client side
3392 * gets the data (the script to execute).
3393@@ -3187,8 +3121,11 @@
3394 TEST_TRUE (WIFEXITED (status));
3395 TEST_EQ (WEXITSTATUS (status), 0);
3396
3397+ TEST_WATCH_UPDATE ();
3398+
3399 /* .. but the post stop should have written data */
3400 TEST_EQ (stat (filename, &statbuf), 0);
3401+ event_poll ();
3402 }
3403 fclose (output);
3404
3405@@ -3241,8 +3178,9 @@
3406 job->goal = JOB_START;
3407 job->state = JOB_SPAWNED;
3408
3409- ret = job_process_run (job, PROCESS_MAIN);
3410- TEST_LT (ret, 0);
3411+ job_process_start (job, PROCESS_MAIN);
3412+ TEST_WATCH_UPDATE ();
3413+ TEST_WATCH_UPDATE ();
3414
3415 /* We don't expect a logfile to be written since there is no
3416 * accompanying shell to write the error.
3417@@ -3253,8 +3191,8 @@
3418 job->goal = JOB_STOP;
3419 job->state = JOB_POST_STOP;
3420
3421- ret = job_process_run (job, PROCESS_POST_STOP);
3422- TEST_EQ (ret, 0);
3423+ job_process_start (job, PROCESS_POST_STOP);
3424+ TEST_WATCH_UPDATE ();
3425
3426 TEST_NE (job->pid[PROCESS_POST_STOP], 0);
3427
3428@@ -3272,6 +3210,7 @@
3429
3430 /* .. but the post stop should have written data */
3431 TEST_EQ (stat (filename, &statbuf), 0);
3432+ event_poll ();
3433 }
3434 fclose (output);
3435
3436@@ -3325,8 +3264,8 @@
3437 job->goal = JOB_START;
3438 job->state = JOB_SPAWNED;
3439
3440- ret = job_process_run (job, PROCESS_MAIN);
3441- TEST_LT (ret, 0);
3442+ job_process_start (job, PROCESS_MAIN);
3443+ TEST_WATCH_UPDATE ();
3444
3445 /* We don't expect a logfile to be written since there is no
3446 * accompanying shell to write the error.
3447@@ -3337,8 +3276,8 @@
3448 job->goal = JOB_STOP;
3449 job->state = JOB_POST_STOP;
3450
3451- ret = job_process_run (job, PROCESS_POST_STOP);
3452- TEST_EQ (ret, 0);
3453+ job_process_start (job, PROCESS_POST_STOP);
3454+ TEST_WATCH_UPDATE ();
3455
3456 TEST_NE (job->pid[PROCESS_POST_STOP], 0);
3457
3458@@ -3351,8 +3290,11 @@
3459 TEST_TRUE (WIFEXITED (status));
3460 TEST_EQ (WEXITSTATUS (status), 0);
3461
3462+ TEST_WATCH_UPDATE ();
3463+
3464 /* .. but the post stop should have written data */
3465 TEST_EQ (stat (filename, &statbuf), 0);
3466+ event_poll ();
3467 }
3468 fclose (output);
3469
3470@@ -3405,8 +3347,8 @@
3471 job->goal = JOB_START;
3472 job->state = JOB_SPAWNED;
3473
3474- ret = job_process_run (job, PROCESS_MAIN);
3475- TEST_LT (ret, 0);
3476+ job_process_start (job, PROCESS_MAIN);
3477+ TEST_WATCH_UPDATE ();
3478
3479 /* We don't expect a logfile to be written since there is no
3480 * accompanying shell to write the error.
3481@@ -3417,12 +3359,13 @@
3482 job->goal = JOB_STOP;
3483 job->state = JOB_POST_STOP;
3484
3485- ret = job_process_run (job, PROCESS_POST_STOP);
3486- TEST_LT (ret, 0);
3487+ job_process_start (job, PROCESS_POST_STOP);
3488+ TEST_WATCH_UPDATE ();
3489
3490 /* Again, no file expected */
3491 TEST_EQ (stat (filename, &statbuf), -1);
3492 TEST_EQ (errno, ENOENT);
3493+ event_poll ();
3494 }
3495 fclose (output);
3496 nih_free (class);
3497@@ -3463,8 +3406,7 @@
3498 job->goal = JOB_START;
3499 job->state = JOB_SPAWNED;
3500
3501- ret = job_process_run (job, PROCESS_MAIN);
3502- TEST_EQ (ret, 0);
3503+ job_process_start (job, PROCESS_MAIN);
3504
3505 TEST_NE (job->pid[PROCESS_MAIN], 0);
3506
3507@@ -3483,8 +3425,8 @@
3508 job->goal = JOB_STOP;
3509 job->state = JOB_POST_STOP;
3510
3511- ret = job_process_run (job, PROCESS_POST_STOP);
3512- TEST_LT (ret, 0);
3513+ job_process_start (job, PROCESS_POST_STOP);
3514+ TEST_WATCH_UPDATE ();
3515
3516 TEST_EQ (job->pid[PROCESS_POST_STOP], 0);
3517 }
3518@@ -3524,8 +3466,8 @@
3519 job->goal = JOB_START;
3520 job->state = JOB_SPAWNED;
3521
3522- ret = job_process_run (job, PROCESS_MAIN);
3523- TEST_EQ (ret, 0);
3524+ job_process_start (job, PROCESS_MAIN);
3525+ TEST_WATCH_UPDATE ();
3526
3527 TEST_NE (job->pid[PROCESS_MAIN], 0);
3528
3529@@ -3585,8 +3527,8 @@
3530 job->goal = JOB_START;
3531 job->state = JOB_SPAWNED;
3532
3533- ret = job_process_run (job, PROCESS_MAIN);
3534- TEST_EQ (ret, 0);
3535+ job_process_start (job, PROCESS_MAIN);
3536+ TEST_WATCH_UPDATE ();
3537
3538 TEST_NE (job->pid[PROCESS_MAIN], 0);
3539
3540@@ -3648,8 +3590,8 @@
3541 job->goal = JOB_START;
3542 job->state = JOB_SPAWNED;
3543
3544- ret = job_process_run (job, PROCESS_MAIN);
3545- TEST_EQ (ret, 0);
3546+ job_process_start (job, PROCESS_MAIN);
3547+ TEST_WATCH_UPDATE ();
3548
3549 TEST_NE (job->pid[PROCESS_MAIN], 0);
3550
3551@@ -3728,8 +3670,7 @@
3552 job->goal = JOB_START;
3553 job->state = JOB_SPAWNED;
3554
3555- ret = job_process_run (job, PROCESS_MAIN);
3556- TEST_EQ (ret, 0);
3557+ job_process_start (job, PROCESS_MAIN);
3558
3559 /* Wait for process to avoid any possibility of EAGAIN in
3560 * log_read_watch().
3561@@ -3802,8 +3743,9 @@
3562 job->goal = JOB_START;
3563 job->state = JOB_SPAWNED;
3564
3565- ret = job_process_run (job, PROCESS_MAIN);
3566- TEST_EQ (ret, 0);
3567+ job_process_start (job, PROCESS_MAIN);
3568+ TEST_WATCH_UPDATE ();
3569+ TEST_WATCH_UPDATE ();
3570
3571 pid = job->pid[PROCESS_MAIN];
3572
3573@@ -3933,8 +3875,8 @@
3574 TEST_EQ_P (job->log[i], NULL);
3575 }
3576
3577- ret = job_process_run (job, PROCESS_MAIN);
3578- TEST_EQ (ret, 0);
3579+ job_process_start (job, PROCESS_MAIN);
3580+ TEST_WATCH_UPDATE ();
3581
3582 pid = job->pid[PROCESS_MAIN];
3583
3584@@ -4006,8 +3948,7 @@
3585 }
3586
3587 TEST_DIVERT_STDERR (output) {
3588- ret = job_process_run (job, PROCESS_MAIN);
3589- TEST_EQ (ret, 0);
3590+ job_process_start (job, PROCESS_MAIN);
3591 }
3592 fclose (output);
3593
3594@@ -4064,13 +4005,8 @@
3595 }
3596
3597 TEST_DIVERT_STDERR (output) {
3598- ret = job_process_run (job, PROCESS_MAIN);
3599- if (geteuid() == 0 || getuid() == pwd->pw_uid) {
3600- TEST_EQ (ret, 0);
3601- }
3602- else {
3603- TEST_EQ (ret, -1);
3604- }
3605+ job_process_start (job, PROCESS_MAIN);
3606+ TEST_WATCH_UPDATE ();
3607 }
3608
3609 if (geteuid() == 0 || getuid() == pwd->pw_uid) {
3610@@ -4081,13 +4017,15 @@
3611 }
3612 else {
3613 TEST_EQ (stat (filename, &statbuf), -1);
3614+ event_poll ();
3615 }
3616
3617 unlink (filename);
3618 nih_free (class);
3619-
3620 }
3621
3622+ /* FIXME with async spawn this test is racy */
3623+
3624 /************************************************************/
3625 TEST_FEATURE ("with multiple processes and log");
3626 TEST_HASH_EMPTY (job_classes);
3627@@ -4128,14 +4066,13 @@
3628 job->goal = JOB_START;
3629 job->state = JOB_SPAWNED;
3630
3631- ret = job_process_run (job, PROCESS_MAIN);
3632- TEST_EQ (ret, 0);
3633-
3634+ job_process_start (job, PROCESS_MAIN);
3635+ while (stat (filename, &statbuf) != 0) {
3636+ TEST_WATCH_UPDATE ();
3637+ }
3638 pid = job->pid[PROCESS_MAIN];
3639 TEST_GT (pid, 0);
3640
3641- TEST_WATCH_UPDATE ();
3642-
3643 TEST_EQ (stat (filename, &statbuf), 0);
3644
3645 output = fopen (filename, "r");
3646@@ -4148,8 +4085,8 @@
3647
3648 TEST_EQ (fclose (output), 0);
3649
3650- ret = job_process_run (job, PROCESS_POST_START);
3651- TEST_EQ (ret, 0);
3652+ job_process_start (job, PROCESS_POST_START);
3653+ TEST_WATCH_UPDATE ();
3654
3655 pid = job->pid[PROCESS_POST_START];
3656 TEST_GT (pid, 0);
3657@@ -4244,6 +4181,8 @@
3658 int status;
3659 struct stat statbuf;
3660 int ret;
3661+ int job_process_fd = -1;
3662+ nih_local NihIoBuffer *buffer = NULL;
3663
3664 log_unflushed_init ();
3665
3666@@ -4257,7 +4196,7 @@
3667 */
3668 TEST_EQ (setenv ("UPSTART_LOGDIR", dirname, 1), 0);
3669
3670- TEST_FUNCTION ("job_process_spawn");
3671+ TEST_FUNCTION ("job_process_spawn_with_fd");
3672 TEST_FILENAME (filename);
3673
3674 args[0] = argv0;
3675@@ -4278,7 +4217,7 @@
3676 class->console = CONSOLE_NONE;
3677 job = job_new (class, "");
3678
3679- pid = job_process_spawn (job, args, NULL, FALSE, -1, PROCESS_MAIN);
3680+ pid = job_process_spawn_with_fd (job, args, NULL, FALSE, -1, PROCESS_MAIN, &job_process_fd);
3681 TEST_GT (pid, 0);
3682
3683 waitpid (pid, NULL, 0);
3684@@ -4319,7 +4258,7 @@
3685 class->console = CONSOLE_NONE;
3686 job = job_new (class, "");
3687
3688- pid = job_process_spawn (job, args, NULL, FALSE, -1, PROCESS_MAIN);
3689+ pid = job_process_spawn_with_fd (job, args, NULL, FALSE, -1, PROCESS_MAIN, &job_process_fd);
3690 TEST_GT (pid, 0);
3691
3692 waitpid (pid, NULL, 0);
3693@@ -4351,7 +4290,7 @@
3694 class->console = CONSOLE_LOG;
3695 job = job_new (class, "");
3696
3697- pid = job_process_spawn (job, args, NULL, FALSE, -1, PROCESS_MAIN);
3698+ pid = job_process_spawn_with_fd (job, args, NULL, FALSE, -1, PROCESS_MAIN, &job_process_fd);
3699 TEST_GT (pid, 0);
3700
3701 waitpid (pid, NULL, 0);
3702@@ -4398,7 +4337,7 @@
3703 class->chdir = "/tmp";
3704 job = job_new (class, "");
3705
3706- pid = job_process_spawn (job, args, NULL, FALSE, -1, PROCESS_MAIN);
3707+ pid = job_process_spawn_with_fd (job, args, NULL, FALSE, -1, PROCESS_MAIN, &job_process_fd);
3708 TEST_GT (pid, 0);
3709
3710 waitpid (pid, NULL, 0);
3711@@ -4430,7 +4369,7 @@
3712 class->console = CONSOLE_NONE;
3713 job = job_new (class, "");
3714
3715- pid = job_process_spawn (job, args, env, FALSE, -1, PROCESS_MAIN);
3716+ pid = job_process_spawn_with_fd (job, args, env, FALSE, -1, PROCESS_MAIN, &job_process_fd);
3717 TEST_GT (pid, 0);
3718
3719 waitpid (pid, NULL, 0);
3720@@ -4460,7 +4399,7 @@
3721 class->console = CONSOLE_NONE;
3722 job = job_new (class, "");
3723
3724- pid = job_process_spawn (job, args, NULL, FALSE, -1, PROCESS_MAIN);
3725+ pid = job_process_spawn_with_fd (job, args, NULL, FALSE, -1, PROCESS_MAIN, &job_process_fd);
3726 TEST_GT (pid, 0);
3727
3728 assert0 (waitid (P_PID, pid, &info, WEXITED | WSTOPPED | WCONTINUED));
3729@@ -4483,7 +4422,7 @@
3730 class = job_class_new (NULL, "test", NULL);
3731 job = job_new (class, "");
3732 class->console = CONSOLE_NONE;
3733- pid = job_process_spawn (job, args, NULL, TRUE, -1, PROCESS_MAIN);
3734+ pid = job_process_spawn_with_fd (job, args, NULL, TRUE, -1, PROCESS_MAIN, &job_process_fd);
3735 TEST_GT (pid, 0);
3736
3737 assert0 (waitid (P_PID, pid, &info, WEXITED | WSTOPPED | WCONTINUED));
3738@@ -4516,8 +4455,12 @@
3739 class->console = CONSOLE_NONE;
3740 job = job_new (class, "");
3741
3742- pid = job_process_spawn (job, args, NULL, FALSE, -1, PROCESS_MAIN);
3743- TEST_LT (pid, 0);
3744+ pid = job_process_spawn_with_fd (job, args, NULL, FALSE, -1, PROCESS_MAIN, &job_process_fd);
3745+ TEST_NE (pid, 0);
3746+
3747+ buffer = read_from_fd (NULL, job_process_fd);
3748+ TEST_NE_P (buffer, NULL);
3749+ job_process_error_handler (buffer->buf, buffer->len);
3750
3751 err = nih_error_get ();
3752 TEST_EQ (err->number, JOB_PROCESS_ERROR);
3753@@ -4528,6 +4471,7 @@
3754 TEST_EQ (perr->arg, 0);
3755 TEST_EQ (perr->errnum, ENOENT);
3756 nih_free (perr);
3757+ nih_free (buffer);
3758
3759 /************************************************************/
3760 TEST_FEATURE ("with no such file, no shell and console log");
3761@@ -4539,29 +4483,36 @@
3762 class = job_class_new (NULL, "test", NULL);
3763 class->console = CONSOLE_LOG;
3764 job = job_new (class, "");
3765+ job->goal = JOB_START;
3766+ job->state = JOB_SPAWNED;
3767
3768 TEST_NE_P (job->log, NULL);
3769 TEST_EQ_P (job->log[PROCESS_MAIN], NULL);
3770- pid = job_process_spawn (job, args, NULL, FALSE, -1, PROCESS_MAIN);
3771- TEST_LT (pid, 0);
3772+ pid = job_process_spawn_with_fd (job, args, NULL, FALSE, -1, PROCESS_MAIN, &job_process_fd);
3773+ job->process_data[PROCESS_MAIN] = NIH_MUST (
3774+ job_process_data_new (job->process_data, job, PROCESS_MAIN, job_process_fd));
3775+ TEST_WATCH_UPDATE ();
3776+ TEST_NE (pid, 0);
3777
3778 TEST_GT (waitpid (-1, NULL, 0), 0);
3779
3780+ NihIo *io = nih_io_reopen (job, job_process_fd, NIH_IO_STREAM, NULL, NULL, NULL, NULL);
3781+ TEST_NE_P (io, NULL);
3782+ buffer = read_from_fd (NULL, job_process_fd);
3783+ TEST_NE_P (buffer, NULL);
3784+ TEST_NE_P (job->process_data[PROCESS_MAIN], NULL);
3785+ TEST_TRUE (job->process_data[PROCESS_MAIN]->valid);
3786+
3787+
3788+ TEST_NE_P (job->log[PROCESS_MAIN], NULL);
3789+
3790+ job_process_child_reader (job->process_data[PROCESS_MAIN], io, buffer->buf, buffer->len);
3791+
3792 /* The log should have been allocated in job_process_spawn,
3793 * but then freed on error.
3794 */
3795 TEST_EQ_P (job->log[PROCESS_MAIN], NULL);
3796
3797- err = nih_error_get ();
3798- TEST_EQ (err->number, JOB_PROCESS_ERROR);
3799- TEST_ALLOC_SIZE (err, sizeof (JobProcessError));
3800-
3801- perr = (JobProcessError *)err;
3802- TEST_EQ (perr->type, JOB_PROCESS_ERROR_EXEC);
3803- TEST_EQ (perr->arg, 0);
3804- TEST_EQ (perr->errnum, ENOENT);
3805- nih_free (perr);
3806-
3807 /* Check that we can spawn a job and pause it
3808 */
3809 TEST_FEATURE ("with debug enabled");
3810@@ -4577,7 +4528,7 @@
3811 args[1] = function;
3812 args[2] = NULL;
3813
3814- pid = job_process_spawn (job, args, NULL, FALSE, -1, PROCESS_MAIN);
3815+ pid = job_process_spawn_with_fd (job, args, NULL, FALSE, -1, PROCESS_MAIN, &job_process_fd);
3816 TEST_GT (pid, 0);
3817
3818 /* Ensure process is still running after some period of time.
3819@@ -4614,7 +4565,7 @@
3820 class->console = CONSOLE_NONE;
3821 job = job_new (class, "");
3822
3823- pid = job_process_spawn (job, args, NULL, FALSE, -1, PROCESS_MAIN);
3824+ pid = job_process_spawn_with_fd (job, args, NULL, FALSE, -1, PROCESS_MAIN, &job_process_fd);
3825 TEST_GT (pid, 0);
3826
3827 waitpid (pid, NULL, 0);
3828@@ -4669,7 +4620,7 @@
3829 class->console = CONSOLE_LOG;
3830 job = job_new (class, "");
3831
3832- pid = job_process_spawn (job, args, NULL, FALSE, -1, PROCESS_MAIN);
3833+ pid = job_process_spawn_with_fd (job, args, NULL, FALSE, -1, PROCESS_MAIN, &job_process_fd);
3834 TEST_GT (pid, 0);
3835
3836 waitpid (pid, NULL, 0);
3837@@ -4742,8 +4693,8 @@
3838 args[2] = filebuf;
3839 args[3] = NULL;
3840
3841- job->pid[PROCESS_MAIN] = job_process_spawn (job, args, NULL,
3842- FALSE, -1, PROCESS_MAIN);
3843+ job->pid[PROCESS_MAIN] = job_process_spawn_with_fd (job, args, NULL,
3844+ FALSE, -1, PROCESS_MAIN, &job_process_fd);
3845 pid = job->pid[PROCESS_MAIN];
3846 TEST_GT (pid, 0);
3847
3848@@ -4769,8 +4720,8 @@
3849 args[2] = filebuf;
3850 args[3] = NULL;
3851
3852- job->pid[PROCESS_POST_START] = job_process_spawn (job, args, NULL,
3853- FALSE, -1, PROCESS_POST_START);
3854+ job->pid[PROCESS_POST_START] = job_process_spawn_with_fd (job, args, NULL,
3855+ FALSE, -1, PROCESS_POST_START, &job_process_fd);
3856 pid = job->pid[PROCESS_POST_START];
3857 TEST_GT (pid, 0);
3858
3859@@ -4867,7 +4818,7 @@
3860 NIH_MUST (nih_str_array_add (&args_array, NULL, &argc, script));
3861 }
3862
3863- pid = job_process_spawn (job, args_array, NULL, FALSE, -1, PROCESS_MAIN);
3864+ pid = job_process_spawn_with_fd (job, args_array, NULL, FALSE, -1, PROCESS_MAIN, &job_process_fd);
3865
3866 if (test_alloc_failed) {
3867 TEST_LT (pid, 0);
3868@@ -4934,7 +4885,7 @@
3869 NIH_MUST (nih_str_array_add (&args_array, NULL, &argc, TEST_SHELL_ARG));
3870 NIH_MUST (nih_str_array_add (&args_array, NULL, &argc, script));
3871
3872- pid = job_process_spawn (job, args_array, NULL, FALSE, -1, PROCESS_MAIN);
3873+ pid = job_process_spawn_with_fd (job, args_array, NULL, FALSE, -1, PROCESS_MAIN, &job_process_fd);
3874 TEST_GT (pid, 0);
3875
3876 TEST_EQ (waitpid (pid, &status, 0), pid);
3877@@ -4990,7 +4941,7 @@
3878 NIH_MUST (nih_str_array_add (&args_array, NULL, &argc, TEST_SHELL_ARG));
3879 NIH_MUST (nih_str_array_add (&args_array, NULL, &argc, script));
3880
3881- pid = job_process_spawn (job, args_array, NULL, FALSE, -1, PROCESS_MAIN);
3882+ pid = job_process_spawn_with_fd (job, args_array, NULL, FALSE, -1, PROCESS_MAIN, &job_process_fd);
3883 TEST_GT (pid, 0);
3884
3885 TEST_EQ (waitpid (pid, &status, 0), pid);
3886@@ -5043,7 +4994,7 @@
3887 NIH_MUST (nih_str_array_add (&args_array, NULL, &argc, "-en"));
3888 NIH_MUST (nih_str_array_add (&args_array, NULL, &argc, "\\000"));
3889
3890- pid = job_process_spawn (job, args_array, NULL, FALSE, -1, PROCESS_MAIN);
3891+ pid = job_process_spawn_with_fd (job, args_array, NULL, FALSE, -1, PROCESS_MAIN, &job_process_fd);
3892 TEST_GT (pid, 0);
3893
3894 TEST_EQ (waitpid (pid, &status, 0), pid);
3895@@ -5098,7 +5049,7 @@
3896 args[3] = filebuf;
3897 args[4] = NULL;
3898
3899- pid = job_process_spawn (job, args, NULL, FALSE, -1, PROCESS_MAIN);
3900+ pid = job_process_spawn_with_fd (job, args, NULL, FALSE, -1, PROCESS_MAIN, &job_process_fd);
3901 TEST_GT (pid, 0);
3902
3903 TEST_NE (waitpid (pid, &status, 0), -1);
3904@@ -5161,7 +5112,7 @@
3905 args[3] = filebuf;
3906 args[4] = NULL;
3907
3908- pid = job_process_spawn (job, args, NULL, FALSE, -1, PROCESS_MAIN);
3909+ pid = job_process_spawn_with_fd (job, args, NULL, FALSE, -1, PROCESS_MAIN, &job_process_fd);
3910 TEST_GT (pid, 0);
3911
3912 TEST_WATCH_UPDATE ();
3913@@ -5243,8 +5194,13 @@
3914 }
3915 }
3916
3917- pid = job_process_spawn (job, args, NULL, FALSE, -1, PROCESS_MAIN);
3918- TEST_LT (pid, 0);
3919+ pid = job_process_spawn_with_fd (job, args, NULL, FALSE, -1, PROCESS_MAIN, &job_process_fd);
3920+ TEST_WATCH_UPDATE ();
3921+ TEST_NE (pid, 0);
3922+
3923+ buffer = read_from_fd (NULL, job_process_fd);
3924+ TEST_NE_P (buffer, NULL);
3925+ job_process_error_handler (buffer->buf, buffer->len);
3926
3927 /* Ensure logging disabled in failure scenarios */
3928 TEST_EQ (class->console, CONSOLE_NONE);
3929@@ -5830,6 +5786,8 @@
3930 job->exit_status = 0;
3931
3932 job_process_handler (NULL, 1, NIH_CHILD_EXITED, 0);
3933+ TEST_EQ (job->state, JOB_SPAWNED);
3934+ job_change_state (job, job_next_state(job));
3935
3936 TEST_EQ (job->goal, JOB_START);
3937 TEST_EQ (job->state, JOB_RUNNING);
3938@@ -9181,7 +9139,7 @@
3939 void
3940 run_tests (void)
3941 {
3942- test_run ();
3943+ test_start ();
3944 test_spawn ();
3945 test_log_path ();
3946 test_kill ();
3947
3948=== modified file 'init/tests/test_util.c'
3949--- init/tests/test_util.c 2013-07-17 14:18:42 +0000
3950+++ init/tests/test_util.c 2014-05-22 13:31:23 +0000
3951@@ -1,5 +1,6 @@
3952+#include "test_util_common.h"
3953+#undef PACKAGE_COPYRIGHT
3954 #include "test_util.h"
3955-#include "test_util_common.h"
3956 #include <nih/logging.h>
3957 #include <nih/test.h>
3958
3959
3960=== modified file 'test/test_util_common.c'
3961--- test/test_util_common.c 2014-04-11 21:15:39 +0000
3962+++ test/test_util_common.c 2014-05-22 13:31:23 +0000
3963@@ -28,6 +28,10 @@
3964 #include <nih/string.h>
3965 #include <nih/signal.h>
3966 #include <nih/logging.h>
3967+#include <nih/timer.h>
3968+#include <nih/io.h>
3969+#include <nih/child.h>
3970+#include <nih/main.h>
3971 #include <nih-dbus/test_dbus.h>
3972
3973 #include <dbus/dbus.h>
3974@@ -986,7 +990,7 @@
3975
3976 /* Clean up if tests forgot to */
3977 cmd = NIH_MUST (nih_sprintf (NULL, "rm %s/*.session 2>/dev/null", path));
3978- system (cmd);
3979+ assert0 (system (cmd));
3980
3981 /* Remove the directory tree the first Session Init created */
3982 assert0 (rmdir (path));
3983@@ -1003,3 +1007,89 @@
3984
3985 }
3986 }
3987+
3988+/**
3989+ * timer_cb:
3990+ *
3991+ * @data: unused,
3992+ * @timer: timer.
3993+ *
3994+ * Exit main loop with an error value indicating that the expected main
3995+ * loop events/actions were not performed within the expected time.
3996+ **/
3997+void
3998+timer_cb (void *data, NihTimer *timer)
3999+{
4000+ nih_assert (timer);
4001+
4002+ /* Return non-zero to denote failure */
4003+ nih_main_loop_exit (42);
4004+}
4005+
4006+/**
4007+ * fd_valid:
4008+ * @fd: file descriptor.
4009+ *
4010+ * Return 1 if @fd is valid, else 0.
4011+ **/
4012+int
4013+fd_valid (int fd)
4014+{
4015+ int flags = 0;
4016+
4017+ if (fd < 0)
4018+ return 0;
4019+
4020+ errno = 0;
4021+ flags = fcntl (fd, F_GETFL);
4022+
4023+ if (flags < 0)
4024+ return 0;
4025+
4026+ /* redundant really */
4027+ if (errno == EBADF)
4028+ return 0;
4029+
4030+ return 1;
4031+}
4032+
4033+/**
4034+ * read_from_fd:
4035+ *
4036+ * @parent: parent,
4037+ * @fd: open file descriptor.
4038+ *
4039+ * Read from the specified fd, close the fd and return the data.
4040+ *
4041+ * Returns: Newly-allocated NihIoBuffer representing data read from @fd.
4042+ *
4043+ **/
4044+NihIoBuffer *
4045+read_from_fd (void *parent, int fd)
4046+{
4047+ NihIoBuffer *buffer = NULL;
4048+ ssize_t len;
4049+
4050+ assert (fd >= 0);
4051+
4052+ buffer = nih_io_buffer_new (parent);
4053+ nih_assert (buffer);
4054+
4055+ while (TRUE) {
4056+
4057+ nih_assert (! nih_io_buffer_resize (buffer, 1024));
4058+
4059+ len = read (fd,
4060+ buffer->buf + buffer->len,
4061+ buffer->size - buffer->len);
4062+
4063+ if (len <= 0)
4064+ break;
4065+ else if (len > 0)
4066+ buffer->len += len;
4067+ }
4068+
4069+ close (fd);
4070+
4071+ return buffer;
4072+}
4073
4074=== modified file 'test/test_util_common.h'
4075--- test/test_util_common.h 2013-11-15 23:47:31 +0000
4076+++ test/test_util_common.h 2014-05-22 13:31:23 +0000
4077@@ -6,6 +6,10 @@
4078 #include <sys/wait.h>
4079
4080 #include <nih-dbus/test_dbus.h>
4081+#include <nih/timer.h>
4082+#include <nih/main.h>
4083+#include <nih/child.h>
4084+#include <nih/io.h>
4085
4086 /**
4087 * TEST_DIR_MODE:
4088@@ -34,6 +38,16 @@
4089
4090 #define TEST_QUIESCE_TOTAL_WAIT_TIME (TEST_EXIT_TIME + TEST_QUIESCE_KILL_PHASE)
4091
4092+/**
4093+ * TEST_MAIN_LOOP_TIMEOUT_SECS:
4094+ *
4095+ * Number of seconds to wait until the main loop is exited in error.
4096+ *
4097+ * To avoid a test failure, all main loops must exit within this
4098+ * number of seconds.
4099+ **/
4100+#define TEST_MAIN_LOOP_TIMEOUT_SECS 5
4101+
4102 /* A 'reasonable' path, but which also contains a marker at the end so
4103 * we know when we're looking at a PATH these tests have set.
4104 */
4105@@ -74,6 +88,41 @@
4106 }
4107
4108 /**
4109+ * TEST_WATCH_LOOP:
4110+ *
4111+ * Loop for NihIo object Updates, and process them until no watches
4112+ * left.
4113+ */
4114+#define TEST_WATCH_LOOP() \
4115+{ \
4116+ /* Loop until we've fed all of the data. */ \
4117+ int first = TRUE; \
4118+ for (;;) { \
4119+ fd_set readfds, writefds, exceptfds; \
4120+ int nfds; \
4121+ \
4122+ nfds = 0; \
4123+ FD_ZERO (&readfds); \
4124+ FD_ZERO (&writefds); \
4125+ FD_ZERO (&exceptfds); \
4126+ \
4127+ nih_io_select_fds (&nfds, &readfds, \
4128+ &writefds, &exceptfds); \
4129+ if (! nfds) { \
4130+ if (first) \
4131+ TEST_FAILED ("expected to have " \
4132+ "data to feed."); \
4133+ break; \
4134+ } \
4135+ first = FALSE; \
4136+ \
4137+ select (nfds, &readfds, &writefds, &exceptfds, NULL); \
4138+ \
4139+ nih_io_handle_fds (&readfds, &writefds, &exceptfds); \
4140+ } \
4141+}
4142+
4143+/**
4144 * _TEST_WATCH_UPDATE:
4145 * @force: if TRUE, force an update,
4146 * @timeout: struct timeval pointer, or NULL if no timeout required.
4147@@ -169,6 +218,30 @@
4148 }
4149
4150 /**
4151+ * TEST_RESET_MAIN_LOOP:
4152+ *
4153+ * Reset main loop and associated test variables.
4154+ **/
4155+#define TEST_RESET_MAIN_LOOP() \
4156+ if (nih_main_loop_functions) { \
4157+ nih_free (nih_main_loop_functions); \
4158+ nih_main_loop_functions = NULL; \
4159+ } \
4160+ if (nih_child_watches) { \
4161+ nih_free (nih_child_watches); \
4162+ nih_child_watches = NULL; \
4163+ } \
4164+ if (nih_timers) { \
4165+ nih_free (nih_timers); \
4166+ nih_timers = NULL; \
4167+ } \
4168+ nih_child_init (); \
4169+ nih_main_loop_init (); \
4170+ nih_timer_init (); \
4171+ nih_io_init ()
4172+
4173+
4174+/**
4175 * obj_string_check:
4176 *
4177 * @a: first object,
4178@@ -702,10 +775,10 @@
4179 int string_check (const char *a, const char *b)
4180 __attribute__ ((warn_unused_result));
4181
4182-const char * get_upstart_binary (void)
4183+const char *get_upstart_binary (void)
4184 __attribute__ ((warn_unused_result));
4185
4186-const char * get_initctl_binary (void)
4187+const char *get_initctl_binary (void)
4188 __attribute__ ((warn_unused_result));
4189
4190 int strcmp_compar (const void *a, const void *b)
4191@@ -731,4 +804,17 @@
4192
4193 void test_common_cleanup (void);
4194
4195+void timer_cb (void *data, NihTimer *timer);
4196+
4197+void test_job_process_handler (void *data, pid_t pid,
4198+ NihChildEvents event, int status);
4199+
4200+void test_main_loop_func (void *data, NihMainLoopFunc *self);
4201+
4202+int fd_valid (int fd)
4203+ __attribute__ ((warn_unused_result));
4204+
4205+NihIoBuffer *read_from_fd (void *parent, int fd)
4206+ __attribute__ ((warn_unused_result));
4207+
4208 #endif /* TEST_UTIL_COMMON_H */
4209
4210=== modified file 'util/tests/test_initctl.c'
4211--- util/tests/test_initctl.c 2014-05-07 19:08:35 +0000
4212+++ util/tests/test_initctl.c 2014-05-22 13:31:23 +0000
4213@@ -11535,7 +11535,7 @@
4214 TEST_NE_P (sessiondir, NULL);
4215
4216 cmd = nih_sprintf (NULL, "rm %s/upstart/sessions/*.session 2>/dev/null", sessiondir);
4217- system (cmd);
4218+ assert0 (system (cmd));
4219
4220 /* Use the "secret" interface */
4221 TEST_EQ (setenv ("UPSTART_CONFDIR", confdir, 1), 0);

Subscribers

People subscribed via source and target branches