diff options
author | David Oberhollenzer <goliath@infraroot.at> | 2019-03-25 17:16:34 +0100 |
---|---|---|
committer | David Oberhollenzer <goliath@infraroot.at> | 2019-03-29 21:00:53 +0100 |
commit | 028394b8a5c6745bbf3ee34ba71d148bca75d247 (patch) | |
tree | 424e21815a67957eae37bd401022afbed70e14a9 /initd | |
parent | 6fa0393be46b1bfdad79643d73d6e54f2df4997c (diff) |
Add service configuration reloading
This commit add the ability to initd to reload the service configuration
while running. The new configuration is merged with the existing one as
follows:
For each target:
- If the existing service list is not NULL, we have not started that
target yet. Simply replace it with the new list.
- If it is NULL, the services have already been started.
- First, remove all entries for services in that target that no
loner exist (except from the 'running' list).
- Second, add new services that we don't have yet. Treat them as
recently diseased and let the user start them manualy.
Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
Diffstat (limited to 'initd')
-rw-r--r-- | initd/init.h | 2 | ||||
-rw-r--r-- | initd/main.c | 3 | ||||
-rw-r--r-- | initd/signal_linux.c | 1 | ||||
-rw-r--r-- | initd/supervisor.c | 79 |
4 files changed, 85 insertions, 0 deletions
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; |