diff --git a/man/openrc-run.8 b/man/openrc-run.8 index 436c0305c..b47f1c212 100644 --- a/man/openrc-run.8 +++ b/man/openrc-run.8 @@ -214,6 +214,8 @@ If using then using .Pa retry is preferred. +.It Ar stopgroup +Signal the whole process group when stopping the daemon. .It Ar respawn_delay Respawn delay .Xr supervise-daemon 8 @@ -296,6 +298,7 @@ retry:stop:start: s6_log_arguments:::start secbits:start:start: stopsig:stop:start:stop +stopgroup:stop:start: supervise_daemon_args::start: timeout_down:::stop timeout_kill:::stop diff --git a/sh/start-stop-daemon.sh b/sh/start-stop-daemon.sh index b87061285..9768e5613 100644 --- a/sh/start-stop-daemon.sh +++ b/sh/start-stop-daemon.sh @@ -100,6 +100,7 @@ ssd_stop() ${procname:+--name} $procname \ ${pidfile:+--pidfile} $chroot$pidfile \ ${stopsig:+--signal} $stopsig \ + ${stopgroup+--stop-group} \ ${_progress} eend $? "Failed to stop ${name:-$RC_SVCNAME}" diff --git a/sh/supervise-daemon.sh b/sh/supervise-daemon.sh index cdb5ef6f1..331b8e908 100644 --- a/sh/supervise-daemon.sh +++ b/sh/supervise-daemon.sh @@ -58,6 +58,7 @@ supervise_start() ${command_user+--user} $command_user \ ${umask+--umask} $umask \ ${notify+--notify} $notify \ + ${stopgroup+--stop-group} \ ${supervise_daemon_args-${start_stop_daemon_args}} \ $command \ -- $command_args $command_args_foreground diff --git a/src/shared/schedules.c b/src/shared/schedules.c index a32d8d3a4..88b20f750 100644 --- a/src/shared/schedules.c +++ b/src/shared/schedules.c @@ -245,13 +245,17 @@ void parse_schedule(const char *applet, const char *string, int timeout) /* return number of processes killed, -1 on error */ int do_stop(const char *applet, const char *exec, const char *const *argv, - pid_t pid, uid_t uid,int sig, bool test, bool quiet) + pid_t pid, uid_t uid, int sig, bool group, bool test, bool quiet) { RC_PIDLIST *pids; RC_PID *pi; RC_PID *np; bool killed; int nkilled = 0; + uid_t target; + char* kind = "PID"; + if (group) + kind = "GID"; if (pid > 0) pids = rc_find_pids(NULL, NULL, 0, pid); @@ -263,24 +267,28 @@ int do_stop(const char *applet, const char *exec, const char *const *argv, LIST_FOREACH_SAFE(pi, pids, entries, np) { if (test) { - einfo("Would send signal %d to PID %d", sig, pi->pid); + einfo("Would send signal %d to %s %d", sig, kind, pi->pid); nkilled++; } else { if (sig) { - syslog(LOG_DEBUG, "Sending signal %d to PID %d", sig, pi->pid); + syslog(LOG_DEBUG, "Sending signal %d to %s %d", sig, kind, pi->pid); if (!quiet) - ebeginv("Sending signal %d to PID %d", sig, pi->pid); + ebeginv("Sending signal %d to %s %d", sig, kind, pi->pid); } errno = 0; - killed = (kill(pi->pid, sig) == 0 || + if (group) + target = -pi->pid; + else + target = pi->pid; + killed = (kill(target, sig) == 0 || errno == ESRCH ? true : false); if (!quiet) eendv(killed ? 0 : 1, - "%s: failed to send signal %d to PID %d: %s", - applet, sig, pi->pid, strerror(errno)); + "%s: failed to send signal %d to %s %d: %s", + applet, kind, sig, pi->pid, strerror(errno)); else if (!killed) - syslog(LOG_ERR, "Failed to send signal %d to PID %d: %s", - sig, pi->pid, strerror(errno)); + syslog(LOG_ERR, "Failed to send signal %d to %s %d: %s", + sig, kind, pi->pid, strerror(errno)); if (!killed) { nkilled = -1; } else { @@ -297,7 +305,7 @@ int do_stop(const char *applet, const char *exec, const char *const *argv, int run_stop_schedule(const char *applet, const char *exec, const char *const *argv, - pid_t pid, uid_t uid, + pid_t pid, uid_t uid, bool group, bool test, bool progress, bool quiet) { SCHEDULEITEM *item = TAILQ_FIRST(&schedule); @@ -317,8 +325,13 @@ int run_stop_schedule(const char *applet, syslog(LOG_DEBUG, "Will stop %s", exec); } if (pid > 0) { - einfov("Will stop PID %d", pid); - syslog(LOG_DEBUG, "Will stop PID %d", pid); + if (!group) { + einfov("Will stop PID %d", pid); + syslog(LOG_DEBUG, "Will stop PID %d", pid); + } else { + einfov("Will stop GID %d", pid); + syslog(LOG_DEBUG, "Will stop GID %d", pid); + } } if (uid) { einfov("Will stop processes owned by UID %d", uid); @@ -344,8 +357,8 @@ int run_stop_schedule(const char *applet, case SC_SIGNAL: nrunning = 0; - nkilled = do_stop(applet, exec, argv, pid, uid, item->value, test, - quiet); + nkilled = do_stop(applet, exec, argv, pid, uid, item->value, group, + test, quiet); if (nkilled == 0) { if (tkilled == 0) { if (progressed) @@ -375,7 +388,7 @@ int run_stop_schedule(const char *applet, nloops++) { if ((nrunning = do_stop(applet, exec, argv, - pid, uid, 0, test, quiet)) == 0) + pid, uid, 0, group, test, quiet)) == 0) return 0; diff --git a/src/shared/schedules.h b/src/shared/schedules.h index 43cf12f77..a3dce06b4 100644 --- a/src/shared/schedules.h +++ b/src/shared/schedules.h @@ -20,10 +20,10 @@ void free_schedulelist(void); int parse_signal(const char *applet, const char *sig); void parse_schedule(const char *applet, const char *string, int timeout); int do_stop(const char *applet, const char *exec, const char *const *argv, - pid_t pid, uid_t uid,int sig, bool test, bool quiet); + pid_t pid, uid_t uid, int sig, bool group, bool test, bool quiet); int run_stop_schedule(const char *applet, const char *exec, const char *const *argv, - pid_t pid, uid_t uid, + pid_t pid, uid_t uid, bool group, bool test, bool progress, bool quiet); #endif diff --git a/src/start-stop-daemon/start-stop-daemon.c b/src/start-stop-daemon/start-stop-daemon.c index ca846657e..72bf5db45 100644 --- a/src/start-stop-daemon/start-stop-daemon.c +++ b/src/start-stop-daemon/start-stop-daemon.c @@ -96,7 +96,7 @@ enum { const char *applet = NULL; const char *extraopts = NULL; -const char getoptstring[] = "I:KN:PR:Sa:bc:d:e:g:ik:mn:op:s:tu:r:w:x:0:1:2:3:4:" \ +const char getoptstring[] = "I:KN:PR:Sa:bc:d:e:Gg:ik:mn:op:s:tu:r:w:x:0:1:2:3:4:" \ getoptstring_COMMON; const struct option longopts[] = { { "capabilities", 1, NULL, LONGOPT_CAPABILITIES}, @@ -115,6 +115,7 @@ const struct option longopts[] = { { "env", 1, NULL, 'e'}, { "umask", 1, NULL, 'k'}, { "group", 1, NULL, 'g'}, + { "stop-group", 0, NULL, 'G'}, { "interpreted", 0, NULL, 'i'}, { "make-pidfile", 0, NULL, 'm'}, { "name", 1, NULL, 'n'}, @@ -154,6 +155,7 @@ const char * const longopts_help[] = { "Set an environment string", "Set the umask for the daemon", "Change the process group", + "Stop the whole process group", "Match process name by interpreter", "Create a pidfile", "Match process name", @@ -343,6 +345,7 @@ int main(int argc, char **argv) char *exec_file = NULL; struct passwd *pw; struct group *gr; + bool stopgroup = false; char *line = NULL; FILE *fp; size_t len; @@ -461,6 +464,10 @@ int main(int argc, char **argv) stop = true; break; + case 'G': /* --stop-group */ + stopgroup = true; + break; + case 'N': /* --nice */ if (sscanf(optarg, "%d", &nicelevel) != 1) eerrorx("%s: invalid nice level `%s'", @@ -813,7 +820,7 @@ int main(int argc, char **argv) pid = 0; } i = run_stop_schedule(applet, exec, (const char *const *)margv, - pid, uid, test, progress, false); + pid, uid, stopgroup, test, progress, false); if (i < 0) /* We failed to stop something */ @@ -1266,7 +1273,7 @@ int main(int argc, char **argv) } else pid = 0; if (do_stop(applet, exec, (const char *const *)margv, - pid, uid, 0, test, false) > 0) + pid, uid, 0, false, test, false) > 0) alive = true; } diff --git a/src/supervise-daemon/supervise-daemon.c b/src/supervise-daemon/supervise-daemon.c index 15b18930b..2c7bcbeb0 100644 --- a/src/supervise-daemon/supervise-daemon.c +++ b/src/supervise-daemon/supervise-daemon.c @@ -85,7 +85,7 @@ enum { const char *applet = NULL; const char *extraopts = NULL; -const char getoptstring[] = "A:a:D:d:e:g:I:Kk:m:N:p:R:r:s:Su:0:1:2:3" \ +const char getoptstring[] = "A:a:D:d:e:Gg:I:Kk:m:N:p:R:r:s:Su:0:1:2:3" \ getoptstring_COMMON; const struct option longopts[] = { { "healthcheck-timer", 1, NULL, 'a'}, @@ -99,6 +99,7 @@ const struct option longopts[] = { { "chdir", 1, NULL, 'd'}, { "env", 1, NULL, 'e'}, { "group", 1, NULL, 'g'}, + { "stop-group", 0, NULL, 'G'}, { "ionice", 1, NULL, 'I'}, { "stop", 0, NULL, 'K'}, { "umask", 1, NULL, 'k'}, @@ -133,6 +134,7 @@ const char * const longopts_help[] = { "Change the PWD", "Set an environment string", "Change the process group", + "Stop the whole process group", "Set an ionice class:data when starting", "Stop daemon", "Set the umask for the daemon", @@ -168,6 +170,7 @@ static int oom_score_adj = INT_MIN; static char *changeuser, *ch_root, *ch_dir; static uid_t uid = 0; static gid_t gid = 0; +static bool stopgroup = false; static int devnull_fd = -1; static int stdin_fd; static int stdout_fd; @@ -735,7 +738,7 @@ RC_NORETURN static void supervisor(char *exec, char **argv) rc_waitpid(health_pid); syslog(LOG_INFO, "stopping %s, pid %d", exec, child_pid); nkilled = run_stop_schedule(applet, NULL, NULL, child_pid, 0, - false, false, true); + stopgroup, false, false, true); if (nkilled < 0) syslog(LOG_INFO, "Unable to kill %d: %s", child_pid, strerror(errno)); @@ -747,7 +750,7 @@ RC_NORETURN static void supervisor(char *exec, char **argv) alarm(0); syslog(LOG_INFO, "stopping %s, pid %d", exec, child_pid); nkilled = run_stop_schedule(applet, NULL, NULL, child_pid, 0, - false, false, true); + stopgroup, false, false, true); if (nkilled > 0) syslog(LOG_INFO, "killed %d processes", nkilled); continue; @@ -1018,6 +1021,10 @@ int main(int argc, char **argv) gid = gr->gr_gid; break; + case 'G': /* -G */ + stopgroup = true; + break; + case 'k': if (parse_mode(&numask, optarg)) eerrorx("%s: invalid mode `%s'", @@ -1225,7 +1232,7 @@ int main(int argc, char **argv) pid = get_pid(applet, pidfile); if (pid != -1) if (do_stop(applet, exec, (const char * const *)argv, pid, uid, - 0, false, true) > 0) + 0, false, false, true) > 0) eerrorx("%s: %s is already running", applet, exec); if (respawn_period > 0 && respawn_delay * respawn_max > respawn_period)