aboutsummaryrefslogtreecommitdiff
path: root/initd
diff options
context:
space:
mode:
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;