aboutsummaryrefslogtreecommitdiff
path: root/initd
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
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')
-rw-r--r--initd/init.h2
-rw-r--r--initd/main.c3
-rw-r--r--initd/signal_linux.c1
-rw-r--r--initd/supervisor.c79
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;