aboutsummaryrefslogtreecommitdiff
path: root/initd
diff options
context:
space:
mode:
authorDavid Oberhollenzer <goliath@infraroot.at>2020-05-13 19:13:04 +0200
committerDavid Oberhollenzer <goliath@infraroot.at>2020-05-14 01:26:14 +0200
commitdbe89195b258c1101b5dd37dfbf5f0d71c25e0fa (patch)
tree6a4192ebe460b8a64f739209bc0269933304da9b /initd
parentf731537024c367368b728ed01c9232c3b1951589 (diff)
initd: split configuration handling into "config.c"
This commit splits off only the handling of the service configuration and handling of the run time state and adds an abstraction layer in the form of functions that have to be called to access the data. Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
Diffstat (limited to 'initd')
-rw-r--r--initd/Makemodule.am2
-rw-r--r--initd/config.c131
-rw-r--r--initd/init.h40
-rw-r--r--initd/main.c104
4 files changed, 185 insertions, 92 deletions
diff --git a/initd/Makemodule.am b/initd/Makemodule.am
index 9f4b872..6f6b523 100644
--- a/initd/Makemodule.am
+++ b/initd/Makemodule.am
@@ -1,4 +1,4 @@
-init_SOURCES = initd/main.c initd/init.h initd/runsvc.c
+init_SOURCES = initd/main.c initd/init.h initd/runsvc.c initd/config.c
init_CPPFLAGS = $(AM_CPPFLAGS)
init_CFLAGS = $(AM_CFLAGS)
init_LDFLAGS = $(AM_LDFLAGS)
diff --git a/initd/config.c b/initd/config.c
new file mode 100644
index 0000000..7f9f25c
--- /dev/null
+++ b/initd/config.c
@@ -0,0 +1,131 @@
+/* SPDX-License-Identifier: ISC */
+#include "init.h"
+
+/* service configurations */
+static service_list_t cfg;
+
+/* service run time data, sorted by target and topological order */
+static svc_run_data_t *rt_data = NULL;
+static size_t rt_count = 0;
+
+/* maps a target to range in rt_data */
+static size_t queue_start[TGT_MAX];
+static size_t queue_count[TGT_MAX];
+
+/* current state */
+static size_t queue_idx = 0;
+static int target = TGT_BOOT;
+static size_t singleshot = 0;
+
+int config_load(void)
+{
+ service_t *it;
+ size_t i, j;
+
+ if (svcscan(SVCDIR, &cfg))
+ return -1;
+
+ /* allocate run time data */
+ rt_count = 0;
+
+ for (i = 0; i < TGT_MAX; ++i) {
+ for (it = cfg.targets[i]; it != NULL; it = it->next)
+ ++rt_count;
+ }
+
+ rt_data = calloc(rt_count, sizeof(rt_data[0]));
+ if (rt_data == NULL) {
+ rt_count = 0;
+ del_svc_list(&cfg);
+ return -1;
+ }
+
+ /* map runtime data to services */
+ j = 0;
+
+ for (i = 0; i < TGT_MAX; ++i) {
+ queue_start[i] = j;
+
+ for (it = cfg.targets[i]; it != NULL; it = it->next) {
+ rt_data[j].svc = it;
+ rt_data[j].state = STATE_OFF;
+ rt_data[j].pid = -1;
+ ++j;
+ }
+
+ queue_count[i] = j - queue_start[i];
+ }
+
+ /* initialize state */
+ for (i = 0; i < queue_count[target]; ++i)
+ rt_data[queue_start[target] + i].state = STATE_QUEUED;
+
+ return 0;
+}
+
+svc_run_data_t *config_rt_data_by_pid(pid_t pid)
+{
+ size_t i;
+
+ if (pid <= 1)
+ return NULL;
+
+ for (i = 0; i < rt_count; ++i) {
+ if (rt_data[i].pid == pid)
+ return rt_data + i;
+ }
+
+ return NULL;
+}
+
+svc_run_data_t *config_dequeue(void)
+{
+ if (queue_idx >= queue_count[target])
+ return NULL;
+
+ return rt_data + queue_start[target] + queue_idx++;
+}
+
+void config_set_target(int tgt)
+{
+ if (target == TGT_REBOOT || target == TGT_SHUTDOWN || target == tgt)
+ return;
+
+ /* TODO:
+ - if there are services left in the queue of the current target:
+ - refuse unless the new target is shutdown/reboot?
+ - mark pending as "STATE_OFF"
+ - if the new target is reboot/shutdown
+ - enqueue the currently running services as "stop those"?
+ */
+
+ target = tgt;
+ queue_idx = 0;
+}
+
+int config_get_current_target(void)
+{
+ return target;
+}
+
+bool config_is_current_target_complete(void)
+{
+ return singleshot == 0 && queue_idx >= queue_count[target];
+}
+
+bool config_should_respawn(void)
+{
+ return target != TGT_REBOOT && target != TGT_SHUTDOWN;
+}
+
+void config_singleshot_started(void)
+{
+ singleshot++;
+}
+
+void config_singleshot_terminated(void)
+{
+ assert(singleshot > 0);
+
+ singleshot--;
+}
diff --git a/initd/init.h b/initd/init.h
index 2c2adb1..813dedb 100644
--- a/initd/init.h
+++ b/initd/init.h
@@ -10,6 +10,7 @@
#include <stdlib.h>
#include <unistd.h>
#include <endian.h>
+#include <assert.h>
#include <stdio.h>
#include <errno.h>
#include <poll.h>
@@ -54,4 +55,43 @@ typedef struct {
*/
pid_t runsvc(service_t *svc);
+/********** config.c **********/
+
+/* load persistent configuration from disk */
+int config_load(void);
+
+svc_run_data_t *config_rt_data_by_pid(pid_t pid);
+
+/*
+ Get the next service that is waiting to be launched. Returns NULL if
+ the queue is empty.
+ */
+svc_run_data_t *config_dequeue(void);
+
+/*
+ Transition to a different target, if possible in the current state.
+
+ The transition may be ignored, e.g. if we are currently in the reboot
+ or shutdown target.
+ */
+void config_set_target(int tgt);
+
+/* get the current run time target from the configuration manager */
+int config_get_current_target(void);
+
+/*
+ Find out if the current target is completed, i.e. there are no more services
+ left in the queue and no active single shot services.
+ */
+bool config_is_current_target_complete(void);
+
+/* Ask whether we should respawn services in the current target */
+bool config_should_respawn(void);
+
+/* notify the configuration manager that a single shot service started */
+void config_singleshot_started(void);
+
+/* notify the configuration manager that a single shot service terminated */
+void config_singleshot_terminated(void);
+
#endif /* INIT_H */
diff --git a/initd/main.c b/initd/main.c
index dc2e631..c804105 100644
--- a/initd/main.c
+++ b/initd/main.c
@@ -1,24 +1,6 @@
/* SPDX-License-Identifier: ISC */
#include "init.h"
-/* service configurations */
-static service_list_t cfg;
-
-/* service run time data, sorted by target and topological order */
-static svc_run_data_t *rt_data = NULL;
-static size_t rt_count = 0;
-
-/* maps a target to range in rt_data */
-static size_t queue_start[TGT_MAX];
-static size_t queue_count[TGT_MAX];
-
-/* current state */
-static size_t queue_idx = 0;
-static int target = TGT_BOOT;
-static size_t singleshot = 0;
-
-/*****************************************************************************/
-
static const char *status_str[] = {
[STATE_OFF] = NULL,
[STATE_QUEUED] = NULL,
@@ -54,76 +36,23 @@ fail:
return;
}
-static void supervisor_init(void)
-{
- int status = STATE_FAILED;
- service_t *it;
- size_t i, j;
-
- if (svcscan(SVCDIR, &cfg))
- goto out;
-
- /* allocate run time data */
- rt_count = 0;
-
- for (i = 0; i < TGT_MAX; ++i) {
- for (it = cfg.targets[i]; it != NULL; it = it->next)
- ++rt_count;
- }
-
- rt_data = calloc(rt_count, sizeof(rt_data[0]));
- if (rt_data == NULL) {
- rt_count = 0;
- goto out;
- }
-
- /* map runtime data to services */
- j = 0;
-
- for (i = 0; i < TGT_MAX; ++i) {
- queue_start[i] = j;
-
- for (it = cfg.targets[i]; it != NULL; it = it->next) {
- rt_data[j].svc = it;
- rt_data[j].state = STATE_OFF;
- rt_data[j].pid = -1;
- ++j;
- }
-
- queue_count[i] = j - queue_start[i];
- }
-
- /* initialize state */
- status = STATE_COMPLETED;
-
- for (i = 0; i < queue_count[target]; ++i)
- rt_data[queue_start[target] + i].state = STATE_QUEUED;
-out:
- print_status("reading configuration from " SVCDIR, status);
-}
-
static svc_run_data_t *wait_for_process(void)
{
svc_run_data_t *rt;
int status;
pid_t pid;
- size_t i;
do {
pid = wait(&status);
- if (pid == -1)
- return NULL;
- for (i = 0; i < rt_count && rt_data[i].pid != pid; ++i)
- ;
- } while (i >= rt_count);
+ rt = config_rt_data_by_pid(pid);
+ } while (rt == NULL);
- rt = rt_data + i;
rt->status = WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE;
rt->pid = -1;
if (rt->svc->type == SVC_RESPAWN) {
- if (target != TGT_REBOOT && target != TGT_SHUTDOWN)
+ if (config_should_respawn())
respawn(rt);
} else {
if (rt->status == EXIT_SUCCESS) {
@@ -135,7 +64,7 @@ static svc_run_data_t *wait_for_process(void)
print_status(rt->svc->desc, rt->state);
if (rt->svc->type == SVC_ONCE)
- singleshot -= 1;
+ config_singleshot_terminated();
}
return rt;
@@ -145,16 +74,10 @@ static void handle_signal(int signo)
{
switch (signo) {
case SIGTERM:
- if (target != TGT_REBOOT && target != TGT_SHUTDOWN) {
- target = TGT_SHUTDOWN;
- queue_idx = 0;
- }
+ config_set_target(TGT_SHUTDOWN);
break;
case SIGINT:
- if (target != TGT_REBOOT && target != TGT_SHUTDOWN) {
- target = TGT_REBOOT;
- queue_idx = 0;
- }
+ config_set_target(TGT_REBOOT);
break;
case SIGHUP:
break;
@@ -165,10 +88,10 @@ static void handle_signal(int signo)
static void check_target_completion(void)
{
- if (singleshot > 0 || queue_idx < queue_count[target])
+ if (!config_is_current_target_complete())
return;
- switch (target) {
+ switch (config_get_current_target()) {
case TGT_BOOT:
break;
case TGT_SHUTDOWN:
@@ -187,9 +110,9 @@ int main(void)
svc_run_data_t *rt, *terminated;
struct sigaction act;
service_t *svc;
- size_t count;
- supervisor_init();
+ if (config_load())
+ return EXIT_FAILURE;
memset(&act, 0, sizeof(act));
act.sa_handler = handle_signal;
@@ -203,9 +126,9 @@ int main(void)
perror("cannot disable CTRL+ALT+DEL");
for (;;) {
- count = queue_count[target];
+ rt = config_dequeue();
- if (queue_idx >= count) {
+ if (rt == NULL) {
terminated = wait_for_process();
if (terminated != NULL)
@@ -213,7 +136,6 @@ int main(void)
continue;
}
- rt = rt_data + queue_start[target] + queue_idx++;
svc = rt->svc;
if (svc->flags & SVC_FLAG_HAS_EXEC) {
@@ -235,7 +157,7 @@ int main(void)
}
break;
case SVC_ONCE:
- singleshot += 1;
+ config_singleshot_started();
break;
}
}