diff --git a/cmd/service/disable.c b/cmd/service/disable.c index 6210a8c..ffaab0a 100644 --- a/cmd/service/disable.c +++ b/cmd/service/disable.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -55,6 +56,8 @@ static int cmd_disable(int argc, char **argv) goto out; } + kill(1, SIGHUP); + ret = EXIT_SUCCESS; out: free(linkname); diff --git a/cmd/service/enable.c b/cmd/service/enable.c index 67cf0aa..8734aec 100644 --- a/cmd/service/enable.c +++ b/cmd/service/enable.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -60,6 +61,8 @@ static int cmd_enable(int argc, char **argv) goto out; } + kill(1, SIGHUP); + ret = EXIT_SUCCESS; out: free(linkname); diff --git a/initd/init.h b/initd/init.h index b98da98..ffc7181 100644 --- a/initd/init.h +++ b/initd/init.h @@ -68,6 +68,8 @@ void supervisor_init(void); bool supervisor_process_queues(void); +void supervisor_reload_config(void); + void supervisor_answer_status_request(int fd, const void *dest_addr, size_t addrlen, E_SERVICE_STATE filter); diff --git a/initd/main.c b/initd/main.c index 2b1a1cc..9cccdc5 100644 --- a/initd/main.c +++ b/initd/main.c @@ -30,6 +30,9 @@ static void handle_signal(void) case SIGINT: supervisor_set_target(TGT_REBOOT); break; + case SIGHUP: + supervisor_reload_config(); + break; case SIGUSR1: if (sockfd >= 0) { close(sockfd); diff --git a/initd/signal_linux.c b/initd/signal_linux.c index bb9d339..b19d715 100644 --- a/initd/signal_linux.c +++ b/initd/signal_linux.c @@ -19,6 +19,7 @@ int sigsetup(void) sigaddset(&mask, SIGINT); sigaddset(&mask, SIGTERM); sigaddset(&mask, SIGUSR1); + sigaddset(&mask, SIGHUP); sfd = signalfd(-1, &mask, SFD_CLOEXEC); if (sfd == -1) { diff --git a/initd/supervisor.c b/initd/supervisor.c index 53a2aec..3f157bf 100644 --- a/initd/supervisor.c +++ b/initd/supervisor.c @@ -13,6 +13,46 @@ static service_t *failed = NULL; static int singleshot = 0; static bool waiting = false; +static bool find_service(service_t *list, service_t *svc) +{ + while (list != NULL) { + if (strcmp(list->fname, svc->fname) == 0) + return true; + + list = list->next; + } + return false; +} + +static void remove_not_in_list(service_t **current, service_t *list, int tgt) +{ + service_t *it = *current, *prev = NULL; + + while (it != NULL) { + if (it->target == tgt && !find_service(list, it)) { + if (prev == NULL) { + delsvc(it); + *current = (*current)->next; + it = *current; + } else { + prev->next = it->next; + delsvc(it); + it = prev->next; + } + } else { + prev = it; + it = it->next; + } + } +} + +static bool have_service(service_t *svc) +{ + return find_service(running, svc) || find_service(terminated, svc) || + find_service(queue, svc) || find_service(completed, svc) || + find_service(failed, svc); +} + static int start_service(service_t *svc) { if (svc->id < 1) @@ -145,6 +185,45 @@ void supervisor_init(void) print_status("reading configuration from " SVCDIR, status, false); } +void supervisor_reload_config(void) +{ + service_list_t newcfg; + service_t *svc; + int i; + + if (svcscan(SVCDIR, &newcfg, RDSVC_NO_EXEC | RDSVC_NO_CTTY)) + return; + + for (i = 0; i < TGT_MAX; ++i) { + if (cfg.targets[i] == NULL) { + remove_not_in_list(&queue, newcfg.targets[i], i); + remove_not_in_list(&terminated, newcfg.targets[i], i); + remove_not_in_list(&completed, newcfg.targets[i], i); + remove_not_in_list(&failed, newcfg.targets[i], i); + + while (newcfg.targets[i] != NULL) { + svc = newcfg.targets[i]; + newcfg.targets[i] = svc->next; + + if (have_service(svc)) { + delsvc(svc); + } else { + svc->id = service_id++; + svc->status = EXIT_SUCCESS; + svc->next = completed; + completed = svc; + } + } + } else { + svc = cfg.targets[i]; + cfg.targets[i] = newcfg.targets[i]; + newcfg.targets[i] = svc; + } + } + + del_svc_list(&newcfg); +} + bool supervisor_process_queues(void) { service_t *svc;