diff --git a/README.md b/README.md index 81a38ed3..353a873c 100644 --- a/README.md +++ b/README.md @@ -232,8 +232,11 @@ For more information, see [doc/plugins.md](doc/plugins.md). By default, Finit monitors `/etc/finit.d/` and `/etc/finit.d/enabled/` registering any changes to `.conf` files. To activate a change the user must call `initctl reload`, which reloads all modified files, stops any -removed services, starts new ones, and restarts any modified ones, with -SIGHUP if the process supports it. +removed services, starts new ones, and restarts any modified ones. If the +command line arguments of a service have changed, the process will be +terminated and then started again with the updated arguments. If the arguments +have not been modified and the process supports SIGHUP, the process will +receive a SIGHUP rather than being terminated and started. For some use-cases the extra step of calling `initctl reload` creates an unnecessary overhead, which can be removed at build-time using: diff --git a/src/service.c b/src/service.c index 3c164d66..56becedc 100644 --- a/src/service.c +++ b/src/service.c @@ -937,23 +937,29 @@ static void parse_name(svc_t *svc, char *arg) */ static void parse_cmdline_args(svc_t *svc, char *cmd) { + int diff = 0; char sep = 0; char *arg; int i = 0; + if (strcmp(svc->args[i], cmd)) + diff++; strlcpy(svc->args[i++], cmd, sizeof(svc->args[0])); - while (i < MAX_NUM_SVC_ARGS) - svc->args[i++][0] = 0; - /* * Copy supplied args. Stop at MAX_NUM_SVC_ARGS-1 to allow the args * array to be zero-terminated. */ for (i = 1; (arg = strtok(NULL, " ")) && i < (MAX_NUM_SVC_ARGS - 1);) { + char prev[sizeof(svc->args[0])]; char ch = arg[0]; size_t len; + if (!sep) { + strlcpy(prev, svc->args[i], sizeof(prev)); + svc->args[i][0] = 0; + } + /* XXX: ugly string arg re-concatenation, fixme */ if (ch == '"' || ch == '\'') sep = ch; @@ -970,6 +976,9 @@ static void parse_cmdline_args(svc_t *svc, char *cmd) continue; } + if (strcmp(svc->args[i], prev)) + diff++; + sep = 0; i++; } @@ -978,8 +987,12 @@ static void parse_cmdline_args(svc_t *svc, char *cmd) * Clear remaining args in case they were set earlier. * This also zero-terminates the args array. */ - while (i < MAX_NUM_SVC_ARGS) - svc->args[i++][0] = 0; + while (i < MAX_NUM_SVC_ARGS) { + if (svc->args[i++][0]) { + svc->args[i-1][0] = 0; + diff++; + } + } #if 0 for (i = 0; i < MAX_NUM_SVC_ARGS; i++) { if (!svc->args[i][0]) @@ -987,6 +1000,10 @@ static void parse_cmdline_args(svc_t *svc, char *cmd) _d("%s ", svc->args[i]); } #endif + + if (diff) + _d("Modified args for %s detected", cmd); + svc->args_dirty = (diff > 0); } @@ -1500,7 +1517,9 @@ restart: case COND_ON: if (svc_is_changed(svc)) { - if (svc->sighup) { + if (svc_nohup(svc)) + service_stop(svc); + else { /* * wait until all processes have been * stopped before continuing... @@ -1508,8 +1527,7 @@ restart: if (sm_is_in_teardown(&sm)) break; service_restart(svc); - } else - service_stop(svc); + } svc_mark_clean(svc); } diff --git a/src/svc.c b/src/svc.c index 352eb30f..fa63cfa7 100644 --- a/src/svc.c +++ b/src/svc.c @@ -498,6 +498,7 @@ void svc_mark_dirty(svc_t *svc) void svc_mark_clean(svc_t *svc) { *((int *)&svc->dirty) = 0; + *((int *)&svc->args_dirty) = 0; } void svc_enable(svc_t *svc) diff --git a/src/svc.h b/src/svc.h index a54f9579..f20d5bec 100644 --- a/src/svc.h +++ b/src/svc.h @@ -142,6 +142,7 @@ typedef struct svc { /* Command, arguments and service description */ char cmd[MAX_ARG_LEN]; char args[MAX_NUM_SVC_ARGS][MAX_ARG_LEN]; + int args_dirty; char desc[MAX_STR_LEN]; char env[MAX_ARG_LEN]; @@ -194,7 +195,7 @@ static inline int svc_is_runtask (svc_t *svc) { return svc && (SVC_TYPE_RUNTAS static inline int svc_is_forking (svc_t *svc) { return (svc_is_daemon(svc) || svc_is_sysv(svc)) && svc->pidfile[0] == '!'; } static inline int svc_in_runlevel (svc_t *svc, int runlevel) { return svc && ISSET(svc->runlevels, runlevel); } -static inline int svc_has_sighup (svc_t *svc) { return svc && 0 != svc->sighup; } +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 void svc_starting (svc_t *svc) { if (svc) svc->starting = 1; }