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

Proposed by James Hunt
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 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
=== modified file 'doc/states.dot'
--- doc/states.dot 2014-03-05 11:17:37 +0000
+++ doc/states.dot 2014-05-22 13:31:23 +0000
@@ -20,44 +20,79 @@
20 */20 */
2121
22digraph {22digraph {
23 rankdir=LR;
24 edge [fontsize=10];23 edge [fontsize=10];
2524
26 waiting [shape=diamond];25 waiting [shape=diamond];
27 starting [label="starting\n(emit starting)"];26 starting [label="starting\n(emit starting)"];
27 security_spawning [label="security-spawning"];
28 security [label="security"];28 security [label="security"];
29 pre_starting [label="pre-starting"];
29 pre_start [label="pre-start"];30 pre_start [label="pre-start"];
31 spawning [label="spawning"];
30 spawned [label="spawned\n(wait for pid)"];32 spawned [label="spawned\n(wait for pid)"];
33 post_starting [label="post-starting"];
31 post_start [label="post-start"];34 post_start [label="post-start"];
32 emit_started [shape=rectangle,label="emit started"];35 emit_started [shape=rectangle,label="emit started"];
33 running [shape=diamond];36 running [shape=diamond];
37 pre_stopping [label="pre-stopping"];
34 pre_stop [label="pre-stop"];38 pre_stop [label="pre-stop"];
35 stopping [label="stopping\n(emit stopping)"];39 stopping [label="stopping\n(emit stopping)"];
36 killed [label="killed\n(wait for SIGCHLD)"];40 killed [label="killed\n(wait for SIGCHLD)"];
41 post_stopping [label="post-stopping"];
37 post_stop [label="post-stop"];42 post_stop [label="post-stop"];
38 emit_stopped [shape=rectangle,label="emit stopped"];43 emit_stopped [shape=rectangle,label="emit stopped"];
3944
40 waiting -> starting [color=green];45 constraint=false;
41 starting -> security [color=green];46 waiting -> starting [color=green,weight=10];
42 security -> pre_start [color=green];47
48 starting -> security_spawning [color=green,weight=10];
49 starting -> stopping [color=red];
50
51 security_spawning -> security [color=green,weight=10];
52 security_spawning -> stopping [color=red];
53
54 security -> pre_starting [color=green,weight=10];
43 security -> stopping [color=red];55 security -> stopping [color=red];
44 starting -> stopping [color=red];56
45 pre_start -> spawned [color=green];57 pre_starting -> pre_start [color=green,weight=10];
58 pre_starting -> stopping [color=red];
59
60 pre_start -> spawning [color=green,weight=10];
46 pre_start -> stopping [color=red];61 pre_start -> stopping [color=red];
47 spawned -> post_start [color=green];62
63 spawning -> spawned [color=green,weight=10];
64 spawning -> stopping [color=red];
65
66 spawned -> post_starting [color=green,weight=10];
48 spawned -> stopping [color=red];67 spawned -> stopping [color=red];
49 post_start -> emit_started -> running [color=green];68
69 post_starting -> post_start [color=green,weight=10];
70 post_starting -> stopping [color=red];
71
72 post_start -> emit_started -> running [color=green,weight=10];
50 post_start -> stopping [color=red];73 post_start -> stopping [color=red];
51 running -> pre_stop [color=red,label="pid > 0"];74
52 running -> stopping [color=red,label="pid == 0"];75 running -> pre_stopping [color=red,fontcolor=red,label="pid > 0",weight=10];
53 running -> stopping [color=green,label="respawn"];76 running -> stopping [color=red,fontcolor=red,label="pid == 0"];
77 running -> stopping [color=green,fontcolor=darkgreen,label="respawn"];
78
79 pre_stopping -> pre_stop [color=green,weight=10];
80 pre_stopping -> pre_stop [color=red,weight=10];
81
54 pre_stop -> running [color=green];82 pre_stop -> running [color=green];
55 pre_stop -> stopping [color=red];83 pre_stop -> stopping [color=red,weight=10];
84
56 stopping -> killed [color=green];85 stopping -> killed [color=green];
57 stopping -> killed [color=red];86 stopping -> killed [color=red];
58 killed -> post_stop [color=green];87
59 killed -> post_stop [color=red];88 killed -> post_stopping [color=green];
89 killed -> post_stopping [color=red];
90
91 post_stopping -> post_stop [color=green,weight=10];
92 post_stopping -> post_stop [color=red];
93
60 post_stop -> starting [color=green];94 post_stop -> starting [color=green];
61 post_stop -> emit_stopped [color=red];95 post_stop -> emit_stopped [color=red,weight=10];
96
62 emit_stopped -> waiting [color=red];97 emit_stopped -> waiting [color=red];
63}98}
6499
=== removed file 'doc/states.png'
65Binary files doc/states.png 2014-03-05 11:17:37 +0000 and doc/states.png 1970-01-01 00:00:00 +0000 differ100Binary files doc/states.png 2014-03-05 11:17:37 +0000 and doc/states.png 1970-01-01 00:00:00 +0000 differ
=== modified file 'init/Makefile.am'
--- init/Makefile.am 2013-11-12 14:00:36 +0000
+++ init/Makefile.am 2014-05-22 13:31:23 +0000
@@ -265,6 +265,7 @@
265 session.o log.o state.o xdg.o apparmor.o \265 session.o log.o state.o xdg.o apparmor.o \
266 com.ubuntu.Upstart.o \266 com.ubuntu.Upstart.o \
267 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \267 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
268 $(top_builddir)/test/libtest_util_common.a \
268 $(NIH_LIBS) \269 $(NIH_LIBS) \
269 $(NIH_DBUS_LIBS) \270 $(NIH_DBUS_LIBS) \
270 $(DBUS_LIBS) \271 $(DBUS_LIBS) \
271272
=== modified file 'init/job.c'
--- init/job.c 2014-05-07 16:34:44 +0000
+++ init/job.c 2014-05-22 13:31:23 +0000
@@ -70,14 +70,6 @@
70 __attribute__ ((warn_unused_result));70 __attribute__ ((warn_unused_result));
7171
72static const char *72static const char *
73job_state_enum_to_str (JobState state)
74 __attribute__ ((warn_unused_result));
75
76static JobState
77job_state_str_to_enum (const char *state)
78 __attribute__ ((warn_unused_result));
79
80static const char *
81job_trace_state_enum_to_str (TraceState state)73job_trace_state_enum_to_str (TraceState state)
82 __attribute__ ((warn_unused_result));74 __attribute__ ((warn_unused_result));
8375
@@ -93,6 +85,31 @@
93job_deserialise_kill_timer (json_object *json)85job_deserialise_kill_timer (json_object *json)
94 __attribute__ ((warn_unused_result));86 __attribute__ ((warn_unused_result));
9587
88int
89job_destroy (Job *job)
90{
91 int i;
92
93 nih_assert (job);
94
95 /* Free any associated NihIo's to avoid the handlers getting
96 * called potentially after the job has been freed.
97 */
98 if (job->process_data) {
99 for (i = 0; i < PROCESS_LAST; i++) {
100 if (job->process_data[i]) {
101 nih_free (job->process_data[i]);
102
103 job->process_data[i] = NULL;
104 }
105 }
106 }
107 nih_list_destroy (&job->entry);
108
109 return 0;
110}
111
112
96/**113/**
97 * job_new:114 * job_new:
98 * @class: class of job,115 * @class: class of job,
@@ -125,7 +142,10 @@
125142
126 nih_list_init (&job->entry);143 nih_list_init (&job->entry);
127144
128 nih_alloc_set_destructor (job, nih_list_destroy);145 /* Ensure unset before destructor could possibly be called */
146 job->process_data = NULL;
147
148 nih_alloc_set_destructor (job, job_destroy);
129149
130 job->name = nih_strdup (job, name);150 job->name = nih_strdup (job, name);
131 if (! job->name)151 if (! job->name)
@@ -207,6 +227,24 @@
207 job_register (job, conn, TRUE);227 job_register (job, conn, TRUE);
208 }228 }
209229
230 /* Since some job processes can run in parallel, we must ensure
231 * that the asynchronous-spawning of such job processes is
232 * handled by providing a handler for each pid.
233 *
234 * Strictly, this is only necessary for certain combinations of
235 * job processes (such as PROCESS_MAIN and PROCESS_POST_START),
236 * however for consistency with other entities (such as Log), we
237 * create a slot for all job processes since there is minimal
238 * overhead (a single pointer) for those job processes tha
239 * cannot run in parallel with others.
240 */
241 job->process_data = nih_alloc (job, sizeof (JobProcessData *) * PROCESS_LAST);
242 if (! job->process_data)
243 goto error;
244
245 for (i = 0; i < PROCESS_LAST; i++)
246 job->process_data[i] = NULL;
247
210 return job;248 return job;
211249
212error:250error:
@@ -398,64 +436,78 @@
398 job->blocker = job_emit_event (job);436 job->blocker = job_emit_event (job);
399437
400 break;438 break;
401 case JOB_SECURITY:439 case JOB_SECURITY_SPAWNING:
402 nih_assert (job->goal == JOB_START);440 nih_assert (job->goal == JOB_START);
403 nih_assert (old_state == JOB_STARTING);441 nih_assert (old_state == JOB_STARTING);
404442
405 if (job->class->process[PROCESS_SECURITY]443 if (job->class->process[PROCESS_SECURITY]
406 && apparmor_available()) {444 && apparmor_available()) {
407 if (job_process_run (job, PROCESS_SECURITY) < 0) {445 job_process_start (job, PROCESS_SECURITY);
408 job_failed (job, PROCESS_SECURITY, -1);446 }
409 job_change_goal (job, JOB_STOP);447 state = job_next_state (job);
410 state = job_next_state (job);448 break;
411 }449 case JOB_SECURITY:
412 } else {450 nih_assert (job->goal == JOB_START);
451 nih_assert (old_state == JOB_SECURITY_SPAWNING);
452
453 if (! (job->class->process[PROCESS_SECURITY]
454 && apparmor_available())) {
413 state = job_next_state (job);455 state = job_next_state (job);
414 }456 }
415
416 break;457 break;
417 case JOB_PRE_START:458 case JOB_PRE_STARTING:
418 nih_assert (job->goal == JOB_START);459 nih_assert (job->goal == JOB_START);
419 nih_assert (old_state == JOB_SECURITY);460 nih_assert (old_state == JOB_SECURITY);
420461 /* spawn pre-start asynchronously, child
462 * watcher asynchronously will change goal to
463 * stop if spawning fails */
421 if (job->class->process[PROCESS_PRE_START]) {464 if (job->class->process[PROCESS_PRE_START]) {
422 if (job_process_run (job, PROCESS_PRE_START) < 0) {465 job_process_start (job, PROCESS_PRE_START);
423 job_failed (job, PROCESS_PRE_START, -1);466 }
424 job_change_goal (job, JOB_STOP);467 state = job_next_state (job);
425 state = job_next_state (job);468 break;
426 }469 case JOB_PRE_START:
427 } else {470 nih_assert (job->goal == JOB_START);
428 state = job_next_state (job);471 nih_assert (old_state == JOB_PRE_STARTING);
429 }
430472
473 /* if no pre-start process, go to next
474 * state. otherwise async child watcher will
475 * trigger us to go to the next state */
476 if (! job->class->process[PROCESS_PRE_START])
477 state = job_next_state (job);
431 break;478 break;
432 case JOB_SPAWNED:479 case JOB_SPAWNING:
433 nih_assert (job->goal == JOB_START);480 nih_assert (job->goal == JOB_START);
434 nih_assert (old_state == JOB_PRE_START);481 nih_assert (old_state == JOB_PRE_START);
435482
436 if (job->class->process[PROCESS_MAIN]) {483 if (job->class->process[PROCESS_MAIN]) {
437 if (job_process_run (job, PROCESS_MAIN) < 0) {484 job_process_start (job, PROCESS_MAIN);
438 job_failed (job, PROCESS_MAIN, -1);485 }
439 job_change_goal (job, JOB_STOP);486 state = job_next_state (job);
440 state = job_next_state (job);487 break;
441 } else if (job->class->expect == EXPECT_NONE)488 case JOB_SPAWNED:
442 state = job_next_state (job);489 nih_assert (job->goal == JOB_START);
443 } else {490 nih_assert (old_state == JOB_SPAWNING);
444 state = job_next_state (job);491 if (! job->class->process[PROCESS_MAIN]) {
445 }492 state = job_next_state (job);
446493 }
447 break;494 break;
448 case JOB_POST_START:495 case JOB_POST_STARTING:
449 nih_assert (job->goal == JOB_START);496 nih_assert (job->goal == JOB_START);
450 nih_assert (old_state == JOB_SPAWNED);497 nih_assert (old_state == JOB_SPAWNED);
451498
452 if (job->class->process[PROCESS_POST_START]) {499 if (job->class->process[PROCESS_POST_START]) {
453 if (job_process_run (job, PROCESS_POST_START) < 0)500 job_process_start (job, PROCESS_POST_START);
454 state = job_next_state (job);501 }
455 } else {502 state = job_next_state (job);
503 break;
504 case JOB_POST_START:
505 nih_assert (job->goal == JOB_START);
506 nih_assert (old_state == JOB_POST_STARTING);
507
508 if (! job->class->process[PROCESS_POST_START]) {
456 state = job_next_state (job);509 state = job_next_state (job);
457 }510 }
458
459 break;511 break;
460 case JOB_RUNNING:512 case JOB_RUNNING:
461 nih_assert (job->goal == JOB_START);513 nih_assert (job->goal == JOB_START);
@@ -482,20 +534,26 @@
482 }534 }
483535
484 break;536 break;
485 case JOB_PRE_STOP:537 case JOB_PRE_STOPPING:
486 nih_assert (job->goal == JOB_STOP);538 nih_assert (job->goal == JOB_STOP);
487 nih_assert (old_state == JOB_RUNNING);539 nih_assert (old_state == JOB_RUNNING);
488540
489 if (job->class->process[PROCESS_PRE_STOP]) {541 if (job->class->process[PROCESS_PRE_STOP]) {
490 if (job_process_run (job, PROCESS_PRE_STOP) < 0)542 job_process_start (job, PROCESS_PRE_STOP);
491 state = job_next_state (job);
492 } else {
493 state = job_next_state (job);
494 }543 }
544 state = job_next_state (job);
545 break;
546 case JOB_PRE_STOP:
547 nih_assert (job->goal == JOB_STOP);
548 nih_assert (old_state == JOB_PRE_STOPPING);
495549
550 if (! job->class->process[PROCESS_PRE_STOP]) {
551 state = job_next_state (job);
552 }
496 break;553 break;
497 case JOB_STOPPING:554 case JOB_STOPPING:
498 nih_assert ((old_state == JOB_STARTING)555 nih_assert ((old_state == JOB_STARTING)
556 || (old_state == JOB_PRE_STARTING)
499 || (old_state == JOB_PRE_START)557 || (old_state == JOB_PRE_START)
500 || (old_state == JOB_SECURITY)558 || (old_state == JOB_SECURITY)
501 || (old_state == JOB_SPAWNED)559 || (old_state == JOB_SPAWNED)
@@ -508,7 +566,6 @@
508 break;566 break;
509 case JOB_KILLED:567 case JOB_KILLED:
510 nih_assert (old_state == JOB_STOPPING);568 nih_assert (old_state == JOB_STOPPING);
511
512 if (job->class->process[PROCESS_MAIN]569 if (job->class->process[PROCESS_MAIN]
513 && (job->pid[PROCESS_MAIN] > 0)) {570 && (job->pid[PROCESS_MAIN] > 0)) {
514 job_process_kill (job, PROCESS_MAIN);571 job_process_kill (job, PROCESS_MAIN);
@@ -517,19 +574,20 @@
517 }574 }
518575
519 break;576 break;
520 case JOB_POST_STOP:577 case JOB_POST_STOPPING:
521 nih_assert (old_state == JOB_KILLED);578 nih_assert (old_state == JOB_KILLED);
522579
523 if (job->class->process[PROCESS_POST_STOP]) {580 if (job->class->process[PROCESS_POST_STOP]) {
524 if (job_process_run (job, PROCESS_POST_STOP) < 0) {581 job_process_start (job, PROCESS_POST_STOP);
525 job_failed (job, PROCESS_POST_STOP, -1);
526 job_change_goal (job, JOB_STOP);
527 state = job_next_state (job);
528 }
529 } else {
530 state = job_next_state (job);
531 }582 }
583 state = job_next_state (job);
584 break;
585 case JOB_POST_STOP:
586 nih_assert (old_state == JOB_POST_STOPPING);
532587
588 if (! job->class->process[PROCESS_POST_STOP]) {
589 state = job_next_state (job);
590 }
533 break;591 break;
534 case JOB_WAITING:592 case JOB_WAITING:
535 nih_assert (job->goal == JOB_STOP);593 nih_assert (job->goal == JOB_STOP);
@@ -617,6 +675,15 @@
617 case JOB_STOP:675 case JOB_STOP:
618 return JOB_STOPPING;676 return JOB_STOPPING;
619 case JOB_START:677 case JOB_START:
678 return JOB_SECURITY_SPAWNING;
679 default:
680 nih_assert_not_reached ();
681 }
682 case JOB_SECURITY_SPAWNING:
683 switch (job->goal) {
684 case JOB_STOP:
685 return JOB_STOPPING;
686 case JOB_START:
620 return JOB_SECURITY;687 return JOB_SECURITY;
621 default:688 default:
622 nih_assert_not_reached ();689 nih_assert_not_reached ();
@@ -626,6 +693,15 @@
626 case JOB_STOP:693 case JOB_STOP:
627 return JOB_STOPPING;694 return JOB_STOPPING;
628 case JOB_START:695 case JOB_START:
696 return JOB_PRE_STARTING;
697 default:
698 nih_assert_not_reached ();
699 }
700 case JOB_PRE_STARTING:
701 switch (job->goal) {
702 case JOB_STOP:
703 return JOB_STOPPING;
704 case JOB_START:
629 return JOB_PRE_START;705 return JOB_PRE_START;
630 default:706 default:
631 nih_assert_not_reached ();707 nih_assert_not_reached ();
@@ -635,6 +711,15 @@
635 case JOB_STOP:711 case JOB_STOP:
636 return JOB_STOPPING;712 return JOB_STOPPING;
637 case JOB_START:713 case JOB_START:
714 return JOB_SPAWNING;
715 default:
716 nih_assert_not_reached ();
717 }
718 case JOB_SPAWNING:
719 switch (job->goal) {
720 case JOB_STOP:
721 return JOB_STOPPING;
722 case JOB_START:
638 return JOB_SPAWNED;723 return JOB_SPAWNED;
639 default:724 default:
640 nih_assert_not_reached ();725 nih_assert_not_reached ();
@@ -644,6 +729,15 @@
644 case JOB_STOP:729 case JOB_STOP:
645 return JOB_STOPPING;730 return JOB_STOPPING;
646 case JOB_START:731 case JOB_START:
732 return JOB_POST_STARTING;
733 default:
734 nih_assert_not_reached ();
735 }
736 case JOB_POST_STARTING:
737 switch (job->goal) {
738 case JOB_STOP:
739 return JOB_STOPPING;
740 case JOB_START:
647 return JOB_POST_START;741 return JOB_POST_START;
648 default:742 default:
649 nih_assert_not_reached ();743 nih_assert_not_reached ();
@@ -665,7 +759,7 @@
665 case JOB_STOP:759 case JOB_STOP:
666 if (job->class->process[PROCESS_MAIN]760 if (job->class->process[PROCESS_MAIN]
667 && (job->pid[PROCESS_MAIN] > 0)) {761 && (job->pid[PROCESS_MAIN] > 0)) {
668 return JOB_PRE_STOP;762 return JOB_PRE_STOPPING;
669 } else {763 } else {
670 return JOB_STOPPING;764 return JOB_STOPPING;
671 }765 }
@@ -674,6 +768,15 @@
674 default:768 default:
675 nih_assert_not_reached ();769 nih_assert_not_reached ();
676 }770 }
771 case JOB_PRE_STOPPING:
772 switch (job->goal) {
773 case JOB_STOP:
774 return JOB_PRE_STOP;
775 case JOB_START:
776 return JOB_PRE_STOP;
777 default:
778 nih_assert_not_reached ();
779 }
677 case JOB_PRE_STOP:780 case JOB_PRE_STOP:
678 switch (job->goal) {781 switch (job->goal) {
679 case JOB_STOP:782 case JOB_STOP:
@@ -698,6 +801,15 @@
698 case JOB_KILLED:801 case JOB_KILLED:
699 switch (job->goal) {802 switch (job->goal) {
700 case JOB_STOP:803 case JOB_STOP:
804 return JOB_POST_STOPPING;
805 case JOB_START:
806 return JOB_POST_STOPPING;
807 default:
808 nih_assert_not_reached ();
809 }
810 case JOB_POST_STOPPING:
811 switch (job->goal) {
812 case JOB_STOP:
701 return JOB_POST_STOP;813 return JOB_POST_STOP;
702 case JOB_START:814 case JOB_START:
703 return JOB_POST_STOP;815 return JOB_POST_STOP;
@@ -870,8 +982,8 @@
870982
871983
872/**984/**
873 * job_emit_event:985 * job_emit_event_with_state:
874 * @job: job generating the event.986 * @job: job generating the event,
875 *987 *
876 * Called from a state change because it believes an event should be988 * Called from a state change because it believes an event should be
877 * emitted. Constructs the event with the right arguments and environment989 * emitted. Constructs the event with the right arguments and environment
@@ -1100,22 +1212,34 @@
1100 return N_("waiting");1212 return N_("waiting");
1101 case JOB_STARTING:1213 case JOB_STARTING:
1102 return N_("starting");1214 return N_("starting");
1215 case JOB_SECURITY_SPAWNING:
1216 return N_("security-spawning");
1103 case JOB_SECURITY:1217 case JOB_SECURITY:
1104 return N_("security");1218 return N_("security");
1219 case JOB_PRE_STARTING:
1220 return N_("pre-starting");
1105 case JOB_PRE_START:1221 case JOB_PRE_START:
1106 return N_("pre-start");1222 return N_("pre-start");
1223 case JOB_SPAWNING:
1224 return N_("spawning");
1107 case JOB_SPAWNED:1225 case JOB_SPAWNED:
1108 return N_("spawned");1226 return N_("spawned");
1227 case JOB_POST_STARTING:
1228 return N_("post-starting");
1109 case JOB_POST_START:1229 case JOB_POST_START:
1110 return N_("post-start");1230 return N_("post-start");
1111 case JOB_RUNNING:1231 case JOB_RUNNING:
1112 return N_("running");1232 return N_("running");
1233 case JOB_PRE_STOPPING:
1234 return N_("pre-stopping");
1113 case JOB_PRE_STOP:1235 case JOB_PRE_STOP:
1114 return N_("pre-stop");1236 return N_("pre-stop");
1115 case JOB_STOPPING:1237 case JOB_STOPPING:
1116 return N_("stopping");1238 return N_("stopping");
1117 case JOB_KILLED:1239 case JOB_KILLED:
1118 return N_("killed");1240 return N_("killed");
1241 case JOB_POST_STOPPING:
1242 return N_("post-stopping");
1119 case JOB_POST_STOP:1243 case JOB_POST_STOP:
1120 return N_("post-stop");1244 return N_("post-stop");
1121 default:1245 default:
@@ -1140,22 +1264,34 @@
1140 return JOB_WAITING;1264 return JOB_WAITING;
1141 } else if (! strcmp (state, "starting")) {1265 } else if (! strcmp (state, "starting")) {
1142 return JOB_STARTING;1266 return JOB_STARTING;
1267 } else if (! strcmp (state, "security-spawning")) {
1268 return JOB_SECURITY_SPAWNING;
1143 } else if (! strcmp (state, "security")) {1269 } else if (! strcmp (state, "security")) {
1144 return JOB_SECURITY;1270 return JOB_SECURITY;
1271 } else if (! strcmp (state, "pre-starting")) {
1272 return JOB_PRE_STARTING;
1145 } else if (! strcmp (state, "pre-start")) {1273 } else if (! strcmp (state, "pre-start")) {
1146 return JOB_PRE_START;1274 return JOB_PRE_START;
1275 } else if (! strcmp (state, "spawning")) {
1276 return JOB_SPAWNING;
1147 } else if (! strcmp (state, "spawned")) {1277 } else if (! strcmp (state, "spawned")) {
1148 return JOB_SPAWNED;1278 return JOB_SPAWNED;
1279 } else if (! strcmp (state, "post-starting")) {
1280 return JOB_POST_STARTING;
1149 } else if (! strcmp (state, "post-start")) {1281 } else if (! strcmp (state, "post-start")) {
1150 return JOB_POST_START;1282 return JOB_POST_START;
1151 } else if (! strcmp (state, "running")) {1283 } else if (! strcmp (state, "running")) {
1152 return JOB_RUNNING;1284 return JOB_RUNNING;
1285 } else if (! strcmp (state, "pre-stopping")) {
1286 return JOB_PRE_STOPPING;
1153 } else if (! strcmp (state, "pre-stop")) {1287 } else if (! strcmp (state, "pre-stop")) {
1154 return JOB_PRE_STOP;1288 return JOB_PRE_STOP;
1155 } else if (! strcmp (state, "stopping")) {1289 } else if (! strcmp (state, "stopping")) {
1156 return JOB_STOPPING;1290 return JOB_STOPPING;
1157 } else if (! strcmp (state, "killed")) {1291 } else if (! strcmp (state, "killed")) {
1158 return JOB_KILLED;1292 return JOB_KILLED;
1293 } else if (! strcmp (state, "post-stopping")) {
1294 return JOB_POST_STOPPING;
1159 } else if (! strcmp (state, "post-stop")) {1295 } else if (! strcmp (state, "post-stop")) {
1160 return JOB_POST_STOP;1296 return JOB_POST_STOP;
1161 } else {1297 } else {
@@ -1626,6 +1762,7 @@
1626 json_object *json_pid;1762 json_object *json_pid;
1627 json_object *json_fds;1763 json_object *json_fds;
1628 json_object *json_logs;1764 json_object *json_logs;
1765 json_object *json_handler_data;
16291766
1630 nih_assert (job);1767 nih_assert (job);
16311768
@@ -1771,6 +1908,33 @@
17711908
1772 json_object_object_add (json, "log", json_logs);1909 json_object_object_add (json, "log", json_logs);
17731910
1911 json_handler_data = json_object_new_array ();
1912
1913 if (! json_handler_data)
1914 return json;
1915
1916 for (int process = 0; process < PROCESS_LAST; process++) {
1917 json_object *json_data = NULL;
1918
1919 /* Only bother serialising if the process data hasn't
1920 * been handled yet.
1921 */
1922 if (job->process_data[process] && job->process_data[process]->valid) {
1923
1924 json_data = job_process_data_serialise (job,
1925 job->process_data[process]);
1926
1927 if (! json_data)
1928 goto error;
1929
1930 }
1931
1932 if (json_object_array_add (json_handler_data, json_data) < 0)
1933 goto error;
1934 }
1935
1936 json_object_object_add (json, "process_data", json_handler_data);
1937
1774 return json;1938 return json;
17751939
1776error:1940error:
@@ -1834,6 +1998,7 @@
1834 json_object *json_fds;1998 json_object *json_fds;
1835 json_object *json_pid;1999 json_object *json_pid;
1836 json_object *json_logs;2000 json_object *json_logs;
2001 json_object *json_process_data;
1837 json_object *json_stop_on = NULL;2002 json_object *json_stop_on = NULL;
1838 size_t len;2003 size_t len;
1839 int ret;2004 int ret;
@@ -2062,6 +2227,38 @@
2062 }2227 }
2063 }2228 }
20642229
2230
2231 if (json_object_object_get_ex (json, "process_data", &json_process_data)) {
2232 if (! state_check_json_type (json_process_data, array))
2233 goto error;
2234
2235 for (int process = 0; process < PROCESS_LAST; process++) {
2236 json_object *json_data = NULL;
2237
2238 json_data = json_object_array_get_idx (json_process_data, process);
2239
2240 if (json_data) {
2241 /* NULL if there was no process_data for this job process, or we failed to
2242 * deserialise it; either way, this should be non-fatal.
2243 */
2244 job->process_data[process] =
2245 job_process_data_deserialise (job->process_data, job, json_data);
2246
2247 if (! job->process_data[process])
2248 goto error;
2249
2250 /* Recreate watch */
2251 if (job->process_data[process]->valid) {
2252 job_register_child_handler (job->process_data[process],
2253 job->process_data[process]->job_process_fd,
2254 job->process_data[process]);
2255 }
2256 } else {
2257 job->process_data[process] = NULL;
2258 }
2259 }
2260 }
2261
2065 return job;2262 return job;
20662263
2067error:2264error:
@@ -2163,19 +2360,25 @@
2163 *2360 *
2164 * Returns: string representation of @state, or NULL if not known.2361 * Returns: string representation of @state, or NULL if not known.
2165 **/2362 **/
2166static const char *2363const char *
2167job_state_enum_to_str (JobState state)2364job_state_enum_to_str (JobState state)
2168{2365{
2169 state_enum_to_str (JOB_WAITING, state);2366 state_enum_to_str (JOB_WAITING, state);
2170 state_enum_to_str (JOB_STARTING, state);2367 state_enum_to_str (JOB_STARTING, state);
2368 state_enum_to_str (JOB_SECURITY_SPAWNING, state);
2171 state_enum_to_str (JOB_SECURITY, state);2369 state_enum_to_str (JOB_SECURITY, state);
2370 state_enum_to_str (JOB_PRE_STARTING, state);
2172 state_enum_to_str (JOB_PRE_START, state);2371 state_enum_to_str (JOB_PRE_START, state);
2372 state_enum_to_str (JOB_SPAWNING, state);
2173 state_enum_to_str (JOB_SPAWNED, state);2373 state_enum_to_str (JOB_SPAWNED, state);
2374 state_enum_to_str (JOB_POST_STARTING, state);
2174 state_enum_to_str (JOB_POST_START, state);2375 state_enum_to_str (JOB_POST_START, state);
2175 state_enum_to_str (JOB_RUNNING, state);2376 state_enum_to_str (JOB_RUNNING, state);
2377 state_enum_to_str (JOB_PRE_STOPPING, state);
2176 state_enum_to_str (JOB_PRE_STOP, state);2378 state_enum_to_str (JOB_PRE_STOP, state);
2177 state_enum_to_str (JOB_STOPPING, state);2379 state_enum_to_str (JOB_STOPPING, state);
2178 state_enum_to_str (JOB_KILLED, state);2380 state_enum_to_str (JOB_KILLED, state);
2381 state_enum_to_str (JOB_POST_STOPPING, state);
2179 state_enum_to_str (JOB_POST_STOP, state);2382 state_enum_to_str (JOB_POST_STOP, state);
21802383
2181 return NULL;2384 return NULL;
@@ -2190,19 +2393,25 @@
2190 *2393 *
2191 * Returns: JobState representation of @state, or -1 if not known.2394 * Returns: JobState representation of @state, or -1 if not known.
2192 **/2395 **/
2193static JobState2396JobState
2194job_state_str_to_enum (const char *state)2397job_state_str_to_enum (const char *state)
2195{2398{
2196 state_str_to_enum (JOB_WAITING, state);2399 state_str_to_enum (JOB_WAITING, state);
2197 state_str_to_enum (JOB_STARTING, state);2400 state_str_to_enum (JOB_STARTING, state);
2401 state_str_to_enum (JOB_SECURITY_SPAWNING, state);
2198 state_str_to_enum (JOB_SECURITY, state);2402 state_str_to_enum (JOB_SECURITY, state);
2403 state_str_to_enum (JOB_PRE_STARTING, state);
2199 state_str_to_enum (JOB_PRE_START, state);2404 state_str_to_enum (JOB_PRE_START, state);
2405 state_str_to_enum (JOB_SPAWNING, state);
2200 state_str_to_enum (JOB_SPAWNED, state);2406 state_str_to_enum (JOB_SPAWNED, state);
2407 state_str_to_enum (JOB_POST_STARTING, state);
2201 state_str_to_enum (JOB_POST_START, state);2408 state_str_to_enum (JOB_POST_START, state);
2202 state_str_to_enum (JOB_RUNNING, state);2409 state_str_to_enum (JOB_RUNNING, state);
2410 state_str_to_enum (JOB_PRE_STOPPING, state);
2203 state_str_to_enum (JOB_PRE_STOP, state);2411 state_str_to_enum (JOB_PRE_STOP, state);
2204 state_str_to_enum (JOB_STOPPING, state);2412 state_str_to_enum (JOB_STOPPING, state);
2205 state_str_to_enum (JOB_KILLED, state);2413 state_str_to_enum (JOB_KILLED, state);
2414 state_str_to_enum (JOB_POST_STOPPING, state);
2206 state_str_to_enum (JOB_POST_STOP, state);2415 state_str_to_enum (JOB_POST_STOP, state);
22072416
2208 return -1;2417 return -1;
@@ -2358,3 +2567,58 @@
2358error:2567error:
2359 return NULL;2568 return NULL;
2360}2569}
2570
2571/**
2572 * job_child_error_handler:
2573 *
2574 * @job: job,
2575 * @process: process that failed to start.
2576 *
2577 * JobProcessErrorHandler that deals with errors resulting from
2578 * a failure to start a job process.
2579 **/
2580void
2581job_child_error_handler (Job *job, ProcessType process)
2582{
2583 nih_assert (job);
2584 nih_assert (process > PROCESS_INVALID);
2585 nih_assert (process < PROCESS_LAST);
2586
2587 job->pid[process] = 0;
2588
2589 switch (process) {
2590 case PROCESS_SECURITY:
2591 job_failed (job, PROCESS_SECURITY, -1);
2592 job_change_goal (job, JOB_STOP);
2593 break;
2594
2595 case PROCESS_PRE_START:
2596 job_failed (job, PROCESS_PRE_START, -1);
2597 job_change_goal (job, JOB_STOP);
2598 job_change_state (job, job_next_state (job));
2599 break;
2600
2601 case PROCESS_MAIN:
2602 job_failed (job, PROCESS_MAIN, -1);
2603 job_change_goal (job, JOB_STOP);
2604 job_change_state (job, job_next_state (job));
2605 break;
2606
2607 case PROCESS_POST_START:
2608 job_change_state (job, job_next_state (job));
2609 break;
2610
2611 case PROCESS_PRE_STOP:
2612 job_change_state (job, job_next_state (job));
2613 break;
2614
2615 case PROCESS_POST_STOP:
2616 job_failed (job, PROCESS_POST_STOP, -1);
2617 job_change_goal (job, JOB_STOP);
2618 job_change_state (job, job_next_state (job));
2619 break;
2620
2621 default:
2622 nih_assert_not_reached ();
2623 }
2624}
23612625
=== modified file 'init/job.h'
--- init/job.h 2013-07-22 01:24:26 +0000
+++ init/job.h 2014-05-22 13:31:23 +0000
@@ -1,6 +1,6 @@
1/* upstart1/* upstart
2 *2 *
3 * Copyright © 2010 Canonical Ltd.3 * Copyright 2010 Canonical Ltd.
4 * Author: Scott James Remnant <scott@netsplit.com>.4 * Author: Scott James Remnant <scott@netsplit.com>.
5 *5 *
6 * This program is free software; you can redistribute it and/or modify6 * This program is free software; you can redistribute it and/or modify
@@ -66,14 +66,20 @@
66typedef enum job_state {66typedef enum job_state {
67 JOB_WAITING,67 JOB_WAITING,
68 JOB_STARTING,68 JOB_STARTING,
69 JOB_SECURITY_SPAWNING,
69 JOB_SECURITY,70 JOB_SECURITY,
71 JOB_PRE_STARTING,
70 JOB_PRE_START,72 JOB_PRE_START,
73 JOB_SPAWNING,
71 JOB_SPAWNED,74 JOB_SPAWNED,
75 JOB_POST_STARTING,
72 JOB_POST_START,76 JOB_POST_START,
73 JOB_RUNNING,77 JOB_RUNNING,
78 JOB_PRE_STOPPING,
74 JOB_PRE_STOP,79 JOB_PRE_STOP,
75 JOB_STOPPING,80 JOB_STOPPING,
76 JOB_KILLED,81 JOB_KILLED,
82 JOB_POST_STOPPING,
77 JOB_POST_STOP83 JOB_POST_STOP
78} JobState;84} JobState;
7985
@@ -91,6 +97,7 @@
91 TRACE_NORMAL97 TRACE_NORMAL
92} TraceState;98} TraceState;
9399
100typedef struct job_process_data JobProcessData;
94101
95/**102/**
96 * Job:103 * Job:
@@ -119,49 +126,102 @@
119 * @respawn_count: number of respawns since @respawn_time,126 * @respawn_count: number of respawns since @respawn_time,
120 * @trace_forks: number of forks traced,127 * @trace_forks: number of forks traced,
121 * @trace_state: state of trace,128 * @trace_state: state of trace,
122 * @log: pointer to array of log objects for handling job output.129 * @log: pointer to array of log objects for handling job output,
130 * @process_data: transitory async job process metadata.
123 *131 *
124 * This structure holds the state of an active job instance being tracked132 * This structure holds the state of an active job instance being tracked
125 * by the init daemon, the configuration details of the job are available133 * by the init daemon, the configuration details of the job are available
126 * from the @class member.134 * from the @class member.
127 **/135 **/
128typedef struct job {136typedef struct job {
129 NihList entry;137 NihList entry;
130138
131 char *name;139 char *name;
132 JobClass *class;140 JobClass *class;
133 char *path;141 char *path;
134142
135 JobGoal goal;143 JobGoal goal;
136 JobState state;144 JobState state;
137 char **env;145 char **env;
138146
139 char **start_env;147 char **start_env;
140 char **stop_env;148 char **stop_env;
141 EventOperator *stop_on;149 EventOperator *stop_on;
142150
143 int *fds;151 int *fds;
144 size_t num_fds;152 size_t num_fds;
145153
146 pid_t *pid;154 pid_t *pid;
147 Event *blocker;155 Event *blocker;
148 NihList blocking;156 NihList blocking;
149157
150 NihTimer *kill_timer;158 NihTimer *kill_timer;
151 ProcessType kill_process;159 ProcessType kill_process;
152160
153 int failed;161 int failed;
154 ProcessType failed_process;162 ProcessType failed_process;
155 int exit_status;163 int exit_status;
156164
157 time_t respawn_time;165 time_t respawn_time;
158 int respawn_count;166 int respawn_count;
159167
160 int trace_forks;168 int trace_forks;
161 TraceState trace_state;169 TraceState trace_state;
162 Log **log;170 Log **log;
171 JobProcessData **process_data;
172
163} Job;173} Job;
164174
175/**
176 * JobProcessData:
177 *
178 * @job: job,
179 * @process: job process to run,
180 * @script: optional script that job should run with,
181 * @shell_fd: file descriptor attached to child that @script should be
182 * written to (or -1 when @script is NULL),
183 * @job_process_fd: open readable file descriptor attached to the child
184 * process used to detect child setup errors,
185 * @status: exit status or signal in higher byte (iff
186 * job_process_terminated() ran before the job_register_child_handler()
187 * handlers),
188 * @valid: FALSE once the data has been handled, else TRUE.
189 *
190 * Used to keep track of asynchronously started job processes.
191 **/
192typedef struct job_process_data {
193 Job *job;
194 ProcessType process;
195 char *script;
196 int shell_fd;
197 int job_process_fd;
198 int status;
199 int valid;
200} JobProcessData;
201
202/**
203 * job_register_child_handler:
204 *
205 * @_parent: parent pointer,
206 * @_fd: file descriptor to monitor,
207 * @_data: data to pass to nih_io_reopen().
208 *
209 * Register a watcher to monitor the job process child error file
210 * descriptor @_fd.
211 **/
212#define job_register_child_handler(_parent, _fd, _data) \
213 while (! nih_io_reopen (_parent, _fd, NIH_IO_STREAM, \
214 (NihIoReader)job_process_child_reader, \
215 (NihIoCloseHandler)job_process_close_handler, \
216 NULL, \
217 _data)) { \
218 NihError *err; \
219 err = nih_error_get (); \
220 if (err->number != ENOMEM) \
221 nih_assert_not_reached (); \
222 nih_free (err); \
223 }
224
165225
166NIH_BEGIN_EXTERN226NIH_BEGIN_EXTERN
167227
@@ -179,7 +239,6 @@
179239
180Event *job_emit_event (Job *job);240Event *job_emit_event (Job *job);
181241
182
183const char *job_name (Job *job);242const char *job_name (Job *job);
184243
185const char *job_goal_name (JobGoal goal)244const char *job_goal_name (JobGoal goal)
@@ -228,6 +287,16 @@
228 const char *job_name)287 const char *job_name)
229 __attribute__ ((warn_unused_result));288 __attribute__ ((warn_unused_result));
230289
290const char *
291job_state_enum_to_str (JobState state)
292 __attribute__ ((warn_unused_result));
293
294JobState
295job_state_str_to_enum (const char *state)
296 __attribute__ ((warn_unused_result));
297
298void job_child_error_handler (Job *job, ProcessType process);
299
231NIH_END_EXTERN300NIH_END_EXTERN
232301
233#endif /* INIT_JOB_H */302#endif /* INIT_JOB_H */
234303
=== modified file 'init/job_class.c'
--- init/job_class.c 2014-05-07 16:34:44 +0000
+++ init/job_class.c 2014-05-22 13:31:23 +0000
@@ -2584,14 +2584,14 @@
2584 if (fd < 0)2584 if (fd < 0)
2585 continue;2585 continue;
25862586
2587 if (state_toggle_cloexec (fd, FALSE) < 0)2587 if (state_modify_cloexec (fd, FALSE) < 0)
2588 goto error;2588 goto error;
25892589
2590 fd = log->fd;2590 fd = log->fd;
2591 if (fd < 0)2591 if (fd < 0)
2592 continue;2592 continue;
25932593
2594 if (state_toggle_cloexec (fd, FALSE) < 0)2594 if (state_modify_cloexec (fd, FALSE) < 0)
2595 goto error;2595 goto error;
2596 }2596 }
2597 }2597 }
25982598
=== modified file 'init/job_process.c'
--- init/job_process.c 2014-01-31 23:45:02 +0000
+++ init/job_process.c 2014-05-22 13:31:23 +0000
@@ -111,8 +111,6 @@
111static void job_process_error_abort (int fd, JobProcessErrorType type,111static void job_process_error_abort (int fd, JobProcessErrorType type,
112 int arg)112 int arg)
113 __attribute__ ((noreturn));113 __attribute__ ((noreturn));
114static int job_process_error_read (int fd)
115 __attribute__ ((warn_unused_result));
116static void job_process_remap_fd (int *fd, int reserved_fd, int error_fd);114static void job_process_remap_fd (int *fd, int reserved_fd, int error_fd);
117115
118/**116/**
@@ -134,7 +132,7 @@
134/* Prototypes for static functions */132/* Prototypes for static functions */
135static void job_process_kill_timer (Job *job, NihTimer *timer);133static void job_process_kill_timer (Job *job, NihTimer *timer);
136static void job_process_terminated (Job *job, ProcessType process,134static void job_process_terminated (Job *job, ProcessType process,
137 int status);135 int status, int state_only);
138static int job_process_catch_runaway (Job *job);136static int job_process_catch_runaway (Job *job);
139static void job_process_stopped (Job *job, ProcessType process);137static void job_process_stopped (Job *job, ProcessType process);
140static void job_process_trace_new (Job *job, ProcessType process);138static void job_process_trace_new (Job *job, ProcessType process);
@@ -149,8 +147,10 @@
149extern int session_end;147extern int session_end;
150extern time_t quiesce_phase_time;148extern time_t quiesce_phase_time;
151149
150
152/**151/**
153 * job_process_run:152 * job_process_start:
153 *
154 * @job: job context for process to be run in,154 * @job: job context for process to be run in,
155 * @process: job process to run.155 * @process: job process to run.
156 *156 *
@@ -174,27 +174,33 @@
174 * In either case the shell is run with the -e option so that commands will174 * In either case the shell is run with the -e option so that commands will
175 * fail if their exit status is not checked.175 * fail if their exit status is not checked.
176 *176 *
177 * This function will block until the job_process_spawn() call succeeds or177 * This function will only block on temporary job_process_spawn_with_fd() error
178 * a non-temporary error occurs (such as file not found). It is up to the178 * (for example fork() failure): in normal operation it returns as soon as
179 * called to decide whether non-temporary errors are a reason to change the179 * the fork() was successful, registering an NihIo which provides
180 * job state or not.180 * asynchronous handling of the child setup stage. The specified error
181 * handler will be called should child setup fail.
181 *182 *
182 * Returns: zero on success, negative value on non-temporary error.183 * It is up to the caller to decide whether non-temporary errors are a reason
184 * to change the job state or not.
183 **/185 **/
184int186void
185job_process_run (Job *job,187job_process_start (Job *job,
186 ProcessType process)188 ProcessType process)
187{189{
188 Process *proc;190 Process *proc;
189 nih_local char **argv = NULL;191 nih_local char **argv = NULL;
190 nih_local char **env = NULL;192 nih_local char **env = NULL;
191 nih_local char *script = NULL;193 nih_local char *script = NULL;
192 char **e;194 char **e;
193 size_t argc, envc;195 size_t argc, envc;
194 int fds[2] = { -1, -1 };196 int fds[2] = { -1, -1 };
195 int error = FALSE, trace = FALSE, shell = FALSE;197 int trace = FALSE, shell = FALSE;
198 int job_process_fd = -1;
199 JobProcessData *process_data = NULL;
196200
197 nih_assert (job != NULL);201 nih_assert (job);
202 nih_assert (process > PROCESS_INVALID);
203 nih_assert (process < PROCESS_LAST);
198204
199 proc = job->class->process[process];205 proc = job->class->process[process];
200 nih_assert (proc != NULL);206 nih_assert (proc != NULL);
@@ -304,35 +310,14 @@
304 trace = TRUE;310 trace = TRUE;
305311
306 /* Spawn the process, repeat until fork() works */312 /* Spawn the process, repeat until fork() works */
307 while ((job->pid[process] = job_process_spawn (job, argv, env,313 while ((job->pid[process] = job_process_spawn_with_fd (job, argv, env,
308 trace, fds[0], process)) < 0) {314 trace, fds[0], process, &job_process_fd)) < 0) {
309 NihError *err;315 NihError *err;
310316
311 err = nih_error_get ();317 err = nih_error_get ();
312 if (err->number == JOB_PROCESS_ERROR) {318 nih_warn ("%s: %s", _("Temporary process spawn error"),
313 /* Non-temporary error condition, we're not going319 err->message);
314 * to be able to spawn this process. Clean up after
315 * ourselves before returning.
316 */
317 if (shell) {
318 close (fds[0]);
319 close (fds[1]);
320 }
321
322 job->pid[process] = 0;
323
324 /* Return non-temporary error condition */
325 nih_warn (_("Failed to spawn %s %s process: %s"),
326 job_name (job), process_name (process),
327 err->message);
328 nih_free (err);
329 return -1;
330 } else if (! error)
331 nih_warn ("%s: %s", _("Temporary process spawn error"),
332 err->message);
333 nih_free (err);320 nih_free (err);
334
335 error = TRUE;
336 }321 }
337322
338 nih_info (_("%s %s process (%d)"),323 nih_info (_("%s %s process (%d)"),
@@ -341,51 +326,50 @@
341 job->trace_forks = 0;326 job->trace_forks = 0;
342 job->trace_state = trace ? TRACE_NEW : TRACE_NONE;327 job->trace_state = trace ? TRACE_NEW : TRACE_NONE;
343328
344 /* Feed the script to the child process */
345 if (shell) {329 if (shell) {
346 NihIo *io;
347
348 /* Clean up and close the reading end (we don't need it) */330 /* Clean up and close the reading end (we don't need it) */
349 close (fds[0]);331 close (fds[0]);
350332 }
351 /* Put the entire script into an NihIo send buffer and333
352 * then mark it for closure so that the shell gets EOF334 /* At this stage, a child process has been spawned, but may not
353 * and the structure gets cleaned up automatically.335 * yet have been setup appropriately. This operation is handled
354 */336 * asynchronously since some setup operations may block,
355 while (! (io = nih_io_reopen (job, fds[1], NIH_IO_STREAM,337 * and even though they are running in a new child process, they could
356 NULL, NULL, NULL, NULL))) {338 * still block PID 1 since the latter needs to wait until the
357 NihError *err;339 * child is fully setup and the appropriate program has been
358340 * exec'd before marking the job as running.
359 err = nih_error_get ();341 *
360 if (err->number != ENOMEM)342 * This is now achieved by creating an NihIo and registering
361 nih_assert_not_reached ();343 * appropriate handlers such that notification of successful
362 nih_free (err);344 * child setup and child error scenarios are handled
363 }345 * automatically.
364346 *
365 /* We're feeding using a pipe, which has a file descriptor347 * job_process_child_reader() handles updating the jobs state.
366 * on the child end even though it open()s it again using348 */
367 * a path. Instruct the shell to close this extra fd and349 process_data = job->process_data[process] =
368 * not to leak it.350 NIH_MUST (job_process_data_new
369 */351 (job->process_data, job, process, job_process_fd));
370 NIH_ZERO (nih_io_printf (io, "exec %d<&-\n",352
371 JOB_PROCESS_SCRIPT_FD));353 if (shell) {
372354 process_data->shell_fd = fds[1];
373 NIH_ZERO (nih_io_write (io, script, strlen (script)));355 process_data->script = script;
374 nih_io_shutdown (io);356 nih_ref (script, process_data);
375 }357 }
376358
377 return 0;359 /* Set up a handler to monitor the child fd asynchronously */
360 job_register_child_handler (job->process_data[process],
361 job_process_fd, process_data);
378}362}
379363
380
381/**364/**
382 * job_process_spawn:365 * job_process_spawn_with_fd:
383 * @job: job of process to be spawned,366 * @job: job of process to be spawned,
384 * @argv: NULL-terminated list of arguments for the process,367 * @argv: NULL-terminated list of arguments for the process,
385 * @env: NULL-terminated list of environment variables for the process,368 * @env: NULL-terminated list of environment variables for the process,
386 * @trace: whether to trace this process,369 * @trace: whether to trace this process,
387 * @script_fd: script file descriptor,370 * @script_fd: script file descriptor,
388 * @process: job process to spawn.371 * @process: job process to spawn,
372 * @job_process_fd: readable child setup pipe file descriptor.
389 *373 *
390 * This function spawns a new process using the class details in @job to set up374 * This function spawns a new process using the class details in @job to set up
391 * the environment for it; the process is always a session and process group375 * the environment for it; the process is always a session and process group
@@ -406,26 +390,30 @@
406 *390 *
407 * This function only spawns the process, it is up to the caller to ensure391 * This function only spawns the process, it is up to the caller to ensure
408 * that the information is saved into the job and that the process is watched,392 * that the information is saved into the job and that the process is watched,
409 * etc.393 * etc. Also, it is up to the caller to monitor @job_process_fd to
394 * ensure the child setup was successful; data available to read
395 * indicates a failure to setup the child environment (represented by a
396 * JOB_PROCESS_ERROR error) whereas if the descriptor is simply
397 * closed setup was successful and the caller can then mark the job
398 * process as started.
410 *399 *
411 * Spawning a process may fail for temporary reasons, usually due to a failure400 * Spawning a process may fail for temporary reasons, usually due to a failure
412 * of the fork() syscall or communication with the child; or more permanent401 * of the fork() syscall.
413 * reasons such as a failure to setup the child environment. These latter
414 * are always represented by a JOB_PROCESS_ERROR error.
415 *402 *
416 * Returns: process id of new process on success, -1 on raised error403 * Returns: process id of new process on success, -1 on raised error
417 **/404 **/
418pid_t405pid_t
419job_process_spawn (Job *job,406job_process_spawn_with_fd (Job *job,
420 char * const argv[],407 char * const argv[],
421 char * const *env,408 char * const *env,
422 int trace,409 int trace,
423 int script_fd,410 int script_fd,
424 ProcessType process)411 ProcessType process,
412 int *job_process_fd)
425{413{
426 sigset_t child_set, orig_set;414 sigset_t child_set, orig_set;
427 pid_t pid;415 pid_t pid;
428 int i, fds[2];416 int i, fds[2] = { -1, -1 };
429 int pty_master = -1;417 int pty_master = -1;
430 int pty_slave = -1;418 int pty_slave = -1;
431 char pts_name[PATH_MAX];419 char pts_name[PATH_MAX];
@@ -438,7 +426,6 @@
438 struct passwd *pwd = NULL;426 struct passwd *pwd = NULL;
439 struct group *grp = NULL;427 struct group *grp = NULL;
440428
441
442 nih_assert (job != NULL);429 nih_assert (job != NULL);
443 nih_assert (job->class != NULL);430 nih_assert (job->class != NULL);
444 nih_assert (job->log != NULL);431 nih_assert (job->log != NULL);
@@ -478,7 +465,7 @@
478 nih_free (err);465 nih_free (err);
479 close (fds[0]);466 close (fds[0]);
480 close (fds[1]);467 close (fds[1]);
481 nih_return_no_memory_error(-1);468 nih_return_no_memory_error (-1);
482 }469 }
483470
484 pty_master = posix_openpt (O_RDWR | O_NOCTTY);471 pty_master = posix_openpt (O_RDWR | O_NOCTTY);
@@ -538,23 +525,10 @@
538 sigprocmask (SIG_SETMASK, &orig_set, NULL);525 sigprocmask (SIG_SETMASK, &orig_set, NULL);
539 close (fds[1]);526 close (fds[1]);
540527
541 /* Read error from the pipe, return if one is raised */528 *job_process_fd = fds[0];
542 if (job_process_error_read (fds[0]) < 0) {529
543 if (class->console == CONSOLE_LOG) {530 nih_io_set_cloexec (*job_process_fd);
544 /* Ensure the pty_master watch gets531
545 * removed and the fd closed.
546 */
547 nih_free (job->log[process]);
548 job->log[process] = NULL;
549 }
550 close (fds[0]);
551 return -1;
552 }
553
554 /* Note that pts_master is closed automatically in the parent when the
555 * log object is destroyed.
556 */
557 close (fds[0]);
558 return pid;532 return pid;
559 } else if (pid < 0) {533 } else if (pid < 0) {
560 nih_error_raise_system ();534 nih_error_raise_system ();
@@ -923,6 +897,10 @@
923 * call exec below.897 * call exec below.
924 */898 */
925 if (class->debug) {899 if (class->debug) {
900 /* Since we have not exec'd at this point, we will still
901 * have a copy of the parents fds open. As such, re-exec
902 * will not work.
903 */
926 close (fds[1]);904 close (fds[1]);
927 raise (SIGSTOP);905 raise (SIGSTOP);
928 }906 }
@@ -985,9 +963,11 @@
985 exit (255);963 exit (255);
986}964}
987965
966
988/**967/**
989 * job_process_error_read:968 * job_process_error_handler:
990 * @fd: reading end of pipe.969 * @buf: data read from child process,
970 * @len: length of data read as @wire_err.
991 *971 *
992 * Read from the reading end of the pipe specified by @fd, if we receive972 * Read from the reading end of the pipe specified by @fd, if we receive
993 * data then the child raised a process error which we reconstruct and raise973 * data then the child raised a process error which we reconstruct and raise
@@ -996,30 +976,26 @@
996 * The reconstructed error will be of JOB_PROCESS_ERROR type, the human-976 * The reconstructed error will be of JOB_PROCESS_ERROR type, the human-
997 * readable message is generated according to the type of process error977 * readable message is generated according to the type of process error
998 * and argument passed along with it.978 * and argument passed along with it.
999 *
1000 * Returns: zero if no error was found, or negative value on raised error.
1001 **/979 **/
1002static int980void
1003job_process_error_read (int fd)981job_process_error_handler (const char *buf, size_t len)
1004{982{
1005 JobProcessWireError wire_err;983 JobProcessWireError *wire_err;
1006 ssize_t len;984 JobProcessError *err;
1007 JobProcessError *err;985 const char *res;
1008 const char *res;986
987 wire_err = (JobProcessWireError *)buf;
988
989 nih_assert (wire_err);
1009990
1010 /* Read the error from the pipe; a zero read indicates that the991 /* Read the error from the pipe; a zero read indicates that the
1011 * exec succeeded so we return success, otherwise if we don't receive992 * exec succeeded so we return success, otherwise if we don't receive
1012 * a JobProcessWireError structure, we return a temporary error so we993 * a JobProcessWireError structure, we return a temporary error so we
1013 * try again.994 * try again.
1014 */995 */
1015 len = read (fd, &wire_err, sizeof (wire_err));996 if (len != sizeof (JobProcessWireError)) {
1016 if (len == 0) {
1017 return 0;
1018 } else if (len < 0) {
1019 nih_return_system_error (-1);
1020 } else if (len != sizeof (wire_err)) {
1021 errno = EILSEQ;997 errno = EILSEQ;
1022 nih_return_system_error (-1);998 nih_return_system_error ();
1023 }999 }
10241000
1025 /* Construct a JobProcessError to be raised containing information1001 /* Construct a JobProcessError to be raised containing information
@@ -1028,9 +1004,9 @@
1028 */1004 */
1029 err = NIH_MUST (nih_new (NULL, JobProcessError));1005 err = NIH_MUST (nih_new (NULL, JobProcessError));
10301006
1031 err->type = wire_err.type;1007 err->type = wire_err->type;
1032 err->arg = wire_err.arg;1008 err->arg = wire_err->arg;
1033 err->errnum = wire_err.errnum;1009 err->errnum = wire_err->errnum;
10341010
1035 err->error.number = JOB_PROCESS_ERROR;1011 err->error.number = JOB_PROCESS_ERROR;
10361012
@@ -1218,7 +1194,6 @@
1218 }1194 }
12191195
1220 nih_error_raise_error (&err->error);1196 nih_error_raise_error (&err->error);
1221 return -1;
1222}1197}
12231198
12241199
@@ -1332,6 +1307,7 @@
1332{1307{
1333 nih_assert (job);1308 nih_assert (job);
1334 nih_assert (timeout);1309 nih_assert (timeout);
1310 nih_assert (job->kill_timer == NULL);
13351311
1336 job->kill_process = process;1312 job->kill_process = process;
1337 job->kill_timer = NIH_MUST (nih_timer_add_timeout (1313 job->kill_timer = NIH_MUST (nih_timer_add_timeout (
@@ -1462,7 +1438,7 @@
1462 job_name (job), process_name (process), pid);1438 job_name (job), process_name (process), pid);
1463 }1439 }
14641440
1465 job_process_terminated (job, process, status);1441 job_process_terminated (job, process, status, FALSE);
1466 break;1442 break;
1467 case NIH_CHILD_KILLED:1443 case NIH_CHILD_KILLED:
1468 case NIH_CHILD_DUMPED:1444 case NIH_CHILD_DUMPED:
@@ -1483,7 +1459,7 @@
1483 }1459 }
14841460
1485 status <<= 8;1461 status <<= 8;
1486 job_process_terminated (job, process, status);1462 job_process_terminated (job, process, status, FALSE);
1487 break;1463 break;
1488 case NIH_CHILD_STOPPED:1464 case NIH_CHILD_STOPPED:
1489 /* Child was stopped by a signal, make sure it was SIGSTOP1465 /* Child was stopped by a signal, make sure it was SIGSTOP
@@ -1560,7 +1536,8 @@
1560 * job_process_terminated:1536 * job_process_terminated:
1561 * @job: job that changed,1537 * @job: job that changed,
1562 * @process: specific process,1538 * @process: specific process,
1563 * @status: exit status or signal in higher byte.1539 * @status: exit status or signal in higher byte,
1540 * @state_only: if TRUE, only update the jobs state (not its goal).
1564 *1541 *
1565 * This function is called whenever a @process attached to @job terminates,1542 * This function is called whenever a @process attached to @job terminates,
1566 * @status should contain the exit status in the lower byte or signal in1543 * @status should contain the exit status in the lower byte or signal in
@@ -1572,7 +1549,8 @@
1572static void1549static void
1573job_process_terminated (Job *job,1550job_process_terminated (Job *job,
1574 ProcessType process,1551 ProcessType process,
1575 int status)1552 int status,
1553 int state_only)
1576{1554{
1577 int failed = FALSE, stop = FALSE, state = TRUE;1555 int failed = FALSE, stop = FALSE, state = TRUE;
1578 struct utmpx *utmptr;1556 struct utmpx *utmptr;
@@ -1580,6 +1558,36 @@
15801558
1581 nih_assert (job != NULL);1559 nih_assert (job != NULL);
15821560
1561 if (job->state == JOB_SECURITY_SPAWNING ||
1562 job->state == JOB_PRE_STARTING ||
1563 job->state == JOB_SPAWNING ||
1564 job->state == JOB_POST_STARTING ||
1565 job->state == JOB_PRE_STOPPING ||
1566 job->state == JOB_POST_STOPPING) {
1567 /* A child process has been spawned by
1568 * job_process_spawn(), but we have not yet received
1569 * confirmation of whether the child setup phase was
1570 * successful or not.
1571 *
1572 * The fact that we are in this function means the child
1573 * setup actually failed, however we handle that
1574 * by waiting for the handlers registered by
1575 * job_register_child_handler() to be called to deal
1576 * with this error.
1577 */
1578 nih_assert (job->process_data);
1579 nih_assert (job->process_data[process]);
1580
1581 /* Add the child data for the *second* call to this
1582 * function when the child pipe has been closed.
1583 */
1584 job->process_data[process]->status = status;
1585
1586 job->state = job_next_state (job);
1587
1588 return;
1589 }
1590
1583 switch (process) {1591 switch (process) {
1584 case PROCESS_MAIN:1592 case PROCESS_MAIN:
1585 nih_assert ((job->state == JOB_RUNNING)1593 nih_assert ((job->state == JOB_RUNNING)
@@ -1701,7 +1709,7 @@
1701 }1709 }
1702 break;1710 break;
1703 case PROCESS_POST_START:1711 case PROCESS_POST_START:
1704 nih_assert (job->state == JOB_POST_START);1712 nih_assert (job->state == JOB_POST_START || job->state == JOB_RUNNING);
17051713
1706 /* We always want to change the state when the post-start1714 /* We always want to change the state when the post-start
1707 * script terminates; if the main process is running, we'll1715 * script terminates; if the main process is running, we'll
@@ -1750,7 +1758,7 @@
1750 job->kill_process = PROCESS_INVALID;1758 job->kill_process = PROCESS_INVALID;
1751 }1759 }
17521760
1753 if (job->class->console == CONSOLE_LOG && job->log[process]) {1761 if (job->class->console == CONSOLE_LOG && job->log[process] && ! state_only) {
1754 int ret;1762 int ret;
17551763
1756 /* It is imperative that we free the log at this stage to ensure1764 /* It is imperative that we free the log at this stage to ensure
@@ -1776,40 +1784,49 @@
1776 job->log[process] = NULL;1784 job->log[process] = NULL;
1777 }1785 }
17781786
1779 /* Find existing utmp entry for the process pid */1787 if (! state_only) {
1780 setutxent();1788 /* Find existing utmp entry for the process pid */
1781 while ((utmptr = getutxent()) != NULL) {1789 setutxent();
1782 if (utmptr->ut_pid == job->pid[process]) {1790 while ((utmptr = getutxent()) != NULL) {
1783 /* set type and clean ut_user, ut_host,1791 if (utmptr->ut_pid == job->pid[process]) {
1784 * ut_time as described in utmp(5)1792 /* set type and clean ut_user, ut_host,
1785 */1793 * ut_time as described in utmp(5)
1786 utmptr->ut_type = DEAD_PROCESS;1794 */
1787 memset(utmptr->ut_user, 0, UT_NAMESIZE);1795 utmptr->ut_type = DEAD_PROCESS;
1788 memset(utmptr->ut_host, 0, UT_HOSTSIZE);1796 memset(utmptr->ut_user, 0, UT_NAMESIZE);
1789 utmptr->ut_time = 0;1797 memset(utmptr->ut_host, 0, UT_HOSTSIZE);
1790 /* Update existing utmp file. */1798 utmptr->ut_time = 0;
1791 pututxline(utmptr);1799 /* Update existing utmp file. */
17921800 pututxline(utmptr);
1793 /* set ut_time for log */1801
1794 gettimeofday(&tv, NULL);1802 /* set ut_time for log */
1795 utmptr->ut_tv.tv_sec = tv.tv_sec;1803 gettimeofday(&tv, NULL);
1796 utmptr->ut_tv.tv_usec = tv.tv_usec;1804 utmptr->ut_tv.tv_sec = tv.tv_sec;
1797 /* Write wtmp entry */1805 utmptr->ut_tv.tv_usec = tv.tv_usec;
1798 updwtmpx (_PATH_WTMP, utmptr);1806 /* Write wtmp entry */
17991807 updwtmpx (_PATH_WTMP, utmptr);
1800 break;1808
1809 break;
1810 }
1801 }1811 }
1812 endutxent();
1813
1814 /* Clear the process pid field */
1815 job->pid[process] = 0;
1802 }1816 }
1803 endutxent();
1804
1805 /* Clear the process pid field */
1806 job->pid[process] = 0;
1807
18081817
1809 /* Mark the job as failed */1818 /* Mark the job as failed */
1810 if (failed)1819 if (failed)
1811 job_failed (job, process, status);1820 job_failed (job, process, status);
18121821
1822 /* Cancel goal transition if the job state only should be
1823 * changed.
1824 */
1825 if (state_only && stop) {
1826 stop = 0;
1827 nih_assert (! failed);
1828 }
1829
1813 /* Change the goal to stop; normally this doesn't have any1830 /* Change the goal to stop; normally this doesn't have any
1814 * side-effects, except when we're in the RUNNING state when it'll1831 * side-effects, except when we're in the RUNNING state when it'll
1815 * change the state as well. We obviously don't want to change the1832 * change the state as well. We obviously don't want to change the
@@ -1887,7 +1904,7 @@
1887 /* Any process can stop on a signal, but we only care about the1904 /* Any process can stop on a signal, but we only care about the
1888 * main process when the state is still spawned.1905 * main process when the state is still spawned.
1889 */1906 */
1890 if ((process != PROCESS_MAIN) || (job->state != JOB_SPAWNED))1907 if ((process != PROCESS_MAIN) || ((job->state != JOB_SPAWNING) && job->state != JOB_SPAWNED))
1891 return;1908 return;
18921909
1893 /* Send SIGCONT back and change the state to the next one, if this1910 /* Send SIGCONT back and change the state to the next one, if this
@@ -1916,14 +1933,16 @@
1916 ProcessType process)1933 ProcessType process)
1917{1934{
1918 nih_assert (job != NULL);1935 nih_assert (job != NULL);
1936
1919 nih_assert ((job->trace_state == TRACE_NEW)1937 nih_assert ((job->trace_state == TRACE_NEW)
1920 || (job->trace_state == TRACE_NEW_CHILD));1938 || (job->trace_state == TRACE_NEW_CHILD));
19211939
1922 /* Any process can get us to trace them, but we only care about the1940 /* Any process can get us to trace them, but we only care about the
1923 * main process when the state is still spawned.1941 * main process when the state is still spawned.
1924 */1942 */
1925 if ((process != PROCESS_MAIN) || (job->state != JOB_SPAWNED))1943 if ((process != PROCESS_MAIN) || ((job->state != JOB_SPAWNING) && (job->state != JOB_SPAWNED))) {
1926 return;1944 return;
1945 }
19271946
1928 /* Set options so that we are notified when the process forks, and1947 /* Set options so that we are notified when the process forks, and
1929 * get a different kind of notification when it execs to a plain1948 * get a different kind of notification when it execs to a plain
@@ -1973,7 +1992,7 @@
1973 /* Any process can get us to trace them, but we only care about the1992 /* Any process can get us to trace them, but we only care about the
1974 * main process when the state is still spawned.1993 * main process when the state is still spawned.
1975 */1994 */
1976 if ((process != PROCESS_MAIN) || (job->state != JOB_SPAWNED))1995 if ((process != PROCESS_MAIN) || ((job->state != JOB_SPAWNING) && (job->state != JOB_SPAWNED)))
1977 return;1996 return;
19781997
1979 /* We need to fork at least twice unless we're expecting a1998 /* We need to fork at least twice unless we're expecting a
@@ -2018,7 +2037,7 @@
2018 /* Any process can get us to trace them, but we only care about the2037 /* Any process can get us to trace them, but we only care about the
2019 * main process when the state is still spawned.2038 * main process when the state is still spawned.
2020 */2039 */
2021 if ((process != PROCESS_MAIN) || (job->state != JOB_SPAWNED)2040 if ((process != PROCESS_MAIN) || ((job->state != JOB_SPAWNING) && (job->state != JOB_SPAWNED))
2022 || (job->trace_state != TRACE_NORMAL))2041 || (job->trace_state != TRACE_NORMAL))
2023 return;2042 return;
20242043
@@ -2053,9 +2072,10 @@
2053 /* Any process can get us to trace them, but we only care about the2072 /* Any process can get us to trace them, but we only care about the
2054 * main process when the state is still spawned.2073 * main process when the state is still spawned.
2055 */2074 */
2056 if ((process != PROCESS_MAIN) || (job->state != JOB_SPAWNED)2075 if ((process != PROCESS_MAIN) || ((job->state != JOB_SPAWNING) && (job->state != JOB_SPAWNED))
2057 || (job->trace_state != TRACE_NORMAL))2076 || (job->trace_state != TRACE_NORMAL)) {
2058 return;2077 return;
2078 }
20592079
2060 /* Obtain the child process id from the ptrace event. */2080 /* Obtain the child process id from the ptrace event. */
2061 if (ptrace (PTRACE_GETEVENTMSG, job->pid[process], NULL, &data) < 0) {2081 if (ptrace (PTRACE_GETEVENTMSG, job->pid[process], NULL, &data) < 0) {
@@ -2121,7 +2141,7 @@
2121 /* Any process can get us to trace them, but we only care about the2141 /* Any process can get us to trace them, but we only care about the
2122 * main process when the state is still spawned and we're tracing it.2142 * main process when the state is still spawned and we're tracing it.
2123 */2143 */
2124 if ((process != PROCESS_MAIN) || (job->state != JOB_SPAWNED)2144 if ((process != PROCESS_MAIN) || ((job->state != JOB_SPAWNING) && job->state != JOB_SPAWNED)
2125 || (job->trace_state != TRACE_NORMAL))2145 || (job->trace_state != TRACE_NORMAL))
2126 return;2146 return;
21272147
@@ -2176,7 +2196,6 @@
2176 if (job->pid[i] == pid) {2196 if (job->pid[i] == pid) {
2177 if (process)2197 if (process)
2178 *process = i;2198 *process = i;
2179
2180 return job;2199 return job;
2181 }2200 }
2182 }2201 }
@@ -2315,16 +2334,426 @@
23152334
2316 nih_assert (fd);2335 nih_assert (fd);
2317 nih_assert (reserved_fd);2336 nih_assert (reserved_fd);
2318 nih_assert (error_fd);2337 nih_assert (error_fd >= 0);
23192338
2320 if (*fd != reserved_fd)2339 if (*fd != reserved_fd) {
2340 /* fd does not need remapping */
2321 return;2341 return;
2342 }
23222343
2323 new = dup (*fd);2344 new = dup (*fd);
2324 if (new < 0) {2345 if (new < 0) {
2325 nih_error_raise_system ();2346 nih_error_raise_system ();
2326 job_process_error_abort (error_fd, JOB_PROCESS_ERROR_DUP, 0);2347 job_process_error_abort (error_fd, JOB_PROCESS_ERROR_DUP, 0);
2327 }2348 }
2349
2328 close (*fd);2350 close (*fd);
2329 *fd = new;2351 *fd = new;
2330}2352}
2353
2354
2355/**
2356 * job_process_child_reader:
2357 *
2358 * @process_data: JobProcessHandlerData structure,
2359 * @io: NihIo with data to be read,
2360 * @buf: buffer data is available in,
2361 * @len: bytes in @buf.
2362 *
2363 * Called automatically when an error occurred setting up the child process.
2364 **/
2365void
2366job_process_child_reader (JobProcessData *process_data,
2367 NihIo *io,
2368 const char *buf,
2369 size_t len)
2370{
2371 Job *job;
2372 ProcessType process;
2373 NihError *err;
2374
2375 /* The job is in the process of being killed which must mean all
2376 * the job pids are dead. Hence, there is no point in attempting
2377 * to talk to them.
2378 */
2379 if (! process_data)
2380 return;
2381 if (! process_data->valid)
2382 return;
2383
2384 nih_assert (io);
2385 nih_assert (buf);
2386
2387 job = process_data->job;
2388 process = process_data->process;
2389
2390 /* Construct the NIH error from the data received from
2391 * the child.
2392 */
2393 job_process_error_handler (buf, len);
2394
2395 err = nih_error_get ();
2396
2397 nih_assert (err->number == JOB_PROCESS_ERROR);
2398
2399 /* Non-temporary error condition */
2400 nih_warn (_("Failed to spawn %s %s process: %s"),
2401 job_name (job), process_name (process),
2402 err->message);
2403 nih_free (err);
2404
2405 /* Non-temporary error condition, we're not going
2406 * to be able to spawn this job.
2407 */
2408 if (process_data->shell_fd != -1) {
2409 close (process_data->shell_fd);
2410
2411 /* Invalidate */
2412 process_data->shell_fd = -1;
2413 }
2414
2415 if (job && job->class->console == CONSOLE_LOG && job->log[process]) {
2416 /* Ensure the pty_master watch gets
2417 * removed and the fd closed.
2418 */
2419 nih_free (job->log[process]);
2420 job->log[process] = NULL;
2421 }
2422
2423 /* Now call the handler registered via job_process_start()
2424 * to deal with the error condition.
2425 */
2426 job_child_error_handler (job, process);
2427
2428 /* Note that pts_master is closed automatically in the parent
2429 * when the log object is destroyed.
2430 */
2431
2432 nih_io_shutdown (io);
2433
2434 /* Invalidate */
2435 process_data->job_process_fd = -1;
2436 process_data->valid = FALSE;
2437}
2438
2439/**
2440 * @process_data: JobProcessData,
2441 * @io: NihIo.
2442 *
2443 * NihIoCloseHandler called when job process starts successfully.
2444 **/
2445void
2446job_process_close_handler (JobProcessData *process_data,
2447 NihIo *io)
2448{
2449 Job *job;
2450 ProcessType process;
2451 int status;
2452
2453 /* The job is in the process of being killed which must mean all
2454 * the job pids are dead. Hence, there is no point in attempting
2455 * to talk to them.
2456 */
2457 if (! process_data)
2458 return;
2459
2460 nih_assert (io);
2461
2462 job = process_data->job;
2463 process = process_data->process;
2464 status = process_data->status;
2465
2466 /* Ensure the job process error fd is closed before attempting
2467 * to handle any scripts.
2468 */
2469 nih_free (io);
2470
2471 /* invalidate */
2472 process_data->job_process_fd = -1;
2473 process_data->valid = FALSE;
2474
2475 job_process_run_bottom (process_data);
2476
2477 if (job && job->state == JOB_SPAWNED) {
2478 if (job->class->expect == EXPECT_NONE) {
2479 nih_assert (process == PROCESS_MAIN);
2480 job_change_state (job, job_next_state (job));
2481 }
2482 }
2483
2484 /* Don't change the jobs goal yet as the process may not have
2485 * actually terminted (and hence will have
2486 * job_process_terminated() called on it again later).
2487 */
2488 switch (job->state) {
2489 /* FIXME: BUG: incomplete list of states!!!! */
2490 case JOB_SECURITY_SPAWNING:
2491 case JOB_PRE_STARTING:
2492 case JOB_SPAWNING:
2493 case JOB_POST_STARTING:
2494 case JOB_PRE_STOPPING:
2495 case JOB_POST_STOPPING:
2496 job_process_terminated (job, process, status, TRUE);
2497 break;
2498
2499 default:
2500 /* NOP */
2501 break;
2502 }
2503}
2504
2505
2506/**
2507 * job_process_run_bottom:
2508 *
2509 * @process_data: JobProcessData.
2510 *
2511 * Perform final job process setup.
2512 **/
2513void
2514job_process_run_bottom (JobProcessData *process_data)
2515{
2516 Job *job;
2517 //JobState state;
2518 char *script;
2519 int shell_fd;
2520
2521 nih_assert (process_data);
2522
2523 job = process_data->job;
2524 shell_fd = process_data->shell_fd;
2525 script = process_data->script;
2526 //state = process_data->state;
2527
2528 /* Handle job process containing a script section by sending the
2529 * script to the child shell.
2530 */
2531 if (script && shell_fd != -1) {
2532 NihIo *io;
2533
2534
2535 /* Put the entire script into an NihIo send buffer and
2536 * then mark it for closure so that the shell gets EOF
2537 * and the structure gets cleaned up automatically.
2538 */
2539 while (! (io = nih_io_reopen (job, shell_fd, NIH_IO_STREAM,
2540 NULL, NULL, NULL, NULL))) {
2541 NihError *err;
2542
2543 err = nih_error_get ();
2544
2545 if (err->number != ENOMEM)
2546 nih_assert_not_reached ();
2547 nih_free (err);
2548 }
2549
2550 /* We're feeding using a pipe, which has a file descriptor
2551 * on the child end even though it open()s it again using
2552 * a path. Instruct the shell to close this extra fd and
2553 * not to leak it.
2554 */
2555 NIH_ZERO (nih_io_printf (io, "exec %d<&-\n",
2556 JOB_PROCESS_SCRIPT_FD));
2557
2558 NIH_ZERO (nih_io_write (io, script, strlen (script)));
2559
2560 /* We're only using the io for writing, so clear the
2561 * default flag.
2562 */
2563 io->watch->events &= ~NIH_IO_READ;
2564
2565 nih_io_shutdown (io);
2566
2567 /* Invalidate now that we've sent the script to the
2568 * child.
2569 */
2570 process_data->shell_fd = -1;
2571 process_data->valid = FALSE;
2572 }
2573
2574 /* Success, so change the job state */
2575 //job->state = state;
2576 //job->state = job_next_state (job);
2577
2578 NIH_LIST_FOREACH (control_conns, iter) {
2579 NihListEntry *entry = (NihListEntry *)iter;
2580 DBusConnection *conn = (DBusConnection *)entry->data;
2581
2582 NIH_ZERO (job_emit_state_changed (
2583 conn, job->path,
2584 job_state_name (job->state)));
2585 }
2586}
2587
2588
2589/**
2590 * job_process_data_new:
2591 *
2592 * @parent: parent pointer,
2593 * @job: job,
2594 * @process: currently-running job process,
2595 * @job_process_fd: error file descriptor connected to job process used
2596 * to signal successful job process setup.
2597 *
2598 * Create a new job process data object to record meta-data for an
2599 * asynchronously-started job process. The lifetime of such objects is
2600 * limited to the time taken for the job process to fail or indicate
2601 * successful startup (both scenarios are handled by @job_process_fd).
2602 *
2603 * Returns: Newly-allocated JobProcess on success, or NULL on
2604 * insufficient memory.
2605 **/
2606JobProcessData *
2607job_process_data_new (void *parent,
2608 Job *job,
2609 ProcessType process,
2610 int job_process_fd)
2611{
2612 JobProcessData *process_data;
2613
2614 nih_assert (job);
2615 nih_assert (job_process_fd != -1);
2616
2617 process_data = NIH_MUST (nih_new (parent, JobProcessData));
2618 if (! process_data)
2619 return NULL;
2620
2621 process_data->process = process;
2622 process_data->job_process_fd = job_process_fd;
2623
2624 process_data->script = NULL;
2625 process_data->shell_fd = -1;
2626 process_data->valid = TRUE;
2627
2628 process_data->job = job;
2629 process_data->status = 0;
2630
2631 return process_data;
2632}
2633
2634/**
2635 * job_process_data_serialise:
2636 *
2637 * @job: job,
2638 * @process_data: job process data.
2639 *
2640 * Returns: JSON-serialised JobProcessData object, or NULL on error.
2641 **/
2642json_object *
2643job_process_data_serialise (const Job *job, const JobProcessData *process_data)
2644{
2645 json_object *json;
2646
2647 nih_assert (job);
2648
2649 json = json_object_new_object ();
2650 if (! json)
2651 return NULL;
2652
2653 /* Job has no "in-flight" process */
2654 if (! process_data)
2655 return json;
2656
2657 /* XXX: Note that Job is not serialised; it's not necessary
2658 * since the JobProcessData itself is serialised within its Job
2659 * and the job pointer can be reinstated on deserialisation.
2660 */
2661
2662 if (! state_set_json_enum_var (json,
2663 process_type_enum_to_str,
2664 "process", process_data->process))
2665 goto error;
2666
2667 if (! state_set_json_string_var_from_obj (json, process_data, script))
2668 goto error;
2669
2670 if (process_data->shell_fd != -1 && process_data->valid) {
2671
2672 /* Clear the cloexec flag to ensure the descriptors
2673 * remains open across the re-exec.
2674 */
2675 if (state_modify_cloexec (process_data->shell_fd, FALSE) < 0)
2676 goto error;
2677
2678 if (state_modify_cloexec (process_data->job_process_fd, FALSE) < 0)
2679 goto error;
2680 }
2681
2682 if (! state_set_json_int_var_from_obj (json, process_data, shell_fd))
2683 goto error;
2684
2685 if (! state_set_json_int_var_from_obj (json, process_data, valid))
2686 goto error;
2687
2688 if (! state_set_json_int_var_from_obj (json, process_data, job_process_fd))
2689 goto error;
2690
2691 return json;
2692
2693error:
2694 json_object_put (json);
2695 return NULL;
2696}
2697
2698/**
2699 * job_process_data_deserialise:
2700 *
2701 * @parent: parent pointer,
2702 * @job: job,
2703 * @json: JSON-serialised JobProcessData object to deserialise.
2704 *
2705 * Returns: JobProcessData object, or NULL on error.
2706 **/
2707JobProcessData *
2708job_process_data_deserialise (void *parent, Job *job, json_object *json)
2709{
2710 JobProcessData *process_data = NULL;
2711 ProcessType process;
2712 int job_process_fd;
2713
2714 nih_assert (job);
2715 nih_assert (json);
2716
2717 if (! state_check_json_type (json, object))
2718 return NULL;
2719
2720 if (! state_get_json_enum_var (json,
2721 process_type_str_to_enum,
2722 "process", process))
2723 return NULL;
2724
2725 if (! state_get_json_int_var (json, "job_process_fd", job_process_fd))
2726 return NULL;
2727
2728 process_data = job_process_data_new (parent, job, process, job_process_fd);
2729 if (! process_data)
2730 return NULL;
2731
2732 if (! state_get_json_string_var_to_obj (json, process_data, script))
2733 goto error;
2734
2735 if (! state_get_json_int_var_to_obj (json, process_data, shell_fd))
2736 goto error;
2737
2738 if (! state_get_json_int_var_to_obj (json, process_data, valid))
2739 goto error;
2740
2741 if (process_data->shell_fd != -1 && process_data->valid) {
2742 /* Reset the cloexec flag to ensure the descriptors
2743 * are not leaked to any child processes.
2744 */
2745 if (state_modify_cloexec (process_data->shell_fd, TRUE) < 0)
2746 goto error;
2747
2748 if (state_modify_cloexec (process_data->job_process_fd, TRUE) < 0)
2749 goto error;
2750 }
2751
2752 return process_data;
2753
2754error:
2755 if (process_data)
2756 nih_free (process_data);
2757
2758 return NULL;
2759}
23312760
=== modified file 'init/job_process.h'
--- init/job_process.h 2013-05-15 13:21:54 +0000
+++ init/job_process.h 2014-05-22 13:31:23 +0000
@@ -125,15 +125,38 @@
125} JobProcessError;125} JobProcessError;
126126
127127
128/**
129 * JobProcessErrorHandler:
130 *
131 * @job: job,
132 * @state: required state job is attempting to achieve,
133 * @process: job process that failed.
134 *
135 * Function that is called when a job process @process fails to start.
136 **/
137typedef void (*JobProcessErrorHandler) (Job *job, JobState state, ProcessType process);
138
128NIH_BEGIN_EXTERN139NIH_BEGIN_EXTERN
129140
130int job_process_run (Job *job, ProcessType process);141void job_process_start (Job *job, ProcessType process);
142void job_process_run_bottom (JobProcessData *handler_data);
143
144void job_process_child_reader (JobProcessData *handler_data, NihIo *io,
145 const char *buf, size_t len);
146
147void job_process_close_handler (JobProcessData *handler_data, NihIo *io);
131148
132pid_t job_process_spawn (Job *job, char * const argv[],149pid_t job_process_spawn (Job *job, char * const argv[],
133 char * const *env, int trace, int script_fd,150 char * const *env, int trace, int script_fd,
134 ProcessType process)151 ProcessType process)
135 __attribute__ ((warn_unused_result));152 __attribute__ ((warn_unused_result));
136153
154pid_t job_process_spawn_with_fd (Job *job, char * const argv[],
155 char * const *env, int trace, int script_fd,
156 ProcessType process, int *job_process_fd)
157 __attribute__ ((warn_unused_result));
158
159
137void job_process_kill (Job *job, ProcessType process);160void job_process_kill (Job *job, ProcessType process);
138161
139void job_process_handler (void *ptr, pid_t pid,162void job_process_handler (void *ptr, pid_t pid,
@@ -145,8 +168,8 @@
145 __attribute__ ((warn_unused_result));168 __attribute__ ((warn_unused_result));
146169
147void job_process_set_kill_timer (Job *job,170void job_process_set_kill_timer (Job *job,
148 ProcessType process,171 ProcessType process,
149 time_t timeout);172 time_t timeout);
150173
151void job_process_adj_kill_timer (Job *job, time_t due);174void job_process_adj_kill_timer (Job *job, time_t due);
152175
@@ -154,6 +177,20 @@
154177
155void job_process_stop_all (void);178void job_process_stop_all (void);
156179
180JobProcessData *
181job_process_data_new (void *parent, Job *job, ProcessType process, int job_process_fd)
182 __attribute__ ((warn_unused_result));
183
184json_object *
185job_process_data_serialise (const Job *job, const JobProcessData *handler_data)
186 __attribute__ ((warn_unused_result));
187
188JobProcessData *
189job_process_data_deserialise (void *parent, Job *job, json_object *json)
190 __attribute__ ((warn_unused_result));
191
192void job_process_error_handler (const char *buf, size_t len);
193
157NIH_END_EXTERN194NIH_END_EXTERN
158195
159#endif /* INIT_JOB_PROCESS_H */196#endif /* INIT_JOB_PROCESS_H */
160197
=== modified file 'init/log.c'
--- init/log.c 2014-05-07 16:34:44 +0000
+++ init/log.c 2014-05-22 13:31:23 +0000
@@ -974,7 +974,7 @@
974 nih_assert (io_watch_fd != -1);974 nih_assert (io_watch_fd != -1);
975975
976 /* re-apply CLOEXEC flag to stop job fd being leaked to children */976 /* re-apply CLOEXEC flag to stop job fd being leaked to children */
977 if (state_toggle_cloexec (io_watch_fd, TRUE) < 0)977 if (state_modify_cloexec (io_watch_fd, TRUE) < 0)
978 return NULL;978 return NULL;
979979
980 if (! state_get_json_int_var (json, "uid", uid))980 if (! state_get_json_int_var (json, "uid", uid))
@@ -993,7 +993,7 @@
993 * we would never close the fd.993 * we would never close the fd.
994 */994 */
995 if (log->fd != -1)995 if (log->fd != -1)
996 (void)state_toggle_cloexec (log->fd, TRUE);996 (void)state_modify_cloexec (log->fd, TRUE);
997997
998 log->unflushed = nih_io_buffer_new (log);998 log->unflushed = nih_io_buffer_new (log);
999 if (! log->unflushed)999 if (! log->unflushed)
10001000
=== modified file 'init/state.c'
--- init/state.c 2014-05-07 16:34:44 +0000
+++ init/state.c 2014-05-22 13:31:23 +0000
@@ -532,7 +532,7 @@
532532
533533
534/**534/**
535 * state_toggle_cloexec:535 * state_modify_cloexec:
536 *536 *
537 * @fd: file descriptor,537 * @fd: file descriptor,
538 * @set: set close-on-exec flag if TRUE, clear if FALSE.538 * @set: set close-on-exec flag if TRUE, clear if FALSE.
@@ -542,7 +542,7 @@
542 * Returns: 0 on success, -1 on error.542 * Returns: 0 on success, -1 on error.
543 **/543 **/
544int544int
545state_toggle_cloexec (int fd, int set)545state_modify_cloexec (int fd, int set)
546{546{
547 long flags;547 long flags;
548 int ret;548 int ret;
549549
=== modified file 'init/state.h'
--- init/state.h 2013-06-04 16:51:55 +0000
+++ init/state.h 2014-05-22 13:31:23 +0000
@@ -1144,7 +1144,7 @@
1144int state_from_string (const char *state)1144int state_from_string (const char *state)
1145 __attribute__ ((warn_unused_result));1145 __attribute__ ((warn_unused_result));
11461146
1147int state_toggle_cloexec (int fd, int set);1147int state_modify_cloexec (int fd, int set);
11481148
1149json_object *1149json_object *
1150state_serialise_str_array (char ** const array)1150state_serialise_str_array (char ** const array)
11511151
=== modified file 'init/tests/test_event.c'
--- init/tests/test_event.c 2013-01-31 17:23:55 +0000
+++ init/tests/test_event.c 2014-05-22 13:31:23 +0000
@@ -300,7 +300,7 @@
300 job = (Job *)nih_hash_lookup (class->instances, "");300 job = (Job *)nih_hash_lookup (class->instances, "");
301301
302 TEST_EQ (job->goal, JOB_START);302 TEST_EQ (job->goal, JOB_START);
303 TEST_EQ (job->state, JOB_RUNNING);303 TEST_EQ (job->state, JOB_SPAWNED);
304 TEST_GT (job->pid[PROCESS_MAIN], 0);304 TEST_GT (job->pid[PROCESS_MAIN], 0);
305305
306 waitpid (job->pid[PROCESS_MAIN], NULL, 0);306 waitpid (job->pid[PROCESS_MAIN], NULL, 0);
@@ -1739,7 +1739,7 @@
1739 job = (Job *)nih_hash_lookup (class->instances, "");1739 job = (Job *)nih_hash_lookup (class->instances, "");
17401740
1741 TEST_EQ (job->goal, JOB_START);1741 TEST_EQ (job->goal, JOB_START);
1742 TEST_EQ (job->state, JOB_RUNNING);1742 TEST_EQ (job->state, JOB_SPAWNED);
1743 TEST_GT (job->pid[PROCESS_MAIN], 0);1743 TEST_GT (job->pid[PROCESS_MAIN], 0);
17441744
1745 waitpid (job->pid[PROCESS_MAIN], NULL, 0);1745 waitpid (job->pid[PROCESS_MAIN], NULL, 0);
17461746
=== modified file 'init/tests/test_job.c'
--- init/tests/test_job.c 2013-11-18 16:38:32 +0000
+++ init/tests/test_job.c 2014-05-22 13:31:23 +0000
@@ -60,7 +60,15 @@
60#include "conf.h"60#include "conf.h"
61#include "control.h"61#include "control.h"
62#include "state.h"62#include "state.h"
63#include "test_util_common.h"
6364
65void
66job_quit_with_state (void *data, NihMainLoopFunc *loop)
67{
68 Job *job;
69 job = (Job *)data;
70 nih_main_loop_exit (job->state);
71}
6472
65char *argv0;73char *argv0;
6674
@@ -165,6 +173,12 @@
165 TEST_EQ_P (job->log[i], NULL);173 TEST_EQ_P (job->log[i], NULL);
166 }174 }
167175
176 TEST_NE_P (job->process_data, NULL);
177 TEST_ALLOC_SIZE (job->log, sizeof (JobProcessData *) * PROCESS_LAST);
178 for (i = 0; i < PROCESS_LAST; i++) {
179 TEST_EQ_P (job->process_data[i], NULL);
180 }
181
168 event_operator_reset (job->stop_on);182 event_operator_reset (job->stop_on);
169183
170 nih_free (job);184 nih_free (job);
@@ -701,6 +715,10 @@
701 char *path, *job_path = NULL, *state;715 char *path, *job_path = NULL, *state;
702 int status;716 int status;
703717
718 nih_error_init ();
719 nih_main_loop_init ();
720 event_init ();
721
704 TEST_FUNCTION ("job_change_state");722 TEST_FUNCTION ("job_change_state");
705 program_name = "test";723 program_name = "test";
706 output = tmpfile ();724 output = tmpfile ();
@@ -1059,7 +1077,7 @@
1059 job->failed_process = PROCESS_INVALID;1077 job->failed_process = PROCESS_INVALID;
1060 job->exit_status = 0;1078 job->exit_status = 0;
10611079
1062 job_change_state (job, JOB_PRE_START);1080 job_change_state (job, JOB_PRE_STARTING);
10631081
1064 TEST_EQ (job->goal, JOB_START);1082 TEST_EQ (job->goal, JOB_START);
1065 TEST_EQ (job->state, JOB_PRE_START);1083 TEST_EQ (job->state, JOB_PRE_START);
@@ -1110,6 +1128,7 @@
1110 blocked = blocked_new (job, BLOCKED_EVENT, cause);1128 blocked = blocked_new (job, BLOCKED_EVENT, cause);
1111 event_block (cause);1129 event_block (cause);
1112 nih_list_add (&job->blocking, &blocked->entry);1130 nih_list_add (&job->blocking, &blocked->entry);
1131 TEST_NE_P (nih_main_loop_add_func (job, job_quit_with_state, job), NULL);
1113 }1132 }
11141133
1115 job->goal = JOB_START;1134 job->goal = JOB_START;
@@ -1125,7 +1144,8 @@
1125 job->failed_process = PROCESS_INVALID;1144 job->failed_process = PROCESS_INVALID;
1126 job->exit_status = 0;1145 job->exit_status = 0;
11271146
1128 job_change_state (job, JOB_PRE_START);1147 job_change_state (job, JOB_PRE_STARTING);
1148 while (nih_main_loop () < JOB_RUNNING) {}
11291149
1130 TEST_EQ (job->goal, JOB_START);1150 TEST_EQ (job->goal, JOB_START);
1131 TEST_EQ (job->state, JOB_RUNNING);1151 TEST_EQ (job->state, JOB_RUNNING);
@@ -1184,6 +1204,7 @@
1184 blocked = blocked_new (job, BLOCKED_EVENT, cause);1204 blocked = blocked_new (job, BLOCKED_EVENT, cause);
1185 event_block (cause);1205 event_block (cause);
1186 nih_list_add (&job->blocking, &blocked->entry);1206 nih_list_add (&job->blocking, &blocked->entry);
1207 TEST_NE_P (nih_main_loop_add_func (job, job_quit_with_state, job), NULL);
1187 }1208 }
11881209
1189 job->goal = JOB_START;1210 job->goal = JOB_START;
@@ -1200,12 +1221,14 @@
1200 job->exit_status = 0;1221 job->exit_status = 0;
12011222
1202 TEST_DIVERT_STDERR (output) {1223 TEST_DIVERT_STDERR (output) {
1203 job_change_state (job, JOB_PRE_START);1224 job_change_state (job, JOB_PRE_STARTING);
1225 while (nih_main_loop() < JOB_STOPPING) {}
1204 }1226 }
1205 rewind (output);1227 rewind (output);
12061228
1207 TEST_EQ (job->goal, JOB_STOP);1229 TEST_EQ (job->goal, JOB_STOP);
1208 TEST_EQ (job->state, JOB_STOPPING);1230 TEST_EQ (job->state, JOB_STOPPING);
1231 TEST_FALSE (job->process_data[PROCESS_PRE_START]->valid);
1209 TEST_EQ (job->pid[PROCESS_PRE_START], 0);1232 TEST_EQ (job->pid[PROCESS_PRE_START], 0);
12101233
1211 TEST_EQ (cause->blockers, 0);1234 TEST_EQ (cause->blockers, 0);
@@ -1269,6 +1292,7 @@
1269 blocked = blocked_new (job, BLOCKED_EVENT, cause);1292 blocked = blocked_new (job, BLOCKED_EVENT, cause);
1270 event_block (cause);1293 event_block (cause);
1271 nih_list_add (&job->blocking, &blocked->entry);1294 nih_list_add (&job->blocking, &blocked->entry);
1295 TEST_NE_P (nih_main_loop_add_func (job, job_quit_with_state, job), NULL);
1272 }1296 }
12731297
1274 job->goal = JOB_START;1298 job->goal = JOB_START;
@@ -1284,7 +1308,8 @@
1284 job->failed_process = PROCESS_INVALID;1308 job->failed_process = PROCESS_INVALID;
1285 job->exit_status = 0;1309 job->exit_status = 0;
12861310
1287 job_change_state (job, JOB_SPAWNED);1311 job_change_state (job, JOB_SPAWNING);
1312 while (nih_main_loop() < JOB_RUNNING) {}
12881313
1289 TEST_EQ (job->goal, JOB_START);1314 TEST_EQ (job->goal, JOB_START);
1290 TEST_EQ (job->state, JOB_RUNNING);1315 TEST_EQ (job->state, JOB_RUNNING);
@@ -1337,6 +1362,7 @@
1337 blocked = blocked_new (job, BLOCKED_EVENT, cause);1362 blocked = blocked_new (job, BLOCKED_EVENT, cause);
1338 event_block (cause);1363 event_block (cause);
1339 nih_list_add (&job->blocking, &blocked->entry);1364 nih_list_add (&job->blocking, &blocked->entry);
1365 TEST_NE_P (nih_main_loop_add_func (job, job_quit_with_state, job), NULL);
1340 }1366 }
13411367
1342 job->goal = JOB_START;1368 job->goal = JOB_START;
@@ -1352,7 +1378,8 @@
1352 job->failed_process = PROCESS_INVALID;1378 job->failed_process = PROCESS_INVALID;
1353 job->exit_status = 0;1379 job->exit_status = 0;
13541380
1355 job_change_state (job, JOB_SPAWNED);1381 job_change_state (job, JOB_SPAWNING);
1382 while (nih_main_loop() < JOB_RUNNING) {}
13561383
1357 TEST_EQ (job->goal, JOB_START);1384 TEST_EQ (job->goal, JOB_START);
1358 TEST_EQ (job->state, JOB_RUNNING);1385 TEST_EQ (job->state, JOB_RUNNING);
@@ -1417,6 +1444,7 @@
1417 blocked = blocked_new (job, BLOCKED_EVENT, cause);1444 blocked = blocked_new (job, BLOCKED_EVENT, cause);
1418 event_block (cause);1445 event_block (cause);
1419 nih_list_add (&job->blocking, &blocked->entry);1446 nih_list_add (&job->blocking, &blocked->entry);
1447 TEST_NE_P (nih_main_loop_add_func (job, job_quit_with_state, job), NULL);
1420 }1448 }
14211449
1422 job->goal = JOB_START;1450 job->goal = JOB_START;
@@ -1432,7 +1460,8 @@
1432 job->failed_process = PROCESS_INVALID;1460 job->failed_process = PROCESS_INVALID;
1433 job->exit_status = 0;1461 job->exit_status = 0;
14341462
1435 job_change_state (job, JOB_SPAWNED);1463 job_change_state (job, JOB_SPAWNING);
1464 while (nih_main_loop() < JOB_RUNNING) {}
14361465
1437 TEST_EQ (job->goal, JOB_START);1466 TEST_EQ (job->goal, JOB_START);
1438 TEST_EQ (job->state, JOB_RUNNING);1467 TEST_EQ (job->state, JOB_RUNNING);
@@ -1507,7 +1536,7 @@
1507 job->failed_process = PROCESS_INVALID;1536 job->failed_process = PROCESS_INVALID;
1508 job->exit_status = 0;1537 job->exit_status = 0;
15091538
1510 job_change_state (job, JOB_SPAWNED);1539 job_change_state (job, JOB_SPAWNING);
15111540
1512 TEST_EQ (job->goal, JOB_START);1541 TEST_EQ (job->goal, JOB_START);
1513 TEST_EQ (job->state, JOB_RUNNING);1542 TEST_EQ (job->state, JOB_RUNNING);
@@ -1556,6 +1585,7 @@
1556 blocked = blocked_new (job, BLOCKED_EVENT, cause);1585 blocked = blocked_new (job, BLOCKED_EVENT, cause);
1557 event_block (cause);1586 event_block (cause);
1558 nih_list_add (&job->blocking, &blocked->entry);1587 nih_list_add (&job->blocking, &blocked->entry);
1588 TEST_NE_P (nih_main_loop_add_func (job, job_quit_with_state, job), NULL);
1559 }1589 }
15601590
1561 job->goal = JOB_START;1591 job->goal = JOB_START;
@@ -1572,12 +1602,14 @@
1572 job->exit_status = 0;1602 job->exit_status = 0;
15731603
1574 TEST_DIVERT_STDERR (output) {1604 TEST_DIVERT_STDERR (output) {
1575 job_change_state (job, JOB_SPAWNED);1605 job_change_state (job, JOB_SPAWNING);
1606 while (nih_main_loop() < JOB_STOPPING) {}
1576 }1607 }
1577 rewind (output);1608 rewind (output);
15781609
1579 TEST_EQ (job->goal, JOB_STOP);1610 TEST_EQ (job->goal, JOB_STOP);
1580 TEST_EQ (job->state, JOB_STOPPING);1611 TEST_EQ (job->state, JOB_STOPPING);
1612 TEST_FALSE (job->process_data[PROCESS_MAIN]->valid);
1581 TEST_EQ (job->pid[PROCESS_MAIN], 0);1613 TEST_EQ (job->pid[PROCESS_MAIN], 0);
15821614
1583 TEST_EQ (cause->blockers, 0);1615 TEST_EQ (cause->blockers, 0);
@@ -1658,7 +1690,7 @@
1658 job->failed_process = PROCESS_INVALID;1690 job->failed_process = PROCESS_INVALID;
1659 job->exit_status = 0;1691 job->exit_status = 0;
16601692
1661 job_change_state (job, JOB_SPAWNED);1693 job_change_state (job, JOB_SPAWNING);
16621694
1663 TEST_EQ (job->goal, JOB_START);1695 TEST_EQ (job->goal, JOB_START);
1664 TEST_EQ (job->state, JOB_SPAWNED);1696 TEST_EQ (job->state, JOB_SPAWNED);
@@ -1727,7 +1759,7 @@
1727 job->failed_process = PROCESS_INVALID;1759 job->failed_process = PROCESS_INVALID;
1728 job->exit_status = 0;1760 job->exit_status = 0;
17291761
1730 job_change_state (job, JOB_POST_START);1762 job_change_state (job, JOB_POST_STARTING);
17311763
1732 TEST_EQ (job->goal, JOB_START);1764 TEST_EQ (job->goal, JOB_START);
1733 TEST_EQ (job->state, JOB_POST_START);1765 TEST_EQ (job->state, JOB_POST_START);
@@ -1794,7 +1826,7 @@
1794 job->failed_process = PROCESS_INVALID;1826 job->failed_process = PROCESS_INVALID;
1795 job->exit_status = 0;1827 job->exit_status = 0;
17961828
1797 job_change_state (job, JOB_POST_START);1829 job_change_state (job, JOB_POST_STARTING);
17981830
1799 TEST_EQ (job->goal, JOB_START);1831 TEST_EQ (job->goal, JOB_START);
1800 TEST_EQ (job->state, JOB_RUNNING);1832 TEST_EQ (job->state, JOB_RUNNING);
@@ -1842,6 +1874,7 @@
1842 blocked = blocked_new (job, BLOCKED_EVENT, cause);1874 blocked = blocked_new (job, BLOCKED_EVENT, cause);
1843 event_block (cause);1875 event_block (cause);
1844 nih_list_add (&job->blocking, &blocked->entry);1876 nih_list_add (&job->blocking, &blocked->entry);
1877 TEST_NE_P (nih_main_loop_add_func (job, job_quit_with_state, job), NULL);
1845 }1878 }
18461879
1847 job->goal = JOB_START;1880 job->goal = JOB_START;
@@ -1858,7 +1891,8 @@
1858 job->exit_status = 0;1891 job->exit_status = 0;
18591892
1860 TEST_DIVERT_STDERR (output) {1893 TEST_DIVERT_STDERR (output) {
1861 job_change_state (job, JOB_POST_START);1894 job_change_state (job, JOB_POST_STARTING);
1895 while (nih_main_loop () < JOB_RUNNING) { }
1862 }1896 }
1863 rewind (output);1897 rewind (output);
18641898
@@ -2058,7 +2092,7 @@
2058 job->failed_process = PROCESS_INVALID;2092 job->failed_process = PROCESS_INVALID;
2059 job->exit_status = 0;2093 job->exit_status = 0;
20602094
2061 job_change_state (job, JOB_PRE_STOP);2095 job_change_state (job, JOB_PRE_STOPPING);
20622096
2063 TEST_EQ (job->goal, JOB_STOP);2097 TEST_EQ (job->goal, JOB_STOP);
2064 TEST_EQ (job->state, JOB_PRE_STOP);2098 TEST_EQ (job->state, JOB_PRE_STOP);
@@ -2125,7 +2159,7 @@
2125 job->failed_process = PROCESS_INVALID;2159 job->failed_process = PROCESS_INVALID;
2126 job->exit_status = 0;2160 job->exit_status = 0;
21272161
2128 job_change_state (job, JOB_PRE_STOP);2162 job_change_state (job, JOB_PRE_STOPPING);
21292163
2130 TEST_EQ (job->goal, JOB_STOP);2164 TEST_EQ (job->goal, JOB_STOP);
2131 TEST_EQ (job->state, JOB_STOPPING);2165 TEST_EQ (job->state, JOB_STOPPING);
@@ -2198,7 +2232,7 @@
2198 job->failed_process = PROCESS_INVALID;2232 job->failed_process = PROCESS_INVALID;
2199 job->exit_status = 0;2233 job->exit_status = 0;
22002234
2201 job_change_state (job, JOB_PRE_STOP);2235 job_change_state (job, JOB_PRE_STOPPING);
22022236
2203 TEST_EQ (job->goal, JOB_STOP);2237 TEST_EQ (job->goal, JOB_STOP);
2204 TEST_EQ (job->state, JOB_STOPPING);2238 TEST_EQ (job->state, JOB_STOPPING);
@@ -2283,7 +2317,7 @@
2283 job->failed_process = PROCESS_INVALID;2317 job->failed_process = PROCESS_INVALID;
2284 job->exit_status = 0;2318 job->exit_status = 0;
22852319
2286 job_change_state (job, JOB_PRE_STOP);2320 job_change_state (job, JOB_PRE_STOPPING);
22872321
2288 TEST_EQ (job->goal, JOB_STOP);2322 TEST_EQ (job->goal, JOB_STOP);
2289 TEST_EQ (job->state, JOB_STOPPING);2323 TEST_EQ (job->state, JOB_STOPPING);
@@ -2348,6 +2382,7 @@
2348 blocked = blocked_new (job, BLOCKED_EVENT, cause);2382 blocked = blocked_new (job, BLOCKED_EVENT, cause);
2349 event_block (cause);2383 event_block (cause);
2350 nih_list_add (&job->blocking, &blocked->entry);2384 nih_list_add (&job->blocking, &blocked->entry);
2385 TEST_NE_P (nih_main_loop_add_func (job, job_quit_with_state, job), NULL);
2351 }2386 }
23522387
2353 job->goal = JOB_STOP;2388 job->goal = JOB_STOP;
@@ -2364,7 +2399,8 @@
2364 job->exit_status = 0;2399 job->exit_status = 0;
23652400
2366 TEST_DIVERT_STDERR (output) {2401 TEST_DIVERT_STDERR (output) {
2367 job_change_state (job, JOB_PRE_STOP);2402 job_change_state (job, JOB_PRE_STOPPING);
2403 while (nih_main_loop () < JOB_STOPPING) {}
2368 }2404 }
2369 rewind (output);2405 rewind (output);
23702406
@@ -3100,7 +3136,7 @@
3100 job->failed_process = PROCESS_INVALID;3136 job->failed_process = PROCESS_INVALID;
3101 job->exit_status = 0;3137 job->exit_status = 0;
31023138
3103 job_change_state (job, JOB_POST_STOP);3139 job_change_state (job, JOB_POST_STOPPING);
31043140
3105 TEST_EQ (job->goal, JOB_STOP);3141 TEST_EQ (job->goal, JOB_STOP);
3106 TEST_EQ (job->state, JOB_POST_STOP);3142 TEST_EQ (job->state, JOB_POST_STOP);
@@ -3168,7 +3204,7 @@
31683204
3169 TEST_FREE_TAG (job);3205 TEST_FREE_TAG (job);
31703206
3171 job_change_state (job, JOB_POST_STOP);3207 job_change_state (job, JOB_POST_STOPPING);
31723208
3173 TEST_FREE (job);3209 TEST_FREE (job);
31743210
@@ -3228,7 +3264,8 @@
3228 TEST_FREE_TAG (job);3264 TEST_FREE_TAG (job);
32293265
3230 TEST_DIVERT_STDERR (output) {3266 TEST_DIVERT_STDERR (output) {
3231 job_change_state (job, JOB_POST_STOP);3267 job_change_state (job, JOB_POST_STOPPING);
3268 TEST_WATCH_LOOP ();
3232 }3269 }
3233 rewind (output);3270 rewind (output);
32343271
@@ -4000,22 +4037,31 @@
40004037
40014038
4002 /* Check that the next state if we're starting a starting job is4039 /* Check that the next state if we're starting a starting job is
4040 * sec-spawning.
4041 */
4042 TEST_FEATURE ("with starting job and a goal of start");
4043 job->goal = JOB_START;
4044 job->state = JOB_STARTING;
4045
4046 TEST_EQ (job_next_state (job), JOB_SECURITY_SPAWNING);
4047
4048 /* Check that the next state if we're starting a sec-spawning job is
4003 * security.4049 * security.
4004 */4050 */
4005 TEST_FEATURE ("with starting job and a goal of start");4051 TEST_FEATURE ("with starting job and a goal of start");
4006 job->goal = JOB_START;4052 job->goal = JOB_START;
4007 job->state = JOB_STARTING;4053 job->state = JOB_SECURITY_SPAWNING;
40084054
4009 TEST_EQ (job_next_state (job), JOB_SECURITY);4055 TEST_EQ (job_next_state (job), JOB_SECURITY);
40104056
4011 /* Check that the next state if we're starting a security job is4057 /* Check that the next state if we're starting a security job is
4012 * pre-start.4058 * pre-starting.
4013 */4059 */
4014 TEST_FEATURE ("with security job and a goal of start");4060 TEST_FEATURE ("with security job and a goal of start");
4015 job->goal = JOB_START;4061 job->goal = JOB_START;
4016 job->state = JOB_SECURITY;4062 job->state = JOB_SECURITY;
40174063
4018 TEST_EQ (job_next_state (job), JOB_PRE_START);4064 TEST_EQ (job_next_state (job), JOB_PRE_STARTING);
40194065
4020 /* Check that the next state if we're stopping an security job is4066 /* Check that the next state if we're stopping an security job is
4021 * stopping.4067 * stopping.
@@ -4026,6 +4072,25 @@
40264072
4027 TEST_EQ (job_next_state (job), JOB_STOPPING);4073 TEST_EQ (job_next_state (job), JOB_STOPPING);
40284074
4075 /* Check that the next state if we're starting a pre-starting job is
4076 * pre-start.
4077 */
4078 TEST_FEATURE ("with pre-stating job and a goal of start");
4079 job->goal = JOB_START;
4080 job->state = JOB_PRE_STARTING;
4081
4082 TEST_EQ (job_next_state (job), JOB_PRE_START);
4083
4084 /* Check that the next state if we're stopping a pre-starting job is
4085 * stopping.
4086 */
4087 TEST_FEATURE ("with pre-starting job and a goal of stop");
4088 job->goal = JOB_STOP;
4089 job->state = JOB_PRE_STARTING;
4090
4091 TEST_EQ (job_next_state (job), JOB_STOPPING);
4092
4093
4029 /* Check that the next state if we're stopping a pre-start job is4094 /* Check that the next state if we're stopping a pre-start job is
4030 * stopping.4095 * stopping.
4031 */4096 */
@@ -4043,6 +4108,15 @@
4043 job->goal = JOB_START;4108 job->goal = JOB_START;
4044 job->state = JOB_PRE_START;4109 job->state = JOB_PRE_START;
40454110
4111 TEST_EQ (job_next_state (job), JOB_SPAWNING);
4112
4113 /* Check that the next state if we're starting a spawning job is
4114 * spawned.
4115 */
4116 TEST_FEATURE ("with pre-start job and a goal of start");
4117 job->goal = JOB_START;
4118 job->state = JOB_SPAWNING;
4119
4046 TEST_EQ (job_next_state (job), JOB_SPAWNED);4120 TEST_EQ (job_next_state (job), JOB_SPAWNED);
40474121
40484122
@@ -4057,11 +4131,21 @@
40574131
40584132
4059 /* Check that the next state if we're starting a spawned job is4133 /* Check that the next state if we're starting a spawned job is
4134 * post-starting.
4135 */
4136 TEST_FEATURE ("with spawned job and a goal of start");
4137 job->goal = JOB_START;
4138 job->state = JOB_SPAWNED;
4139
4140 TEST_EQ (job_next_state (job), JOB_POST_STARTING);
4141
4142
4143 /* Check that the next state if we're starting a post-staring job is
4060 * post-start.4144 * post-start.
4061 */4145 */
4062 TEST_FEATURE ("with spawned job and a goal of start");4146 TEST_FEATURE ("with post-starting job and a goal of start");
4063 job->goal = JOB_START;4147 job->goal = JOB_START;
4064 job->state = JOB_SPAWNED;4148 job->state = JOB_POST_STARTING;
40654149
4066 TEST_EQ (job_next_state (job), JOB_POST_START);4150 TEST_EQ (job_next_state (job), JOB_POST_START);
40674151
@@ -4106,6 +4190,17 @@
4106 job->state = JOB_RUNNING;4190 job->state = JOB_RUNNING;
4107 job->pid[PROCESS_MAIN] = 1;4191 job->pid[PROCESS_MAIN] = 1;
41084192
4193 TEST_EQ (job_next_state (job), JOB_PRE_STOPPING);
4194
4195 /* Check that the next state if we're stopping a job with pre-stop is
4196 * pre-stop. This is the "normal" stop process, as called from the
4197 * goal change event.
4198 */
4199 TEST_FEATURE ("with pre-stopping job and a goal of stop");
4200 job->goal = JOB_STOP;
4201 job->state = JOB_PRE_STOPPING;
4202 job->pid[PROCESS_MAIN] = 1;
4203
4109 TEST_EQ (job_next_state (job), JOB_PRE_STOP);4204 TEST_EQ (job_next_state (job), JOB_PRE_STOP);
41104205
41114206
@@ -4193,6 +4288,16 @@
4193 job->goal = JOB_START;4288 job->goal = JOB_START;
4194 job->state = JOB_KILLED;4289 job->state = JOB_KILLED;
41954290
4291 TEST_EQ (job_next_state (job), JOB_POST_STOPPING);
4292
4293
4294 /* Check that the next state if we're starting a post-stopping
4295 * job is post-stop.
4296 */
4297 TEST_FEATURE ("with post-stopping job and a goal of start");
4298 job->goal = JOB_START;
4299 job->state = JOB_POST_STOPPING;
4300
4196 TEST_EQ (job_next_state (job), JOB_POST_STOP);4301 TEST_EQ (job_next_state (job), JOB_POST_STOP);
41974302
41984303
@@ -4203,6 +4308,16 @@
4203 job->goal = JOB_STOP;4308 job->goal = JOB_STOP;
4204 job->state = JOB_KILLED;4309 job->state = JOB_KILLED;
42054310
4311 TEST_EQ (job_next_state (job), JOB_POST_STOPPING);
4312
4313
4314 /* Check that the next state if we're stopping a post-stopping
4315 * job is post-stop.
4316 */
4317 TEST_FEATURE ("with post-stopping job and a goal of stop");
4318 job->goal = JOB_STOP;
4319 job->state = JOB_POST_STOPPING;
4320
4206 TEST_EQ (job_next_state (job), JOB_POST_STOP);4321 TEST_EQ (job_next_state (job), JOB_POST_STOP);
42074322
42084323
42094324
=== modified file 'init/tests/test_job_process.c'
--- init/tests/test_job_process.c 2013-11-11 10:13:08 +0000
+++ init/tests/test_job_process.c 2014-05-22 13:31:23 +0000
@@ -1,3 +1,6 @@
1/*
2 * FIXME: test_job_process has been left behind
3 */
1/* upstart4/* upstart
2 *5 *
3 * test_job_process.c - test suite for init/job_process.c6 * test_job_process.c - test suite for init/job_process.c
@@ -147,33 +150,6 @@
147static int get_available_pty_count (void) __attribute__((unused));150static int get_available_pty_count (void) __attribute__((unused));
148static void close_all_files (void);151static void close_all_files (void);
149152
150/**
151 * fd_valid:
152 * @fd: file descriptor.
153 *
154 * Return 1 if @fd is valid, else 0.
155 **/
156static int
157fd_valid (int fd)
158{
159 int flags = 0;
160
161 if (fd < 0)
162 return 0;
163
164 errno = 0;
165 flags = fcntl (fd, F_GETFL);
166
167 if (flags < 0)
168 return 0;
169
170 /* redundant really */
171 if (errno == EBADF)
172 return 0;
173
174 return 1;
175}
176
177static void153static void
178child (enum child_tests test,154child (enum child_tests test,
179 const char *filename)155 const char *filename)
@@ -409,7 +385,7 @@
409 * (Such tests are handled in the bundled test_user_sessions.sh script).385 * (Such tests are handled in the bundled test_user_sessions.sh script).
410 */386 */
411void387void
412test_run (void)388test_start (void)
413{389{
414 char dirname[PATH_MAX];390 char dirname[PATH_MAX];
415 JobClass *class = NULL;391 JobClass *class = NULL;
@@ -418,7 +394,7 @@
418 struct stat statbuf;394 struct stat statbuf;
419 char filename[PATH_MAX], buf[80];395 char filename[PATH_MAX], buf[80];
420 char function[PATH_MAX];396 char function[PATH_MAX];
421 int ret = -1, status, first;397 int status;
422 siginfo_t info;398 siginfo_t info;
423 char filebuf[1024];399 char filebuf[1024];
424 struct passwd *pwd;400 struct passwd *pwd;
@@ -433,7 +409,7 @@
433 log_unflushed_init ();409 log_unflushed_init ();
434 job_class_init ();410 job_class_init ();
435411
436 TEST_FUNCTION ("job_process_run");412 TEST_FUNCTION ("job_process_start");
437413
438 TEST_FILENAME (filename);414 TEST_FILENAME (filename);
439 program_name = "test";415 program_name = "test";
@@ -467,8 +443,7 @@
467 job->state = JOB_SPAWNED;443 job->state = JOB_SPAWNED;
468 }444 }
469445
470 ret = job_process_run (job, PROCESS_MAIN);446 job_process_start (job, PROCESS_MAIN);
471 TEST_EQ (ret, 0);
472447
473 TEST_NE (job->pid[PROCESS_MAIN], 0);448 TEST_NE (job->pid[PROCESS_MAIN], 0);
474449
@@ -502,8 +477,7 @@
502 job->state = JOB_SPAWNED;477 job->state = JOB_SPAWNED;
503 }478 }
504479
505 ret = job_process_run (job, PROCESS_MAIN);480 job_process_start (job, PROCESS_MAIN);
506 TEST_EQ (ret, 0);
507481
508 TEST_NE (job->pid[PROCESS_MAIN], 0);482 TEST_NE (job->pid[PROCESS_MAIN], 0);
509483
@@ -544,8 +518,7 @@
544 job->state = JOB_SPAWNED;518 job->state = JOB_SPAWNED;
545 }519 }
546520
547 ret = job_process_run (job, PROCESS_MAIN);521 job_process_start (job, PROCESS_MAIN);
548 TEST_EQ (ret, 0);
549522
550 TEST_NE (job->pid[PROCESS_MAIN], 0);523 TEST_NE (job->pid[PROCESS_MAIN], 0);
551524
@@ -584,8 +557,7 @@
584 job->state = JOB_SPAWNED;557 job->state = JOB_SPAWNED;
585 }558 }
586559
587 ret = job_process_run (job, PROCESS_MAIN);560 job_process_start (job, PROCESS_MAIN);
588 TEST_EQ (ret, 0);
589561
590 TEST_NE (job->pid[PROCESS_MAIN], 0);562 TEST_NE (job->pid[PROCESS_MAIN], 0);
591563
@@ -625,8 +597,7 @@
625 job->state = JOB_SPAWNED;597 job->state = JOB_SPAWNED;
626 }598 }
627599
628 ret = job_process_run (job, PROCESS_MAIN);600 job_process_start (job, PROCESS_MAIN);
629 TEST_EQ (ret, 0);
630601
631 TEST_NE (job->pid[PROCESS_MAIN], 0);602 TEST_NE (job->pid[PROCESS_MAIN], 0);
632603
@@ -672,8 +643,7 @@
672 "CRACKLE=FIZZ"));643 "CRACKLE=FIZZ"));
673 }644 }
674645
675 ret = job_process_run (job, PROCESS_MAIN);646 job_process_start (job, PROCESS_MAIN);
676 TEST_EQ (ret, 0);
677647
678 TEST_NE (job->pid[PROCESS_MAIN], 0);648 TEST_NE (job->pid[PROCESS_MAIN], 0);
679649
@@ -728,8 +698,7 @@
728 "CRACKLE=FIZZ"));698 "CRACKLE=FIZZ"));
729 }699 }
730700
731 ret = job_process_run (job, PROCESS_MAIN);701 job_process_start (job, PROCESS_MAIN);
732 TEST_EQ (ret, 0);
733702
734 TEST_NE (job->pid[PROCESS_MAIN], 0);703 TEST_NE (job->pid[PROCESS_MAIN], 0);
735704
@@ -785,8 +754,7 @@
785 "CRACKLE=FIZZ"));754 "CRACKLE=FIZZ"));
786 }755 }
787756
788 ret = job_process_run (job, PROCESS_PRE_STOP);757 job_process_start (job, PROCESS_PRE_STOP);
789 TEST_EQ (ret, 0);
790758
791 TEST_NE (job->pid[PROCESS_PRE_STOP], 0);759 TEST_NE (job->pid[PROCESS_PRE_STOP], 0);
792760
@@ -843,8 +811,7 @@
843 "CRACKLE=FIZZ"));811 "CRACKLE=FIZZ"));
844 }812 }
845813
846 ret = job_process_run (job, PROCESS_POST_STOP);814 job_process_start (job, PROCESS_POST_STOP);
847 TEST_EQ (ret, 0);
848815
849 TEST_NE (job->pid[PROCESS_POST_STOP], 0);816 TEST_NE (job->pid[PROCESS_POST_STOP], 0);
850817
@@ -894,36 +861,11 @@
894 job->state = JOB_SPAWNED;861 job->state = JOB_SPAWNED;
895 }862 }
896863
897 ret = job_process_run (job, PROCESS_MAIN);864 job_process_start (job, PROCESS_MAIN);
898 TEST_EQ (ret, 0);
899865
900 TEST_NE (job->pid[PROCESS_MAIN], 0);866 TEST_NE (job->pid[PROCESS_MAIN], 0);
901867
902 /* Loop until we've fed all of the data. */868 TEST_WATCH_LOOP ();
903 first = TRUE;
904 for (;;) {
905 fd_set readfds, writefds, exceptfds;
906 int nfds;
907
908 nfds = 0;
909 FD_ZERO (&readfds);
910 FD_ZERO (&writefds);
911 FD_ZERO (&exceptfds);
912
913 nih_io_select_fds (&nfds, &readfds,
914 &writefds, &exceptfds);
915 if (! nfds) {
916 if (first)
917 TEST_FAILED ("expected to have "
918 "data to feed.");
919 break;
920 }
921 first = FALSE;
922
923 select (nfds, &readfds, &writefds, &exceptfds, NULL);
924
925 nih_io_handle_fds (&readfds, &writefds, &exceptfds);
926 }
927869
928 waitpid (job->pid[PROCESS_MAIN], &status, 0);870 waitpid (job->pid[PROCESS_MAIN], &status, 0);
929 TEST_TRUE (WIFEXITED (status));871 TEST_TRUE (WIFEXITED (status));
@@ -962,8 +904,7 @@
962 job->trace_state = TRACE_NORMAL;904 job->trace_state = TRACE_NORMAL;
963 }905 }
964906
965 ret = job_process_run (job, PROCESS_MAIN);907 job_process_start (job, PROCESS_MAIN);
966 TEST_EQ (ret, 0);
967908
968 TEST_EQ (job->trace_forks, 0);909 TEST_EQ (job->trace_forks, 0);
969 TEST_EQ (job->trace_state, TRACE_NONE);910 TEST_EQ (job->trace_state, TRACE_NONE);
@@ -1002,8 +943,7 @@
1002 job->trace_state = TRACE_NORMAL;943 job->trace_state = TRACE_NORMAL;
1003 }944 }
1004945
1005 ret = job_process_run (job, PROCESS_PRE_START);946 job_process_start (job, PROCESS_PRE_START);
1006 TEST_EQ (ret, 0);
1007947
1008 TEST_EQ (job->trace_forks, 0);948 TEST_EQ (job->trace_forks, 0);
1009 TEST_EQ (job->trace_state, TRACE_NONE);949 TEST_EQ (job->trace_state, TRACE_NONE);
@@ -1044,8 +984,7 @@
1044 job->trace_state = TRACE_NORMAL;984 job->trace_state = TRACE_NORMAL;
1045 }985 }
1046986
1047 ret = job_process_run (job, PROCESS_MAIN);987 job_process_start (job, PROCESS_MAIN);
1048 TEST_EQ (ret, 0);
1049988
1050 TEST_EQ (job->trace_forks, 0);989 TEST_EQ (job->trace_forks, 0);
1051 TEST_EQ (job->trace_state, TRACE_NEW);990 TEST_EQ (job->trace_state, TRACE_NEW);
@@ -1095,8 +1034,7 @@
1095 job->trace_state = TRACE_NORMAL;1034 job->trace_state = TRACE_NORMAL;
1096 }1035 }
10971036
1098 ret = job_process_run (job, PROCESS_MAIN);1037 job_process_start (job, PROCESS_MAIN);
1099 TEST_EQ (ret, 0);
11001038
1101 TEST_EQ (job->trace_forks, 0);1039 TEST_EQ (job->trace_forks, 0);
1102 TEST_EQ (job->trace_state, TRACE_NEW);1040 TEST_EQ (job->trace_state, TRACE_NEW);
@@ -1122,7 +1060,7 @@
1122 }1060 }
11231061
1124 /* Check that if we try and run a command that doesn't exist,1062 /* Check that if we try and run a command that doesn't exist,
1125 * job_process_run() raises a ProcessError and the command doesn't1063 * job_process_start() raises a ProcessError and the command doesn't
1126 * have any stored process id for it.1064 * have any stored process id for it.
1127 */1065 */
1128 TEST_FEATURE ("with no such file");1066 TEST_FEATURE ("with no such file");
@@ -1144,11 +1082,12 @@
1144 }1082 }
11451083
1146 TEST_DIVERT_STDERR (output) {1084 TEST_DIVERT_STDERR (output) {
1147 ret = job_process_run (job, PROCESS_MAIN);1085 job_process_start (job, PROCESS_MAIN);
1086 TEST_WATCH_LOOP ();
1087 event_poll ();
1148 }1088 }
1149 rewind (output);1089 rewind (output);
1150 TEST_LT (ret, 0);1090
1151
1152 TEST_EQ (job->pid[PROCESS_MAIN], 0);1091 TEST_EQ (job->pid[PROCESS_MAIN], 0);
11531092
1154 TEST_FILE_EQ (output, ("test: Failed to spawn test (foo) main "1093 TEST_FILE_EQ (output, ("test: Failed to spawn test (foo) main "
@@ -1195,8 +1134,7 @@
1195 job->goal = JOB_START;1134 job->goal = JOB_START;
1196 job->state = JOB_SPAWNED;1135 job->state = JOB_SPAWNED;
11971136
1198 ret = job_process_run (job, PROCESS_MAIN);1137 job_process_start (job, PROCESS_MAIN);
1199 TEST_EQ (ret, 0);
12001138
1201 TEST_NE (job->pid[PROCESS_MAIN], 0);1139 TEST_NE (job->pid[PROCESS_MAIN], 0);
12021140
@@ -1263,8 +1201,7 @@
1263 job->goal = JOB_START;1201 job->goal = JOB_START;
1264 job->state = JOB_SPAWNED;1202 job->state = JOB_SPAWNED;
12651203
1266 ret = job_process_run (job, PROCESS_MAIN);1204 job_process_start (job, PROCESS_MAIN);
1267 TEST_EQ (ret, 0);
12681205
1269 TEST_NE (job->pid[PROCESS_MAIN], 0);1206 TEST_NE (job->pid[PROCESS_MAIN], 0);
12701207
@@ -1331,8 +1268,7 @@
1331 job->goal = JOB_START;1268 job->goal = JOB_START;
1332 job->state = JOB_SPAWNED;1269 job->state = JOB_SPAWNED;
13331270
1334 ret = job_process_run (job, PROCESS_MAIN);1271 job_process_start (job, PROCESS_MAIN);
1335 TEST_EQ (ret, 0);
13361272
1337 TEST_NE (job->pid[PROCESS_MAIN], 0);1273 TEST_NE (job->pid[PROCESS_MAIN], 0);
13381274
@@ -1399,8 +1335,7 @@
1399 job->goal = JOB_START;1335 job->goal = JOB_START;
1400 job->state = JOB_SPAWNED;1336 job->state = JOB_SPAWNED;
14011337
1402 ret = job_process_run (job, PROCESS_MAIN);1338 job_process_start (job, PROCESS_MAIN);
1403 TEST_EQ (ret, 0);
14041339
1405 TEST_NE (job->pid[PROCESS_MAIN], 0);1340 TEST_NE (job->pid[PROCESS_MAIN], 0);
14061341
@@ -1462,8 +1397,7 @@
1462 job->goal = JOB_START;1397 job->goal = JOB_START;
1463 job->state = JOB_SPAWNED;1398 job->state = JOB_SPAWNED;
14641399
1465 ret = job_process_run (job, PROCESS_MAIN);1400 job_process_start (job, PROCESS_MAIN);
1466 TEST_EQ (ret, 0);
14671401
1468 TEST_NE (job->pid[PROCESS_MAIN], 0);1402 TEST_NE (job->pid[PROCESS_MAIN], 0);
14691403
@@ -1499,8 +1433,7 @@
1499 job->goal = JOB_START;1433 job->goal = JOB_START;
1500 job->state = JOB_SPAWNED;1434 job->state = JOB_SPAWNED;
15011435
1502 ret = job_process_run (job, PROCESS_MAIN);1436 job_process_start (job, PROCESS_MAIN);
1503 TEST_EQ (ret, 0);
15041437
1505 TEST_NE (job->pid[PROCESS_MAIN], 0);1438 TEST_NE (job->pid[PROCESS_MAIN], 0);
15061439
@@ -1536,8 +1469,7 @@
1536 job->goal = JOB_START;1469 job->goal = JOB_START;
1537 job->state = JOB_SPAWNED;1470 job->state = JOB_SPAWNED;
15381471
1539 ret = job_process_run (job, PROCESS_MAIN);1472 job_process_start (job, PROCESS_MAIN);
1540 TEST_EQ (ret, 0);
15411473
1542 TEST_NE (job->pid[PROCESS_MAIN], 0);1474 TEST_NE (job->pid[PROCESS_MAIN], 0);
15431475
@@ -1583,11 +1515,13 @@
1583 job->goal = JOB_START;1515 job->goal = JOB_START;
1584 job->state = JOB_SPAWNED;1516 job->state = JOB_SPAWNED;
15851517
1586 ret = job_process_run (job, PROCESS_MAIN);1518 job_process_start (job, PROCESS_MAIN);
1587 TEST_EQ (ret, 0);
15881519
1589 TEST_NE (job->pid[PROCESS_MAIN], 0);1520 TEST_NE (job->pid[PROCESS_MAIN], 0);
15901521
1522 /* XXX: call 0: async process setup */
1523 TEST_WATCH_UPDATE ();
1524
1591 /* XXX: call 1: wait for script write to child shell */1525 /* XXX: call 1: wait for script write to child shell */
1592 TEST_WATCH_UPDATE ();1526 TEST_WATCH_UPDATE ();
15931527
@@ -1613,10 +1547,10 @@
16131547
1614 /* Note we can't use TEST_ALLOC_FAIL() for this test since on1548 /* Note we can't use TEST_ALLOC_FAIL() for this test since on
1615 * the ENOMEM loop all we could do is discard the error and1549 * the ENOMEM loop all we could do is discard the error and
1616 * continue since job_process_run() calls job_process_spawn()1550 * continue since job_process_start() calls job_process_spawn()
1617 * repeatedly until it works, but the alloc fails in log_new()1551 * repeatedly until it works, but the alloc fails in log_new()
1618 * invoked by job_process_spawn() such that when we've left1552 * invoked by job_process_spawn() such that when we've left
1619 * job_process_run(), it's too late.1553 * job_process_start(), it's too late.
1620 *1554 *
1621 * However, we test this scenario in test_spawn() so all is not1555 * However, we test this scenario in test_spawn() so all is not
1622 * lost.1556 * lost.
@@ -1637,8 +1571,7 @@
1637 job->goal = JOB_START;1571 job->goal = JOB_START;
1638 job->state = JOB_SPAWNED;1572 job->state = JOB_SPAWNED;
16391573
1640 ret = job_process_run (job, PROCESS_MAIN);1574 job_process_start (job, PROCESS_MAIN);
1641 TEST_EQ (ret, 0);
16421575
1643 TEST_NE (job->pid[PROCESS_MAIN], 0);1576 TEST_NE (job->pid[PROCESS_MAIN], 0);
16441577
@@ -1695,11 +1628,13 @@
1695 job->goal = JOB_START;1628 job->goal = JOB_START;
1696 job->state = JOB_SPAWNED;1629 job->state = JOB_SPAWNED;
16971630
1698 ret = job_process_run (job, PROCESS_MAIN);1631 job_process_start (job, PROCESS_MAIN);
1699 TEST_EQ (ret, 0);
17001632
1701 TEST_NE (job->pid[PROCESS_MAIN], 0);1633 TEST_NE (job->pid[PROCESS_MAIN], 0);
17021634
1635 /* wait for process to setup */
1636 TEST_WATCH_UPDATE ();
1637
1703 /* wait for read from pty allowing logger to write to log file */1638 /* wait for read from pty allowing logger to write to log file */
1704 TEST_WATCH_UPDATE ();1639 TEST_WATCH_UPDATE ();
17051640
@@ -1779,11 +1714,13 @@
1779 job->goal = JOB_START;1714 job->goal = JOB_START;
1780 job->state = JOB_SPAWNED;1715 job->state = JOB_SPAWNED;
17811716
1782 ret = job_process_run (job, PROCESS_MAIN);1717 job_process_start (job, PROCESS_MAIN);
1783 TEST_EQ (ret, 0);
17841718
1785 TEST_NE (job->pid[PROCESS_MAIN], 0);1719 TEST_NE (job->pid[PROCESS_MAIN], 0);
17861720
1721 /* wait for process to setup */
1722 TEST_WATCH_UPDATE ();
1723
1787 /* wait for read from pty allowing logger to write to log file */1724 /* wait for read from pty allowing logger to write to log file */
1788 TEST_WATCH_UPDATE ();1725 TEST_WATCH_UPDATE ();
17891726
@@ -1861,10 +1798,10 @@
18611798
1862 /* Note we can't use TEST_ALLOC_FAIL() for this test since on1799 /* Note we can't use TEST_ALLOC_FAIL() for this test since on
1863 * the ENOMEM loop all we could do is discard the error and1800 * the ENOMEM loop all we could do is discard the error and
1864 * continue since job_process_run() calls job_process_spawn()1801 * continue since job_process_start() calls job_process_spawn()
1865 * repeatedly until it works, but the alloc fails in log_new()1802 * repeatedly until it works, but the alloc fails in log_new()
1866 * invoked by job_process_spawn() such that when we've left1803 * invoked by job_process_spawn() such that when we've left
1867 * job_process_run(), it's too late.1804 * job_process_start(), it's too late.
1868 *1805 *
1869 * However, we test this scenario in test_spawn() so all is not1806 * However, we test this scenario in test_spawn() so all is not
1870 * lost.1807 * lost.
@@ -1885,11 +1822,13 @@
1885 job->goal = JOB_START;1822 job->goal = JOB_START;
1886 job->state = JOB_SPAWNED;1823 job->state = JOB_SPAWNED;
18871824
1888 ret = job_process_run (job, PROCESS_MAIN);1825 job_process_start (job, PROCESS_MAIN);
1889 TEST_EQ (ret, 0);
18901826
1891 TEST_NE (job->pid[PROCESS_MAIN], 0);1827 TEST_NE (job->pid[PROCESS_MAIN], 0);
18921828
1829 /* wait for process to setup */
1830 TEST_WATCH_UPDATE ();
1831
1893 /* XXX: call 1: wait for script write to child shell */1832 /* XXX: call 1: wait for script write to child shell */
1894 TEST_WATCH_UPDATE ();1833 TEST_WATCH_UPDATE ();
18951834
@@ -1948,11 +1887,13 @@
1948 job->goal = JOB_START;1887 job->goal = JOB_START;
1949 job->state = JOB_SPAWNED;1888 job->state = JOB_SPAWNED;
19501889
1951 ret = job_process_run (job, PROCESS_MAIN);1890 job_process_start (job, PROCESS_MAIN);
1952 TEST_EQ (ret, 0);
19531891
1954 TEST_NE (job->pid[PROCESS_MAIN], 0);1892 TEST_NE (job->pid[PROCESS_MAIN], 0);
19551893
1894 /* wait for process to setup */
1895 TEST_WATCH_UPDATE ();
1896
1956 /* wait for read from pty allowing logger to write to log file */1897 /* wait for read from pty allowing logger to write to log file */
1957 TEST_WATCH_UPDATE ();1898 TEST_WATCH_UPDATE ();
19581899
@@ -2017,11 +1958,13 @@
2017 job->goal = JOB_START;1958 job->goal = JOB_START;
2018 job->state = JOB_SPAWNED;1959 job->state = JOB_SPAWNED;
20191960
2020 ret = job_process_run (job, PROCESS_MAIN);1961 job_process_start (job, PROCESS_MAIN);
2021 TEST_EQ (ret, 0);
20221962
2023 TEST_NE (job->pid[PROCESS_MAIN], 0);1963 TEST_NE (job->pid[PROCESS_MAIN], 0);
20241964
1965 /* wait for process to setup */
1966 TEST_WATCH_UPDATE ();
1967
2025 /* XXX: call 1: wait for script write to child shell */1968 /* XXX: call 1: wait for script write to child shell */
2026 TEST_WATCH_UPDATE ();1969 TEST_WATCH_UPDATE ();
20271970
@@ -2064,10 +2007,10 @@
20642007
2065 /* Note we can't use TEST_ALLOC_FAIL() for this test since on2008 /* Note we can't use TEST_ALLOC_FAIL() for this test since on
2066 * the ENOMEM loop all we could do is discard the error and2009 * the ENOMEM loop all we could do is discard the error and
2067 * continue since job_process_run() calls job_process_spawn()2010 * continue since job_process_start() calls job_process_spawn()
2068 * repeatedly until it works, but the alloc fails in log_new()2011 * repeatedly until it works, but the alloc fails in log_new()
2069 * invoked by job_process_spawn() such that when we've left2012 * invoked by job_process_spawn() such that when we've left
2070 * job_process_run(), it's too late.2013 * job_process_start(), it's too late.
2071 *2014 *
2072 * However, we test this scenario in test_spawn() so all is not2015 * However, we test this scenario in test_spawn() so all is not
2073 * lost.2016 * lost.
@@ -2088,8 +2031,7 @@
2088 job->goal = JOB_START;2031 job->goal = JOB_START;
2089 job->state = JOB_SPAWNED;2032 job->state = JOB_SPAWNED;
20902033
2091 ret = job_process_run (job, PROCESS_MAIN);2034 job_process_start (job, PROCESS_MAIN);
2092 TEST_EQ (ret, 0);
20932035
2094 TEST_NE (job->pid[PROCESS_MAIN], 0);2036 TEST_NE (job->pid[PROCESS_MAIN], 0);
20952037
@@ -2135,7 +2077,7 @@
2135 * XXX: TEST_WATCH_UPDATE() *TWICE* to ensure select(2) is2077 * XXX: TEST_WATCH_UPDATE() *TWICE* to ensure select(2) is
2136 * XXX: called twice.2078 * XXX: called twice.
2137 *2079 *
2138 * This is required since job_process_run() uses an NihIo object2080 * This is required since job_process_start() uses an NihIo object
2139 * to squirt the script to the shell sub-process and this2081 * to squirt the script to the shell sub-process and this
2140 * triggers select to return when the data is written to the shell.2082 * triggers select to return when the data is written to the shell.
2141 * However, we don't care about that directly - we care more about2083 * However, we don't care about that directly - we care more about
@@ -2144,7 +2086,7 @@
2144 * written.2086 * written.
2145 *2087 *
2146 * Note that the 2nd call to TEST_WATCH_UPDATE would not be2088 * Note that the 2nd call to TEST_WATCH_UPDATE would not be
2147 * required should job_process_run() simple invoke write(2) to2089 * required should job_process_start() simple invoke write(2) to
2148 * send the data.2090 * send the data.
2149 */2091 */
21502092
@@ -2165,11 +2107,13 @@
2165 job->goal = JOB_START;2107 job->goal = JOB_START;
2166 job->state = JOB_SPAWNED;2108 job->state = JOB_SPAWNED;
21672109
2168 ret = job_process_run (job, PROCESS_MAIN);2110 job_process_start (job, PROCESS_MAIN);
2169 TEST_EQ (ret, 0);
21702111
2171 TEST_NE (job->pid[PROCESS_MAIN], 0);2112 TEST_NE (job->pid[PROCESS_MAIN], 0);
21722113
2114 /* wait for process to setup */
2115 TEST_WATCH_UPDATE ();
2116
2173 /* XXX: call 1: wait for script write to child shell */2117 /* XXX: call 1: wait for script write to child shell */
2174 TEST_WATCH_UPDATE ();2118 TEST_WATCH_UPDATE ();
21752119
@@ -2227,8 +2171,7 @@
2227 job->goal = JOB_START;2171 job->goal = JOB_START;
2228 job->state = JOB_SPAWNED;2172 job->state = JOB_SPAWNED;
22292173
2230 ret = job_process_run (job, PROCESS_MAIN);2174 job_process_start (job, PROCESS_MAIN);
2231 TEST_EQ (ret, 0);
22322175
2233 TEST_NE (job->pid[PROCESS_MAIN], 0);2176 TEST_NE (job->pid[PROCESS_MAIN], 0);
22342177
@@ -2287,8 +2230,7 @@
2287 job->goal = JOB_START;2230 job->goal = JOB_START;
2288 job->state = JOB_SPAWNED;2231 job->state = JOB_SPAWNED;
22892232
2290 ret = job_process_run (job, PROCESS_MAIN);2233 job_process_start (job, PROCESS_MAIN);
2291 TEST_EQ (ret, 0);
22922234
2293 TEST_NE (job->pid[PROCESS_MAIN], 0);2235 TEST_NE (job->pid[PROCESS_MAIN], 0);
22942236
@@ -2352,8 +2294,7 @@
2352 job->goal = JOB_START;2294 job->goal = JOB_START;
2353 job->state = JOB_SPAWNED;2295 job->state = JOB_SPAWNED;
23542296
2355 ret = job_process_run (job, PROCESS_MAIN);2297 job_process_start (job, PROCESS_MAIN);
2356 TEST_EQ (ret, 0);
23572298
2358 TEST_NE (job->pid[PROCESS_MAIN], 0);2299 TEST_NE (job->pid[PROCESS_MAIN], 0);
23592300
@@ -2414,12 +2355,12 @@
2414 job->goal = JOB_START;2355 job->goal = JOB_START;
2415 job->state = JOB_SPAWNED;2356 job->state = JOB_SPAWNED;
24162357
2417 ret = job_process_run (job, PROCESS_MAIN);2358 job_process_start (job, PROCESS_MAIN);
2418 TEST_EQ (ret, 0);
24192359
2420 TEST_NE (job->pid[PROCESS_MAIN], 0);2360 TEST_NE (job->pid[PROCESS_MAIN], 0);
24212361
2422 TEST_WATCH_UPDATE ();2362 TEST_WATCH_UPDATE ();
2363 TEST_WATCH_UPDATE ();
2423 waitpid (job->pid[PROCESS_MAIN], &status, 0);2364 waitpid (job->pid[PROCESS_MAIN], &status, 0);
2424 TEST_TRUE (WIFEXITED (status));2365 TEST_TRUE (WIFEXITED (status));
2425 TEST_EQ (WEXITSTATUS (status), 0);2366 TEST_EQ (WEXITSTATUS (status), 0);
@@ -2474,8 +2415,7 @@
2474 job->goal = JOB_START;2415 job->goal = JOB_START;
2475 job->state = JOB_SPAWNED;2416 job->state = JOB_SPAWNED;
24762417
2477 ret = job_process_run (job, PROCESS_MAIN);2418 job_process_start (job, PROCESS_MAIN);
2478 TEST_EQ (ret, 0);
24792419
2480 TEST_NE (job->pid[PROCESS_MAIN], 0);2420 TEST_NE (job->pid[PROCESS_MAIN], 0);
24812421
@@ -2537,8 +2477,7 @@
2537 job->goal = JOB_START;2477 job->goal = JOB_START;
2538 job->state = JOB_SPAWNED;2478 job->state = JOB_SPAWNED;
25392479
2540 ret = job_process_run (job, PROCESS_MAIN);2480 job_process_start (job, PROCESS_MAIN);
2541 TEST_EQ (ret, 0);
25422481
2543 TEST_NE (job->pid[PROCESS_MAIN], 0);2482 TEST_NE (job->pid[PROCESS_MAIN], 0);
25442483
@@ -2597,12 +2536,12 @@
2597 job->goal = JOB_START;2536 job->goal = JOB_START;
2598 job->state = JOB_SPAWNED;2537 job->state = JOB_SPAWNED;
25992538
2600 ret = job_process_run (job, PROCESS_MAIN);2539 job_process_start (job, PROCESS_MAIN);
2601 TEST_EQ (ret, 0);
26022540
2603 TEST_NE (job->pid[PROCESS_MAIN], 0);2541 TEST_NE (job->pid[PROCESS_MAIN], 0);
26042542
2605 TEST_WATCH_UPDATE ();2543 TEST_WATCH_UPDATE ();
2544 TEST_WATCH_UPDATE ();
26062545
2607 waitpid (job->pid[PROCESS_MAIN], &status, 0);2546 waitpid (job->pid[PROCESS_MAIN], &status, 0);
2608 TEST_TRUE (WIFEXITED (status));2547 TEST_TRUE (WIFEXITED (status));
@@ -2659,8 +2598,7 @@
2659 job->goal = JOB_START;2598 job->goal = JOB_START;
2660 job->state = JOB_SPAWNED;2599 job->state = JOB_SPAWNED;
26612600
2662 ret = job_process_run (job, PROCESS_MAIN);2601 job_process_start (job, PROCESS_MAIN);
2663 TEST_EQ (ret, 0);
26642602
2665 TEST_NE (job->pid[PROCESS_MAIN], 0);2603 TEST_NE (job->pid[PROCESS_MAIN], 0);
26662604
@@ -2725,8 +2663,7 @@
2725 job->goal = JOB_START;2663 job->goal = JOB_START;
2726 job->state = JOB_SPAWNED;2664 job->state = JOB_SPAWNED;
27272665
2728 ret = job_process_run (job, PROCESS_MAIN);2666 job_process_start (job, PROCESS_MAIN);
2729 TEST_EQ (ret, 0);
27302667
2731 TEST_NE (job->pid[PROCESS_MAIN], 0);2668 TEST_NE (job->pid[PROCESS_MAIN], 0);
27322669
@@ -2787,12 +2724,12 @@
2787 job->goal = JOB_START;2724 job->goal = JOB_START;
2788 job->state = JOB_SPAWNED;2725 job->state = JOB_SPAWNED;
27892726
2790 ret = job_process_run (job, PROCESS_MAIN);2727 job_process_start (job, PROCESS_MAIN);
2791 TEST_EQ (ret, 0);
27922728
2793 TEST_NE (job->pid[PROCESS_MAIN], 0);2729 TEST_NE (job->pid[PROCESS_MAIN], 0);
27942730
2795 TEST_WATCH_UPDATE ();2731 TEST_WATCH_UPDATE ();
2732 TEST_WATCH_UPDATE ();
27962733
2797 waitpid (job->pid[PROCESS_MAIN], &status, 0);2734 waitpid (job->pid[PROCESS_MAIN], &status, 0);
2798 TEST_TRUE (WIFEXITED (status));2735 TEST_TRUE (WIFEXITED (status));
@@ -2851,8 +2788,7 @@
2851 job->goal = JOB_START;2788 job->goal = JOB_START;
2852 job->state = JOB_SPAWNED;2789 job->state = JOB_SPAWNED;
28532790
2854 ret = job_process_run (job, PROCESS_MAIN);2791 job_process_start (job, PROCESS_MAIN);
2855 TEST_EQ (ret, 0);
28562792
2857 TEST_NE (job->pid[PROCESS_MAIN], 0);2793 TEST_NE (job->pid[PROCESS_MAIN], 0);
28582794
@@ -2913,8 +2849,7 @@
2913 job->goal = JOB_START;2849 job->goal = JOB_START;
2914 job->state = JOB_SPAWNED;2850 job->state = JOB_SPAWNED;
29152851
2916 ret = job_process_run (job, PROCESS_MAIN);2852 job_process_start (job, PROCESS_MAIN);
2917 TEST_EQ (ret, 0);
29182853
2919 TEST_NE (job->pid[PROCESS_MAIN], 0);2854 TEST_NE (job->pid[PROCESS_MAIN], 0);
29202855
@@ -2973,8 +2908,7 @@
2973 job->goal = JOB_START;2908 job->goal = JOB_START;
2974 job->state = JOB_SPAWNED;2909 job->state = JOB_SPAWNED;
29752910
2976 ret = job_process_run (job, PROCESS_MAIN);2911 job_process_start (job, PROCESS_MAIN);
2977 TEST_EQ (ret, 0);
29782912
2979 TEST_NE (job->pid[PROCESS_MAIN], 0);2913 TEST_NE (job->pid[PROCESS_MAIN], 0);
29802914
@@ -3037,8 +2971,7 @@
3037 job->goal = JOB_START;2971 job->goal = JOB_START;
3038 job->state = JOB_SPAWNED;2972 job->state = JOB_SPAWNED;
30392973
3040 ret = job_process_run (job, PROCESS_MAIN);2974 job_process_start (job, PROCESS_MAIN);
3041 TEST_EQ (ret, 0);
30422975
3043 TEST_NE (job->pid[PROCESS_MAIN], 0);2976 TEST_NE (job->pid[PROCESS_MAIN], 0);
30442977
@@ -3112,8 +3045,9 @@
3112 output = tmpfile ();3045 output = tmpfile ();
3113 TEST_NE_P (output, NULL);3046 TEST_NE_P (output, NULL);
3114 TEST_DIVERT_STDERR (output) {3047 TEST_DIVERT_STDERR (output) {
3115 ret = job_process_run (job, PROCESS_MAIN);3048 job_process_start (job, PROCESS_MAIN);
3116 TEST_LT (ret, 0);3049 TEST_WATCH_UPDATE ();
3050 event_poll ();
3117 }3051 }
3118 fclose (output);3052 fclose (output);
31193053
@@ -3161,8 +3095,8 @@
3161 job->goal = JOB_START;3095 job->goal = JOB_START;
3162 job->state = JOB_SPAWNED;3096 job->state = JOB_SPAWNED;
31633097
3164 ret = job_process_run (job, PROCESS_MAIN);3098 job_process_start (job, PROCESS_MAIN);
3165 TEST_LT (ret, 0);3099 TEST_WATCH_UPDATE ();
31663100
3167 /* We don't expect a logfile to be written since there is no3101 /* We don't expect a logfile to be written since there is no
3168 * accompanying shell to write the error.3102 * accompanying shell to write the error.
@@ -3173,10 +3107,10 @@
3173 job->goal = JOB_STOP;3107 job->goal = JOB_STOP;
3174 job->state = JOB_POST_STOP;3108 job->state = JOB_POST_STOP;
31753109
3176 ret = job_process_run (job, PROCESS_POST_STOP);3110 job_process_start (job, PROCESS_POST_STOP);
3177 TEST_EQ (ret, 0);
31783111
3179 TEST_NE (job->pid[PROCESS_POST_STOP], 0);3112 TEST_NE (job->pid[PROCESS_POST_STOP], 0);
3113 TEST_WATCH_UPDATE ();
31803114
3181 /* Flush the io so that the shell on the client side3115 /* Flush the io so that the shell on the client side
3182 * gets the data (the script to execute).3116 * gets the data (the script to execute).
@@ -3187,8 +3121,11 @@
3187 TEST_TRUE (WIFEXITED (status));3121 TEST_TRUE (WIFEXITED (status));
3188 TEST_EQ (WEXITSTATUS (status), 0);3122 TEST_EQ (WEXITSTATUS (status), 0);
31893123
3124 TEST_WATCH_UPDATE ();
3125
3190 /* .. but the post stop should have written data */3126 /* .. but the post stop should have written data */
3191 TEST_EQ (stat (filename, &statbuf), 0);3127 TEST_EQ (stat (filename, &statbuf), 0);
3128 event_poll ();
3192 }3129 }
3193 fclose (output);3130 fclose (output);
31943131
@@ -3241,8 +3178,9 @@
3241 job->goal = JOB_START;3178 job->goal = JOB_START;
3242 job->state = JOB_SPAWNED;3179 job->state = JOB_SPAWNED;
32433180
3244 ret = job_process_run (job, PROCESS_MAIN);3181 job_process_start (job, PROCESS_MAIN);
3245 TEST_LT (ret, 0);3182 TEST_WATCH_UPDATE ();
3183 TEST_WATCH_UPDATE ();
32463184
3247 /* We don't expect a logfile to be written since there is no3185 /* We don't expect a logfile to be written since there is no
3248 * accompanying shell to write the error.3186 * accompanying shell to write the error.
@@ -3253,8 +3191,8 @@
3253 job->goal = JOB_STOP;3191 job->goal = JOB_STOP;
3254 job->state = JOB_POST_STOP;3192 job->state = JOB_POST_STOP;
32553193
3256 ret = job_process_run (job, PROCESS_POST_STOP);3194 job_process_start (job, PROCESS_POST_STOP);
3257 TEST_EQ (ret, 0);3195 TEST_WATCH_UPDATE ();
32583196
3259 TEST_NE (job->pid[PROCESS_POST_STOP], 0);3197 TEST_NE (job->pid[PROCESS_POST_STOP], 0);
32603198
@@ -3272,6 +3210,7 @@
32723210
3273 /* .. but the post stop should have written data */3211 /* .. but the post stop should have written data */
3274 TEST_EQ (stat (filename, &statbuf), 0);3212 TEST_EQ (stat (filename, &statbuf), 0);
3213 event_poll ();
3275 }3214 }
3276 fclose (output);3215 fclose (output);
32773216
@@ -3325,8 +3264,8 @@
3325 job->goal = JOB_START;3264 job->goal = JOB_START;
3326 job->state = JOB_SPAWNED;3265 job->state = JOB_SPAWNED;
33273266
3328 ret = job_process_run (job, PROCESS_MAIN);3267 job_process_start (job, PROCESS_MAIN);
3329 TEST_LT (ret, 0);3268 TEST_WATCH_UPDATE ();
33303269
3331 /* We don't expect a logfile to be written since there is no3270 /* We don't expect a logfile to be written since there is no
3332 * accompanying shell to write the error.3271 * accompanying shell to write the error.
@@ -3337,8 +3276,8 @@
3337 job->goal = JOB_STOP;3276 job->goal = JOB_STOP;
3338 job->state = JOB_POST_STOP;3277 job->state = JOB_POST_STOP;
33393278
3340 ret = job_process_run (job, PROCESS_POST_STOP);3279 job_process_start (job, PROCESS_POST_STOP);
3341 TEST_EQ (ret, 0);3280 TEST_WATCH_UPDATE ();
33423281
3343 TEST_NE (job->pid[PROCESS_POST_STOP], 0);3282 TEST_NE (job->pid[PROCESS_POST_STOP], 0);
33443283
@@ -3351,8 +3290,11 @@
3351 TEST_TRUE (WIFEXITED (status));3290 TEST_TRUE (WIFEXITED (status));
3352 TEST_EQ (WEXITSTATUS (status), 0);3291 TEST_EQ (WEXITSTATUS (status), 0);
33533292
3293 TEST_WATCH_UPDATE ();
3294
3354 /* .. but the post stop should have written data */3295 /* .. but the post stop should have written data */
3355 TEST_EQ (stat (filename, &statbuf), 0);3296 TEST_EQ (stat (filename, &statbuf), 0);
3297 event_poll ();
3356 }3298 }
3357 fclose (output);3299 fclose (output);
33583300
@@ -3405,8 +3347,8 @@
3405 job->goal = JOB_START;3347 job->goal = JOB_START;
3406 job->state = JOB_SPAWNED;3348 job->state = JOB_SPAWNED;
34073349
3408 ret = job_process_run (job, PROCESS_MAIN);3350 job_process_start (job, PROCESS_MAIN);
3409 TEST_LT (ret, 0);3351 TEST_WATCH_UPDATE ();
34103352
3411 /* We don't expect a logfile to be written since there is no3353 /* We don't expect a logfile to be written since there is no
3412 * accompanying shell to write the error.3354 * accompanying shell to write the error.
@@ -3417,12 +3359,13 @@
3417 job->goal = JOB_STOP;3359 job->goal = JOB_STOP;
3418 job->state = JOB_POST_STOP;3360 job->state = JOB_POST_STOP;
34193361
3420 ret = job_process_run (job, PROCESS_POST_STOP);3362 job_process_start (job, PROCESS_POST_STOP);
3421 TEST_LT (ret, 0);3363 TEST_WATCH_UPDATE ();
34223364
3423 /* Again, no file expected */3365 /* Again, no file expected */
3424 TEST_EQ (stat (filename, &statbuf), -1);3366 TEST_EQ (stat (filename, &statbuf), -1);
3425 TEST_EQ (errno, ENOENT);3367 TEST_EQ (errno, ENOENT);
3368 event_poll ();
3426 }3369 }
3427 fclose (output);3370 fclose (output);
3428 nih_free (class);3371 nih_free (class);
@@ -3463,8 +3406,7 @@
3463 job->goal = JOB_START;3406 job->goal = JOB_START;
3464 job->state = JOB_SPAWNED;3407 job->state = JOB_SPAWNED;
34653408
3466 ret = job_process_run (job, PROCESS_MAIN);3409 job_process_start (job, PROCESS_MAIN);
3467 TEST_EQ (ret, 0);
34683410
3469 TEST_NE (job->pid[PROCESS_MAIN], 0);3411 TEST_NE (job->pid[PROCESS_MAIN], 0);
34703412
@@ -3483,8 +3425,8 @@
3483 job->goal = JOB_STOP;3425 job->goal = JOB_STOP;
3484 job->state = JOB_POST_STOP;3426 job->state = JOB_POST_STOP;
34853427
3486 ret = job_process_run (job, PROCESS_POST_STOP);3428 job_process_start (job, PROCESS_POST_STOP);
3487 TEST_LT (ret, 0);3429 TEST_WATCH_UPDATE ();
34883430
3489 TEST_EQ (job->pid[PROCESS_POST_STOP], 0);3431 TEST_EQ (job->pid[PROCESS_POST_STOP], 0);
3490 }3432 }
@@ -3524,8 +3466,8 @@
3524 job->goal = JOB_START;3466 job->goal = JOB_START;
3525 job->state = JOB_SPAWNED;3467 job->state = JOB_SPAWNED;
35263468
3527 ret = job_process_run (job, PROCESS_MAIN);3469 job_process_start (job, PROCESS_MAIN);
3528 TEST_EQ (ret, 0);3470 TEST_WATCH_UPDATE ();
35293471
3530 TEST_NE (job->pid[PROCESS_MAIN], 0);3472 TEST_NE (job->pid[PROCESS_MAIN], 0);
35313473
@@ -3585,8 +3527,8 @@
3585 job->goal = JOB_START;3527 job->goal = JOB_START;
3586 job->state = JOB_SPAWNED;3528 job->state = JOB_SPAWNED;
35873529
3588 ret = job_process_run (job, PROCESS_MAIN);3530 job_process_start (job, PROCESS_MAIN);
3589 TEST_EQ (ret, 0);3531 TEST_WATCH_UPDATE ();
35903532
3591 TEST_NE (job->pid[PROCESS_MAIN], 0);3533 TEST_NE (job->pid[PROCESS_MAIN], 0);
35923534
@@ -3648,8 +3590,8 @@
3648 job->goal = JOB_START;3590 job->goal = JOB_START;
3649 job->state = JOB_SPAWNED;3591 job->state = JOB_SPAWNED;
36503592
3651 ret = job_process_run (job, PROCESS_MAIN);3593 job_process_start (job, PROCESS_MAIN);
3652 TEST_EQ (ret, 0);3594 TEST_WATCH_UPDATE ();
36533595
3654 TEST_NE (job->pid[PROCESS_MAIN], 0);3596 TEST_NE (job->pid[PROCESS_MAIN], 0);
36553597
@@ -3728,8 +3670,7 @@
3728 job->goal = JOB_START;3670 job->goal = JOB_START;
3729 job->state = JOB_SPAWNED;3671 job->state = JOB_SPAWNED;
37303672
3731 ret = job_process_run (job, PROCESS_MAIN);3673 job_process_start (job, PROCESS_MAIN);
3732 TEST_EQ (ret, 0);
37333674
3734 /* Wait for process to avoid any possibility of EAGAIN in3675 /* Wait for process to avoid any possibility of EAGAIN in
3735 * log_read_watch().3676 * log_read_watch().
@@ -3802,8 +3743,9 @@
3802 job->goal = JOB_START;3743 job->goal = JOB_START;
3803 job->state = JOB_SPAWNED;3744 job->state = JOB_SPAWNED;
38043745
3805 ret = job_process_run (job, PROCESS_MAIN);3746 job_process_start (job, PROCESS_MAIN);
3806 TEST_EQ (ret, 0);3747 TEST_WATCH_UPDATE ();
3748 TEST_WATCH_UPDATE ();
38073749
3808 pid = job->pid[PROCESS_MAIN];3750 pid = job->pid[PROCESS_MAIN];
38093751
@@ -3933,8 +3875,8 @@
3933 TEST_EQ_P (job->log[i], NULL);3875 TEST_EQ_P (job->log[i], NULL);
3934 }3876 }
39353877
3936 ret = job_process_run (job, PROCESS_MAIN);3878 job_process_start (job, PROCESS_MAIN);
3937 TEST_EQ (ret, 0);3879 TEST_WATCH_UPDATE ();
39383880
3939 pid = job->pid[PROCESS_MAIN];3881 pid = job->pid[PROCESS_MAIN];
39403882
@@ -4006,8 +3948,7 @@
4006 }3948 }
40073949
4008 TEST_DIVERT_STDERR (output) {3950 TEST_DIVERT_STDERR (output) {
4009 ret = job_process_run (job, PROCESS_MAIN);3951 job_process_start (job, PROCESS_MAIN);
4010 TEST_EQ (ret, 0);
4011 }3952 }
4012 fclose (output);3953 fclose (output);
40133954
@@ -4064,13 +4005,8 @@
4064 }4005 }
40654006
4066 TEST_DIVERT_STDERR (output) {4007 TEST_DIVERT_STDERR (output) {
4067 ret = job_process_run (job, PROCESS_MAIN);4008 job_process_start (job, PROCESS_MAIN);
4068 if (geteuid() == 0 || getuid() == pwd->pw_uid) {4009 TEST_WATCH_UPDATE ();
4069 TEST_EQ (ret, 0);
4070 }
4071 else {
4072 TEST_EQ (ret, -1);
4073 }
4074 }4010 }
40754011
4076 if (geteuid() == 0 || getuid() == pwd->pw_uid) {4012 if (geteuid() == 0 || getuid() == pwd->pw_uid) {
@@ -4081,13 +4017,15 @@
4081 }4017 }
4082 else {4018 else {
4083 TEST_EQ (stat (filename, &statbuf), -1);4019 TEST_EQ (stat (filename, &statbuf), -1);
4020 event_poll ();
4084 }4021 }
40854022
4086 unlink (filename);4023 unlink (filename);
4087 nih_free (class);4024 nih_free (class);
4088
4089 }4025 }
40904026
4027 /* FIXME with async spawn this test is racy */
4028
4091 /************************************************************/4029 /************************************************************/
4092 TEST_FEATURE ("with multiple processes and log");4030 TEST_FEATURE ("with multiple processes and log");
4093 TEST_HASH_EMPTY (job_classes);4031 TEST_HASH_EMPTY (job_classes);
@@ -4128,14 +4066,13 @@
4128 job->goal = JOB_START;4066 job->goal = JOB_START;
4129 job->state = JOB_SPAWNED;4067 job->state = JOB_SPAWNED;
41304068
4131 ret = job_process_run (job, PROCESS_MAIN);4069 job_process_start (job, PROCESS_MAIN);
4132 TEST_EQ (ret, 0);4070 while (stat (filename, &statbuf) != 0) {
41334071 TEST_WATCH_UPDATE ();
4072 }
4134 pid = job->pid[PROCESS_MAIN];4073 pid = job->pid[PROCESS_MAIN];
4135 TEST_GT (pid, 0);4074 TEST_GT (pid, 0);
41364075
4137 TEST_WATCH_UPDATE ();
4138
4139 TEST_EQ (stat (filename, &statbuf), 0);4076 TEST_EQ (stat (filename, &statbuf), 0);
41404077
4141 output = fopen (filename, "r");4078 output = fopen (filename, "r");
@@ -4148,8 +4085,8 @@
41484085
4149 TEST_EQ (fclose (output), 0);4086 TEST_EQ (fclose (output), 0);
41504087
4151 ret = job_process_run (job, PROCESS_POST_START);4088 job_process_start (job, PROCESS_POST_START);
4152 TEST_EQ (ret, 0);4089 TEST_WATCH_UPDATE ();
41534090
4154 pid = job->pid[PROCESS_POST_START];4091 pid = job->pid[PROCESS_POST_START];
4155 TEST_GT (pid, 0);4092 TEST_GT (pid, 0);
@@ -4244,6 +4181,8 @@
4244 int status;4181 int status;
4245 struct stat statbuf;4182 struct stat statbuf;
4246 int ret;4183 int ret;
4184 int job_process_fd = -1;
4185 nih_local NihIoBuffer *buffer = NULL;
42474186
4248 log_unflushed_init ();4187 log_unflushed_init ();
42494188
@@ -4257,7 +4196,7 @@
4257 */4196 */
4258 TEST_EQ (setenv ("UPSTART_LOGDIR", dirname, 1), 0);4197 TEST_EQ (setenv ("UPSTART_LOGDIR", dirname, 1), 0);
42594198
4260 TEST_FUNCTION ("job_process_spawn");4199 TEST_FUNCTION ("job_process_spawn_with_fd");
4261 TEST_FILENAME (filename);4200 TEST_FILENAME (filename);
42624201
4263 args[0] = argv0;4202 args[0] = argv0;
@@ -4278,7 +4217,7 @@
4278 class->console = CONSOLE_NONE;4217 class->console = CONSOLE_NONE;
4279 job = job_new (class, "");4218 job = job_new (class, "");
42804219
4281 pid = job_process_spawn (job, args, NULL, FALSE, -1, PROCESS_MAIN);4220 pid = job_process_spawn_with_fd (job, args, NULL, FALSE, -1, PROCESS_MAIN, &job_process_fd);
4282 TEST_GT (pid, 0);4221 TEST_GT (pid, 0);
42834222
4284 waitpid (pid, NULL, 0);4223 waitpid (pid, NULL, 0);
@@ -4319,7 +4258,7 @@
4319 class->console = CONSOLE_NONE;4258 class->console = CONSOLE_NONE;
4320 job = job_new (class, "");4259 job = job_new (class, "");
43214260
4322 pid = job_process_spawn (job, args, NULL, FALSE, -1, PROCESS_MAIN);4261 pid = job_process_spawn_with_fd (job, args, NULL, FALSE, -1, PROCESS_MAIN, &job_process_fd);
4323 TEST_GT (pid, 0);4262 TEST_GT (pid, 0);
43244263
4325 waitpid (pid, NULL, 0);4264 waitpid (pid, NULL, 0);
@@ -4351,7 +4290,7 @@
4351 class->console = CONSOLE_LOG;4290 class->console = CONSOLE_LOG;
4352 job = job_new (class, "");4291 job = job_new (class, "");
43534292
4354 pid = job_process_spawn (job, args, NULL, FALSE, -1, PROCESS_MAIN);4293 pid = job_process_spawn_with_fd (job, args, NULL, FALSE, -1, PROCESS_MAIN, &job_process_fd);
4355 TEST_GT (pid, 0);4294 TEST_GT (pid, 0);
43564295
4357 waitpid (pid, NULL, 0);4296 waitpid (pid, NULL, 0);
@@ -4398,7 +4337,7 @@
4398 class->chdir = "/tmp";4337 class->chdir = "/tmp";
4399 job = job_new (class, "");4338 job = job_new (class, "");
44004339
4401 pid = job_process_spawn (job, args, NULL, FALSE, -1, PROCESS_MAIN);4340 pid = job_process_spawn_with_fd (job, args, NULL, FALSE, -1, PROCESS_MAIN, &job_process_fd);
4402 TEST_GT (pid, 0);4341 TEST_GT (pid, 0);
44034342
4404 waitpid (pid, NULL, 0);4343 waitpid (pid, NULL, 0);
@@ -4430,7 +4369,7 @@
4430 class->console = CONSOLE_NONE;4369 class->console = CONSOLE_NONE;
4431 job = job_new (class, "");4370 job = job_new (class, "");
44324371
4433 pid = job_process_spawn (job, args, env, FALSE, -1, PROCESS_MAIN);4372 pid = job_process_spawn_with_fd (job, args, env, FALSE, -1, PROCESS_MAIN, &job_process_fd);
4434 TEST_GT (pid, 0);4373 TEST_GT (pid, 0);
44354374
4436 waitpid (pid, NULL, 0);4375 waitpid (pid, NULL, 0);
@@ -4460,7 +4399,7 @@
4460 class->console = CONSOLE_NONE;4399 class->console = CONSOLE_NONE;
4461 job = job_new (class, "");4400 job = job_new (class, "");
44624401
4463 pid = job_process_spawn (job, args, NULL, FALSE, -1, PROCESS_MAIN);4402 pid = job_process_spawn_with_fd (job, args, NULL, FALSE, -1, PROCESS_MAIN, &job_process_fd);
4464 TEST_GT (pid, 0);4403 TEST_GT (pid, 0);
44654404
4466 assert0 (waitid (P_PID, pid, &info, WEXITED | WSTOPPED | WCONTINUED));4405 assert0 (waitid (P_PID, pid, &info, WEXITED | WSTOPPED | WCONTINUED));
@@ -4483,7 +4422,7 @@
4483 class = job_class_new (NULL, "test", NULL);4422 class = job_class_new (NULL, "test", NULL);
4484 job = job_new (class, "");4423 job = job_new (class, "");
4485 class->console = CONSOLE_NONE;4424 class->console = CONSOLE_NONE;
4486 pid = job_process_spawn (job, args, NULL, TRUE, -1, PROCESS_MAIN);4425 pid = job_process_spawn_with_fd (job, args, NULL, TRUE, -1, PROCESS_MAIN, &job_process_fd);
4487 TEST_GT (pid, 0);4426 TEST_GT (pid, 0);
44884427
4489 assert0 (waitid (P_PID, pid, &info, WEXITED | WSTOPPED | WCONTINUED));4428 assert0 (waitid (P_PID, pid, &info, WEXITED | WSTOPPED | WCONTINUED));
@@ -4516,8 +4455,12 @@
4516 class->console = CONSOLE_NONE;4455 class->console = CONSOLE_NONE;
4517 job = job_new (class, "");4456 job = job_new (class, "");
45184457
4519 pid = job_process_spawn (job, args, NULL, FALSE, -1, PROCESS_MAIN);4458 pid = job_process_spawn_with_fd (job, args, NULL, FALSE, -1, PROCESS_MAIN, &job_process_fd);
4520 TEST_LT (pid, 0);4459 TEST_NE (pid, 0);
4460
4461 buffer = read_from_fd (NULL, job_process_fd);
4462 TEST_NE_P (buffer, NULL);
4463 job_process_error_handler (buffer->buf, buffer->len);
45214464
4522 err = nih_error_get ();4465 err = nih_error_get ();
4523 TEST_EQ (err->number, JOB_PROCESS_ERROR);4466 TEST_EQ (err->number, JOB_PROCESS_ERROR);
@@ -4528,6 +4471,7 @@
4528 TEST_EQ (perr->arg, 0);4471 TEST_EQ (perr->arg, 0);
4529 TEST_EQ (perr->errnum, ENOENT);4472 TEST_EQ (perr->errnum, ENOENT);
4530 nih_free (perr);4473 nih_free (perr);
4474 nih_free (buffer);
45314475
4532 /************************************************************/4476 /************************************************************/
4533 TEST_FEATURE ("with no such file, no shell and console log");4477 TEST_FEATURE ("with no such file, no shell and console log");
@@ -4539,29 +4483,36 @@
4539 class = job_class_new (NULL, "test", NULL);4483 class = job_class_new (NULL, "test", NULL);
4540 class->console = CONSOLE_LOG;4484 class->console = CONSOLE_LOG;
4541 job = job_new (class, "");4485 job = job_new (class, "");
4486 job->goal = JOB_START;
4487 job->state = JOB_SPAWNED;
45424488
4543 TEST_NE_P (job->log, NULL);4489 TEST_NE_P (job->log, NULL);
4544 TEST_EQ_P (job->log[PROCESS_MAIN], NULL);4490 TEST_EQ_P (job->log[PROCESS_MAIN], NULL);
4545 pid = job_process_spawn (job, args, NULL, FALSE, -1, PROCESS_MAIN);4491 pid = job_process_spawn_with_fd (job, args, NULL, FALSE, -1, PROCESS_MAIN, &job_process_fd);
4546 TEST_LT (pid, 0);4492 job->process_data[PROCESS_MAIN] = NIH_MUST (
4493 job_process_data_new (job->process_data, job, PROCESS_MAIN, job_process_fd));
4494 TEST_WATCH_UPDATE ();
4495 TEST_NE (pid, 0);
45474496
4548 TEST_GT (waitpid (-1, NULL, 0), 0);4497 TEST_GT (waitpid (-1, NULL, 0), 0);
45494498
4499 NihIo *io = nih_io_reopen (job, job_process_fd, NIH_IO_STREAM, NULL, NULL, NULL, NULL);
4500 TEST_NE_P (io, NULL);
4501 buffer = read_from_fd (NULL, job_process_fd);
4502 TEST_NE_P (buffer, NULL);
4503 TEST_NE_P (job->process_data[PROCESS_MAIN], NULL);
4504 TEST_TRUE (job->process_data[PROCESS_MAIN]->valid);
4505
4506
4507 TEST_NE_P (job->log[PROCESS_MAIN], NULL);
4508
4509 job_process_child_reader (job->process_data[PROCESS_MAIN], io, buffer->buf, buffer->len);
4510
4550 /* The log should have been allocated in job_process_spawn,4511 /* The log should have been allocated in job_process_spawn,
4551 * but then freed on error.4512 * but then freed on error.
4552 */4513 */
4553 TEST_EQ_P (job->log[PROCESS_MAIN], NULL);4514 TEST_EQ_P (job->log[PROCESS_MAIN], NULL);
45544515
4555 err = nih_error_get ();
4556 TEST_EQ (err->number, JOB_PROCESS_ERROR);
4557 TEST_ALLOC_SIZE (err, sizeof (JobProcessError));
4558
4559 perr = (JobProcessError *)err;
4560 TEST_EQ (perr->type, JOB_PROCESS_ERROR_EXEC);
4561 TEST_EQ (perr->arg, 0);
4562 TEST_EQ (perr->errnum, ENOENT);
4563 nih_free (perr);
4564
4565 /* Check that we can spawn a job and pause it4516 /* Check that we can spawn a job and pause it
4566 */4517 */
4567 TEST_FEATURE ("with debug enabled");4518 TEST_FEATURE ("with debug enabled");
@@ -4577,7 +4528,7 @@
4577 args[1] = function;4528 args[1] = function;
4578 args[2] = NULL;4529 args[2] = NULL;
45794530
4580 pid = job_process_spawn (job, args, NULL, FALSE, -1, PROCESS_MAIN);4531 pid = job_process_spawn_with_fd (job, args, NULL, FALSE, -1, PROCESS_MAIN, &job_process_fd);
4581 TEST_GT (pid, 0);4532 TEST_GT (pid, 0);
45824533
4583 /* Ensure process is still running after some period of time.4534 /* Ensure process is still running after some period of time.
@@ -4614,7 +4565,7 @@
4614 class->console = CONSOLE_NONE;4565 class->console = CONSOLE_NONE;
4615 job = job_new (class, "");4566 job = job_new (class, "");
46164567
4617 pid = job_process_spawn (job, args, NULL, FALSE, -1, PROCESS_MAIN);4568 pid = job_process_spawn_with_fd (job, args, NULL, FALSE, -1, PROCESS_MAIN, &job_process_fd);
4618 TEST_GT (pid, 0);4569 TEST_GT (pid, 0);
46194570
4620 waitpid (pid, NULL, 0);4571 waitpid (pid, NULL, 0);
@@ -4669,7 +4620,7 @@
4669 class->console = CONSOLE_LOG;4620 class->console = CONSOLE_LOG;
4670 job = job_new (class, "");4621 job = job_new (class, "");
46714622
4672 pid = job_process_spawn (job, args, NULL, FALSE, -1, PROCESS_MAIN);4623 pid = job_process_spawn_with_fd (job, args, NULL, FALSE, -1, PROCESS_MAIN, &job_process_fd);
4673 TEST_GT (pid, 0);4624 TEST_GT (pid, 0);
46744625
4675 waitpid (pid, NULL, 0);4626 waitpid (pid, NULL, 0);
@@ -4742,8 +4693,8 @@
4742 args[2] = filebuf;4693 args[2] = filebuf;
4743 args[3] = NULL;4694 args[3] = NULL;
47444695
4745 job->pid[PROCESS_MAIN] = job_process_spawn (job, args, NULL,4696 job->pid[PROCESS_MAIN] = job_process_spawn_with_fd (job, args, NULL,
4746 FALSE, -1, PROCESS_MAIN);4697 FALSE, -1, PROCESS_MAIN, &job_process_fd);
4747 pid = job->pid[PROCESS_MAIN];4698 pid = job->pid[PROCESS_MAIN];
4748 TEST_GT (pid, 0);4699 TEST_GT (pid, 0);
47494700
@@ -4769,8 +4720,8 @@
4769 args[2] = filebuf;4720 args[2] = filebuf;
4770 args[3] = NULL;4721 args[3] = NULL;
47714722
4772 job->pid[PROCESS_POST_START] = job_process_spawn (job, args, NULL,4723 job->pid[PROCESS_POST_START] = job_process_spawn_with_fd (job, args, NULL,
4773 FALSE, -1, PROCESS_POST_START);4724 FALSE, -1, PROCESS_POST_START, &job_process_fd);
4774 pid = job->pid[PROCESS_POST_START];4725 pid = job->pid[PROCESS_POST_START];
4775 TEST_GT (pid, 0);4726 TEST_GT (pid, 0);
47764727
@@ -4867,7 +4818,7 @@
4867 NIH_MUST (nih_str_array_add (&args_array, NULL, &argc, script));4818 NIH_MUST (nih_str_array_add (&args_array, NULL, &argc, script));
4868 }4819 }
48694820
4870 pid = job_process_spawn (job, args_array, NULL, FALSE, -1, PROCESS_MAIN);4821 pid = job_process_spawn_with_fd (job, args_array, NULL, FALSE, -1, PROCESS_MAIN, &job_process_fd);
48714822
4872 if (test_alloc_failed) {4823 if (test_alloc_failed) {
4873 TEST_LT (pid, 0);4824 TEST_LT (pid, 0);
@@ -4934,7 +4885,7 @@
4934 NIH_MUST (nih_str_array_add (&args_array, NULL, &argc, TEST_SHELL_ARG));4885 NIH_MUST (nih_str_array_add (&args_array, NULL, &argc, TEST_SHELL_ARG));
4935 NIH_MUST (nih_str_array_add (&args_array, NULL, &argc, script));4886 NIH_MUST (nih_str_array_add (&args_array, NULL, &argc, script));
49364887
4937 pid = job_process_spawn (job, args_array, NULL, FALSE, -1, PROCESS_MAIN);4888 pid = job_process_spawn_with_fd (job, args_array, NULL, FALSE, -1, PROCESS_MAIN, &job_process_fd);
4938 TEST_GT (pid, 0);4889 TEST_GT (pid, 0);
49394890
4940 TEST_EQ (waitpid (pid, &status, 0), pid);4891 TEST_EQ (waitpid (pid, &status, 0), pid);
@@ -4990,7 +4941,7 @@
4990 NIH_MUST (nih_str_array_add (&args_array, NULL, &argc, TEST_SHELL_ARG));4941 NIH_MUST (nih_str_array_add (&args_array, NULL, &argc, TEST_SHELL_ARG));
4991 NIH_MUST (nih_str_array_add (&args_array, NULL, &argc, script));4942 NIH_MUST (nih_str_array_add (&args_array, NULL, &argc, script));
49924943
4993 pid = job_process_spawn (job, args_array, NULL, FALSE, -1, PROCESS_MAIN);4944 pid = job_process_spawn_with_fd (job, args_array, NULL, FALSE, -1, PROCESS_MAIN, &job_process_fd);
4994 TEST_GT (pid, 0);4945 TEST_GT (pid, 0);
49954946
4996 TEST_EQ (waitpid (pid, &status, 0), pid);4947 TEST_EQ (waitpid (pid, &status, 0), pid);
@@ -5043,7 +4994,7 @@
5043 NIH_MUST (nih_str_array_add (&args_array, NULL, &argc, "-en"));4994 NIH_MUST (nih_str_array_add (&args_array, NULL, &argc, "-en"));
5044 NIH_MUST (nih_str_array_add (&args_array, NULL, &argc, "\\000"));4995 NIH_MUST (nih_str_array_add (&args_array, NULL, &argc, "\\000"));
50454996
5046 pid = job_process_spawn (job, args_array, NULL, FALSE, -1, PROCESS_MAIN);4997 pid = job_process_spawn_with_fd (job, args_array, NULL, FALSE, -1, PROCESS_MAIN, &job_process_fd);
5047 TEST_GT (pid, 0);4998 TEST_GT (pid, 0);
50484999
5049 TEST_EQ (waitpid (pid, &status, 0), pid);5000 TEST_EQ (waitpid (pid, &status, 0), pid);
@@ -5098,7 +5049,7 @@
5098 args[3] = filebuf;5049 args[3] = filebuf;
5099 args[4] = NULL;5050 args[4] = NULL;
51005051
5101 pid = job_process_spawn (job, args, NULL, FALSE, -1, PROCESS_MAIN);5052 pid = job_process_spawn_with_fd (job, args, NULL, FALSE, -1, PROCESS_MAIN, &job_process_fd);
5102 TEST_GT (pid, 0);5053 TEST_GT (pid, 0);
51035054
5104 TEST_NE (waitpid (pid, &status, 0), -1);5055 TEST_NE (waitpid (pid, &status, 0), -1);
@@ -5161,7 +5112,7 @@
5161 args[3] = filebuf;5112 args[3] = filebuf;
5162 args[4] = NULL;5113 args[4] = NULL;
51635114
5164 pid = job_process_spawn (job, args, NULL, FALSE, -1, PROCESS_MAIN);5115 pid = job_process_spawn_with_fd (job, args, NULL, FALSE, -1, PROCESS_MAIN, &job_process_fd);
5165 TEST_GT (pid, 0);5116 TEST_GT (pid, 0);
51665117
5167 TEST_WATCH_UPDATE ();5118 TEST_WATCH_UPDATE ();
@@ -5243,8 +5194,13 @@
5243 }5194 }
5244 }5195 }
52455196
5246 pid = job_process_spawn (job, args, NULL, FALSE, -1, PROCESS_MAIN);5197 pid = job_process_spawn_with_fd (job, args, NULL, FALSE, -1, PROCESS_MAIN, &job_process_fd);
5247 TEST_LT (pid, 0);5198 TEST_WATCH_UPDATE ();
5199 TEST_NE (pid, 0);
5200
5201 buffer = read_from_fd (NULL, job_process_fd);
5202 TEST_NE_P (buffer, NULL);
5203 job_process_error_handler (buffer->buf, buffer->len);
52485204
5249 /* Ensure logging disabled in failure scenarios */5205 /* Ensure logging disabled in failure scenarios */
5250 TEST_EQ (class->console, CONSOLE_NONE);5206 TEST_EQ (class->console, CONSOLE_NONE);
@@ -5830,6 +5786,8 @@
5830 job->exit_status = 0;5786 job->exit_status = 0;
58315787
5832 job_process_handler (NULL, 1, NIH_CHILD_EXITED, 0);5788 job_process_handler (NULL, 1, NIH_CHILD_EXITED, 0);
5789 TEST_EQ (job->state, JOB_SPAWNED);
5790 job_change_state (job, job_next_state(job));
58335791
5834 TEST_EQ (job->goal, JOB_START);5792 TEST_EQ (job->goal, JOB_START);
5835 TEST_EQ (job->state, JOB_RUNNING);5793 TEST_EQ (job->state, JOB_RUNNING);
@@ -9181,7 +9139,7 @@
9181void9139void
9182run_tests (void)9140run_tests (void)
9183{9141{
9184 test_run ();9142 test_start ();
9185 test_spawn ();9143 test_spawn ();
9186 test_log_path ();9144 test_log_path ();
9187 test_kill ();9145 test_kill ();
91889146
=== modified file 'init/tests/test_util.c'
--- init/tests/test_util.c 2013-07-17 14:18:42 +0000
+++ init/tests/test_util.c 2014-05-22 13:31:23 +0000
@@ -1,5 +1,6 @@
1#include "test_util_common.h"
2#undef PACKAGE_COPYRIGHT
1#include "test_util.h"3#include "test_util.h"
2#include "test_util_common.h"
3#include <nih/logging.h>4#include <nih/logging.h>
4#include <nih/test.h>5#include <nih/test.h>
56
67
=== modified file 'test/test_util_common.c'
--- test/test_util_common.c 2014-04-11 21:15:39 +0000
+++ test/test_util_common.c 2014-05-22 13:31:23 +0000
@@ -28,6 +28,10 @@
28#include <nih/string.h>28#include <nih/string.h>
29#include <nih/signal.h>29#include <nih/signal.h>
30#include <nih/logging.h>30#include <nih/logging.h>
31#include <nih/timer.h>
32#include <nih/io.h>
33#include <nih/child.h>
34#include <nih/main.h>
31#include <nih-dbus/test_dbus.h>35#include <nih-dbus/test_dbus.h>
3236
33#include <dbus/dbus.h>37#include <dbus/dbus.h>
@@ -986,7 +990,7 @@
986990
987 /* Clean up if tests forgot to */991 /* Clean up if tests forgot to */
988 cmd = NIH_MUST (nih_sprintf (NULL, "rm %s/*.session 2>/dev/null", path));992 cmd = NIH_MUST (nih_sprintf (NULL, "rm %s/*.session 2>/dev/null", path));
989 system (cmd);993 assert0 (system (cmd));
990994
991 /* Remove the directory tree the first Session Init created */995 /* Remove the directory tree the first Session Init created */
992 assert0 (rmdir (path));996 assert0 (rmdir (path));
@@ -1003,3 +1007,89 @@
10031007
1004 }1008 }
1005}1009}
1010
1011/**
1012 * timer_cb:
1013 *
1014 * @data: unused,
1015 * @timer: timer.
1016 *
1017 * Exit main loop with an error value indicating that the expected main
1018 * loop events/actions were not performed within the expected time.
1019 **/
1020void
1021timer_cb (void *data, NihTimer *timer)
1022{
1023 nih_assert (timer);
1024
1025 /* Return non-zero to denote failure */
1026 nih_main_loop_exit (42);
1027}
1028
1029/**
1030 * fd_valid:
1031 * @fd: file descriptor.
1032 *
1033 * Return 1 if @fd is valid, else 0.
1034 **/
1035int
1036fd_valid (int fd)
1037{
1038 int flags = 0;
1039
1040 if (fd < 0)
1041 return 0;
1042
1043 errno = 0;
1044 flags = fcntl (fd, F_GETFL);
1045
1046 if (flags < 0)
1047 return 0;
1048
1049 /* redundant really */
1050 if (errno == EBADF)
1051 return 0;
1052
1053 return 1;
1054}
1055
1056/**
1057 * read_from_fd:
1058 *
1059 * @parent: parent,
1060 * @fd: open file descriptor.
1061 *
1062 * Read from the specified fd, close the fd and return the data.
1063 *
1064 * Returns: Newly-allocated NihIoBuffer representing data read from @fd.
1065 *
1066 **/
1067NihIoBuffer *
1068read_from_fd (void *parent, int fd)
1069{
1070 NihIoBuffer *buffer = NULL;
1071 ssize_t len;
1072
1073 assert (fd >= 0);
1074
1075 buffer = nih_io_buffer_new (parent);
1076 nih_assert (buffer);
1077
1078 while (TRUE) {
1079
1080 nih_assert (! nih_io_buffer_resize (buffer, 1024));
1081
1082 len = read (fd,
1083 buffer->buf + buffer->len,
1084 buffer->size - buffer->len);
1085
1086 if (len <= 0)
1087 break;
1088 else if (len > 0)
1089 buffer->len += len;
1090 }
1091
1092 close (fd);
1093
1094 return buffer;
1095}
10061096
=== modified file 'test/test_util_common.h'
--- test/test_util_common.h 2013-11-15 23:47:31 +0000
+++ test/test_util_common.h 2014-05-22 13:31:23 +0000
@@ -6,6 +6,10 @@
6#include <sys/wait.h>6#include <sys/wait.h>
77
8#include <nih-dbus/test_dbus.h>8#include <nih-dbus/test_dbus.h>
9#include <nih/timer.h>
10#include <nih/main.h>
11#include <nih/child.h>
12#include <nih/io.h>
913
10/**14/**
11 * TEST_DIR_MODE:15 * TEST_DIR_MODE:
@@ -34,6 +38,16 @@
3438
35#define TEST_QUIESCE_TOTAL_WAIT_TIME (TEST_EXIT_TIME + TEST_QUIESCE_KILL_PHASE)39#define TEST_QUIESCE_TOTAL_WAIT_TIME (TEST_EXIT_TIME + TEST_QUIESCE_KILL_PHASE)
3640
41/**
42 * TEST_MAIN_LOOP_TIMEOUT_SECS:
43 *
44 * Number of seconds to wait until the main loop is exited in error.
45 *
46 * To avoid a test failure, all main loops must exit within this
47 * number of seconds.
48 **/
49#define TEST_MAIN_LOOP_TIMEOUT_SECS 5
50
37/* A 'reasonable' path, but which also contains a marker at the end so51/* A 'reasonable' path, but which also contains a marker at the end so
38 * we know when we're looking at a PATH these tests have set.52 * we know when we're looking at a PATH these tests have set.
39 */53 */
@@ -74,6 +88,41 @@
74}88}
7589
76/**90/**
91 * TEST_WATCH_LOOP:
92 *
93 * Loop for NihIo object Updates, and process them until no watches
94 * left.
95 */
96#define TEST_WATCH_LOOP() \
97{ \
98 /* Loop until we've fed all of the data. */ \
99 int first = TRUE; \
100 for (;;) { \
101 fd_set readfds, writefds, exceptfds; \
102 int nfds; \
103 \
104 nfds = 0; \
105 FD_ZERO (&readfds); \
106 FD_ZERO (&writefds); \
107 FD_ZERO (&exceptfds); \
108 \
109 nih_io_select_fds (&nfds, &readfds, \
110 &writefds, &exceptfds); \
111 if (! nfds) { \
112 if (first) \
113 TEST_FAILED ("expected to have " \
114 "data to feed."); \
115 break; \
116 } \
117 first = FALSE; \
118 \
119 select (nfds, &readfds, &writefds, &exceptfds, NULL); \
120 \
121 nih_io_handle_fds (&readfds, &writefds, &exceptfds); \
122 } \
123}
124
125/**
77 * _TEST_WATCH_UPDATE:126 * _TEST_WATCH_UPDATE:
78 * @force: if TRUE, force an update,127 * @force: if TRUE, force an update,
79 * @timeout: struct timeval pointer, or NULL if no timeout required.128 * @timeout: struct timeval pointer, or NULL if no timeout required.
@@ -169,6 +218,30 @@
169}218}
170219
171/**220/**
221 * TEST_RESET_MAIN_LOOP:
222 *
223 * Reset main loop and associated test variables.
224 **/
225#define TEST_RESET_MAIN_LOOP() \
226 if (nih_main_loop_functions) { \
227 nih_free (nih_main_loop_functions); \
228 nih_main_loop_functions = NULL; \
229 } \
230 if (nih_child_watches) { \
231 nih_free (nih_child_watches); \
232 nih_child_watches = NULL; \
233 } \
234 if (nih_timers) { \
235 nih_free (nih_timers); \
236 nih_timers = NULL; \
237 } \
238 nih_child_init (); \
239 nih_main_loop_init (); \
240 nih_timer_init (); \
241 nih_io_init ()
242
243
244/**
172 * obj_string_check:245 * obj_string_check:
173 *246 *
174 * @a: first object,247 * @a: first object,
@@ -702,10 +775,10 @@
702int string_check (const char *a, const char *b)775int string_check (const char *a, const char *b)
703 __attribute__ ((warn_unused_result));776 __attribute__ ((warn_unused_result));
704777
705const char * get_upstart_binary (void)778const char *get_upstart_binary (void)
706 __attribute__ ((warn_unused_result));779 __attribute__ ((warn_unused_result));
707780
708const char * get_initctl_binary (void)781const char *get_initctl_binary (void)
709 __attribute__ ((warn_unused_result));782 __attribute__ ((warn_unused_result));
710783
711int strcmp_compar (const void *a, const void *b)784int strcmp_compar (const void *a, const void *b)
@@ -731,4 +804,17 @@
731804
732void test_common_cleanup (void);805void test_common_cleanup (void);
733806
807void timer_cb (void *data, NihTimer *timer);
808
809void test_job_process_handler (void *data, pid_t pid,
810 NihChildEvents event, int status);
811
812void test_main_loop_func (void *data, NihMainLoopFunc *self);
813
814int fd_valid (int fd)
815 __attribute__ ((warn_unused_result));
816
817NihIoBuffer *read_from_fd (void *parent, int fd)
818 __attribute__ ((warn_unused_result));
819
734#endif /* TEST_UTIL_COMMON_H */820#endif /* TEST_UTIL_COMMON_H */
735821
=== modified file 'util/tests/test_initctl.c'
--- util/tests/test_initctl.c 2014-05-07 19:08:35 +0000
+++ util/tests/test_initctl.c 2014-05-22 13:31:23 +0000
@@ -11535,7 +11535,7 @@
11535 TEST_NE_P (sessiondir, NULL);11535 TEST_NE_P (sessiondir, NULL);
11536 11536
11537 cmd = nih_sprintf (NULL, "rm %s/upstart/sessions/*.session 2>/dev/null", sessiondir);11537 cmd = nih_sprintf (NULL, "rm %s/upstart/sessions/*.session 2>/dev/null", sessiondir);
11538 system (cmd);11538 assert0 (system (cmd));
1153911539
11540 /* Use the "secret" interface */11540 /* Use the "secret" interface */
11541 TEST_EQ (setenv ("UPSTART_CONFDIR", confdir, 1), 0);11541 TEST_EQ (setenv ("UPSTART_CONFDIR", confdir, 1), 0);

Subscribers

People subscribed via source and target branches