Merge lp:~xnox/upstart/shrink-notifications into lp:upstart

Proposed by Dimitri John Ledkov on 2014-07-01
Status: Merged
Merged at revision: 1645
Proposed branch: lp:~xnox/upstart/shrink-notifications
Merge into: lp:upstart
Diff against target: 1622 lines (+778/-166)
7 files modified
ChangeLog (+15/-0)
init/job.c (+0/-5)
init/job_process.c (+13/-6)
init/job_process.h (+4/-0)
init/tests/test_job_process.c (+512/-148)
test/test_util_common.c (+9/-4)
util/tests/test_initctl.c (+225/-3)
To merge this branch: bzr merge lp:~xnox/upstart/shrink-notifications
Reviewer Review Type Date Requested Status
James Hunt 2014-07-01 Needs Fixing on 2014-07-09
Review via email: mp+225200@code.launchpad.net
To post a comment you must log in.
James Hunt (jamesodhunt) wrote :

As discussed, we should not be disabling tests so need to get to the bottom of the failures.

review: Needs Fixing
1641. By Dimitri John Ledkov on 2014-07-02

Wait for the right pid to exit, reset main-loop state between tests

Dimitri John Ledkov (xnox) wrote :

Thanks for pointing out that the test-harness is broken and not the test. And hence the test fails because of bad environment.

* added helpers to install handlers, which can be reset with the TEST_RESET_MAIN_LOOP()
* realized that i need to pass the desired pid to the exit handler, instead of simply quiting on the first one
* modified affected tests to use main loop and properly clean-up environment before and after it self

All tests pass now \o/

James Hunt (jamesodhunt) wrote :

Thanks! However, test_job_process.c is still failing for me:

#2 0x0000000000433a2d in test_start () at tests/test_job_process.c:4160
4160 TEST_FILE_END (output);

Also, re-exec is failing occasionally for me with EBADF thrown by nih_io_reopen().

Also, could you remove that stale comment in job_process_close_handler().

review: Needs Fixing
1642. By Dimitri John Ledkov on 2014-07-03

Catch up trunk

1643. By Dimitri John Ledkov on 2014-07-03

Reduce races in 'with multiple processes and log' test by waiting for sufficiently large log file to be written.

1644. By Dimitri John Ledkov on 2014-07-03

remove stale comment

Dimitri John Ledkov (xnox) wrote :

> Thanks! However, test_job_process.c is still failing for me:
>
> #2 0x0000000000433a2d in test_start () at tests/test_job_process.c:4160
> 4160 TEST_FILE_END (output);
>

That test is racy since async branch introduction and has a comment to denote as such. I've not committed a couple of guards to reduce spurious failures of this test, by waiting for sufficiently large enough log file to be written.

> Also, re-exec is failing occasionally for me with EBADF thrown by
> nih_io_reopen().
>

=/

> Also, could you remove that stale comment in job_process_close_handler().

Done.

James Hunt (jamesodhunt) wrote :

test_job_process.c is frequently hanging for me and there are a few instances spinning at 100% CPU in the background.

review: Needs Fixing
1645. By Dimitri John Ledkov on 2014-07-08

Merge trunk

1646. By Dimitri John Ledkov on 2014-07-08

100 interations pass

Dimitri John Ledkov (xnox) wrote :

Backed out jodh's merged tests.
Made tests resilient to tests (pass 100+ iterations).

Fixed races:
- sigchild ariving, before read handler is called

Fixed aborts:
- due to multiple io reads, since process_fd pipe was not cleared
- job_process_error_handler returning EILSEQ
- double freeing io, when read handler is called before close handles

James Hunt (jamesodhunt) wrote :

Still racy I'm afraid:

not ok 48 - with single-line command running an invalid command, then a 1-line post-stop script
        wrong value for child_exit_status[1], expected 255 got 0
        at tests/test_job_process.c:3193 (test_start).
Aborted (core dumped)
ERROR: failed on iteration 6

#2 0x0000000000428c92 in test_start () at tests/test_job_process.c:3193
3193 TEST_EQ (child_exit_status[1], 255);
(gdb) p child_exit_status[1]
$1 = 0
(gdb)

review: Needs Fixing
Dimitri John Ledkov (xnox) wrote :

> Still racy I'm afraid:
>
> not ok 48 - with single-line command running an invalid command, then a 1-line
> post-stop script
> wrong value for child_exit_status[1], expected 255 got 0
> at tests/test_job_process.c:3193 (test_start).
> Aborted (core dumped)
> ERROR: failed on iteration 6
>
> #2 0x0000000000428c92 in test_start () at tests/test_job_process.c:3193
> 3193 TEST_EQ (child_exit_status[1], 255);
> (gdb) p child_exit_status[1]
> $1 = 0
> (gdb)

It is better than it was before.

What about review of the actual code changes? Do you approve those?

James Hunt (jamesodhunt) wrote :

I don't understand the change you've made to job_process_handler():

=== modified file 'init/job_process.c'
--- init/job_process.c 2014-07-08 14:11:53 +0000
+++ init/job_process.c 2014-07-10 07:54:25 +0000
@@ -1474,6 +1474,11 @@
        job = job_process_find (pid, &process);
        if (! job)
                return;
+
+ /* Child setup process died, before finishing the setup.
+ */
+ if (job->process_data[process] && job->process_data[process]->valid)
+ return;

This seems to be what is causing the branch to fail to boot too.

1647. By Dimitri John Ledkov on 2014-07-10

Backout "fix" that causes boot regression.

This is meant to skip child process sigchild processing if
asynchronous setup notification pipe has not been closed/read-from
yet.

1648. By Dimitri John Ledkov on 2014-07-10

Merge trunk

1649. By Dimitri John Ledkov on 2014-07-10

Assert job_change_state is not blocked

1650. By Dimitri John Ledkov on 2014-07-10

Back out more of -r1647

1651. By Dimitri John Ledkov on 2014-07-10

Revert asserting no blockers, as we can get blockers.

1652. By Dimitri John Ledkov on 2014-07-10

Don't transition and return if blocked.... and don't assert before that check.

1653. By Dimitri John Ledkov on 2014-07-10

Merge

1654. By Dimitri John Ledkov on 2014-07-11

Derace real & mock signal handlers

1655. By Dimitri John Ledkov on 2014-07-11

Merge jodh tests

1656. By Dimitri John Ledkov on 2014-07-11

Make test_initctl pass without inotify support.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'ChangeLog'
2--- ChangeLog 2014-07-08 14:11:53 +0000
3+++ ChangeLog 2014-07-11 12:53:11 +0000
4@@ -1,3 +1,18 @@
5+2014-07-09 James Hunt <james.hunt@ubuntu.com>
6+
7+ * init/job_process.c: Unhide job_process_error_abort() to allow it to be
8+ called by the tests.
9+ * init/tests/test_job_process.c: RESILIENT_TEST_CHILD(): New macro
10+ to work around a bug in NIH's TEST_CHILD() where it doesn't handle
11+ EINTR.
12+ * init/tests/test_job_process.c: test_handler(): New tests to ensure
13+ async handling can cope with both 'waitid() before select()' and
14+ vice versa:
15+ - "with child exit notification before child setup success notification"
16+ - "with child exit notification before child setup failure notification"
17+ - "with child setup success notification before child exit notification"
18+ - "with child setup failure notification before child exit notification"
19+
20 2014-07-08 James Hunt <james.hunt@ubuntu.com>
21
22 * init/main.c: main():
23
24=== modified file 'init/job.c'
25--- init/job.c 2014-06-12 14:23:47 +0000
26+++ init/job.c 2014-07-11 12:53:11 +0000
27@@ -396,11 +396,6 @@
28 {
29 nih_assert (job != NULL);
30
31- /* We may not be blocked by any events when doing first
32- * transition.
33- */
34- nih_assert (job->blocker == NULL);
35-
36 while (job->state != state) {
37 JobState old_state;
38 int unused;
39
40=== modified file 'init/job_process.c'
41--- init/job_process.c 2014-07-08 14:11:53 +0000
42+++ init/job_process.c 2014-07-11 12:53:11 +0000
43@@ -111,9 +111,6 @@
44 int disable_respawn = FALSE;
45
46 /* Prototypes for static functions */
47-static void job_process_error_abort (int fd, JobProcessErrorType type,
48- int arg)
49- __attribute__ ((noreturn));
50 static void job_process_remap_fd (int *fd, int reserved_fd, int error_fd);
51
52 /**
53@@ -983,7 +980,7 @@
54 *
55 * This function calls the exit() system call, so never returns.
56 **/
57-static void
58+void
59 job_process_error_abort (int fd,
60 JobProcessErrorType type,
61 int arg)
62@@ -2457,7 +2454,15 @@
63
64 err = nih_error_get ();
65
66- nih_assert (err->number == JOB_PROCESS_ERROR);
67+ if (err->number != JOB_PROCESS_ERROR) {
68+ nih_warn ("%s: %s", _("Temporary process spawn error"),
69+ err->message);
70+ nih_free (err);
71+ return;
72+ }
73+
74+ /* Wilco. Out. */
75+ nih_io_buffer_shrink (io->recv_buf, len);
76
77 /* Non-temporary error condition */
78 nih_warn (_("Failed to spawn %s %s process: %s"),
79@@ -2491,12 +2496,12 @@
80 /* Note that pts_master is closed automatically in the parent
81 * when the log object is destroyed.
82 */
83+ process_data->valid = FALSE;
84
85 nih_io_shutdown (io);
86
87 /* Invalidate */
88 process_data->job_process_fd = -1;
89- process_data->valid = FALSE;
90 }
91
92 /**
93@@ -2519,6 +2524,8 @@
94 */
95 if (! process_data)
96 return;
97+ if (! process_data->valid)
98+ return;
99
100 nih_assert (io);
101
102
103=== modified file 'init/job_process.h'
104--- init/job_process.h 2014-06-02 20:29:33 +0000
105+++ init/job_process.h 2014-07-11 12:53:11 +0000
106@@ -194,6 +194,10 @@
107
108 void job_process_error_handler (const char *buf, size_t len);
109
110+void job_process_error_abort (int fd, JobProcessErrorType type,
111+ int arg)
112+ __attribute__ ((noreturn));
113+
114 NIH_END_EXTERN
115
116 #endif /* INIT_JOB_PROCESS_H */
117
118=== modified file 'init/tests/test_job_process.c'
119--- init/tests/test_job_process.c 2014-07-07 10:15:25 +0000
120+++ init/tests/test_job_process.c 2014-07-11 12:53:11 +0000
121@@ -122,6 +122,80 @@
122 TEST_EQ (ok, TRUE); \
123 } while (0)
124
125+
126+/*
127+ * Register regular child handler.
128+ * Register another handler to be called after the primary
129+ * Upstart handler to allow the test to exit the main loop
130+ * quickly on success.
131+ * Process the event queue each time through the main loop
132+ */
133+
134+#define TEST_INSTALL_CHILD_HANDLERS() \
135+ NIH_MUST (nih_child_add_watch (NULL, \
136+ -1, \
137+ NIH_CHILD_ALL, \
138+ test_job_process_handler,\
139+ NULL)); \
140+ NIH_MUST (nih_child_add_watch (NULL, \
141+ -1, \
142+ NIH_CHILD_ALL, \
143+ job_process_handler, \
144+ NULL)); \
145+ NIH_MUST (nih_main_loop_add_func (NULL, (NihMainLoopCb)event_poll, \
146+ NULL))
147+
148+
149+#define TEST_CLEAR_CHILD_STATUS() \
150+ do { \
151+ TEST_EQ (waitid (P_ALL, 0, &siginfo, WEXITED | WNOWAIT), -1); \
152+ TEST_EQ (errno, ECHILD); \
153+ errno = 0; \
154+ child_exit_after = 1; \
155+ for (int _i = 0; _i < PROCESS_LAST; _i++) { \
156+ child_exit_status[_i] = -1; \
157+ } \
158+ } while (0)
159+
160+
161+/* Modified version of NIH's TEST_CHILD() that is resilient
162+ * to temporary errors.
163+ */
164+#define RESILIENT_TEST_CHILD(_pid) \
165+ do { \
166+ int _test_fds[2]; \
167+ fflush (stdout); \
168+ fflush (stderr); \
169+ assert0 (pipe (_test_fds)); \
170+ _pid = fork (); \
171+ if (_pid > 0) { \
172+ ssize_t ret; \
173+ char _test_buf[1]; \
174+ close (_test_fds[1]); \
175+ while (TRUE) { \
176+ ret = read (_test_fds[0], _test_buf, 1); \
177+ if (ret > 0) { \
178+ assert (ret == 1); \
179+ break; \
180+ } else if (ret < 0 && errno != EINTR) { \
181+ nih_assert_not_reached (); \
182+ } else { \
183+ nih_assert_not_reached (); \
184+ } \
185+ } \
186+ close (_test_fds[0]); \
187+ } else if (_pid == 0) { \
188+ close (_test_fds[0]); \
189+ assert (write (_test_fds[1], "\n", 1) == 1); \
190+ close (_test_fds[1]); \
191+ } \
192+ } while (0); \
193+ if (_pid == 0) \
194+ for (int _test_child = 0; _test_child < 2; _test_child++) \
195+ if (_test_child) { \
196+ abort (); \
197+ } else
198+
199 /* Sadly we can't test everything that job_process_spawn() does simply because
200 * a lot of it can only be done by root, or in the case of the console stuff,
201 * kills whatever had /dev/console (usually X).
202@@ -147,6 +221,36 @@
203 static int get_available_pty_count (void) __attribute__((unused));
204 static void close_all_files (void);
205
206+static int child_exit_status[PROCESS_LAST];
207+static int child_exit_after;
208+
209+/**
210+ * test_job_process_handler:
211+ *
212+ * @data: existing NihList that this function will add entries to,
213+ * @pid: process that changed,
214+ * @event: event that occurred on the child,
215+ * @status: exit status, signal raised or ptrace event.
216+ *
217+ * Handler that just sets some globals and requests the main loop to
218+ * exit to allow the test that installs it to check the values passed to
219+ * this function as appropriate.
220+ **/
221+void
222+test_job_process_handler (void *data,
223+ pid_t pid,
224+ NihChildEvents event,
225+ int status)
226+{
227+ if (event != NIH_CHILD_EXITED)
228+ return;
229+ child_exit_after--;
230+ child_exit_status[child_exit_after] = status;
231+ if (child_exit_after < 1)
232+ nih_main_loop_exit (0);
233+}
234+
235+
236 static void
237 child (enum child_tests test,
238 const char *filename)
239@@ -1056,6 +1160,7 @@
240 nih_free (class);
241 }
242
243+
244 /* Check that if we try and run a command that doesn't exist,
245 * job_process_start() raises a ProcessError and the command doesn't
246 * have any stored process id for it.
247@@ -1063,10 +1168,14 @@
248 TEST_FEATURE ("with no such file");
249 TEST_HASH_EMPTY (job_classes);
250
251+ TEST_RESET_MAIN_LOOP ();
252+ TEST_INSTALL_CHILD_HANDLERS ();
253+
254 output = tmpfile ();
255
256 TEST_ALLOC_FAIL {
257 TEST_ALLOC_SAFE {
258+ TEST_HASH_EMPTY (job_classes);
259 class = job_class_new (NULL, "test", NULL);
260 class->console = CONSOLE_NONE;
261 class->process[PROCESS_MAIN] = process_new (class);
262@@ -1076,12 +1185,16 @@
263 job = job_new (class, "foo");
264 job->goal = JOB_START;
265 job->state = JOB_SPAWNED;
266+
267+ nih_hash_add (job_classes, &class->entry);
268+ TEST_CLEAR_CHILD_STATUS ();
269 }
270
271 TEST_DIVERT_STDERR (output) {
272 job_process_start (job, PROCESS_MAIN);
273- TEST_WATCH_LOOP ();
274- event_poll ();
275+ TEST_GT (job->pid[PROCESS_MAIN], 0);
276+ TEST_EQ (nih_main_loop (), 0);
277+ TEST_EQ (child_exit_status[PROCESS_MAIN], 255);
278 }
279 rewind (output);
280
281@@ -1098,6 +1211,8 @@
282
283 TEST_EQ (rmdir (dirname), 0);
284
285+ TEST_RESET_MAIN_LOOP ();
286+
287 TEST_FILENAME (dirname);
288 TEST_EQ (mkdir (dirname, 0755), 0);
289
290@@ -3018,6 +3133,9 @@
291 TEST_FEATURE ("with single-line command running an invalid command");
292 TEST_HASH_EMPTY (job_classes);
293
294+ TEST_RESET_MAIN_LOOP ();
295+ TEST_INSTALL_CHILD_HANDLERS ();
296+
297 class = job_class_new (NULL, "buzz", NULL);
298 TEST_NE_P (class, NULL);
299
300@@ -3039,14 +3157,21 @@
301 job->goal = JOB_START;
302 job->state = JOB_SPAWNED;
303
304+ /* XXX: Manually add the class so job_process_find() works */
305+ nih_hash_add (job_classes, &class->entry);
306+
307 output = tmpfile ();
308 TEST_NE_P (output, NULL);
309+ TEST_CLEAR_CHILD_STATUS ();
310 TEST_DIVERT_STDERR (output) {
311 job_process_start (job, PROCESS_MAIN);
312- TEST_WATCH_UPDATE ();
313- TEST_WATCH_UPDATE ();
314- event_poll ();
315+ TEST_GT (job->pid[PROCESS_MAIN], 0);
316+ TEST_EQ (nih_main_loop (), 0);
317+ TEST_EQ (child_exit_status[PROCESS_MAIN], 255);
318 }
319+
320+ TEST_FILE_END (output);
321+
322 fclose (output);
323
324 /* We don't expect a logfile to be written since there is no
325@@ -3056,11 +3181,14 @@
326 TEST_EQ (errno, ENOENT);
327
328 nih_free (class);
329+ TEST_RESET_MAIN_LOOP ();
330
331 /************************************************************/
332 TEST_FEATURE ("with single-line command running an invalid command, then a 1-line post-stop script");
333 TEST_HASH_EMPTY (job_classes);
334
335+ TEST_INSTALL_CHILD_HANDLERS ();
336+
337 class = job_class_new (NULL, "asterix", NULL);
338 TEST_NE_P (class, NULL);
339
340@@ -3086,6 +3214,9 @@
341
342 job = job_new (class, "");
343
344+ /* XXX: Manually add the class so job_process_find() works */
345+ nih_hash_add (job_classes, &class->entry);
346+
347 output = tmpfile ();
348 TEST_NE_P (output, NULL);
349 TEST_DIVERT_STDERR (output) {
350@@ -3093,37 +3224,18 @@
351 job->goal = JOB_START;
352 job->state = JOB_SPAWNED;
353
354+ TEST_CLEAR_CHILD_STATUS ();
355+ child_exit_after = 2;
356 job_process_start (job, PROCESS_MAIN);
357- TEST_WATCH_UPDATE ();
358-
359- /* We don't expect a logfile to be written since there is no
360- * accompanying shell to write the error.
361- */
362- TEST_EQ (stat (filename, &statbuf), -1);
363- TEST_EQ (errno, ENOENT);
364-
365- job->goal = JOB_STOP;
366- job->state = JOB_POST_STOP;
367-
368- job_process_start (job, PROCESS_POST_STOP);
369-
370- TEST_NE (job->pid[PROCESS_POST_STOP], 0);
371- TEST_WATCH_UPDATE ();
372-
373- /* Flush the io so that the shell on the client side
374- * gets the data (the script to execute).
375- */
376- TEST_WATCH_UPDATE ();
377-
378- waitpid (job->pid[PROCESS_POST_STOP], &status, 0);
379- TEST_TRUE (WIFEXITED (status));
380- TEST_EQ (WEXITSTATUS (status), 0);
381-
382- TEST_WATCH_UPDATE ();
383-
384- /* .. but the post stop should have written data */
385+ TEST_GT (job->pid[PROCESS_MAIN], 0);
386+ TEST_EQ (nih_main_loop (), 0);
387+ /* Check exit status in reverse order */
388+ /* Main */
389+ TEST_EQ (child_exit_status[1], 255);
390+ /* Post-stop */
391+ TEST_EQ (child_exit_status[0], 0);
392+ /* And the post stop should have written data */
393 TEST_EQ (stat (filename, &statbuf), 0);
394- event_poll ();
395 }
396 fclose (output);
397
398@@ -3144,6 +3256,9 @@
399 TEST_FEATURE ("with single-line command running an invalid command, then a 2-line post-stop script");
400 TEST_HASH_EMPTY (job_classes);
401
402+ TEST_RESET_MAIN_LOOP ();
403+ TEST_INSTALL_CHILD_HANDLERS ();
404+
405 class = job_class_new (NULL, "asterix", NULL);
406 TEST_NE_P (class, NULL);
407
408@@ -3168,6 +3283,8 @@
409 TEST_EQ (errno, ENOENT);
410
411 job = job_new (class, "");
412+ /* XXX: Manually add the class so job_process_find() works */
413+ nih_hash_add (job_classes, &class->entry);
414
415 output = tmpfile ();
416 TEST_NE_P (output, NULL);
417@@ -3176,39 +3293,17 @@
418 job->goal = JOB_START;
419 job->state = JOB_SPAWNED;
420
421+ TEST_CLEAR_CHILD_STATUS ();
422+ child_exit_after = 2;
423 job_process_start (job, PROCESS_MAIN);
424- TEST_WATCH_UPDATE ();
425- TEST_WATCH_UPDATE ();
426-
427- /* We don't expect a logfile to be written since there is no
428- * accompanying shell to write the error.
429- */
430- TEST_EQ (stat (filename, &statbuf), -1);
431- TEST_EQ (errno, ENOENT);
432-
433- job->goal = JOB_STOP;
434- job->state = JOB_POST_STOP;
435-
436- job_process_start (job, PROCESS_POST_STOP);
437- TEST_WATCH_UPDATE ();
438-
439- TEST_NE (job->pid[PROCESS_POST_STOP], 0);
440-
441- /* Flush the io so that the shell on the client side
442- * gets the data (the script to execute).
443- */
444- TEST_WATCH_UPDATE ();
445-
446- waitpid (job->pid[PROCESS_POST_STOP], &status, 0);
447- TEST_TRUE (WIFEXITED (status));
448- TEST_EQ (WEXITSTATUS (status), 0);
449-
450- /* Allow the log to be written */
451- TEST_WATCH_UPDATE ();
452-
453- /* .. but the post stop should have written data */
454+ TEST_NE (job->pid[PROCESS_MAIN], 0);
455+
456+ TEST_EQ (nih_main_loop (), 0);
457+ TEST_EQ (child_exit_status[1], 255);
458+ TEST_EQ (child_exit_status[0], 0);
459+
460+ /* And the post stop should have written data */
461 TEST_EQ (stat (filename, &statbuf), 0);
462- event_poll ();
463 }
464 fclose (output);
465
466@@ -3225,6 +3320,7 @@
467 TEST_EQ (unlink (filename), 0);
468
469 nih_free (class);
470+ TEST_RESET_MAIN_LOOP ();
471
472 /************************************************************/
473 TEST_FEATURE ("with single-line command running an invalid command, then a post-stop command");
474@@ -3255,6 +3351,9 @@
475
476 job = job_new (class, "");
477
478+ TEST_RESET_MAIN_LOOP ();
479+ TEST_INSTALL_CHILD_HANDLERS ();
480+
481 output = tmpfile ();
482 TEST_NE_P (output, NULL);
483 TEST_DIVERT_STDERR (output) {
484@@ -3262,37 +3361,19 @@
485 job->goal = JOB_START;
486 job->state = JOB_SPAWNED;
487
488+ TEST_CLEAR_CHILD_STATUS ();
489+ child_exit_after = 2;
490+
491 job_process_start (job, PROCESS_MAIN);
492- TEST_WATCH_UPDATE ();
493-
494- /* We don't expect a logfile to be written since there is no
495- * accompanying shell to write the error.
496- */
497- TEST_EQ (stat (filename, &statbuf), -1);
498- TEST_EQ (errno, ENOENT);
499-
500- job->goal = JOB_STOP;
501- job->state = JOB_POST_STOP;
502-
503- job_process_start (job, PROCESS_POST_STOP);
504- TEST_WATCH_UPDATE ();
505-
506- TEST_NE (job->pid[PROCESS_POST_STOP], 0);
507-
508- /* Flush the io so that the shell on the client side
509- * gets the data (the script to execute).
510- */
511- TEST_WATCH_UPDATE ();
512-
513- waitpid (job->pid[PROCESS_POST_STOP], &status, 0);
514- TEST_TRUE (WIFEXITED (status));
515- TEST_EQ (WEXITSTATUS (status), 0);
516-
517- TEST_WATCH_UPDATE ();
518-
519- /* .. but the post stop should have written data */
520+ TEST_GT (job->pid[PROCESS_MAIN], 0);
521+ TEST_EQ (nih_main_loop (), 0);
522+ TEST_GT (job->pid[PROCESS_POST_STOP], 0);
523+ TEST_EQ (child_exit_status[1], 255);
524+ TEST_EQ (child_exit_status[0], 0);
525+
526+ /* The post stop should have written data */
527 TEST_EQ (stat (filename, &statbuf), 0);
528- event_poll ();
529+
530 }
531 fclose (output);
532
533@@ -3309,6 +3390,8 @@
534
535 nih_free (class);
536
537+ TEST_RESET_MAIN_LOOP ();
538+
539 /************************************************************/
540 TEST_FEATURE ("with single-line command running an invalid command, then an invalid post-stop command");
541 TEST_HASH_EMPTY (job_classes);
542@@ -3338,6 +3421,9 @@
543
544 job = job_new (class, "");
545
546+ TEST_RESET_MAIN_LOOP ();
547+ TEST_INSTALL_CHILD_HANDLERS ();
548+
549 output = tmpfile ();
550 TEST_NE_P (output, NULL);
551 TEST_DIVERT_STDERR (output) {
552@@ -3345,29 +3431,24 @@
553 job->goal = JOB_START;
554 job->state = JOB_SPAWNED;
555
556+ TEST_CLEAR_CHILD_STATUS ();
557+ child_exit_after = 2;
558+
559 job_process_start (job, PROCESS_MAIN);
560- TEST_WATCH_UPDATE ();
561-
562- /* We don't expect a logfile to be written since there is no
563- * accompanying shell to write the error.
564- */
565- TEST_EQ (stat (filename, &statbuf), -1);
566- TEST_EQ (errno, ENOENT);
567-
568- job->goal = JOB_STOP;
569- job->state = JOB_POST_STOP;
570-
571- job_process_start (job, PROCESS_POST_STOP);
572- TEST_WATCH_UPDATE ();
573+ TEST_GT (job->pid[PROCESS_MAIN], 0);
574+ TEST_EQ (nih_main_loop (), 0);
575+ TEST_EQ (child_exit_status[1], 255);
576+ TEST_EQ (child_exit_status[0], 255);
577
578 /* Again, no file expected */
579 TEST_EQ (stat (filename, &statbuf), -1);
580 TEST_EQ (errno, ENOENT);
581- event_poll ();
582 }
583 fclose (output);
584 nih_free (class);
585
586+ TEST_RESET_MAIN_LOOP ();
587+
588 /************************************************************/
589 TEST_FEATURE ("with single-line command running a valid command, then a 1-line invalid post-stop command");
590 TEST_HASH_EMPTY (job_classes);
591@@ -3397,6 +3478,9 @@
592
593 job = job_new (class, "");
594
595+ TEST_RESET_MAIN_LOOP ();
596+ TEST_INSTALL_CHILD_HANDLERS ();
597+
598 output = tmpfile ();
599 TEST_NE_P (output, NULL);
600 TEST_DIVERT_STDERR (output) {
601@@ -3404,29 +3488,26 @@
602 job->goal = JOB_START;
603 job->state = JOB_SPAWNED;
604
605+ TEST_CLEAR_CHILD_STATUS ();
606+
607 job_process_start (job, PROCESS_MAIN);
608-
609- TEST_NE (job->pid[PROCESS_MAIN], 0);
610-
611- waitpid (job->pid[PROCESS_MAIN], &status, 0);
612- TEST_TRUE (WIFEXITED (status));
613- TEST_EQ (WEXITSTATUS (status), 0);
614-
615- /* Flush the io so that the shell on the client side
616- * gets the data (the script to execute).
617- */
618- TEST_WATCH_UPDATE ();
619+ TEST_GT (job->pid[PROCESS_MAIN], 0);
620+ TEST_EQ (nih_main_loop (), 0);
621+ TEST_EQ (child_exit_status[0], 0);
622+ TEST_EQ (child_exit_status[1], -1);
623
624 /* Expect a log file */
625 TEST_EQ (stat (filename, &statbuf), 0);
626
627 job->goal = JOB_STOP;
628 job->state = JOB_POST_STOP;
629+
630+ TEST_CLEAR_CHILD_STATUS ();
631
632 job_process_start (job, PROCESS_POST_STOP);
633- TEST_WATCH_UPDATE ();
634-
635- TEST_EQ (job->pid[PROCESS_POST_STOP], 0);
636+ TEST_GT (job->pid[PROCESS_POST_STOP], 0);
637+ TEST_EQ (nih_main_loop (), 0);
638+ TEST_EQ (child_exit_status[0], 255);
639 }
640 fclose (output);
641
642@@ -3443,10 +3524,15 @@
643
644 nih_free (class);
645
646+ TEST_RESET_MAIN_LOOP ();
647+
648 /************************************************************/
649 TEST_FEATURE ("with multi-line script running an invalid command");
650 TEST_HASH_EMPTY (job_classes);
651
652+ TEST_RESET_MAIN_LOOP ();
653+ TEST_INSTALL_CHILD_HANDLERS ();
654+
655 class = job_class_new (NULL, "blah", NULL);
656 TEST_NE_P (class, NULL);
657
658@@ -3463,17 +3549,13 @@
659 job = job_new (class, "");
660 job->goal = JOB_START;
661 job->state = JOB_SPAWNED;
662+ nih_hash_add (job_classes, &class->entry);
663+ TEST_CLEAR_CHILD_STATUS ();
664
665 job_process_start (job, PROCESS_MAIN);
666- TEST_WATCH_UPDATE ();
667-
668- TEST_NE (job->pid[PROCESS_MAIN], 0);
669-
670- TEST_WATCH_UPDATE ();
671- waitpid (job->pid[PROCESS_MAIN], &status, 0);
672- TEST_TRUE (WIFEXITED (status));
673- TEST_NE (WEXITSTATUS (status), 0);
674- TEST_WATCH_UPDATE ();
675+ TEST_GT (job->pid[PROCESS_MAIN], 0);
676+ TEST_EQ (nih_main_loop (), 0);
677+ TEST_EQ (child_exit_status[0], 127);
678
679 TEST_EQ (stat (filename, &statbuf), 0);
680
681@@ -3502,6 +3584,7 @@
682
683 TEST_EQ (unlink (filename), 0);
684 nih_free (class);
685+ TEST_RESET_MAIN_LOOP ();
686
687 /************************************************************/
688 TEST_FEATURE ("with multi-line script that writes 1 line to stdout then 1 line to stderr");
689@@ -3977,6 +4060,9 @@
690 */
691 TEST_FEATURE ("with setuid");
692 TEST_HASH_EMPTY (job_classes);
693+ TEST_RESET_MAIN_LOOP ();
694+ TEST_INSTALL_CHILD_HANDLERS ();
695+
696
697 TEST_NE_P (output, NULL);
698 TEST_ALLOC_FAIL {
699@@ -3999,30 +4085,30 @@
700 job->goal = JOB_START;
701 job->state = JOB_SPAWNED;
702
703+ nih_hash_add (job_classes, &class->entry);
704+ TEST_CLEAR_CHILD_STATUS ();
705+
706 output = tmpfile ();
707 }
708
709 TEST_DIVERT_STDERR (output) {
710 job_process_start (job, PROCESS_MAIN);
711- TEST_WATCH_UPDATE ();
712+ TEST_GT (job->pid[PROCESS_MAIN], 0);
713+ TEST_EQ (nih_main_loop (), 0);
714 }
715
716 if (geteuid() == 0 || getuid() == pwd->pw_uid) {
717- TEST_NE (job->pid[PROCESS_MAIN], 0);
718-
719- waitpid (job->pid[PROCESS_MAIN], NULL, 0);
720 TEST_EQ (stat (filename, &statbuf), 0);
721- }
722- else {
723+ } else {
724 TEST_EQ (stat (filename, &statbuf), -1);
725- event_poll ();
726 }
727
728 unlink (filename);
729 nih_free (class);
730 }
731+
732+ TEST_RESET_MAIN_LOOP ();
733
734- /* FIXME with async spawn this test is racy */
735
736 /************************************************************/
737 TEST_FEATURE ("with multiple processes and log");
738@@ -4062,10 +4148,10 @@
739
740 job = job_new (class, "");
741 job->goal = JOB_START;
742- job->state = JOB_SPAWNED;
743+ job->state = JOB_SPAWNING;
744
745 job_process_start (job, PROCESS_MAIN);
746- while (stat (filename, &statbuf) != 0) {
747+ while (stat (filename, &statbuf) != 0 || statbuf.st_size < 9) {
748 TEST_WATCH_UPDATE ();
749 }
750 pid = job->pid[PROCESS_MAIN];
751@@ -4077,9 +4163,7 @@
752 TEST_NE_P (output, NULL);
753
754 /* initial output from main process */
755- CHECK_FILE_EQ (output, "started\r\n", TRUE);
756-
757- TEST_FILE_END (output);
758+ TEST_FILE_EQ (output, "started\r\n");
759
760 TEST_EQ (fclose (output), 0);
761
762@@ -4093,7 +4177,10 @@
763 waitpid (pid, &status, 0);
764 TEST_TRUE (WIFEXITED (status));
765 TEST_EQ (WEXITSTATUS (status), 0);
766- TEST_WATCH_UPDATE ();
767+
768+ while (stat (filename, &statbuf) != 0 || statbuf.st_size < 25) {
769+ TEST_WATCH_UPDATE ();
770+ }
771
772 output = fopen (filename, "r");
773 TEST_NE_P (output, NULL);
774@@ -5488,6 +5575,8 @@
775 char dirname[PATH_MAX];
776 nih_local char *logfile = NULL;
777 int fds[2] = { -1, -1};
778+ NihIo *io = NULL;
779+ nih_local NihIoBuffer *buffer= NULL;
780
781 TEST_FILENAME (dirname);
782 TEST_EQ (mkdir (dirname, 0755), 0);
783@@ -8770,13 +8859,288 @@
784
785 fclose (output);
786
787+ nih_free (event);
788+ event_poll ();
789+
790+ TEST_RESET_MAIN_LOOP ();
791+
792+ TEST_NE_P (class->process[PROCESS_MAIN], NULL);
793+ TEST_EQ_P (class->process[PROCESS_PRE_START], NULL);
794+ TEST_EQ_P (class->process[PROCESS_POST_START], NULL);
795+ TEST_EQ_P (class->process[PROCESS_PRE_STOP], NULL);
796+ TEST_EQ_P (class->process[PROCESS_POST_STOP], NULL);
797+ TEST_EQ_P (class->process[PROCESS_SECURITY], NULL);
798+
799+ /************************************************************/
800+ /* Ensure that if a child is setup successfully and then exits
801+ * before the main loop detects the child fd has closed (due to
802+ * the child calling execvp()), that the state is correct.
803+ */
804+ TEST_FEATURE ("with child exit notification before child setup success notification");
805+
806+ job = job_new (class, "");
807+ TEST_NE_P (job, NULL);
808+
809+ job->goal = JOB_START;
810+ job->state = JOB_SPAWNING;
811+
812+ assert0 (pipe (fds));
813+
814+ job->process_data[PROCESS_MAIN] = job_process_data_new (job->process_data,
815+ job, PROCESS_MAIN, fds[0]);
816+ TEST_NE_P (job->process_data[PROCESS_MAIN], NULL);
817+
818+ TEST_NE_P (class->process[PROCESS_MAIN], NULL);
819+ TEST_EQ_P (class->process[PROCESS_PRE_START], NULL);
820+ TEST_EQ_P (class->process[PROCESS_POST_START], NULL);
821+ TEST_EQ_P (class->process[PROCESS_PRE_STOP], NULL);
822+ TEST_EQ_P (class->process[PROCESS_POST_STOP], NULL);
823+ TEST_EQ_P (class->process[PROCESS_SECURITY], NULL);
824+
825+ /* used to check if job_process_terminated() called */
826+ job->process_data[PROCESS_MAIN]->status = -1;
827+
828+ TEST_CHILD (job->pid[PROCESS_MAIN]) {
829+ close (fds[0]);
830+
831+ nih_io_set_cloexec (fds[1]);
832+
833+ execl ("/bin/true", "/bin/true", NULL);
834+ }
835+ close (fds[1]);
836+
837+ TEST_FREE_TAG (job);
838+
839+ job_process_handler (NULL, job->pid[PROCESS_MAIN],
840+ NIH_CHILD_EXITED, 0);
841+
842+ TEST_NOT_FREE (job);
843+
844+ TEST_TRUE (job->process_data[PROCESS_MAIN]->valid);
845+ TEST_EQ (job->process_data[PROCESS_MAIN]->job_process_fd, fds[0]);
846+ TEST_EQ (job->process_data[PROCESS_MAIN]->shell_fd, -1);
847+ TEST_EQ_P (job->process_data[PROCESS_MAIN]->script, NULL);
848+
849+ /* job_process_terminated() should have been called now and the
850+ * status recorded.
851+ */
852+ TEST_EQ (job->process_data[PROCESS_MAIN]->status, 0);
853+
854+ /* goal should not change until the IO handlers have had a
855+ * chance to run.
856+ */
857+ TEST_EQ (job->goal, JOB_START);
858+ TEST_EQ (job->state, JOB_SPAWNED);
859+
860+ TEST_NE_P (job->process_data[PROCESS_MAIN], NULL);
861+
862+ close (fds[0]);
863+
864+ pid = job->pid[PROCESS_MAIN];
865+
866+ TEST_EQ (timed_waitpid (pid, 5), pid);
867+
868+ nih_free (job);
869+ TEST_RESET_MAIN_LOOP ();
870+
871+ /************************************************************/
872+ /* Ensure that if a child failed to be setup and then exits
873+ * before the main loop detects the child fd has data to read
874+ * that the state is correct.
875+ */
876+ TEST_FEATURE ("with child exit notification before child setup failure notification");
877+
878+ job = job_new (class, "");
879+ TEST_NE_P (job, NULL);
880+
881+ job->goal = JOB_START;
882+ job->state = JOB_SPAWNING;
883+
884+ assert0 (pipe (fds));
885+
886+ job->process_data[PROCESS_MAIN] = job_process_data_new (job->process_data,
887+ job, PROCESS_MAIN, fds[0]);
888+ TEST_NE_P (job->process_data[PROCESS_MAIN], NULL);
889+ TEST_EQ (job->process_data[PROCESS_MAIN]->job_process_fd, fds[0]);
890+ TEST_EQ (job->process_data[PROCESS_MAIN]->process, PROCESS_MAIN);
891+
892+ TEST_CHILD (job->pid[PROCESS_MAIN]) {
893+ close (fds[0]);
894+
895+ nih_error_raise_no_memory ();
896+ job_process_error_abort (fds[1], JOB_PROCESS_ERROR_CGROUP_SETUP, 0);
897+ }
898+ close (fds[1]);
899+
900+ TEST_FREE_TAG (job);
901+
902+ job_process_handler (NULL, job->pid[PROCESS_MAIN],
903+ NIH_CHILD_DUMPED, 255);
904+
905+ TEST_NOT_FREE (job);
906+
907+ /* goal should not change until the IO handlers have had a
908+ * chance to run.
909+ */
910+ TEST_EQ (job->goal, JOB_START);
911+
912+ TEST_EQ (job->state, JOB_SPAWNED);
913+ TEST_NE_P (job->process_data[PROCESS_MAIN], NULL);
914+
915+ /* Still valid because the IO handlers haven't fired yet */
916+ TEST_TRUE (job->process_data[PROCESS_MAIN]->valid);
917+ TEST_EQ (job->process_data[PROCESS_MAIN]->job_process_fd, fds[0]);
918+
919+ TEST_EQ (job->process_data[PROCESS_MAIN]->shell_fd, -1);
920+ TEST_EQ_P (job->process_data[PROCESS_MAIN]->script, NULL);
921+
922+ /* job_process_terminated() will have been called now */
923+ status = job->process_data[PROCESS_MAIN]->status;
924+ TEST_GT (status, 0);
925+
926+ TEST_TRUE (WIFEXITED (status));
927+ TEST_EQ (WEXITSTATUS (status), 255);
928+
929+ /* slurp - don't care about content */
930+ buffer = read_from_fd (NULL, fds[0]);
931+ close (fds[0]);
932+
933+ pid = job->pid[PROCESS_MAIN];
934+ TEST_EQ (timed_waitpid (pid, 5), pid);
935+
936+ nih_free (job);
937+ TEST_RESET_MAIN_LOOP ();
938+
939+ /************************************************************/
940+ TEST_FEATURE ("with child setup success notification before child exit notification");
941+
942+ job = job_new (class, "");
943+ TEST_NE_P (job, NULL);
944+
945+ job->goal = JOB_START;
946+ job->state = JOB_SPAWNING;
947+
948+ assert0 (pipe (fds));
949+
950+ job->process_data[PROCESS_MAIN] = job_process_data_new (job->process_data,
951+ job, PROCESS_MAIN, fds[0]);
952+ TEST_NE_P (job->process_data[PROCESS_MAIN], NULL);
953+ TEST_EQ (job->process_data[PROCESS_MAIN]->job_process_fd, fds[0]);
954+ TEST_EQ (job->process_data[PROCESS_MAIN]->process, PROCESS_MAIN);
955+
956+ io = nih_io_reopen (job->process_data[PROCESS_MAIN],
957+ fds[0],
958+ NIH_IO_STREAM,
959+ (NihIoReader)job_process_child_reader,
960+ (NihIoCloseHandler)job_process_close_handler,
961+ NULL,
962+ job->process_data[PROCESS_MAIN]);
963+ TEST_NE_P (io, NULL);
964+
965+ TEST_CHILD (job->pid[PROCESS_MAIN]) {
966+ close (fds[0]);
967+
968+ nih_io_set_cloexec (fds[1]);
969+
970+ execl ("/bin/true", "/bin/true", NULL);
971+ }
972+ close (fds[1]);
973+
974+ job_process_close_handler (job->process_data[PROCESS_MAIN], io);
975+
976+ TEST_EQ (job->goal, JOB_START);
977+ TEST_EQ (job->state, JOB_SPAWNED);
978+ TEST_NE_P (job->process_data[PROCESS_MAIN], NULL);
979+
980+ /* Invalid because the IO handlers have now run */
981+ TEST_FALSE (job->process_data[PROCESS_MAIN]->valid);
982+ TEST_EQ (job->process_data[PROCESS_MAIN]->job_process_fd, -1);
983+
984+ TEST_EQ (job->process_data[PROCESS_MAIN]->shell_fd, -1);
985+ TEST_EQ_P (job->process_data[PROCESS_MAIN]->script, NULL);
986+ TEST_EQ (job->process_data[PROCESS_MAIN]->status, 0);
987+
988+ close (fds[0]);
989+
990+ pid = job->pid[PROCESS_MAIN];
991+ TEST_EQ (timed_waitpid (pid, 5), pid);
992+
993+ nih_free (job);
994+ TEST_RESET_MAIN_LOOP ();
995+
996+ /************************************************************/
997+ TEST_FEATURE ("with child setup failure notification before child exit notification");
998+
999+ job = job_new (class, "");
1000+ TEST_NE_P (job, NULL);
1001+
1002+ job->goal = JOB_START;
1003+ job->state = JOB_SPAWNED;
1004+
1005+ assert0 (pipe (fds));
1006+
1007+ job->process_data[PROCESS_MAIN] = job_process_data_new (job->process_data,
1008+ job, PROCESS_MAIN, fds[0]);
1009+ TEST_NE_P (job->process_data[PROCESS_MAIN], NULL);
1010+ TEST_EQ (job->process_data[PROCESS_MAIN]->job_process_fd, fds[0]);
1011+ TEST_EQ (job->process_data[PROCESS_MAIN]->process, PROCESS_MAIN);
1012+
1013+ /* Can't use job_register_child_handler() as we want the return
1014+ * value.
1015+ */
1016+ io = nih_io_reopen (job->process_data[PROCESS_MAIN],
1017+ fds[0],
1018+ NIH_IO_STREAM,
1019+ (NihIoReader)job_process_child_reader,
1020+ (NihIoCloseHandler)job_process_close_handler,
1021+ NULL,
1022+ job->process_data[PROCESS_MAIN]);
1023+ TEST_NE_P (io, NULL);
1024+
1025+ RESILIENT_TEST_CHILD (job->pid[PROCESS_MAIN]) {
1026+ close (fds[0]);
1027+ nih_error_raise_no_memory ();
1028+ job_process_error_abort (fds[1], JOB_PROCESS_ERROR_CGROUP_SETUP, 0);
1029+ }
1030+ close (fds[1]);
1031+ pid = job->pid[PROCESS_MAIN];
1032+
1033+ buffer = read_from_fd (NULL, fds[0]);
1034+
1035+ job_process_child_reader (job->process_data[PROCESS_MAIN],
1036+ io, buffer->buf, buffer->len);
1037+
1038+ /* Setup failed, so goal should have changed to stop */
1039+ TEST_EQ (job->goal, JOB_STOP);
1040+ TEST_EQ (job->state, JOB_STOPPING);
1041+
1042+ TEST_NE_P (job->process_data[PROCESS_MAIN], NULL);
1043+
1044+ /* Invalid because the IO handlers have now run */
1045+ TEST_FALSE (job->process_data[PROCESS_MAIN]->valid);
1046+ TEST_EQ (job->process_data[PROCESS_MAIN]->job_process_fd, -1);
1047+
1048+ TEST_EQ (job->process_data[PROCESS_MAIN]->shell_fd, -1);
1049+ TEST_EQ_P (job->process_data[PROCESS_MAIN]->script, NULL);
1050+ TEST_EQ (job->process_data[PROCESS_MAIN]->shell_fd, -1);
1051+
1052+ /* Still zero because the process handler hasn't run yet */
1053+ TEST_EQ (job->process_data[PROCESS_MAIN]->status, 0);
1054+
1055+ close (fds[0]);
1056+
1057+ TEST_EQ (timed_waitpid (pid, 5), pid);
1058+
1059+ nih_free (job);
1060+
1061+ TEST_RESET_MAIN_LOOP ();
1062+
1063+ /************************************************************/
1064+
1065 nih_free (class);
1066 file->job = NULL;
1067 nih_free (source);
1068
1069- nih_free (event);
1070- event_poll ();
1071-
1072 TEST_EQ (rmdir (dirname), 0);
1073 TEST_EQ (unsetenv ("UPSTART_LOGDIR"), 0);
1074 }
1075
1076=== modified file 'test/test_util_common.c'
1077--- test/test_util_common.c 2014-06-02 23:32:49 +0000
1078+++ test/test_util_common.c 2014-07-11 12:53:11 +0000
1079@@ -375,6 +375,8 @@
1080 *
1081 * Simplified waitpid(2) with timeout using a pipe to allow select(2)
1082 * with timeout to be used to wait for process state change.
1083+ *
1084+ * Returns: as waitpid(2).
1085 **/
1086 pid_t
1087 timed_waitpid (pid_t pid, time_t timeout)
1088@@ -1000,7 +1002,7 @@
1089 nih_local char *cmd = NULL;
1090
1091 /* Clean up if tests forgot to */
1092- cmd = NIH_MUST (nih_sprintf (NULL, "rm %s/*.session 2>/dev/null", path));
1093+ cmd = NIH_MUST (nih_sprintf (NULL, "rm -f %s/*.session 2>/dev/null", path));
1094 assert0 (system (cmd));
1095
1096 /* Remove the directory tree the first Session Init created */
1097@@ -1094,10 +1096,13 @@
1098 buffer->buf + buffer->len,
1099 buffer->size - buffer->len);
1100
1101- if (len <= 0)
1102- break;
1103- else if (len > 0)
1104+ if (len < 0 && errno != EAGAIN && errno != EINTR) {
1105+ break;
1106+ } else if (! len) {
1107+ break;
1108+ } else if (len > 0) {
1109 buffer->len += len;
1110+ }
1111 }
1112
1113 close (fd);
1114
1115=== modified file 'util/tests/test_initctl.c'
1116--- util/tests/test_initctl.c 2014-07-01 15:34:42 +0000
1117+++ util/tests/test_initctl.c 2014-07-11 12:53:11 +0000
1118@@ -10968,9 +10968,9 @@
1119 /*******************************************************************/
1120 TEST_FEATURE ("single job");
1121
1122- START_UPSTART (upstart_pid, FALSE);
1123 CREATE_FILE (dirname, "foo.conf",
1124 "exec echo hello");
1125+ START_UPSTART (upstart_pid, FALSE);
1126
1127 cmd = nih_sprintf (NULL, "%s list 2>&1", get_initctl ());
1128 TEST_NE_P (cmd, NULL);
1129@@ -10984,10 +10984,10 @@
1130 /*******************************************************************/
1131 TEST_FEATURE ("3 jobs and re-exec");
1132
1133- START_UPSTART (upstart_pid, FALSE);
1134- CREATE_FILE (dirname, "foo.conf", "exec echo foo");
1135+ CREATE_FILE (dirname, "foo.conf", "exec echo foo");
1136 CREATE_FILE (dirname, "bar.conf", "exec echo bar");
1137 CREATE_FILE (dirname, "baz.conf", "exec echo bar");
1138+ START_UPSTART (upstart_pid, FALSE);
1139
1140 cmd = nih_sprintf (NULL, "%s list 2>&1", get_initctl ());
1141 TEST_NE_P (cmd, NULL);
1142@@ -11110,6 +11110,12 @@
1143
1144 CREATE_FILE (confdir, "foo.conf", contents);
1145
1146+ cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ());
1147+ TEST_NE_P (cmd, NULL);
1148+ RUN_COMMAND (NULL, cmd, &output, &lines);
1149+ TEST_EQ (lines, 0);
1150+ nih_free (output);
1151+
1152 cmd = nih_sprintf (NULL, "%s start foo 2>&1", get_initctl ());
1153 TEST_NE_P (cmd, NULL);
1154 RUN_COMMAND (NULL, cmd, &output, &lines);
1155@@ -12482,6 +12488,12 @@
1156 "author \"foo\"\n"
1157 "description \"wibble\"");
1158
1159+ cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ());
1160+ TEST_NE_P (cmd, NULL);
1161+ RUN_COMMAND (NULL, cmd, &output, &lines);
1162+ TEST_EQ (lines, 0);
1163+ nih_free (output);
1164+
1165 cmd = nih_sprintf (NULL, "%s show-config foo 2>&1", get_initctl ());
1166 TEST_NE_P (cmd, NULL);
1167 RUN_COMMAND (NULL, cmd, &output, &lines);
1168@@ -12507,6 +12519,12 @@
1169 "emits \"thing\"\n"
1170 "description \"wibble\"");
1171
1172+ cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ());
1173+ TEST_NE_P (cmd, NULL);
1174+ RUN_COMMAND (NULL, cmd, &output, &lines);
1175+ TEST_EQ (lines, 0);
1176+ nih_free (output);
1177+
1178 cmd = nih_sprintf (NULL, "%s show-config foo 2>&1", get_initctl ());
1179 TEST_NE_P (cmd, NULL);
1180 RUN_COMMAND (NULL, cmd, &output, &lines);
1181@@ -12535,6 +12553,12 @@
1182 "emits \"thong\"\n"
1183 "description \"wibble\"");
1184
1185+ cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ());
1186+ TEST_NE_P (cmd, NULL);
1187+ RUN_COMMAND (NULL, cmd, &output, &lines);
1188+ TEST_EQ (lines, 0);
1189+ nih_free (output);
1190+
1191 cmd = nih_sprintf (NULL, "%s show-config foo 2>&1", get_initctl ());
1192 TEST_NE_P (cmd, NULL);
1193 RUN_COMMAND (NULL, cmd, &output, &lines);
1194@@ -12564,6 +12588,12 @@
1195 "start on (A and B)\n"
1196 "description \"wibble\"");
1197
1198+ cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ());
1199+ TEST_NE_P (cmd, NULL);
1200+ RUN_COMMAND (NULL, cmd, &output, &lines);
1201+ TEST_EQ (lines, 0);
1202+ nih_free (output);
1203+
1204 cmd = nih_sprintf (NULL, "%s show-config foo 2>&1", get_initctl ());
1205 TEST_NE_P (cmd, NULL);
1206 RUN_COMMAND (NULL, cmd, &output, &lines);
1207@@ -12593,6 +12623,12 @@
1208 "start on (A and B)\n"
1209 "description \"wibble\"");
1210
1211+ cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ());
1212+ TEST_NE_P (cmd, NULL);
1213+ RUN_COMMAND (NULL, cmd, &output, &lines);
1214+ TEST_EQ (lines, 0);
1215+ nih_free (output);
1216+
1217 cmd = nih_sprintf (NULL, "%s show-config foo 2>&1", get_initctl ());
1218 TEST_NE_P (cmd, NULL);
1219 RUN_COMMAND (NULL, cmd, &output, &lines);
1220@@ -12625,6 +12661,12 @@
1221 "emits \"stime\"\n"
1222 "description \"wibble\"");
1223
1224+ cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ());
1225+ TEST_NE_P (cmd, NULL);
1226+ RUN_COMMAND (NULL, cmd, &output, &lines);
1227+ TEST_EQ (lines, 0);
1228+ nih_free (output);
1229+
1230 cmd = nih_sprintf (NULL, "%s show-config foo 2>&1", get_initctl ());
1231 TEST_NE_P (cmd, NULL);
1232 RUN_COMMAND (NULL, cmd, &output, &lines);
1233@@ -12657,6 +12699,12 @@
1234 "stop on (A or B)\n"
1235 "description \"wibble\"");
1236
1237+ cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ());
1238+ TEST_NE_P (cmd, NULL);
1239+ RUN_COMMAND (NULL, cmd, &output, &lines);
1240+ TEST_EQ (lines, 0);
1241+ nih_free (output);
1242+
1243 cmd = nih_sprintf (NULL, "%s show-config foo 2>&1", get_initctl ());
1244 TEST_NE_P (cmd, NULL);
1245 RUN_COMMAND (NULL, cmd, &output, &lines);
1246@@ -12686,6 +12734,12 @@
1247 "stop on (A or B)\n"
1248 "description \"wibble\"");
1249
1250+ cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ());
1251+ TEST_NE_P (cmd, NULL);
1252+ RUN_COMMAND (NULL, cmd, &output, &lines);
1253+ TEST_EQ (lines, 0);
1254+ nih_free (output);
1255+
1256 cmd = nih_sprintf (NULL, "%s show-config foo 2>&1", get_initctl ());
1257 TEST_NE_P (cmd, NULL);
1258 RUN_COMMAND (NULL, cmd, &output, &lines);
1259@@ -12718,6 +12772,12 @@
1260 "emits \"stime\"\n"
1261 "description \"wibble\"");
1262
1263+ cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ());
1264+ TEST_NE_P (cmd, NULL);
1265+ RUN_COMMAND (NULL, cmd, &output, &lines);
1266+ TEST_EQ (lines, 0);
1267+ nih_free (output);
1268+
1269 cmd = nih_sprintf (NULL, "%s show-config foo 2>&1", get_initctl ());
1270 TEST_NE_P (cmd, NULL);
1271 RUN_COMMAND (NULL, cmd, &output, &lines);
1272@@ -12753,6 +12813,12 @@
1273 "start on (starting JOB=\"boo\" or B x=y)\n"
1274 "description \"wibble\"");
1275
1276+ cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ());
1277+ TEST_NE_P (cmd, NULL);
1278+ RUN_COMMAND (NULL, cmd, &output, &lines);
1279+ TEST_EQ (lines, 0);
1280+ nih_free (output);
1281+
1282 cmd = nih_sprintf (NULL, "%s show-config foo 2>&1", get_initctl ());
1283 TEST_NE_P (cmd, NULL);
1284 RUN_COMMAND (NULL, cmd, &output, &lines);
1285@@ -12791,6 +12857,12 @@
1286 "start on (starting JOB=\"boo\" P=Q c=sea or B x=y)\n"
1287 "description \"wibble\"");
1288
1289+ cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ());
1290+ TEST_NE_P (cmd, NULL);
1291+ RUN_COMMAND (NULL, cmd, &output, &lines);
1292+ TEST_EQ (lines, 0);
1293+ nih_free (output);
1294+
1295 cmd = nih_sprintf (NULL, "%s show-config foo 2>&1", get_initctl ());
1296 TEST_NE_P (cmd, NULL);
1297 RUN_COMMAND (NULL, cmd, &output, &lines);
1298@@ -12830,6 +12902,12 @@
1299 "start on A and (B FOO=BAR or starting C x=y)\n"
1300 "description \"wibble\"");
1301
1302+ cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ());
1303+ TEST_NE_P (cmd, NULL);
1304+ RUN_COMMAND (NULL, cmd, &output, &lines);
1305+ TEST_EQ (lines, 0);
1306+ nih_free (output);
1307+
1308 cmd = nih_sprintf (NULL, "%s show-config foo 2>&1", get_initctl ());
1309 TEST_NE_P (cmd, NULL);
1310 RUN_COMMAND (NULL, cmd, &output, &lines);
1311@@ -12876,6 +12954,12 @@
1312 "(stopped gdm or stopped kdm or stopped xdm A=B or stopping lxdm)))\n"
1313 "description \"wibble\"");
1314
1315+ cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ());
1316+ TEST_NE_P (cmd, NULL);
1317+ RUN_COMMAND (NULL, cmd, &output, &lines);
1318+ TEST_EQ (lines, 0);
1319+ nih_free (output);
1320+
1321 cmd = nih_sprintf (NULL, "%s show-config foo 2>&1", get_initctl ());
1322 TEST_NE_P (cmd, NULL);
1323 RUN_COMMAND (NULL, cmd, &output, &lines);
1324@@ -13011,6 +13095,12 @@
1325 "task\n"
1326 "exec true");
1327
1328+ cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ());
1329+ TEST_NE_P (cmd, NULL);
1330+ RUN_COMMAND (NULL, cmd, &output, &lines);
1331+ TEST_EQ (lines, 0);
1332+ nih_free (output);
1333+
1334 cmd = nih_sprintf (NULL, "%s check-config 2>&1", get_initctl ());
1335 TEST_NE_P (cmd, NULL);
1336 RUN_COMMAND (NULL, cmd, &output, &lines);
1337@@ -13031,6 +13121,12 @@
1338 CREATE_FILE (dirname, "baz.conf",
1339 "emits wibble");
1340
1341+ cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ());
1342+ TEST_NE_P (cmd, NULL);
1343+ RUN_COMMAND (NULL, cmd, &output, &lines);
1344+ TEST_EQ (lines, 0);
1345+ nih_free (output);
1346+
1347 cmd = nih_sprintf (NULL, "%s check-config 2>&1", get_initctl ());
1348 TEST_NE_P (cmd, NULL);
1349 RUN_COMMAND (NULL, cmd, &output, &lines);
1350@@ -13052,6 +13148,12 @@
1351 "task\n"
1352 "exec true");
1353
1354+ cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ());
1355+ TEST_NE_P (cmd, NULL);
1356+ RUN_COMMAND (NULL, cmd, &output, &lines);
1357+ TEST_EQ (lines, 0);
1358+ nih_free (output);
1359+
1360 cmd = nih_sprintf (NULL, "%s check-config --ignore-events=wibble 2>&1",
1361 get_initctl ());
1362 TEST_NE_P (cmd, NULL);
1363@@ -13067,6 +13169,12 @@
1364 CREATE_FILE (dirname, "foo.conf",
1365 "start on (fred and wilma)");
1366
1367+ cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ());
1368+ TEST_NE_P (cmd, NULL);
1369+ RUN_COMMAND (NULL, cmd, &output, &lines);
1370+ TEST_EQ (lines, 0);
1371+ nih_free (output);
1372+
1373 cmd = nih_sprintf (NULL, "%s check-config --ignore-events=wilma,foo,fred 2>&1",
1374 get_initctl ());
1375 TEST_NE_P (cmd, NULL);
1376@@ -13091,6 +13199,12 @@
1377 CREATE_FILE (dirname, "mountall.conf", "exec true");
1378 CREATE_FILE (dirname, "gdm.conf" , "exec true");
1379
1380+ cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ());
1381+ TEST_NE_P (cmd, NULL);
1382+ RUN_COMMAND (NULL, cmd, &output, &lines);
1383+ TEST_EQ (lines, 0);
1384+ nih_free (output);
1385+
1386 cmd = nih_sprintf (NULL, "%s check-config --ignore-events=runlevel 2>&1",
1387 get_initctl ());
1388 TEST_NE_P (cmd, NULL);
1389@@ -13115,6 +13229,12 @@
1390
1391 CREATE_FILE (dirname, "mountall.conf", "exec true");
1392
1393+ cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ());
1394+ TEST_NE_P (cmd, NULL);
1395+ RUN_COMMAND (NULL, cmd, &output, &lines);
1396+ TEST_EQ (lines, 0);
1397+ nih_free (output);
1398+
1399 cmd = nih_sprintf (NULL, "%s check-config --ignore-events=runlevel 2>&1",
1400 get_initctl ());
1401 TEST_NE_P (cmd, NULL);
1402@@ -13146,6 +13266,12 @@
1403 CREATE_FILE (dirname, "mountall.conf", "exec true");
1404 CREATE_FILE (dirname, "gdm.conf" , "exec true");
1405
1406+ cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ());
1407+ TEST_NE_P (cmd, NULL);
1408+ RUN_COMMAND (NULL, cmd, &output, &lines);
1409+ TEST_EQ (lines, 0);
1410+ nih_free (output);
1411+
1412 cmd = nih_sprintf (NULL, "%s check-config --ignore-events=runlevel 2>&1",
1413 get_initctl ());
1414 TEST_NE_P (cmd, NULL);
1415@@ -13170,6 +13296,12 @@
1416
1417 CREATE_FILE (dirname, "mountall.conf", "exec true");
1418
1419+ cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ());
1420+ TEST_NE_P (cmd, NULL);
1421+ RUN_COMMAND (NULL, cmd, &output, &lines);
1422+ TEST_EQ (lines, 0);
1423+ nih_free (output);
1424+
1425 cmd = nih_sprintf (NULL, "%s check-config --ignore-events=runlevel 2>&1",
1426 get_initctl ());
1427 TEST_NE_P (cmd, NULL);
1428@@ -13203,6 +13335,12 @@
1429 CREATE_FILE (dirname, "portmap.conf", "exec true");
1430 CREATE_FILE (dirname, "beano.conf", "exec true");
1431
1432+ cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ());
1433+ TEST_NE_P (cmd, NULL);
1434+ RUN_COMMAND (NULL, cmd, &output, &lines);
1435+ TEST_EQ (lines, 0);
1436+ nih_free (output);
1437+
1438 cmd = nih_sprintf (NULL, "%s check-config --ignore-events=runlevel 2>&1",
1439 get_initctl ());
1440 TEST_NE_P (cmd, NULL);
1441@@ -13240,6 +13378,12 @@
1442 "emits hello");
1443 CREATE_FILE (dirname, "gdm.conf", "exec true");
1444
1445+ cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ());
1446+ TEST_NE_P (cmd, NULL);
1447+ RUN_COMMAND (NULL, cmd, &output, &lines);
1448+ TEST_EQ (lines, 0);
1449+ nih_free (output);
1450+
1451 cmd = nih_sprintf (NULL, "%s check-config >&1",
1452 get_initctl ());
1453 TEST_NE_P (cmd, NULL);
1454@@ -13272,6 +13416,12 @@
1455 CREATE_FILE (dirname, "mountall.conf", "exec true");
1456 CREATE_FILE (dirname, "portmap.conf", "exec true");
1457
1458+ cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ());
1459+ TEST_NE_P (cmd, NULL);
1460+ RUN_COMMAND (NULL, cmd, &output, &lines);
1461+ TEST_EQ (lines, 0);
1462+ nih_free (output);
1463+
1464 cmd = nih_sprintf (NULL, "%s check-config 2>&1",
1465 get_initctl ());
1466 TEST_NE_P (cmd, NULL);
1467@@ -13313,6 +13463,12 @@
1468 CREATE_FILE (dirname, "wibble.conf", "emits wibble");
1469 CREATE_FILE (dirname, "beano.conf", "exec true");
1470
1471+ cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ());
1472+ TEST_NE_P (cmd, NULL);
1473+ RUN_COMMAND (NULL, cmd, &output, &lines);
1474+ TEST_EQ (lines, 0);
1475+ nih_free (output);
1476+
1477 cmd = nih_sprintf (NULL, "%s check-config 2>&1",
1478 get_initctl ());
1479 TEST_NE_P (cmd, NULL);
1480@@ -13350,6 +13506,12 @@
1481 CREATE_FILE (dirname, "wibble.conf", "emits wibble");
1482 CREATE_FILE (dirname, "beano.conf", "exec true");
1483
1484+ cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ());
1485+ TEST_NE_P (cmd, NULL);
1486+ RUN_COMMAND (NULL, cmd, &output, &lines);
1487+ TEST_EQ (lines, 0);
1488+ nih_free (output);
1489+
1490 cmd = nih_sprintf (NULL, "%s check-config --warn 2>&1",
1491 get_initctl ());
1492 TEST_NE_P (cmd, NULL);
1493@@ -16080,6 +16242,12 @@
1494 "author \"foo\"\n"
1495 "description \"wibble\"");
1496
1497+ cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ());
1498+ TEST_NE_P (cmd, NULL);
1499+ RUN_COMMAND (NULL, cmd, &output, &lines);
1500+ TEST_EQ (lines, 0);
1501+ nih_free (output);
1502+
1503 cmd = nih_sprintf (NULL, "%s usage foo 2>&1", get_initctl ());
1504 TEST_NE_P (cmd, NULL);
1505 RUN_COMMAND (NULL, cmd, &output, &lines);
1506@@ -16096,6 +16264,12 @@
1507 CREATE_FILE (dirname, "foo.conf",
1508 "usage \"this is usage\"");
1509
1510+ cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ());
1511+ TEST_NE_P (cmd, NULL);
1512+ RUN_COMMAND (NULL, cmd, &output, &lines);
1513+ TEST_EQ (lines, 0);
1514+ nih_free (output);
1515+
1516 cmd = nih_sprintf (NULL, "%s usage foo 2>&1", get_initctl ());
1517 TEST_NE_P (cmd, NULL);
1518 RUN_COMMAND (NULL, cmd, &output, &lines);
1519@@ -16113,6 +16287,12 @@
1520 "instance $FOO\n"
1521 "usage \"this is usage\"");
1522
1523+ cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ());
1524+ TEST_NE_P (cmd, NULL);
1525+ RUN_COMMAND (NULL, cmd, &output, &lines);
1526+ TEST_EQ (lines, 0);
1527+ nih_free (output);
1528+
1529 memset (&command, 0, sizeof command);
1530 args[0] = "foo";
1531 args[1] = NULL;
1532@@ -16246,6 +16426,12 @@
1533
1534 CREATE_FILE (confdir, "foo.conf", "exec env");
1535
1536+ cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ());
1537+ TEST_NE_P (cmd, NULL);
1538+ RUN_COMMAND (NULL, cmd, &output, &line_count);
1539+ TEST_EQ (line_count, 0);
1540+ nih_free (output);
1541+
1542 cmd = nih_sprintf (NULL, "%s start foo 2>&1", get_initctl ());
1543 TEST_NE_P (cmd, NULL);
1544 RUN_COMMAND (NULL, cmd, &output, &line_count);
1545@@ -16393,6 +16579,12 @@
1546
1547 CREATE_FILE (confdir, "empty-env.conf", contents);
1548
1549+ cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ());
1550+ TEST_NE_P (cmd, NULL);
1551+ RUN_COMMAND (NULL, cmd, &output, &line_count);
1552+ TEST_EQ (line_count, 0);
1553+ nih_free (output);
1554+
1555 cmd = nih_sprintf (NULL, "%s start empty-env 2>&1", get_initctl ());
1556 TEST_NE_P (cmd, NULL);
1557 RUN_COMMAND (NULL, cmd, &output, &line_count);
1558@@ -17504,6 +17696,12 @@
1559
1560 CREATE_FILE (confdir, "modified-env.conf", "exec env");
1561
1562+ cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ());
1563+ TEST_NE_P (cmd, NULL);
1564+ RUN_COMMAND (NULL, cmd, &output, &line_count);
1565+ TEST_EQ (line_count, 0);
1566+ nih_free (output);
1567+
1568 cmd = nih_sprintf (NULL, "%s start modified-env 2>&1", get_initctl ());
1569 TEST_NE_P (cmd, NULL);
1570 RUN_COMMAND (NULL, cmd, &output, &line_count);
1571@@ -17629,6 +17827,12 @@
1572
1573 CREATE_FILE (confdir, "foo.conf", contents);
1574
1575+ cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ());
1576+ TEST_NE_P (cmd, NULL);
1577+ RUN_COMMAND (NULL, cmd, &output, &line_count);
1578+ TEST_EQ (line_count, 0);
1579+ nih_free (output);
1580+
1581 cmd = nih_sprintf (NULL, "%s start foo 2>&1", get_initctl ());
1582 TEST_NE_P (cmd, NULL);
1583
1584@@ -17674,6 +17878,12 @@
1585
1586 CREATE_FILE (confdir, "foo.conf", contents);
1587
1588+ cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ());
1589+ TEST_NE_P (cmd, NULL);
1590+ RUN_COMMAND (NULL, cmd, &output, &line_count);
1591+ TEST_EQ (line_count, 0);
1592+ nih_free (output);
1593+
1594 cmd = nih_sprintf (NULL, "%s start foo 2>&1", get_initctl ());
1595 TEST_NE_P (cmd, NULL);
1596 RUN_COMMAND (NULL, cmd, &output, &line_count);
1597@@ -17705,6 +17915,12 @@
1598
1599 CREATE_FILE (confdir, "bar.conf", contents);
1600
1601+ cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ());
1602+ TEST_NE_P (cmd, NULL);
1603+ RUN_COMMAND (NULL, cmd, &output, &line_count);
1604+ TEST_EQ (line_count, 0);
1605+ nih_free (output);
1606+
1607 cmd = nih_sprintf (NULL, "%s start bar 2>&1", get_initctl ());
1608 TEST_NE_P (cmd, NULL);
1609 RUN_COMMAND (NULL, cmd, &output, &line_count);
1610@@ -17788,6 +18004,12 @@
1611
1612 CREATE_FILE (confdir, "foo.conf", "exec env");
1613
1614+ cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ());
1615+ TEST_NE_P (cmd, NULL);
1616+ RUN_COMMAND (NULL, cmd, &output, &lines);
1617+ TEST_EQ (lines, 0);
1618+ nih_free (output);
1619+
1620 cmd = nih_sprintf (NULL, "%s start foo 2>&1", get_initctl ());
1621 TEST_NE_P (cmd, NULL);
1622 RUN_COMMAND (NULL, cmd, &output, &lines);

Subscribers

People subscribed via source and target branches