From 028394b8a5c6745bbf3ee34ba71d148bca75d247 Mon Sep 17 00:00:00 2001 From: David Oberhollenzer Date: Mon, 25 Mar 2019 17:16:34 +0100 Subject: 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 --- initd/supervisor.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) (limited to 'initd/supervisor.c') 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; -- cgit v1.2.3