1
0
Fork 0
mirror of https://github.com/pygos/init.git synced 2024-11-21 18:59:46 +01:00

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>
This commit is contained in:
David Oberhollenzer 2019-03-25 17:16:34 +01:00
parent 6fa0393be4
commit 028394b8a5
6 changed files with 91 additions and 0 deletions

View file

@ -4,6 +4,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <string.h> #include <string.h>
#include <signal.h>
#include <stdio.h> #include <stdio.h>
#include <errno.h> #include <errno.h>
@ -55,6 +56,8 @@ static int cmd_disable(int argc, char **argv)
goto out; goto out;
} }
kill(1, SIGHUP);
ret = EXIT_SUCCESS; ret = EXIT_SUCCESS;
out: out:
free(linkname); free(linkname);

View file

@ -4,6 +4,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <string.h> #include <string.h>
#include <signal.h>
#include <stdio.h> #include <stdio.h>
#include <errno.h> #include <errno.h>
@ -60,6 +61,8 @@ static int cmd_enable(int argc, char **argv)
goto out; goto out;
} }
kill(1, SIGHUP);
ret = EXIT_SUCCESS; ret = EXIT_SUCCESS;
out: out:
free(linkname); free(linkname);

View file

@ -68,6 +68,8 @@ void supervisor_init(void);
bool supervisor_process_queues(void); bool supervisor_process_queues(void);
void supervisor_reload_config(void);
void supervisor_answer_status_request(int fd, const void *dest_addr, void supervisor_answer_status_request(int fd, const void *dest_addr,
size_t addrlen, E_SERVICE_STATE filter); size_t addrlen, E_SERVICE_STATE filter);

View file

@ -30,6 +30,9 @@ static void handle_signal(void)
case SIGINT: case SIGINT:
supervisor_set_target(TGT_REBOOT); supervisor_set_target(TGT_REBOOT);
break; break;
case SIGHUP:
supervisor_reload_config();
break;
case SIGUSR1: case SIGUSR1:
if (sockfd >= 0) { if (sockfd >= 0) {
close(sockfd); close(sockfd);

View file

@ -19,6 +19,7 @@ int sigsetup(void)
sigaddset(&mask, SIGINT); sigaddset(&mask, SIGINT);
sigaddset(&mask, SIGTERM); sigaddset(&mask, SIGTERM);
sigaddset(&mask, SIGUSR1); sigaddset(&mask, SIGUSR1);
sigaddset(&mask, SIGHUP);
sfd = signalfd(-1, &mask, SFD_CLOEXEC); sfd = signalfd(-1, &mask, SFD_CLOEXEC);
if (sfd == -1) { if (sfd == -1) {

View file

@ -13,6 +13,46 @@ static service_t *failed = NULL;
static int singleshot = 0; static int singleshot = 0;
static bool waiting = false; 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) static int start_service(service_t *svc)
{ {
if (svc->id < 1) if (svc->id < 1)
@ -145,6 +185,45 @@ void supervisor_init(void)
print_status("reading configuration from " SVCDIR, status, false); 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) bool supervisor_process_queues(void)
{ {
service_t *svc; service_t *svc;