| === modified file 'init/errors.h' |
| --- init/errors.h 2011-05-05 10:13:49 +0000 |
| +++ init/errors.h 2011-05-12 20:42:28 +0000 |
| @@ -40,6 +40,7 @@ |
| /* Errors while parsing configuration files */ |
| PARSE_ILLEGAL_INTERVAL, |
| PARSE_ILLEGAL_EXIT, |
| + PARSE_ILLEGAL_SIGNAL, |
| PARSE_ILLEGAL_UMASK, |
| PARSE_ILLEGAL_NICE, |
| PARSE_ILLEGAL_OOM, |
| @@ -60,6 +61,7 @@ |
| #define ENVIRON_MISMATCHED_BRACES_STR N_("Mismatched braces") |
| #define PARSE_ILLEGAL_INTERVAL_STR N_("Illegal interval, expected number of seconds") |
| #define PARSE_ILLEGAL_EXIT_STR N_("Illegal exit status, expected integer") |
| +#define PARSE_ILLEGAL_SIGNAL_STR N_("Illegal signal status, expected integer") |
| #define PARSE_ILLEGAL_UMASK_STR N_("Illegal file creation mask, expected octal integer") |
| #define PARSE_ILLEGAL_NICE_STR N_("Illegal nice value, expected -20 to 19") |
| #define PARSE_ILLEGAL_OOM_STR N_("Illegal oom adjustment, expected -16 to 15 or 'never'") |
| |
| === modified file 'init/job_class.c' |
| --- init/job_class.c 2011-05-05 10:13:49 +0000 |
| +++ init/job_class.c 2011-05-12 20:42:28 +0000 |
| @@ -26,6 +26,7 @@ |
| |
| #include <errno.h> |
| #include <string.h> |
| +#include <signal.h> |
| |
| #include <nih/macros.h> |
| #include <nih/alloc.h> |
| @@ -199,6 +200,7 @@ |
| class->task = FALSE; |
| |
| class->kill_timeout = JOB_DEFAULT_KILL_TIMEOUT; |
| + class->kill_signal = SIGTERM; |
| |
| class->respawn = FALSE; |
| class->respawn_limit = JOB_DEFAULT_RESPAWN_LIMIT; |
| |
| === modified file 'init/job_class.h' |
| --- init/job_class.h 2011-05-12 19:31:50 +0000 |
| +++ init/job_class.h 2011-05-12 20:42:28 +0000 |
| @@ -85,6 +85,7 @@ |
| * @expect: what to expect before entering the next state after spawned, |
| * @task: start requests are not unblocked until instances have finished, |
| * @kill_timeout: time to wait between sending TERM and KILL signals, |
| + * @kill_signal: first signal to send (usually SIGTERM), |
| * @respawn: instances should be restarted if main process fails, |
| * @respawn_limit: number of respawns in @respawn_interval that we permit, |
| * @respawn_interval: barrier for @respawn_limit, |
| @@ -129,6 +130,7 @@ |
| int task; |
| |
| time_t kill_timeout; |
| + int kill_signal; |
| |
| int respawn; |
| int respawn_limit; |
| |
| === modified file 'init/job_process.c' |
| --- init/job_process.c 2011-05-12 19:31:50 +0000 |
| +++ init/job_process.c 2011-05-12 20:42:28 +0000 |
| @@ -802,9 +802,9 @@ |
| * @process: process to be killed. |
| * |
| * This function forces a @job to leave its current state by sending |
| - * @process the TERM signal, and maybe later the KILL signal. The actual |
| - * state changes are performed by job_child_reaper when the process |
| - * has actually terminated. |
| + * @process the "kill signal" defined signal (TERM by default), and maybe |
| + * later the KILL signal. The actual state changes are performed by |
| + * job_child_reaper when the process has actually terminated. |
| **/ |
| void |
| job_process_kill (Job *job, |
| @@ -815,15 +815,17 @@ |
| nih_assert (job->kill_timer == NULL); |
| nih_assert (job->kill_process = -1); |
| |
| - nih_info (_("Sending TERM signal to %s %s process (%d)"), |
| + nih_info (_("Sending %s signal to %s %s process (%d)"), |
| + nih_signal_to_name (job->class->kill_signal), |
| job_name (job), process_name (process), job->pid[process]); |
| |
| - if (system_kill (job->pid[process], FALSE) < 0) { |
| + if (system_kill (job->pid[process], job->class->kill_signal) < 0) { |
| NihError *err; |
| |
| err = nih_error_get (); |
| if (err->number != ESRCH) |
| - nih_warn (_("Failed to send TERM signal to %s %s process (%d): %s"), |
| + nih_warn (_("Failed to send %s signal to %s %s process (%d): %s"), |
| + nih_signal_to_name (job->class->kill_signal), |
| job_name (job), process_name (process), |
| job->pid[process], err->message); |
| nih_free (err); |
| @@ -863,15 +865,17 @@ |
| job->kill_timer = NULL; |
| job->kill_process = -1; |
| |
| - nih_info (_("Sending KILL signal to %s %s process (%d)"), |
| + nih_info (_("Sending %s signal to %s %s process (%d)"), |
| + "KILL", |
| job_name (job), process_name (process), job->pid[process]); |
| |
| - if (system_kill (job->pid[process], TRUE) < 0) { |
| + if (system_kill (job->pid[process], SIGKILL) < 0) { |
| NihError *err; |
| |
| err = nih_error_get (); |
| if (err->number != ESRCH) |
| - nih_warn (_("Failed to send KILL signal to %s %s process (%d): %s"), |
| + nih_warn (_("Failed to send %s signal to %s %s process (%d): %s"), |
| + "KILL", |
| job_name (job), process_name (process), |
| job->pid[process], err->message); |
| nih_free (err); |
| |
| === modified file 'init/man/init.5' |
| --- init/man/init.5 2011-05-12 19:31:50 +0000 |
| +++ init/man/init.5 2011-05-12 20:42:28 +0000 |
| @@ -563,10 +563,20 @@ |
| .\" |
| .SS Miscellaneous |
| .TP |
| +.B kill signal \fISIGNAL |
| +Specifies the stopping signal, |
| +.I SIGTERM |
| +by default, a job's main process will receive when stopping the |
| +running job. |
| + |
| +.nf |
| +kill signal INT |
| +.fi |
| +.\" |
| +.TP |
| .B kill timeout \fIINTERVAL |
| Specifies the interval between sending the job's main process the |
| -.I SIGTERM |
| -and |
| +"stopping" (see above) and |
| .I SIGKILL |
| signals when stopping the running job. |
| .\" |
| |
| === modified file 'init/parse_job.c' |
| --- init/parse_job.c 2011-05-12 19:31:50 +0000 |
| +++ init/parse_job.c 2011-05-12 20:42:28 +0000 |
| @@ -1782,6 +1782,7 @@ |
| { |
| size_t a_pos, a_lineno; |
| int ret = -1; |
| + char *endptr; |
| nih_local char *arg = NULL; |
| |
| nih_assert (class != NULL); |
| @@ -1799,7 +1800,6 @@ |
| |
| if (! strcmp (arg, "timeout")) { |
| nih_local char *timearg = NULL; |
| - char *endptr; |
| |
| /* Update error position to the timeout value */ |
| *pos = a_pos; |
| @@ -1816,14 +1816,40 @@ |
| if (errno || *endptr || (class->kill_timeout < 0)) |
| nih_return_error (-1, PARSE_ILLEGAL_INTERVAL, |
| _(PARSE_ILLEGAL_INTERVAL_STR)); |
| - |
| - ret = nih_config_skip_comment (file, len, &a_pos, &a_lineno); |
| - |
| + } else if (! strcmp (arg, "signal")) { |
| + unsigned long status; |
| + nih_local char *sigarg = NULL; |
| + int signal; |
| + |
| + /* Update error position to the exit status */ |
| + *pos = a_pos; |
| + if (lineno) |
| + *lineno = a_lineno; |
| + |
| + sigarg = nih_config_next_arg (NULL, file, len, &a_pos, |
| + &a_lineno); |
| + |
| + if (! sigarg) |
| + goto finish; |
| + |
| + signal = nih_signal_from_name (sigarg); |
| + if (signal < 0) { |
| + errno = 0; |
| + status = strtoul (sigarg, &endptr, 10); |
| + if (errno || *endptr || (status > INT_MAX)) |
| + nih_return_error (-1, PARSE_ILLEGAL_SIGNAL, |
| + _(PARSE_ILLEGAL_SIGNAL_STR)); |
| + } |
| + |
| + /* Set the signal */ |
| + class->kill_signal = signal; |
| } else { |
| nih_return_error (-1, NIH_CONFIG_UNKNOWN_STANZA, |
| _(NIH_CONFIG_UNKNOWN_STANZA_STR)); |
| } |
| |
| + ret = nih_config_skip_comment (file, len, &a_pos, &a_lineno); |
| + |
| finish: |
| *pos = a_pos; |
| if (lineno) |
| |
| === modified file 'init/system.c' |
| --- init/system.c 2010-02-26 15:29:07 +0000 |
| +++ init/system.c 2011-05-12 20:42:28 +0000 |
| @@ -48,27 +48,21 @@ |
| /** |
| * system_kill: |
| * @pid: process id of process, |
| - * @force: force the death. |
| - * |
| - * Kill all processes in the same process group as @pid, which may not |
| - * necessarily be the group leader. |
| - * |
| - * When @force is FALSE, the TERM signal is sent; when it is TRUE, KILL |
| - * is sent instead. |
| + * @signal: signal to send. |
| + * |
| + * Send all processes in the same process group as @pid, which may not |
| + * necessarily be the group leader the @signal. |
| * |
| * Returns: zero on success, negative value on raised error. |
| **/ |
| int |
| system_kill (pid_t pid, |
| - int force) |
| + int signal) |
| { |
| - int signal; |
| pid_t pgid; |
| |
| nih_assert (pid > 0); |
| |
| - signal = (force ? SIGKILL : SIGTERM); |
| - |
| pgid = getpgid (pid); |
| |
| if (kill (pgid > 0 ? -pgid : pid, signal) < 0) |
| |
| === modified file 'init/system.h' |
| --- init/system.h 2010-02-26 15:29:07 +0000 |
| +++ init/system.h 2011-05-12 20:42:28 +0000 |
| @@ -29,7 +29,7 @@ |
| |
| NIH_BEGIN_EXTERN |
| |
| -int system_kill (pid_t pid, int force) |
| +int system_kill (pid_t pid, int signal) |
| __attribute__ ((warn_unused_result)); |
| |
| int system_setup_console (ConsoleType type, int reset) |
| |
| === modified file 'init/tests/test_job_class.c' |
| --- init/tests/test_job_class.c 2011-05-05 10:13:49 +0000 |
| +++ init/tests/test_job_class.c 2011-05-12 20:42:28 +0000 |
| @@ -121,6 +121,7 @@ |
| TEST_EQ (class->task, FALSE); |
| |
| TEST_EQ (class->kill_timeout, 5); |
| + TEST_EQ (class->kill_signal, SIGTERM); |
| |
| TEST_EQ (class->respawn, FALSE); |
| TEST_EQ (class->respawn_limit, 10); |
| |
| === modified file 'init/tests/test_parse_job.c' |
| --- init/tests/test_parse_job.c 2011-05-12 19:31:50 +0000 |
| +++ init/tests/test_parse_job.c 2011-05-12 20:42:28 +0000 |
| @@ -4799,6 +4799,39 @@ |
| } |
| |
| |
| + /* Check that a kill stanza with the signal argument and signal, |
| + * sets the right signal on the jobs class. |
| + */ |
| + TEST_FEATURE ("with signal and single argument"); |
| + strcpy (buf, "kill signal INT\n"); |
| + |
| + TEST_ALLOC_FAIL { |
| + pos = 0; |
| + lineno = 1; |
| + job = parse_job (NULL, "test", buf, strlen (buf), |
| + &pos, &lineno); |
| + |
| + if (test_alloc_failed) { |
| + TEST_EQ_P (job, NULL); |
| + |
| + err = nih_error_get (); |
| + TEST_EQ (err->number, ENOMEM); |
| + nih_free (err); |
| + |
| + continue; |
| + } |
| + |
| + TEST_EQ (pos, strlen (buf)); |
| + TEST_EQ (lineno, 2); |
| + |
| + TEST_ALLOC_SIZE (job, sizeof (JobClass)); |
| + |
| + TEST_EQ (job->kill_signal, SIGINT); |
| + |
| + nih_free (job); |
| + } |
| + |
| + |
| /* Check that the last of multiple kill stanzas is used. |
| */ |
| TEST_FEATURE ("with multiple timeout and single argument stanzas"); |
| @@ -4832,6 +4865,37 @@ |
| } |
| |
| |
| + TEST_FEATURE ("with multiple signal and single argument stanzas"); |
| + strcpy (buf, "kill signal INT\n"); |
| + strcat (buf, "kill signal TERM\n"); |
| + |
| + TEST_ALLOC_FAIL { |
| + pos = 0; |
| + lineno = 1; |
| + job = parse_job (NULL, "test", buf, strlen (buf), |
| + &pos, &lineno); |
| + |
| + if (test_alloc_failed) { |
| + TEST_EQ_P (job, NULL); |
| + |
| + err = nih_error_get (); |
| + TEST_EQ (err->number, ENOMEM); |
| + nih_free (err); |
| + |
| + continue; |
| + } |
| + |
| + TEST_EQ (pos, strlen (buf)); |
| + TEST_EQ (lineno, 3); |
| + |
| + TEST_ALLOC_SIZE (job, sizeof (JobClass)); |
| + |
| + TEST_EQ (job->kill_signal, SIGTERM); |
| + |
| + nih_free (job); |
| + } |
| + |
| + |
| /* Check that a kill stanza without an argument results in a syntax |
| * error. |
| */ |
| @@ -4889,6 +4953,25 @@ |
| nih_free (err); |
| |
| |
| + /* Check that a kill stanza with the timeout argument but no timeout |
| + * results in a syntax error. |
| + */ |
| + TEST_FEATURE ("with signal and missing argument"); |
| + strcpy (buf, "kill signal\n"); |
| + |
| + pos = 0; |
| + lineno = 1; |
| + job = parse_job (NULL, "test", buf, strlen (buf), &pos, &lineno); |
| + |
| + TEST_EQ_P (job, NULL); |
| + |
| + err = nih_error_get (); |
| + TEST_EQ (err->number, NIH_CONFIG_EXPECTED_TOKEN); |
| + TEST_EQ (pos, 11); |
| + TEST_EQ (lineno, 1); |
| + nih_free (err); |
| + |
| + |
| /* Check that a kill timeout stanza with a non-integer argument |
| * results in a syntax error. |
| */ |
| @@ -4965,6 +5048,25 @@ |
| nih_free (err); |
| |
| |
| + /* Check that a kill signal stanza with an unknown signal argument |
| + * results in a syntax error. |
| + */ |
| + TEST_FEATURE ("with signal and unknown signal argument"); |
| + strcpy (buf, "kill signal foo\n"); |
| + |
| + pos = 0; |
| + lineno = 1; |
| + job = parse_job (NULL, "test", buf, strlen (buf), &pos, &lineno); |
| + |
| + TEST_EQ_P (job, NULL); |
| + |
| + err = nih_error_get (); |
| + TEST_EQ (err->number, PARSE_ILLEGAL_SIGNAL); |
| + TEST_EQ (pos, 12); |
| + TEST_EQ (lineno, 1); |
| + nih_free (err); |
| + |
| + |
| /* Check that a kill stanza with the timeout argument and timeout, |
| * but with an extra argument afterwards results in a syntax |
| * error. |
| @@ -4983,6 +5085,26 @@ |
| TEST_EQ (pos, 16); |
| TEST_EQ (lineno, 1); |
| nih_free (err); |
| + |
| + |
| + /* Check that a kill stanza with the signal argument and signal, |
| + * but with an extra argument afterwards results in a syntax |
| + * error. |
| + */ |
| + TEST_FEATURE ("with signal and extra argument"); |
| + strcpy (buf, "kill signal INT foo\n"); |
| + |
| + pos = 0; |
| + lineno = 1; |
| + job = parse_job (NULL, "test", buf, strlen (buf), &pos, &lineno); |
| + |
| + TEST_EQ_P (job, NULL); |
| + |
| + err = nih_error_get (); |
| + TEST_EQ (err->number, NIH_CONFIG_UNEXPECTED_TOKEN); |
| + TEST_EQ (pos, 16); |
| + TEST_EQ (lineno, 1); |
| + nih_free (err); |
| } |
| |
| void |
| |
| === modified file 'init/tests/test_system.c' |
| --- init/tests/test_system.c 2009-06-23 09:29:35 +0000 |
| +++ init/tests/test_system.c 2011-05-12 20:42:28 +0000 |
| @@ -51,7 +51,7 @@ |
| setpgid (pid1, pid1); |
| setpgid (pid2, pid1); |
| |
| - ret = system_kill (pid1, FALSE); |
| + ret = system_kill (pid1, SIGTERM); |
| waitpid (pid1, &status, 0); |
| |
| TEST_EQ (ret, 0); |
| @@ -79,7 +79,7 @@ |
| setpgid (pid1, pid1); |
| setpgid (pid2, pid1); |
| |
| - ret = system_kill (pid1, TRUE); |
| + ret = system_kill (pid1, SIGKILL); |
| waitpid (pid1, &status, 0); |
| |
| TEST_EQ (ret, 0); |
| @@ -114,7 +114,7 @@ |
| kill (pid1, SIGTERM); |
| waitpid (pid1, &status, 0); |
| |
| - ret = system_kill (pid2, FALSE); |
| + ret = system_kill (pid2, SIGTERM); |
| waitpid (pid2, &status, 0); |
| |
| TEST_EQ (ret, 0); |
| |
| === modified file 'po/ChangeLog' |
| --- po/ChangeLog 2011-03-17 01:03:01 +0000 |
| +++ po/ChangeLog 2011-05-12 20:42:28 +0000 |
| @@ -1,3 +1,7 @@ |
| +2011-05-12 Marc - A. Dahlhaus <mad@wol.de> |
| + |
| + * POTFILES.in: Add errors.h |
| + |
| 2011-03-16 Scott James Remnant <scott@netsplit.com> |
| |
| * Makevars.template (COPYRIGHT_HOLDER): Update copyright. |
| |
| === modified file 'po/POTFILES.in' |
| --- po/POTFILES.in 2010-02-04 03:42:29 +0000 |
| +++ po/POTFILES.in 2011-05-05 09:06:21 +0000 |
| @@ -3,6 +3,7 @@ |
| init/conf.c |
| init/control.c |
| init/environ.c |
| +init/errors.h |
| init/event.c |
| init/event_operator.c |
| init/job.c |
| |