From 1192506d43cf2fc9aeaf72e23a9a43f14d7c3738 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Wed, 26 Feb 2020 18:10:37 +0100 Subject: [PATCH] Support for custom halt:signal, default SIGTERM Signed-off-by: Joachim Nilsson --- docs/config.md | 7 +++++ src/service.c | 27 +++++++++++++---- src/sig.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/sig.h | 3 ++ src/svc.c | 3 ++ src/svc.h | 3 +- 6 files changed, 117 insertions(+), 7 deletions(-) diff --git a/docs/config.md b/docs/config.md index 298d15cc..32076165 100644 --- a/docs/config.md +++ b/docs/config.md @@ -231,6 +231,13 @@ Syntax name: + When stopping a service (run/task/sysv/service), either manually or + when moving to another runlevel, Finit starts by sending `SIGTERM`, to + allow the process to shut down gracefully. If the process has not + been collected within 3 seconds, Finit sends `SIGKILL`. To halt the + process using a different signal, use the option `halt:SIGNAL`, e.g., + `halt:SIGPWR`. + * `inetd service/proto[@iflist] [LVLS] /path/to/daemon args` Launch a daemon when a client initiates a connection on an Internet port. Available services are listed in the UNIX `/etc/services` file. diff --git a/src/service.c b/src/service.c index 66cc51d7..1331f8ee 100644 --- a/src/service.c +++ b/src/service.c @@ -472,9 +472,10 @@ static int service_stop(svc_t *svc) if (svc->pid <= 1) return 1; - _d("Sending SIGTERM to pid:%d name:%s", svc->pid, pid_get_name(svc->pid, NULL, 0)); - logit(LOG_CONSOLE | LOG_NOTICE, "Stopping %s:%s, PID: %d, sending SIGTERM ...", - basename(svc->cmd), svc->id, svc->pid); + _d("Sending %s to pid:%d name:%s", sig_name(svc->sighalt), + svc->pid, pid_get_name(svc->pid, NULL, 0)); + logit(LOG_CONSOLE | LOG_NOTICE, "Stopping %s:%s, PID: %d, sending %s ...", + basename(svc->cmd), svc->id, svc->pid, sig_name(svc->sighalt)); } else { logit(LOG_CONSOLE | LOG_NOTICE, "Calling '%s stop' ...", svc->cmd); } @@ -488,7 +489,7 @@ static int service_stop(svc_t *svc) if (svc->pid <= 1) goto cleanup; - res = kill(svc->pid, SIGTERM); + res = kill(svc->pid, svc->sighalt); /* PID lost or forking process never really started */ if (res == -1 && ESRCH == errno) { @@ -644,6 +645,17 @@ static void parse_log(svc_t *svc, char *arg) } } +static void parse_sighalt(svc_t *svc, char *arg) +{ + int signo; + + signo = sig_num(arg); + if (signo == -1) + return; + + svc->sighalt = signo; +} + /* * name: */ @@ -757,7 +769,7 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file) char *username = NULL, *log = NULL, *pid = NULL; char *service = NULL, *proto = NULL, *ifaces = NULL; char *cmd, *desc, *runlevels = NULL, *cond = NULL; - char *name = NULL; + char *name = NULL, *halt = NULL; svc_t *svc; plugin_t *plugin = NULL; @@ -819,6 +831,8 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file) name = cmd; else if (!strncasecmp(cmd, "manual:yes", 10)) manual = 1; + else if (!strncasecmp(cmd, "halt:", 5)) + halt = &cmd[5]; else if (cmd[0] != '/' && strchr(cmd, '/')) service = cmd; /* inetd service/proto */ else @@ -945,7 +959,8 @@ recreate: conf_parse_cond(svc, cond); parse_name(svc, name); - + if (halt) + parse_sighalt(svc, halt); if (log) parse_log(svc, log); if (desc) diff --git a/src/sig.c b/src/sig.c index be52d85c..5a064500 100644 --- a/src/sig.c +++ b/src/sig.c @@ -98,6 +98,55 @@ static uev_t sighup_watcher, sigint_watcher, sigpwr_watcher; static uev_t sigchld_watcher; static uev_t sigstop_watcher, sigtstp_watcher, sigcont_watcher; +static struct sigmap { + int num; + char *name; +} signames[] = { + /* ISO C99 signals. */ + { SIGINT, "SIGINT" }, + { SIGILL, "SIGILL" }, + { SIGABRT, "SIGABRT" }, + { SIGFPE, "SIGFPE" }, + { SIGSEGV, "SIGSEGV" }, + { SIGTERM, "SIGTERM" }, + /* Historical signals specified by POSIX. */ + { SIGHUP, "SIGHUP" }, + { SIGQUIT, "SIGQUIT" }, + { SIGTRAP, "SIGTRAP" }, + { SIGKILL, "SIGKILL" }, + { SIGBUS, "SIGBUS" }, + { SIGSYS, "SIGSYS" }, + { SIGPIPE, "SIGPIPE" }, + { SIGALRM, "SIGALRM" }, + + /* New(er) POSIX signals (1003.1-2008, 1003.1-2013). */ + { SIGURG, "SIGURG" }, + { SIGSTOP, "SIGSTOP" }, + { SIGTSTP, "SIGTSTP" }, + { SIGCONT, "SIGCONT" }, + { SIGCHLD, "SIGCHLD" }, + { SIGTTIN, "SIGTTIN" }, + { SIGTTOU, "SIGTTOU" }, + { SIGPOLL, "SIGPOLL" }, + { SIGXCPU, "SIGXCPU" }, + { SIGXFSZ, "SIGXFSZ" }, + { SIGVTALRM, "SIGVTALRM" }, + { SIGPROF, "SIGPROF" }, + { SIGUSR1, "SIGUSR1" }, + { SIGUSR2, "SIGUSR2" }, + + /* Nonstandard signals found in all modern POSIX systems + (including both BSD and Linux). */ + { SIGWINCH, "SIGWINCH" }, + { SIGSTKFLT, "SIGSTKFLT" }, + { SIGPWR, "SIGPWR" }, + + /* Archaic names for compatibility. */ + { SIGIO, "SIGIO" }, + { SIGIOT, "SIGIOT" }, + { SIGCLD, "SIGCLD" }, +}; + void mdadm_wait(void); void unmount_tmpfs(void); void unmount_regular(void); @@ -369,6 +418,38 @@ int sig_stopped(void) return stopped; } +/* + * Convert SIGFOO to a number, if it exists + */ +int sig_num(const char *name) +{ + size_t i, offset = 0; + + if (strncasecmp(name, "SIG", 3)) + offset = 3; + + for (i = 0; i < NELEMS(signames); i++) { + if (strcasecmp(name, &signames[i].name[offset])) + continue; + + return signames[i].num; + } + + return -1; +} + +const char *sig_name(int signo) +{ + size_t i; + + for (i = 0; i < NELEMS(signames); i++) { + if (signames[i].num == signo) + return signames[i].name; + } + + return "SIGUNKOWN"; +} + /* * Inital signal setup - ignore everything but SIGCHLD until we're capable of responding */ diff --git a/src/sig.h b/src/sig.h index e6d43e0d..f54c2ce4 100644 --- a/src/sig.h +++ b/src/sig.h @@ -70,10 +70,13 @@ extern shutop_t halt; void do_shutdown (shutop_t op); int sig_stopped (void); +int sig_num (const char *name); void sig_init (void); void sig_unblock (void); void sig_setup (uev_ctx_t *ctx); +const char *sig_name(int signo); + #endif /* FINIT_SIG_H_ */ /** diff --git a/src/svc.c b/src/svc.c index 2248b729..551921fd 100644 --- a/src/svc.c +++ b/src/svc.c @@ -104,6 +104,9 @@ svc_t *svc_new(char *cmd, char *id, int type) /* Default description, if missing */ strlcpy(svc->desc, svc->name, sizeof(svc->desc)); + /* Default HALT signal to send */ + svc->sighalt = SIGTERM; + TAILQ_INSERT_TAIL(&svc_list, svc, link); return svc; diff --git a/src/svc.h b/src/svc.h index 1e48ba19..a1c49ee8 100644 --- a/src/svc.h +++ b/src/svc.h @@ -75,7 +75,7 @@ typedef enum { #define MAX_NUM_FDS 64 /* Max number of I/O plugins */ #define MAX_NUM_SVC_ARGS 32 -/* Time after SIGTERM that we SIGKILL stopping processes */ +/* Time after SIGTERM (svc->sighalt) that we SIGKILL stopping processes */ #define SVC_TERM_TIMEOUT 3000 /* @@ -95,6 +95,7 @@ typedef struct svc { struct rlimit rlimit[RLIMIT_NLIMITS]; /* Service details */ + int sighalt; /* Signal to stop prorcess, default: SIGTERM */ pid_t pid; char pidfile[256]; long start_time; /* Start time, as seconds since boot, from sysinfo() */