diff --git a/src/service.c b/src/service.c index 29bdb8ce..97109006 100644 --- a/src/service.c +++ b/src/service.c @@ -1120,34 +1120,27 @@ int service_stop(svc_t *svc) } /** - * service_restart - Restart a service by sending %SIGHUP + * service_reload - Reload a service * @svc: Service to reload * * This function does some basic checks of the runtime state of Finit - * and a sanity check of the @svc before sending %SIGHUP. + * and a sanity check of the @svc before sending %SIGHUP or calling + * the reload:script command. * * Returns: * POSIX OK(0) or non-zero on error. */ -static int service_restart(svc_t *svc) +static int service_reload(svc_t *svc) { + const char *id = svc_ident(svc, NULL, 0); int do_progress = 1; pid_t lost = 0; int rc; - /* Ignore if finit is SIGSTOP'ed */ - if (is_norespawn()) + /* Ignore if service is invalid or finit is SIGSTOP'ed */ + if (!svc || is_norespawn()) return 1; - if (!svc || !svc->sighup) - return 1; - - if (svc->pid <= 1) { - dbg("%s: bad PID %d for %s, SIGHUP", svc_ident(svc, NULL, 0), svc->pid, svc->cmd); - svc->start_time = svc->pid = 0; - return 1; - } - /* Skip progress if desc disabled or bootstrap task */ if (!svc->desc[0] || svc_in_runlevel(svc, INIT_LEVEL)) do_progress = 0; @@ -1155,14 +1148,28 @@ static int service_restart(svc_t *svc) if (do_progress) print_desc("Restarting ", svc->desc); - dbg("Sending SIGHUP to PID %d", svc->pid); - logit(LOG_CONSOLE | LOG_NOTICE, "Restarting %s[%d], sending SIGHUP ...", - svc_ident(svc, NULL, 0), svc->pid); - rc = kill(svc->pid, SIGHUP); - if (rc == -1 && (errno == ESRCH || errno == ENOENT)) { - /* nobody home, reset internal state machine */ - lost = svc->pid; + if (svc->reload_script[0]) { + logit(LOG_CONSOLE | LOG_NOTICE, "%s[%d], calling %s ...", id, svc->pid, svc->reload_script); + rc = run(svc->reload_script, NULL); + } else if (svc->sighup) { + if (svc->pid <= 1) { + dbg("%s[%d]: bad PID, cannot reload service", id, svc->pid); + svc->start_time = svc->pid = 0; + goto done; + } + dbg("%s[%d], sending SIGHUP", id, svc->pid); + logit(LOG_CONSOLE | LOG_NOTICE, "%s[%d], sending SIGHUP ...", id, svc->pid); + rc = kill(svc->pid, SIGHUP); + if (rc == -1 && (errno == ESRCH || errno == ENOENT)) { + /* nobody home, reset internal state machine */ + lost = svc->pid; + } } else { + warnx("%s: neither HUP nor reload:script defined, no action.", id); + rc = 1; + } + + if (!rc) { /* Declare we're waiting for svc to re-assert/touch its pidfile */ svc_starting(svc); @@ -1172,7 +1179,7 @@ static int service_restart(svc_t *svc) touch(pid_file(svc)); } } - +done: if (do_progress) print_result(rc); @@ -1601,7 +1608,7 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file) char *id = NULL, *env = NULL, *cgroup = NULL; char *pre_script = NULL, *post_script = NULL; char *ready_script = NULL, *conflict = NULL; - char *cleanup_script = NULL; + char *reload_script = NULL, *cleanup_script = NULL; char ident[MAX_IDENT_LEN]; char *ifstmt = NULL; char *notify = NULL; @@ -1711,6 +1718,8 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file) ready_script = arg; else if (MATCH_CMD(cmd, "cleanup:", arg)) cleanup_script = arg; + else if (MATCH_CMD(cmd, "reload:", arg)) + reload_script = arg; else if (MATCH_CMD(cmd, "env:", arg)) env = arg; /* catch both cgroup: and cgroup. handled in parse_cgroup() */ @@ -1906,6 +1915,11 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file) else memset(svc->cleanup_script, 0, sizeof(svc->cleanup_script)); + if (reload_script) + parse_script(svc, "reload", reload_script, NULL, svc->reload_script, sizeof(svc->reload_script)); + else + memset(svc->reload_script, 0, sizeof(svc->reload_script)); + if (!svc_is_tty(svc)) { if (log) parse_log(svc, log); @@ -2151,7 +2165,7 @@ void service_update_rdeps(void) continue; /* Service supports reloading conf without stop/start */ - if (!svc_is_nohup(svc)) + if (!svc_is_noreload(svc)) continue; /* Yup, no need to stop start rdeps */ svc_mark_affected(mkcond(svc, cond, sizeof(cond))); @@ -2786,7 +2800,11 @@ restart: case COND_ON: if (svc_is_changed(svc)) { - if (svc_nohup(svc) || !svc_is_daemon(svc)) { + /* + * If service does not suport reload, or its command line + * arguments have been modified, we need to stop-start it. + */ + if (svc_is_noreload(svc) || svc->args_dirty) { service_stop(svc); } else { /* @@ -2796,7 +2814,7 @@ restart: if (sm_in_reload()) break; - service_restart(svc); + service_reload(svc); } svc_mark_clean(svc); diff --git a/src/svc.h b/src/svc.h index c855a5ec..c1b2bff1 100644 --- a/src/svc.h +++ b/src/svc.h @@ -212,6 +212,9 @@ typedef struct svc { char cleanup_script[MAX_CMD_LEN]; int cleanup_tmo; + /* When set, used instead of SIGHUP or stop-start */ + char reload_script[MAX_CMD_LEN]; + /* * Used to forcefully kill services that won't shutdown on * termination and to delay restarts of crashing services. @@ -272,10 +275,9 @@ static inline int svc_is_tty (svc_t *svc) { return svc && SVC_TYPE_TTY static inline int svc_is_runtask (svc_t *svc) { return svc && (SVC_TYPE_RUNTASK & svc->type);} static inline int svc_is_forking (svc_t *svc) { return svc && svc->forking; } static inline int svc_is_manual (svc_t *svc) { return svc && svc->manual; } -static inline int svc_is_nohup (svc_t *svc) { return svc && (0 == svc->sighup); } +static inline int svc_is_noreload (svc_t *svc) { return svc && (0 == svc->sighup && 0 == svc->reload_script[0]); } static inline int svc_in_runlevel (svc_t *svc, int runlevel) { return svc && ISSET(svc->runlevels, runlevel); } -static inline int svc_nohup (svc_t *svc) { return svc && (0 == svc->sighup || 0 != svc->args_dirty); } static inline int svc_has_pidfile (svc_t *svc) { return svc_is_daemon(svc) && svc->pidfile[0] != 0 && svc->pidfile[0] != '!'; } static inline int svc_has_pre (svc_t *svc) { return svc->pre_script[0]; } static inline int svc_has_post (svc_t *svc) { return svc->post_script[0]; }