diff --git a/docs/config.md b/docs/config.md index 274b0a25..4615b028 100644 --- a/docs/config.md +++ b/docs/config.md @@ -152,6 +152,20 @@ Syntax task [s] echo "foo" | cat >/tmp/bar ``` +* `sysv [LVLS] /path/to/init-script -- Optional description`__ + Similar to `task` is the `sysv` stanza, which can be used to call SysV + style scripts. The primary intention for this command is to be able to + re-use much of existing setup and init scripts in Linux distributions. + + When entering an allowed runlevel, Finit calls `init-script start`, + when entering a disallowed runlevel, Finit calls `init-script stop`, + and if the Finit .conf, where `sysv` stanza is declared, is modified, + Finit calls `init-script restart` on `initctl restart`. Similar + to how a `service` stanza works. + + > **Note:** there is currently now supervision of daemons started as + > sysv services. I.e., the `pid:!...` support is still missing. + * `service [LVLS] /path/to/daemon ARGS -- Optional description` Service, or daemon, to be monitored and automatically restarted if it exits prematurely. Please note that you often need to provide a diff --git a/src/cond-w.c b/src/cond-w.c index 1972e1ac..7211c432 100644 --- a/src/cond-w.c +++ b/src/cond-w.c @@ -128,6 +128,7 @@ static int svc_has_cond(svc_t *svc) case SVC_TYPE_SERVICE: case SVC_TYPE_TASK: case SVC_TYPE_RUN: + case SVC_TYPE_SYSV: return 1; default: diff --git a/src/conf.c b/src/conf.c index aefeb8ba..c6315dae 100644 --- a/src/conf.c +++ b/src/conf.c @@ -464,6 +464,12 @@ static void parse_dynamic(char *line, struct rlimit rlimit[], char *file) return; } + /* Similar to task but is treated like a SysV init script */ + if (MATCH_CMD(line, "sysv ", x)) { + service_register(SVC_TYPE_SYSV, x, rlimit, file); + return; + } + /* Classic inetd service */ if (MATCH_CMD(line, "inetd ", x)) { #ifdef INETD_ENABLED diff --git a/src/service.c b/src/service.c index 6ef37981..37bb7414 100644 --- a/src/service.c +++ b/src/service.c @@ -166,12 +166,19 @@ static int service_start(svc_t *svc) if (svc_is_inetd(svc)) return inetd_start(&svc->inetd); #endif + if (svc_is_sysv(svc)) { + _d("Starting SYSV script %s", svc->cmd); + if (svc_is_runtask(svc)) + _d("SYSV is class:runtask"); + else + _d("SYSV is *NOT* class:runtask"); + } if (!svc->desc[0]) do_progress = 0; if (do_progress) { - if (svc_is_daemon(svc)) + if (svc_is_daemon(svc) || svc_is_sysv(svc)) print_desc("Starting ", svc->desc); else print_desc("", svc->desc); @@ -224,9 +231,15 @@ static int service_start(svc_t *svc) } } - /* Serve copy of args to process in case it modifies them. */ - for (i = 0; i < (MAX_NUM_SVC_ARGS - 1) && svc->args[i][0] != 0; i++) - args[i] = svc->args[i]; + if (!svc_is_sysv(svc)) { + /* Serve copy of args to process in case it modifies them. */ + for (i = 0; i < (MAX_NUM_SVC_ARGS - 1) && svc->args[i][0] != 0; i++) + args[i] = svc->args[i]; + } else { + i = 0; + args[i++] = svc->cmd; + args[i++] = "start"; + } args[i] = NULL; /* Redirect inetd socket to stdin for connection */ @@ -454,18 +467,43 @@ static int service_stop(svc_t *svc) #endif service_timeout_cancel(svc); - if (svc->pid <= 1) - return 1; + if (!svc_is_sysv(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); + } else { + logit(LOG_CONSOLE | LOG_NOTICE, "Calling '%s stop' ...", svc->cmd); + } - _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); svc_set_state(svc, SVC_STOPPING_STATE); if (runlevel != 1) print_desc("Stopping ", svc->desc); - res = kill(svc->pid, SIGTERM); + if (!svc_is_sysv(svc)) { + res = kill(svc->pid, SIGTERM); + } else { + char *args[] = { svc->cmd, "stop", NULL }; + pid_t pid; + + pid = fork(); + switch (pid) { + case 0: + exec_runtask(svc->cmd, args); + _exit(0); + break; + case -1: + _pe("Failed fork() to call sysv script '%s stop'", svc->cmd); + res = 1; + break; + default: + res = WEXITSTATUS(complete(svc->cmd, pid)); + break; + } + } if (runlevel != 1) print_result(res); @@ -473,6 +511,15 @@ static int service_stop(svc_t *svc) return res; } +/* + * SysV start/stop script wrapper for service_stop() + */ +static int sysv_stop(svc_t *svc) +{ + svc_set_state(svc, SVC_READY_STATE); + return service_stop(svc); +} + /** * service_restart - Restart a service by sending %SIGHUP * @svc: Service to reload @@ -1092,6 +1139,14 @@ restart: case SVC_HALTED_STATE: if (enabled) svc_set_state(svc, SVC_READY_STATE); + + if (svc_is_sysv(svc)) { + if (!enabled && sm_is_in_teardown(&sm)) { + sysv_stop(svc); + svc_set_state(svc, SVC_HALTED_STATE); + } + break; + } break; case SVC_DONE_STATE: @@ -1119,6 +1174,7 @@ restart: case SVC_TYPE_INETD_CONN: case SVC_TYPE_TASK: case SVC_TYPE_RUN: + case SVC_TYPE_SYSV: svc_set_state(svc, SVC_DONE_STATE); break; diff --git a/src/sm.c b/src/sm.c index a18e0885..fb80f441 100644 --- a/src/sm.c +++ b/src/sm.c @@ -117,7 +117,7 @@ restart: switch (sm->state) { case SM_BOOTSTRAP_STATE: _d("Bootstrapping all services in runlevel S from %s", FINIT_CONF); - service_step_all(SVC_TYPE_RUN | SVC_TYPE_TASK | SVC_TYPE_SERVICE); + service_step_all(SVC_TYPE_RUNTASK | SVC_TYPE_SERVICE); sm->state = SM_RUNNING_STATE; break; diff --git a/src/svc.h b/src/svc.h index 57f90a58..61a9ab3f 100644 --- a/src/svc.h +++ b/src/svc.h @@ -43,10 +43,11 @@ typedef enum { SVC_TYPE_RUN = 4, /* Like task, but wait for completion */ SVC_TYPE_INETD = 8, /* Classic inetd service */ SVC_TYPE_INETD_CONN = 16, /* Single inetd connection */ + SVC_TYPE_SYSV = 32, /* SysV style init.d script w/ start/stop */ } svc_type_t; #define SVC_TYPE_ANY (-1) -#define SVC_TYPE_RUNTASK (6) +#define SVC_TYPE_RUNTASK (SVC_TYPE_RUN | SVC_TYPE_TASK | SVC_TYPE_SYSV) typedef enum { SVC_HALTED_STATE = 0, /* Not allowed in runlevel, or not enabled. */ @@ -182,6 +183,7 @@ int svc_parse_jobstr (char *str, size_t len, int (*found)(svc_t *) static inline int svc_is_inetd (svc_t *svc) { return svc && SVC_TYPE_INETD == svc->type; } static inline int svc_is_inetd_conn(svc_t *svc) { return svc && SVC_TYPE_INETD_CONN == svc->type; } static inline int svc_is_daemon (svc_t *svc) { return svc && SVC_TYPE_SERVICE == svc->type; } +static inline int svc_is_sysv (svc_t *svc) { return svc && SVC_TYPE_SYSV == svc->type; } static inline int svc_is_runtask (svc_t *svc) { return svc && (SVC_TYPE_RUNTASK & svc->type); } static inline int svc_in_runlevel (svc_t *svc, int runlevel) { return svc && ISSET(svc->runlevels, runlevel); }