aboutsummaryrefslogtreecommitdiff
path: root/initd/supervisor.c
diff options
context:
space:
mode:
authorDavid Oberhollenzer <goliath@infraroot.at>2019-03-25 17:16:34 +0100
committerDavid Oberhollenzer <goliath@infraroot.at>2019-03-29 21:00:53 +0100
commit028394b8a5c6745bbf3ee34ba71d148bca75d247 (patch)
tree424e21815a67957eae37bd401022afbed70e14a9 /initd/supervisor.c
parent6fa0393be46b1bfdad79643d73d6e54f2df4997c (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/supervisor.c')
-rw-r--r--initd/supervisor.c79
1 files changed, 79 insertions, 0 deletions
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;