Merge authors: Dimitri John Ledkov (xnox) James Hunt (jamesodhunt) Related merge proposals: https://code.launchpad.net/~xnox/upstart/shrink-notifications/+merge/225200 proposed by: Dimitri John Ledkov (xnox) review: Needs Fixing - James Hunt (jamesodhunt) ------------------------------------------------------------ revno: 1645 [merge] committer: Dimitri John Ledkov <dimitri.led...@canonical.com> branch nick: trunk timestamp: Fri 2014-07-11 17:36:49 +0100 message: Merge race fixes modified: ChangeLog init/job.c init/job_process.c init/job_process.h init/tests/test_job_process.c test/test_util_common.c util/tests/test_initctl.c
-- lp:upstart https://code.launchpad.net/~upstart-devel/upstart/trunk Your team Upstart Reviewers is subscribed to branch lp:upstart. To unsubscribe from this branch go to https://code.launchpad.net/~upstart-devel/upstart/trunk/+edit-subscription
=== modified file 'ChangeLog' --- ChangeLog 2014-07-08 14:11:53 +0000 +++ ChangeLog 2014-07-10 16:07:57 +0000 @@ -1,3 +1,18 @@ +2014-07-09 James Hunt <james.h...@ubuntu.com> + + * init/job_process.c: Unhide job_process_error_abort() to allow it to be + called by the tests. + * init/tests/test_job_process.c: RESILIENT_TEST_CHILD(): New macro + to work around a bug in NIH's TEST_CHILD() where it doesn't handle + EINTR. + * init/tests/test_job_process.c: test_handler(): New tests to ensure + async handling can cope with both 'waitid() before select()' and + vice versa: + - "with child exit notification before child setup success notification" + - "with child exit notification before child setup failure notification" + - "with child setup success notification before child exit notification" + - "with child setup failure notification before child exit notification" + 2014-07-08 James Hunt <james.h...@ubuntu.com> * init/main.c: main(): === modified file 'init/job.c' --- init/job.c 2014-06-12 14:23:47 +0000 +++ init/job.c 2014-07-10 16:05:04 +0000 @@ -396,11 +396,6 @@ { nih_assert (job != NULL); - /* We may not be blocked by any events when doing first - * transition. - */ - nih_assert (job->blocker == NULL); - while (job->state != state) { JobState old_state; int unused; === modified file 'init/job_process.c' --- init/job_process.c 2014-07-08 14:11:53 +0000 +++ init/job_process.c 2014-07-10 16:07:57 +0000 @@ -111,9 +111,6 @@ int disable_respawn = FALSE; /* Prototypes for static functions */ -static void job_process_error_abort (int fd, JobProcessErrorType type, - int arg) - __attribute__ ((noreturn)); static void job_process_remap_fd (int *fd, int reserved_fd, int error_fd); /** @@ -983,7 +980,7 @@ * * This function calls the exit() system call, so never returns. **/ -static void +void job_process_error_abort (int fd, JobProcessErrorType type, int arg) @@ -2457,7 +2454,15 @@ err = nih_error_get (); - nih_assert (err->number == JOB_PROCESS_ERROR); + if (err->number != JOB_PROCESS_ERROR) { + nih_warn ("%s: %s", _("Temporary process spawn error"), + err->message); + nih_free (err); + return; + } + + /* Wilco. Out. */ + nih_io_buffer_shrink (io->recv_buf, len); /* Non-temporary error condition */ nih_warn (_("Failed to spawn %s %s process: %s"), @@ -2491,12 +2496,12 @@ /* Note that pts_master is closed automatically in the parent * when the log object is destroyed. */ + process_data->valid = FALSE; nih_io_shutdown (io); /* Invalidate */ process_data->job_process_fd = -1; - process_data->valid = FALSE; } /** @@ -2519,6 +2524,8 @@ */ if (! process_data) return; + if (! process_data->valid) + return; nih_assert (io); === modified file 'init/job_process.h' --- init/job_process.h 2014-06-02 20:29:33 +0000 +++ init/job_process.h 2014-07-09 16:12:52 +0000 @@ -194,6 +194,10 @@ void job_process_error_handler (const char *buf, size_t len); +void job_process_error_abort (int fd, JobProcessErrorType type, + int arg) + __attribute__ ((noreturn)); + NIH_END_EXTERN #endif /* INIT_JOB_PROCESS_H */ === modified file 'init/tests/test_job_process.c' --- init/tests/test_job_process.c 2014-07-07 10:15:25 +0000 +++ init/tests/test_job_process.c 2014-07-11 12:18:16 +0000 @@ -122,6 +122,80 @@ TEST_EQ (ok, TRUE); \ } while (0) + +/* + * Register regular child handler. + * Register another handler to be called after the primary + * Upstart handler to allow the test to exit the main loop + * quickly on success. + * Process the event queue each time through the main loop + */ + +#define TEST_INSTALL_CHILD_HANDLERS() \ + NIH_MUST (nih_child_add_watch (NULL, \ + -1, \ + NIH_CHILD_ALL, \ + test_job_process_handler,\ + NULL)); \ + NIH_MUST (nih_child_add_watch (NULL, \ + -1, \ + NIH_CHILD_ALL, \ + job_process_handler, \ + NULL)); \ + NIH_MUST (nih_main_loop_add_func (NULL, (NihMainLoopCb)event_poll, \ + NULL)) + + +#define TEST_CLEAR_CHILD_STATUS() \ + do { \ + TEST_EQ (waitid (P_ALL, 0, &siginfo, WEXITED | WNOWAIT), -1); \ + TEST_EQ (errno, ECHILD); \ + errno = 0; \ + child_exit_after = 1; \ + for (int _i = 0; _i < PROCESS_LAST; _i++) { \ + child_exit_status[_i] = -1; \ + } \ + } while (0) + + +/* Modified version of NIH's TEST_CHILD() that is resilient + * to temporary errors. + */ +#define RESILIENT_TEST_CHILD(_pid) \ + do { \ + int _test_fds[2]; \ + fflush (stdout); \ + fflush (stderr); \ + assert0 (pipe (_test_fds)); \ + _pid = fork (); \ + if (_pid > 0) { \ + ssize_t ret; \ + char _test_buf[1]; \ + close (_test_fds[1]); \ + while (TRUE) { \ + ret = read (_test_fds[0], _test_buf, 1); \ + if (ret > 0) { \ + assert (ret == 1); \ + break; \ + } else if (ret < 0 && errno != EINTR) { \ + nih_assert_not_reached (); \ + } else { \ + nih_assert_not_reached (); \ + } \ + } \ + close (_test_fds[0]); \ + } else if (_pid == 0) { \ + close (_test_fds[0]); \ + assert (write (_test_fds[1], "\n", 1) == 1); \ + close (_test_fds[1]); \ + } \ + } while (0); \ + if (_pid == 0) \ + for (int _test_child = 0; _test_child < 2; _test_child++) \ + if (_test_child) { \ + abort (); \ + } else + /* Sadly we can't test everything that job_process_spawn() does simply because * a lot of it can only be done by root, or in the case of the console stuff, * kills whatever had /dev/console (usually X). @@ -147,6 +221,36 @@ static int get_available_pty_count (void) __attribute__((unused)); static void close_all_files (void); +static int child_exit_status[PROCESS_LAST]; +static int child_exit_after; + +/** + * test_job_process_handler: + * + * @data: existing NihList that this function will add entries to, + * @pid: process that changed, + * @event: event that occurred on the child, + * @status: exit status, signal raised or ptrace event. + * + * Handler that just sets some globals and requests the main loop to + * exit to allow the test that installs it to check the values passed to + * this function as appropriate. + **/ +void +test_job_process_handler (void *data, + pid_t pid, + NihChildEvents event, + int status) +{ + if (event != NIH_CHILD_EXITED) + return; + child_exit_after--; + child_exit_status[child_exit_after] = status; + if (child_exit_after < 1) + nih_main_loop_exit (0); +} + + static void child (enum child_tests test, const char *filename) @@ -1056,6 +1160,7 @@ nih_free (class); } + /* Check that if we try and run a command that doesn't exist, * job_process_start() raises a ProcessError and the command doesn't * have any stored process id for it. @@ -1063,10 +1168,14 @@ TEST_FEATURE ("with no such file"); TEST_HASH_EMPTY (job_classes); + TEST_RESET_MAIN_LOOP (); + TEST_INSTALL_CHILD_HANDLERS (); + output = tmpfile (); TEST_ALLOC_FAIL { TEST_ALLOC_SAFE { + TEST_HASH_EMPTY (job_classes); class = job_class_new (NULL, "test", NULL); class->console = CONSOLE_NONE; class->process[PROCESS_MAIN] = process_new (class); @@ -1076,12 +1185,16 @@ job = job_new (class, "foo"); job->goal = JOB_START; job->state = JOB_SPAWNED; + + nih_hash_add (job_classes, &class->entry); + TEST_CLEAR_CHILD_STATUS (); } TEST_DIVERT_STDERR (output) { job_process_start (job, PROCESS_MAIN); - TEST_WATCH_LOOP (); - event_poll (); + TEST_GT (job->pid[PROCESS_MAIN], 0); + TEST_EQ (nih_main_loop (), 0); + TEST_EQ (child_exit_status[PROCESS_MAIN], 255); } rewind (output); @@ -1098,6 +1211,8 @@ TEST_EQ (rmdir (dirname), 0); + TEST_RESET_MAIN_LOOP (); + TEST_FILENAME (dirname); TEST_EQ (mkdir (dirname, 0755), 0); @@ -3018,6 +3133,9 @@ TEST_FEATURE ("with single-line command running an invalid command"); TEST_HASH_EMPTY (job_classes); + TEST_RESET_MAIN_LOOP (); + TEST_INSTALL_CHILD_HANDLERS (); + class = job_class_new (NULL, "buzz", NULL); TEST_NE_P (class, NULL); @@ -3039,14 +3157,21 @@ job->goal = JOB_START; job->state = JOB_SPAWNED; + /* XXX: Manually add the class so job_process_find() works */ + nih_hash_add (job_classes, &class->entry); + output = tmpfile (); TEST_NE_P (output, NULL); + TEST_CLEAR_CHILD_STATUS (); TEST_DIVERT_STDERR (output) { job_process_start (job, PROCESS_MAIN); - TEST_WATCH_UPDATE (); - TEST_WATCH_UPDATE (); - event_poll (); + TEST_GT (job->pid[PROCESS_MAIN], 0); + TEST_EQ (nih_main_loop (), 0); + TEST_EQ (child_exit_status[PROCESS_MAIN], 255); } + + TEST_FILE_END (output); + fclose (output); /* We don't expect a logfile to be written since there is no @@ -3056,11 +3181,14 @@ TEST_EQ (errno, ENOENT); nih_free (class); + TEST_RESET_MAIN_LOOP (); /************************************************************/ TEST_FEATURE ("with single-line command running an invalid command, then a 1-line post-stop script"); TEST_HASH_EMPTY (job_classes); + TEST_INSTALL_CHILD_HANDLERS (); + class = job_class_new (NULL, "asterix", NULL); TEST_NE_P (class, NULL); @@ -3086,6 +3214,9 @@ job = job_new (class, ""); + /* XXX: Manually add the class so job_process_find() works */ + nih_hash_add (job_classes, &class->entry); + output = tmpfile (); TEST_NE_P (output, NULL); TEST_DIVERT_STDERR (output) { @@ -3093,37 +3224,18 @@ job->goal = JOB_START; job->state = JOB_SPAWNED; + TEST_CLEAR_CHILD_STATUS (); + child_exit_after = 2; job_process_start (job, PROCESS_MAIN); - TEST_WATCH_UPDATE (); - - /* We don't expect a logfile to be written since there is no - * accompanying shell to write the error. - */ - TEST_EQ (stat (filename, &statbuf), -1); - TEST_EQ (errno, ENOENT); - - job->goal = JOB_STOP; - job->state = JOB_POST_STOP; - - job_process_start (job, PROCESS_POST_STOP); - - TEST_NE (job->pid[PROCESS_POST_STOP], 0); - TEST_WATCH_UPDATE (); - - /* Flush the io so that the shell on the client side - * gets the data (the script to execute). - */ - TEST_WATCH_UPDATE (); - - waitpid (job->pid[PROCESS_POST_STOP], &status, 0); - TEST_TRUE (WIFEXITED (status)); - TEST_EQ (WEXITSTATUS (status), 0); - - TEST_WATCH_UPDATE (); - - /* .. but the post stop should have written data */ + TEST_GT (job->pid[PROCESS_MAIN], 0); + TEST_EQ (nih_main_loop (), 0); + /* Check exit status in reverse order */ + /* Main */ + TEST_EQ (child_exit_status[1], 255); + /* Post-stop */ + TEST_EQ (child_exit_status[0], 0); + /* And the post stop should have written data */ TEST_EQ (stat (filename, &statbuf), 0); - event_poll (); } fclose (output); @@ -3144,6 +3256,9 @@ TEST_FEATURE ("with single-line command running an invalid command, then a 2-line post-stop script"); TEST_HASH_EMPTY (job_classes); + TEST_RESET_MAIN_LOOP (); + TEST_INSTALL_CHILD_HANDLERS (); + class = job_class_new (NULL, "asterix", NULL); TEST_NE_P (class, NULL); @@ -3168,6 +3283,8 @@ TEST_EQ (errno, ENOENT); job = job_new (class, ""); + /* XXX: Manually add the class so job_process_find() works */ + nih_hash_add (job_classes, &class->entry); output = tmpfile (); TEST_NE_P (output, NULL); @@ -3176,39 +3293,17 @@ job->goal = JOB_START; job->state = JOB_SPAWNED; + TEST_CLEAR_CHILD_STATUS (); + child_exit_after = 2; job_process_start (job, PROCESS_MAIN); - TEST_WATCH_UPDATE (); - TEST_WATCH_UPDATE (); - - /* We don't expect a logfile to be written since there is no - * accompanying shell to write the error. - */ - TEST_EQ (stat (filename, &statbuf), -1); - TEST_EQ (errno, ENOENT); - - job->goal = JOB_STOP; - job->state = JOB_POST_STOP; - - job_process_start (job, PROCESS_POST_STOP); - TEST_WATCH_UPDATE (); - - TEST_NE (job->pid[PROCESS_POST_STOP], 0); - - /* Flush the io so that the shell on the client side - * gets the data (the script to execute). - */ - TEST_WATCH_UPDATE (); - - waitpid (job->pid[PROCESS_POST_STOP], &status, 0); - TEST_TRUE (WIFEXITED (status)); - TEST_EQ (WEXITSTATUS (status), 0); - - /* Allow the log to be written */ - TEST_WATCH_UPDATE (); - - /* .. but the post stop should have written data */ + TEST_NE (job->pid[PROCESS_MAIN], 0); + + TEST_EQ (nih_main_loop (), 0); + TEST_EQ (child_exit_status[1], 255); + TEST_EQ (child_exit_status[0], 0); + + /* And the post stop should have written data */ TEST_EQ (stat (filename, &statbuf), 0); - event_poll (); } fclose (output); @@ -3225,6 +3320,7 @@ TEST_EQ (unlink (filename), 0); nih_free (class); + TEST_RESET_MAIN_LOOP (); /************************************************************/ TEST_FEATURE ("with single-line command running an invalid command, then a post-stop command"); @@ -3255,6 +3351,9 @@ job = job_new (class, ""); + TEST_RESET_MAIN_LOOP (); + TEST_INSTALL_CHILD_HANDLERS (); + output = tmpfile (); TEST_NE_P (output, NULL); TEST_DIVERT_STDERR (output) { @@ -3262,37 +3361,19 @@ job->goal = JOB_START; job->state = JOB_SPAWNED; + TEST_CLEAR_CHILD_STATUS (); + child_exit_after = 2; + job_process_start (job, PROCESS_MAIN); - TEST_WATCH_UPDATE (); - - /* We don't expect a logfile to be written since there is no - * accompanying shell to write the error. - */ - TEST_EQ (stat (filename, &statbuf), -1); - TEST_EQ (errno, ENOENT); - - job->goal = JOB_STOP; - job->state = JOB_POST_STOP; - - job_process_start (job, PROCESS_POST_STOP); - TEST_WATCH_UPDATE (); - - TEST_NE (job->pid[PROCESS_POST_STOP], 0); - - /* Flush the io so that the shell on the client side - * gets the data (the script to execute). - */ - TEST_WATCH_UPDATE (); - - waitpid (job->pid[PROCESS_POST_STOP], &status, 0); - TEST_TRUE (WIFEXITED (status)); - TEST_EQ (WEXITSTATUS (status), 0); - - TEST_WATCH_UPDATE (); - - /* .. but the post stop should have written data */ + TEST_GT (job->pid[PROCESS_MAIN], 0); + TEST_EQ (nih_main_loop (), 0); + TEST_GT (job->pid[PROCESS_POST_STOP], 0); + TEST_EQ (child_exit_status[1], 255); + TEST_EQ (child_exit_status[0], 0); + + /* The post stop should have written data */ TEST_EQ (stat (filename, &statbuf), 0); - event_poll (); + } fclose (output); @@ -3309,6 +3390,8 @@ nih_free (class); + TEST_RESET_MAIN_LOOP (); + /************************************************************/ TEST_FEATURE ("with single-line command running an invalid command, then an invalid post-stop command"); TEST_HASH_EMPTY (job_classes); @@ -3338,6 +3421,9 @@ job = job_new (class, ""); + TEST_RESET_MAIN_LOOP (); + TEST_INSTALL_CHILD_HANDLERS (); + output = tmpfile (); TEST_NE_P (output, NULL); TEST_DIVERT_STDERR (output) { @@ -3345,29 +3431,24 @@ job->goal = JOB_START; job->state = JOB_SPAWNED; + TEST_CLEAR_CHILD_STATUS (); + child_exit_after = 2; + job_process_start (job, PROCESS_MAIN); - TEST_WATCH_UPDATE (); - - /* We don't expect a logfile to be written since there is no - * accompanying shell to write the error. - */ - TEST_EQ (stat (filename, &statbuf), -1); - TEST_EQ (errno, ENOENT); - - job->goal = JOB_STOP; - job->state = JOB_POST_STOP; - - job_process_start (job, PROCESS_POST_STOP); - TEST_WATCH_UPDATE (); + TEST_GT (job->pid[PROCESS_MAIN], 0); + TEST_EQ (nih_main_loop (), 0); + TEST_EQ (child_exit_status[1], 255); + TEST_EQ (child_exit_status[0], 255); /* Again, no file expected */ TEST_EQ (stat (filename, &statbuf), -1); TEST_EQ (errno, ENOENT); - event_poll (); } fclose (output); nih_free (class); + TEST_RESET_MAIN_LOOP (); + /************************************************************/ TEST_FEATURE ("with single-line command running a valid command, then a 1-line invalid post-stop command"); TEST_HASH_EMPTY (job_classes); @@ -3397,6 +3478,9 @@ job = job_new (class, ""); + TEST_RESET_MAIN_LOOP (); + TEST_INSTALL_CHILD_HANDLERS (); + output = tmpfile (); TEST_NE_P (output, NULL); TEST_DIVERT_STDERR (output) { @@ -3404,29 +3488,26 @@ job->goal = JOB_START; job->state = JOB_SPAWNED; + TEST_CLEAR_CHILD_STATUS (); + job_process_start (job, PROCESS_MAIN); - - TEST_NE (job->pid[PROCESS_MAIN], 0); - - waitpid (job->pid[PROCESS_MAIN], &status, 0); - TEST_TRUE (WIFEXITED (status)); - TEST_EQ (WEXITSTATUS (status), 0); - - /* Flush the io so that the shell on the client side - * gets the data (the script to execute). - */ - TEST_WATCH_UPDATE (); + TEST_GT (job->pid[PROCESS_MAIN], 0); + TEST_EQ (nih_main_loop (), 0); + TEST_EQ (child_exit_status[0], 0); + TEST_EQ (child_exit_status[1], -1); /* Expect a log file */ TEST_EQ (stat (filename, &statbuf), 0); job->goal = JOB_STOP; job->state = JOB_POST_STOP; + + TEST_CLEAR_CHILD_STATUS (); job_process_start (job, PROCESS_POST_STOP); - TEST_WATCH_UPDATE (); - - TEST_EQ (job->pid[PROCESS_POST_STOP], 0); + TEST_GT (job->pid[PROCESS_POST_STOP], 0); + TEST_EQ (nih_main_loop (), 0); + TEST_EQ (child_exit_status[0], 255); } fclose (output); @@ -3443,10 +3524,15 @@ nih_free (class); + TEST_RESET_MAIN_LOOP (); + /************************************************************/ TEST_FEATURE ("with multi-line script running an invalid command"); TEST_HASH_EMPTY (job_classes); + TEST_RESET_MAIN_LOOP (); + TEST_INSTALL_CHILD_HANDLERS (); + class = job_class_new (NULL, "blah", NULL); TEST_NE_P (class, NULL); @@ -3463,17 +3549,13 @@ job = job_new (class, ""); job->goal = JOB_START; job->state = JOB_SPAWNED; + nih_hash_add (job_classes, &class->entry); + TEST_CLEAR_CHILD_STATUS (); job_process_start (job, PROCESS_MAIN); - TEST_WATCH_UPDATE (); - - TEST_NE (job->pid[PROCESS_MAIN], 0); - - TEST_WATCH_UPDATE (); - waitpid (job->pid[PROCESS_MAIN], &status, 0); - TEST_TRUE (WIFEXITED (status)); - TEST_NE (WEXITSTATUS (status), 0); - TEST_WATCH_UPDATE (); + TEST_GT (job->pid[PROCESS_MAIN], 0); + TEST_EQ (nih_main_loop (), 0); + TEST_EQ (child_exit_status[0], 127); TEST_EQ (stat (filename, &statbuf), 0); @@ -3502,6 +3584,7 @@ TEST_EQ (unlink (filename), 0); nih_free (class); + TEST_RESET_MAIN_LOOP (); /************************************************************/ TEST_FEATURE ("with multi-line script that writes 1 line to stdout then 1 line to stderr"); @@ -3977,6 +4060,9 @@ */ TEST_FEATURE ("with setuid"); TEST_HASH_EMPTY (job_classes); + TEST_RESET_MAIN_LOOP (); + TEST_INSTALL_CHILD_HANDLERS (); + TEST_NE_P (output, NULL); TEST_ALLOC_FAIL { @@ -3999,30 +4085,30 @@ job->goal = JOB_START; job->state = JOB_SPAWNED; + nih_hash_add (job_classes, &class->entry); + TEST_CLEAR_CHILD_STATUS (); + output = tmpfile (); } TEST_DIVERT_STDERR (output) { job_process_start (job, PROCESS_MAIN); - TEST_WATCH_UPDATE (); + TEST_GT (job->pid[PROCESS_MAIN], 0); + TEST_EQ (nih_main_loop (), 0); } if (geteuid() == 0 || getuid() == pwd->pw_uid) { - TEST_NE (job->pid[PROCESS_MAIN], 0); - - waitpid (job->pid[PROCESS_MAIN], NULL, 0); TEST_EQ (stat (filename, &statbuf), 0); - } - else { + } else { TEST_EQ (stat (filename, &statbuf), -1); - event_poll (); } unlink (filename); nih_free (class); } + + TEST_RESET_MAIN_LOOP (); - /* FIXME with async spawn this test is racy */ /************************************************************/ TEST_FEATURE ("with multiple processes and log"); @@ -4062,10 +4148,10 @@ job = job_new (class, ""); job->goal = JOB_START; - job->state = JOB_SPAWNED; + job->state = JOB_SPAWNING; job_process_start (job, PROCESS_MAIN); - while (stat (filename, &statbuf) != 0) { + while (stat (filename, &statbuf) != 0 || statbuf.st_size < 9) { TEST_WATCH_UPDATE (); } pid = job->pid[PROCESS_MAIN]; @@ -4077,9 +4163,7 @@ TEST_NE_P (output, NULL); /* initial output from main process */ - CHECK_FILE_EQ (output, "started\r\n", TRUE); - - TEST_FILE_END (output); + TEST_FILE_EQ (output, "started\r\n"); TEST_EQ (fclose (output), 0); @@ -4093,7 +4177,10 @@ waitpid (pid, &status, 0); TEST_TRUE (WIFEXITED (status)); TEST_EQ (WEXITSTATUS (status), 0); - TEST_WATCH_UPDATE (); + + while (stat (filename, &statbuf) != 0 || statbuf.st_size < 25) { + TEST_WATCH_UPDATE (); + } output = fopen (filename, "r"); TEST_NE_P (output, NULL); @@ -5488,6 +5575,8 @@ char dirname[PATH_MAX]; nih_local char *logfile = NULL; int fds[2] = { -1, -1}; + NihIo *io = NULL; + nih_local NihIoBuffer *buffer= NULL; TEST_FILENAME (dirname); TEST_EQ (mkdir (dirname, 0755), 0); @@ -8770,13 +8859,288 @@ fclose (output); + nih_free (event); + event_poll (); + + TEST_RESET_MAIN_LOOP (); + + TEST_NE_P (class->process[PROCESS_MAIN], NULL); + TEST_EQ_P (class->process[PROCESS_PRE_START], NULL); + TEST_EQ_P (class->process[PROCESS_POST_START], NULL); + TEST_EQ_P (class->process[PROCESS_PRE_STOP], NULL); + TEST_EQ_P (class->process[PROCESS_POST_STOP], NULL); + TEST_EQ_P (class->process[PROCESS_SECURITY], NULL); + + /************************************************************/ + /* Ensure that if a child is setup successfully and then exits + * before the main loop detects the child fd has closed (due to + * the child calling execvp()), that the state is correct. + */ + TEST_FEATURE ("with child exit notification before child setup success notification"); + + job = job_new (class, ""); + TEST_NE_P (job, NULL); + + job->goal = JOB_START; + job->state = JOB_SPAWNING; + + assert0 (pipe (fds)); + + job->process_data[PROCESS_MAIN] = job_process_data_new (job->process_data, + job, PROCESS_MAIN, fds[0]); + TEST_NE_P (job->process_data[PROCESS_MAIN], NULL); + + TEST_NE_P (class->process[PROCESS_MAIN], NULL); + TEST_EQ_P (class->process[PROCESS_PRE_START], NULL); + TEST_EQ_P (class->process[PROCESS_POST_START], NULL); + TEST_EQ_P (class->process[PROCESS_PRE_STOP], NULL); + TEST_EQ_P (class->process[PROCESS_POST_STOP], NULL); + TEST_EQ_P (class->process[PROCESS_SECURITY], NULL); + + /* used to check if job_process_terminated() called */ + job->process_data[PROCESS_MAIN]->status = -1; + + TEST_CHILD (job->pid[PROCESS_MAIN]) { + close (fds[0]); + + nih_io_set_cloexec (fds[1]); + + execl ("/bin/true", "/bin/true", NULL); + } + close (fds[1]); + + TEST_FREE_TAG (job); + + job_process_handler (NULL, job->pid[PROCESS_MAIN], + NIH_CHILD_EXITED, 0); + + TEST_NOT_FREE (job); + + TEST_TRUE (job->process_data[PROCESS_MAIN]->valid); + TEST_EQ (job->process_data[PROCESS_MAIN]->job_process_fd, fds[0]); + TEST_EQ (job->process_data[PROCESS_MAIN]->shell_fd, -1); + TEST_EQ_P (job->process_data[PROCESS_MAIN]->script, NULL); + + /* job_process_terminated() should have been called now and the + * status recorded. + */ + TEST_EQ (job->process_data[PROCESS_MAIN]->status, 0); + + /* goal should not change until the IO handlers have had a + * chance to run. + */ + TEST_EQ (job->goal, JOB_START); + TEST_EQ (job->state, JOB_SPAWNED); + + TEST_NE_P (job->process_data[PROCESS_MAIN], NULL); + + close (fds[0]); + + pid = job->pid[PROCESS_MAIN]; + + TEST_EQ (timed_waitpid (pid, 5), pid); + + nih_free (job); + TEST_RESET_MAIN_LOOP (); + + /************************************************************/ + /* Ensure that if a child failed to be setup and then exits + * before the main loop detects the child fd has data to read + * that the state is correct. + */ + TEST_FEATURE ("with child exit notification before child setup failure notification"); + + job = job_new (class, ""); + TEST_NE_P (job, NULL); + + job->goal = JOB_START; + job->state = JOB_SPAWNING; + + assert0 (pipe (fds)); + + job->process_data[PROCESS_MAIN] = job_process_data_new (job->process_data, + job, PROCESS_MAIN, fds[0]); + TEST_NE_P (job->process_data[PROCESS_MAIN], NULL); + TEST_EQ (job->process_data[PROCESS_MAIN]->job_process_fd, fds[0]); + TEST_EQ (job->process_data[PROCESS_MAIN]->process, PROCESS_MAIN); + + TEST_CHILD (job->pid[PROCESS_MAIN]) { + close (fds[0]); + + nih_error_raise_no_memory (); + job_process_error_abort (fds[1], JOB_PROCESS_ERROR_CGROUP_SETUP, 0); + } + close (fds[1]); + + TEST_FREE_TAG (job); + + job_process_handler (NULL, job->pid[PROCESS_MAIN], + NIH_CHILD_DUMPED, 255); + + TEST_NOT_FREE (job); + + /* goal should not change until the IO handlers have had a + * chance to run. + */ + TEST_EQ (job->goal, JOB_START); + + TEST_EQ (job->state, JOB_SPAWNED); + TEST_NE_P (job->process_data[PROCESS_MAIN], NULL); + + /* Still valid because the IO handlers haven't fired yet */ + TEST_TRUE (job->process_data[PROCESS_MAIN]->valid); + TEST_EQ (job->process_data[PROCESS_MAIN]->job_process_fd, fds[0]); + + TEST_EQ (job->process_data[PROCESS_MAIN]->shell_fd, -1); + TEST_EQ_P (job->process_data[PROCESS_MAIN]->script, NULL); + + /* job_process_terminated() will have been called now */ + status = job->process_data[PROCESS_MAIN]->status; + TEST_GT (status, 0); + + TEST_TRUE (WIFEXITED (status)); + TEST_EQ (WEXITSTATUS (status), 255); + + /* slurp - don't care about content */ + buffer = read_from_fd (NULL, fds[0]); + close (fds[0]); + + pid = job->pid[PROCESS_MAIN]; + TEST_EQ (timed_waitpid (pid, 5), pid); + + nih_free (job); + TEST_RESET_MAIN_LOOP (); + + /************************************************************/ + TEST_FEATURE ("with child setup success notification before child exit notification"); + + job = job_new (class, ""); + TEST_NE_P (job, NULL); + + job->goal = JOB_START; + job->state = JOB_SPAWNING; + + assert0 (pipe (fds)); + + job->process_data[PROCESS_MAIN] = job_process_data_new (job->process_data, + job, PROCESS_MAIN, fds[0]); + TEST_NE_P (job->process_data[PROCESS_MAIN], NULL); + TEST_EQ (job->process_data[PROCESS_MAIN]->job_process_fd, fds[0]); + TEST_EQ (job->process_data[PROCESS_MAIN]->process, PROCESS_MAIN); + + io = nih_io_reopen (job->process_data[PROCESS_MAIN], + fds[0], + NIH_IO_STREAM, + (NihIoReader)job_process_child_reader, + (NihIoCloseHandler)job_process_close_handler, + NULL, + job->process_data[PROCESS_MAIN]); + TEST_NE_P (io, NULL); + + TEST_CHILD (job->pid[PROCESS_MAIN]) { + close (fds[0]); + + nih_io_set_cloexec (fds[1]); + + execl ("/bin/true", "/bin/true", NULL); + } + close (fds[1]); + + job_process_close_handler (job->process_data[PROCESS_MAIN], io); + + TEST_EQ (job->goal, JOB_START); + TEST_EQ (job->state, JOB_SPAWNED); + TEST_NE_P (job->process_data[PROCESS_MAIN], NULL); + + /* Invalid because the IO handlers have now run */ + TEST_FALSE (job->process_data[PROCESS_MAIN]->valid); + TEST_EQ (job->process_data[PROCESS_MAIN]->job_process_fd, -1); + + TEST_EQ (job->process_data[PROCESS_MAIN]->shell_fd, -1); + TEST_EQ_P (job->process_data[PROCESS_MAIN]->script, NULL); + TEST_EQ (job->process_data[PROCESS_MAIN]->status, 0); + + close (fds[0]); + + pid = job->pid[PROCESS_MAIN]; + TEST_EQ (timed_waitpid (pid, 5), pid); + + nih_free (job); + TEST_RESET_MAIN_LOOP (); + + /************************************************************/ + TEST_FEATURE ("with child setup failure notification before child exit notification"); + + job = job_new (class, ""); + TEST_NE_P (job, NULL); + + job->goal = JOB_START; + job->state = JOB_SPAWNED; + + assert0 (pipe (fds)); + + job->process_data[PROCESS_MAIN] = job_process_data_new (job->process_data, + job, PROCESS_MAIN, fds[0]); + TEST_NE_P (job->process_data[PROCESS_MAIN], NULL); + TEST_EQ (job->process_data[PROCESS_MAIN]->job_process_fd, fds[0]); + TEST_EQ (job->process_data[PROCESS_MAIN]->process, PROCESS_MAIN); + + /* Can't use job_register_child_handler() as we want the return + * value. + */ + io = nih_io_reopen (job->process_data[PROCESS_MAIN], + fds[0], + NIH_IO_STREAM, + (NihIoReader)job_process_child_reader, + (NihIoCloseHandler)job_process_close_handler, + NULL, + job->process_data[PROCESS_MAIN]); + TEST_NE_P (io, NULL); + + RESILIENT_TEST_CHILD (job->pid[PROCESS_MAIN]) { + close (fds[0]); + nih_error_raise_no_memory (); + job_process_error_abort (fds[1], JOB_PROCESS_ERROR_CGROUP_SETUP, 0); + } + close (fds[1]); + pid = job->pid[PROCESS_MAIN]; + + buffer = read_from_fd (NULL, fds[0]); + + job_process_child_reader (job->process_data[PROCESS_MAIN], + io, buffer->buf, buffer->len); + + /* Setup failed, so goal should have changed to stop */ + TEST_EQ (job->goal, JOB_STOP); + TEST_EQ (job->state, JOB_STOPPING); + + TEST_NE_P (job->process_data[PROCESS_MAIN], NULL); + + /* Invalid because the IO handlers have now run */ + TEST_FALSE (job->process_data[PROCESS_MAIN]->valid); + TEST_EQ (job->process_data[PROCESS_MAIN]->job_process_fd, -1); + + TEST_EQ (job->process_data[PROCESS_MAIN]->shell_fd, -1); + TEST_EQ_P (job->process_data[PROCESS_MAIN]->script, NULL); + TEST_EQ (job->process_data[PROCESS_MAIN]->shell_fd, -1); + + /* Still zero because the process handler hasn't run yet */ + TEST_EQ (job->process_data[PROCESS_MAIN]->status, 0); + + close (fds[0]); + + TEST_EQ (timed_waitpid (pid, 5), pid); + + nih_free (job); + + TEST_RESET_MAIN_LOOP (); + + /************************************************************/ + nih_free (class); file->job = NULL; nih_free (source); - nih_free (event); - event_poll (); - TEST_EQ (rmdir (dirname), 0); TEST_EQ (unsetenv ("UPSTART_LOGDIR"), 0); } === modified file 'test/test_util_common.c' --- test/test_util_common.c 2014-06-02 23:32:49 +0000 +++ test/test_util_common.c 2014-07-10 16:45:19 +0000 @@ -375,6 +375,8 @@ * * Simplified waitpid(2) with timeout using a pipe to allow select(2) * with timeout to be used to wait for process state change. + * + * Returns: as waitpid(2). **/ pid_t timed_waitpid (pid_t pid, time_t timeout) @@ -1000,7 +1002,7 @@ nih_local char *cmd = NULL; /* Clean up if tests forgot to */ - cmd = NIH_MUST (nih_sprintf (NULL, "rm %s/*.session 2>/dev/null", path)); + cmd = NIH_MUST (nih_sprintf (NULL, "rm -f %s/*.session 2>/dev/null", path)); assert0 (system (cmd)); /* Remove the directory tree the first Session Init created */ @@ -1094,10 +1096,13 @@ buffer->buf + buffer->len, buffer->size - buffer->len); - if (len <= 0) - break; - else if (len > 0) + if (len < 0 && errno != EAGAIN && errno != EINTR) { + break; + } else if (! len) { + break; + } else if (len > 0) { buffer->len += len; + } } close (fd); === modified file 'util/tests/test_initctl.c' --- util/tests/test_initctl.c 2014-07-01 15:34:42 +0000 +++ util/tests/test_initctl.c 2014-07-11 12:52:59 +0000 @@ -10968,9 +10968,9 @@ /*******************************************************************/ TEST_FEATURE ("single job"); - START_UPSTART (upstart_pid, FALSE); CREATE_FILE (dirname, "foo.conf", "exec echo hello"); + START_UPSTART (upstart_pid, FALSE); cmd = nih_sprintf (NULL, "%s list 2>&1", get_initctl ()); TEST_NE_P (cmd, NULL); @@ -10984,10 +10984,10 @@ /*******************************************************************/ TEST_FEATURE ("3 jobs and re-exec"); - START_UPSTART (upstart_pid, FALSE); - CREATE_FILE (dirname, "foo.conf", "exec echo foo"); + CREATE_FILE (dirname, "foo.conf", "exec echo foo"); CREATE_FILE (dirname, "bar.conf", "exec echo bar"); CREATE_FILE (dirname, "baz.conf", "exec echo bar"); + START_UPSTART (upstart_pid, FALSE); cmd = nih_sprintf (NULL, "%s list 2>&1", get_initctl ()); TEST_NE_P (cmd, NULL); @@ -11110,6 +11110,12 @@ CREATE_FILE (confdir, "foo.conf", contents); + cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); + TEST_NE_P (cmd, NULL); + RUN_COMMAND (NULL, cmd, &output, &lines); + TEST_EQ (lines, 0); + nih_free (output); + cmd = nih_sprintf (NULL, "%s start foo 2>&1", get_initctl ()); TEST_NE_P (cmd, NULL); RUN_COMMAND (NULL, cmd, &output, &lines); @@ -12482,6 +12488,12 @@ "author \"foo\"\n" "description \"wibble\""); + cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); + TEST_NE_P (cmd, NULL); + RUN_COMMAND (NULL, cmd, &output, &lines); + TEST_EQ (lines, 0); + nih_free (output); + cmd = nih_sprintf (NULL, "%s show-config foo 2>&1", get_initctl ()); TEST_NE_P (cmd, NULL); RUN_COMMAND (NULL, cmd, &output, &lines); @@ -12507,6 +12519,12 @@ "emits \"thing\"\n" "description \"wibble\""); + cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); + TEST_NE_P (cmd, NULL); + RUN_COMMAND (NULL, cmd, &output, &lines); + TEST_EQ (lines, 0); + nih_free (output); + cmd = nih_sprintf (NULL, "%s show-config foo 2>&1", get_initctl ()); TEST_NE_P (cmd, NULL); RUN_COMMAND (NULL, cmd, &output, &lines); @@ -12535,6 +12553,12 @@ "emits \"thong\"\n" "description \"wibble\""); + cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); + TEST_NE_P (cmd, NULL); + RUN_COMMAND (NULL, cmd, &output, &lines); + TEST_EQ (lines, 0); + nih_free (output); + cmd = nih_sprintf (NULL, "%s show-config foo 2>&1", get_initctl ()); TEST_NE_P (cmd, NULL); RUN_COMMAND (NULL, cmd, &output, &lines); @@ -12564,6 +12588,12 @@ "start on (A and B)\n" "description \"wibble\""); + cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); + TEST_NE_P (cmd, NULL); + RUN_COMMAND (NULL, cmd, &output, &lines); + TEST_EQ (lines, 0); + nih_free (output); + cmd = nih_sprintf (NULL, "%s show-config foo 2>&1", get_initctl ()); TEST_NE_P (cmd, NULL); RUN_COMMAND (NULL, cmd, &output, &lines); @@ -12593,6 +12623,12 @@ "start on (A and B)\n" "description \"wibble\""); + cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); + TEST_NE_P (cmd, NULL); + RUN_COMMAND (NULL, cmd, &output, &lines); + TEST_EQ (lines, 0); + nih_free (output); + cmd = nih_sprintf (NULL, "%s show-config foo 2>&1", get_initctl ()); TEST_NE_P (cmd, NULL); RUN_COMMAND (NULL, cmd, &output, &lines); @@ -12625,6 +12661,12 @@ "emits \"stime\"\n" "description \"wibble\""); + cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); + TEST_NE_P (cmd, NULL); + RUN_COMMAND (NULL, cmd, &output, &lines); + TEST_EQ (lines, 0); + nih_free (output); + cmd = nih_sprintf (NULL, "%s show-config foo 2>&1", get_initctl ()); TEST_NE_P (cmd, NULL); RUN_COMMAND (NULL, cmd, &output, &lines); @@ -12657,6 +12699,12 @@ "stop on (A or B)\n" "description \"wibble\""); + cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); + TEST_NE_P (cmd, NULL); + RUN_COMMAND (NULL, cmd, &output, &lines); + TEST_EQ (lines, 0); + nih_free (output); + cmd = nih_sprintf (NULL, "%s show-config foo 2>&1", get_initctl ()); TEST_NE_P (cmd, NULL); RUN_COMMAND (NULL, cmd, &output, &lines); @@ -12686,6 +12734,12 @@ "stop on (A or B)\n" "description \"wibble\""); + cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); + TEST_NE_P (cmd, NULL); + RUN_COMMAND (NULL, cmd, &output, &lines); + TEST_EQ (lines, 0); + nih_free (output); + cmd = nih_sprintf (NULL, "%s show-config foo 2>&1", get_initctl ()); TEST_NE_P (cmd, NULL); RUN_COMMAND (NULL, cmd, &output, &lines); @@ -12718,6 +12772,12 @@ "emits \"stime\"\n" "description \"wibble\""); + cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); + TEST_NE_P (cmd, NULL); + RUN_COMMAND (NULL, cmd, &output, &lines); + TEST_EQ (lines, 0); + nih_free (output); + cmd = nih_sprintf (NULL, "%s show-config foo 2>&1", get_initctl ()); TEST_NE_P (cmd, NULL); RUN_COMMAND (NULL, cmd, &output, &lines); @@ -12753,6 +12813,12 @@ "start on (starting JOB=\"boo\" or B x=y)\n" "description \"wibble\""); + cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); + TEST_NE_P (cmd, NULL); + RUN_COMMAND (NULL, cmd, &output, &lines); + TEST_EQ (lines, 0); + nih_free (output); + cmd = nih_sprintf (NULL, "%s show-config foo 2>&1", get_initctl ()); TEST_NE_P (cmd, NULL); RUN_COMMAND (NULL, cmd, &output, &lines); @@ -12791,6 +12857,12 @@ "start on (starting JOB=\"boo\" P=Q c=sea or B x=y)\n" "description \"wibble\""); + cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); + TEST_NE_P (cmd, NULL); + RUN_COMMAND (NULL, cmd, &output, &lines); + TEST_EQ (lines, 0); + nih_free (output); + cmd = nih_sprintf (NULL, "%s show-config foo 2>&1", get_initctl ()); TEST_NE_P (cmd, NULL); RUN_COMMAND (NULL, cmd, &output, &lines); @@ -12830,6 +12902,12 @@ "start on A and (B FOO=BAR or starting C x=y)\n" "description \"wibble\""); + cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); + TEST_NE_P (cmd, NULL); + RUN_COMMAND (NULL, cmd, &output, &lines); + TEST_EQ (lines, 0); + nih_free (output); + cmd = nih_sprintf (NULL, "%s show-config foo 2>&1", get_initctl ()); TEST_NE_P (cmd, NULL); RUN_COMMAND (NULL, cmd, &output, &lines); @@ -12876,6 +12954,12 @@ "(stopped gdm or stopped kdm or stopped xdm A=B or stopping lxdm)))\n" "description \"wibble\""); + cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); + TEST_NE_P (cmd, NULL); + RUN_COMMAND (NULL, cmd, &output, &lines); + TEST_EQ (lines, 0); + nih_free (output); + cmd = nih_sprintf (NULL, "%s show-config foo 2>&1", get_initctl ()); TEST_NE_P (cmd, NULL); RUN_COMMAND (NULL, cmd, &output, &lines); @@ -13011,6 +13095,12 @@ "task\n" "exec true"); + cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); + TEST_NE_P (cmd, NULL); + RUN_COMMAND (NULL, cmd, &output, &lines); + TEST_EQ (lines, 0); + nih_free (output); + cmd = nih_sprintf (NULL, "%s check-config 2>&1", get_initctl ()); TEST_NE_P (cmd, NULL); RUN_COMMAND (NULL, cmd, &output, &lines); @@ -13031,6 +13121,12 @@ CREATE_FILE (dirname, "baz.conf", "emits wibble"); + cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); + TEST_NE_P (cmd, NULL); + RUN_COMMAND (NULL, cmd, &output, &lines); + TEST_EQ (lines, 0); + nih_free (output); + cmd = nih_sprintf (NULL, "%s check-config 2>&1", get_initctl ()); TEST_NE_P (cmd, NULL); RUN_COMMAND (NULL, cmd, &output, &lines); @@ -13052,6 +13148,12 @@ "task\n" "exec true"); + cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); + TEST_NE_P (cmd, NULL); + RUN_COMMAND (NULL, cmd, &output, &lines); + TEST_EQ (lines, 0); + nih_free (output); + cmd = nih_sprintf (NULL, "%s check-config --ignore-events=wibble 2>&1", get_initctl ()); TEST_NE_P (cmd, NULL); @@ -13067,6 +13169,12 @@ CREATE_FILE (dirname, "foo.conf", "start on (fred and wilma)"); + cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); + TEST_NE_P (cmd, NULL); + RUN_COMMAND (NULL, cmd, &output, &lines); + TEST_EQ (lines, 0); + nih_free (output); + cmd = nih_sprintf (NULL, "%s check-config --ignore-events=wilma,foo,fred 2>&1", get_initctl ()); TEST_NE_P (cmd, NULL); @@ -13091,6 +13199,12 @@ CREATE_FILE (dirname, "mountall.conf", "exec true"); CREATE_FILE (dirname, "gdm.conf" , "exec true"); + cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); + TEST_NE_P (cmd, NULL); + RUN_COMMAND (NULL, cmd, &output, &lines); + TEST_EQ (lines, 0); + nih_free (output); + cmd = nih_sprintf (NULL, "%s check-config --ignore-events=runlevel 2>&1", get_initctl ()); TEST_NE_P (cmd, NULL); @@ -13115,6 +13229,12 @@ CREATE_FILE (dirname, "mountall.conf", "exec true"); + cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); + TEST_NE_P (cmd, NULL); + RUN_COMMAND (NULL, cmd, &output, &lines); + TEST_EQ (lines, 0); + nih_free (output); + cmd = nih_sprintf (NULL, "%s check-config --ignore-events=runlevel 2>&1", get_initctl ()); TEST_NE_P (cmd, NULL); @@ -13146,6 +13266,12 @@ CREATE_FILE (dirname, "mountall.conf", "exec true"); CREATE_FILE (dirname, "gdm.conf" , "exec true"); + cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); + TEST_NE_P (cmd, NULL); + RUN_COMMAND (NULL, cmd, &output, &lines); + TEST_EQ (lines, 0); + nih_free (output); + cmd = nih_sprintf (NULL, "%s check-config --ignore-events=runlevel 2>&1", get_initctl ()); TEST_NE_P (cmd, NULL); @@ -13170,6 +13296,12 @@ CREATE_FILE (dirname, "mountall.conf", "exec true"); + cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); + TEST_NE_P (cmd, NULL); + RUN_COMMAND (NULL, cmd, &output, &lines); + TEST_EQ (lines, 0); + nih_free (output); + cmd = nih_sprintf (NULL, "%s check-config --ignore-events=runlevel 2>&1", get_initctl ()); TEST_NE_P (cmd, NULL); @@ -13203,6 +13335,12 @@ CREATE_FILE (dirname, "portmap.conf", "exec true"); CREATE_FILE (dirname, "beano.conf", "exec true"); + cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); + TEST_NE_P (cmd, NULL); + RUN_COMMAND (NULL, cmd, &output, &lines); + TEST_EQ (lines, 0); + nih_free (output); + cmd = nih_sprintf (NULL, "%s check-config --ignore-events=runlevel 2>&1", get_initctl ()); TEST_NE_P (cmd, NULL); @@ -13240,6 +13378,12 @@ "emits hello"); CREATE_FILE (dirname, "gdm.conf", "exec true"); + cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); + TEST_NE_P (cmd, NULL); + RUN_COMMAND (NULL, cmd, &output, &lines); + TEST_EQ (lines, 0); + nih_free (output); + cmd = nih_sprintf (NULL, "%s check-config >&1", get_initctl ()); TEST_NE_P (cmd, NULL); @@ -13272,6 +13416,12 @@ CREATE_FILE (dirname, "mountall.conf", "exec true"); CREATE_FILE (dirname, "portmap.conf", "exec true"); + cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); + TEST_NE_P (cmd, NULL); + RUN_COMMAND (NULL, cmd, &output, &lines); + TEST_EQ (lines, 0); + nih_free (output); + cmd = nih_sprintf (NULL, "%s check-config 2>&1", get_initctl ()); TEST_NE_P (cmd, NULL); @@ -13313,6 +13463,12 @@ CREATE_FILE (dirname, "wibble.conf", "emits wibble"); CREATE_FILE (dirname, "beano.conf", "exec true"); + cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); + TEST_NE_P (cmd, NULL); + RUN_COMMAND (NULL, cmd, &output, &lines); + TEST_EQ (lines, 0); + nih_free (output); + cmd = nih_sprintf (NULL, "%s check-config 2>&1", get_initctl ()); TEST_NE_P (cmd, NULL); @@ -13350,6 +13506,12 @@ CREATE_FILE (dirname, "wibble.conf", "emits wibble"); CREATE_FILE (dirname, "beano.conf", "exec true"); + cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); + TEST_NE_P (cmd, NULL); + RUN_COMMAND (NULL, cmd, &output, &lines); + TEST_EQ (lines, 0); + nih_free (output); + cmd = nih_sprintf (NULL, "%s check-config --warn 2>&1", get_initctl ()); TEST_NE_P (cmd, NULL); @@ -16080,6 +16242,12 @@ "author \"foo\"\n" "description \"wibble\""); + cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); + TEST_NE_P (cmd, NULL); + RUN_COMMAND (NULL, cmd, &output, &lines); + TEST_EQ (lines, 0); + nih_free (output); + cmd = nih_sprintf (NULL, "%s usage foo 2>&1", get_initctl ()); TEST_NE_P (cmd, NULL); RUN_COMMAND (NULL, cmd, &output, &lines); @@ -16096,6 +16264,12 @@ CREATE_FILE (dirname, "foo.conf", "usage \"this is usage\""); + cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); + TEST_NE_P (cmd, NULL); + RUN_COMMAND (NULL, cmd, &output, &lines); + TEST_EQ (lines, 0); + nih_free (output); + cmd = nih_sprintf (NULL, "%s usage foo 2>&1", get_initctl ()); TEST_NE_P (cmd, NULL); RUN_COMMAND (NULL, cmd, &output, &lines); @@ -16113,6 +16287,12 @@ "instance $FOO\n" "usage \"this is usage\""); + cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); + TEST_NE_P (cmd, NULL); + RUN_COMMAND (NULL, cmd, &output, &lines); + TEST_EQ (lines, 0); + nih_free (output); + memset (&command, 0, sizeof command); args[0] = "foo"; args[1] = NULL; @@ -16246,6 +16426,12 @@ CREATE_FILE (confdir, "foo.conf", "exec env"); + cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); + TEST_NE_P (cmd, NULL); + RUN_COMMAND (NULL, cmd, &output, &line_count); + TEST_EQ (line_count, 0); + nih_free (output); + cmd = nih_sprintf (NULL, "%s start foo 2>&1", get_initctl ()); TEST_NE_P (cmd, NULL); RUN_COMMAND (NULL, cmd, &output, &line_count); @@ -16393,6 +16579,12 @@ CREATE_FILE (confdir, "empty-env.conf", contents); + cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); + TEST_NE_P (cmd, NULL); + RUN_COMMAND (NULL, cmd, &output, &line_count); + TEST_EQ (line_count, 0); + nih_free (output); + cmd = nih_sprintf (NULL, "%s start empty-env 2>&1", get_initctl ()); TEST_NE_P (cmd, NULL); RUN_COMMAND (NULL, cmd, &output, &line_count); @@ -17504,6 +17696,12 @@ CREATE_FILE (confdir, "modified-env.conf", "exec env"); + cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); + TEST_NE_P (cmd, NULL); + RUN_COMMAND (NULL, cmd, &output, &line_count); + TEST_EQ (line_count, 0); + nih_free (output); + cmd = nih_sprintf (NULL, "%s start modified-env 2>&1", get_initctl ()); TEST_NE_P (cmd, NULL); RUN_COMMAND (NULL, cmd, &output, &line_count); @@ -17629,6 +17827,12 @@ CREATE_FILE (confdir, "foo.conf", contents); + cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); + TEST_NE_P (cmd, NULL); + RUN_COMMAND (NULL, cmd, &output, &line_count); + TEST_EQ (line_count, 0); + nih_free (output); + cmd = nih_sprintf (NULL, "%s start foo 2>&1", get_initctl ()); TEST_NE_P (cmd, NULL); @@ -17674,6 +17878,12 @@ CREATE_FILE (confdir, "foo.conf", contents); + cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); + TEST_NE_P (cmd, NULL); + RUN_COMMAND (NULL, cmd, &output, &line_count); + TEST_EQ (line_count, 0); + nih_free (output); + cmd = nih_sprintf (NULL, "%s start foo 2>&1", get_initctl ()); TEST_NE_P (cmd, NULL); RUN_COMMAND (NULL, cmd, &output, &line_count); @@ -17705,6 +17915,12 @@ CREATE_FILE (confdir, "bar.conf", contents); + cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); + TEST_NE_P (cmd, NULL); + RUN_COMMAND (NULL, cmd, &output, &line_count); + TEST_EQ (line_count, 0); + nih_free (output); + cmd = nih_sprintf (NULL, "%s start bar 2>&1", get_initctl ()); TEST_NE_P (cmd, NULL); RUN_COMMAND (NULL, cmd, &output, &line_count); @@ -17788,6 +18004,12 @@ CREATE_FILE (confdir, "foo.conf", "exec env"); + cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); + TEST_NE_P (cmd, NULL); + RUN_COMMAND (NULL, cmd, &output, &lines); + TEST_EQ (lines, 0); + nih_free (output); + cmd = nih_sprintf (NULL, "%s start foo 2>&1", get_initctl ()); TEST_NE_P (cmd, NULL); RUN_COMMAND (NULL, cmd, &output, &lines);
-- upstart-devel mailing list upstart-devel@lists.ubuntu.com Modify settings or unsubscribe at: https://lists.ubuntu.com/mailman/listinfo/upstart-devel