aboutsummaryrefslogtreecommitdiff
path: root/initd
diff options
context:
space:
mode:
authorDavid Oberhollenzer <goliath@infraroot.at>2020-05-13 17:55:45 +0200
committerDavid Oberhollenzer <goliath@infraroot.at>2020-05-13 17:55:45 +0200
commit2cfc263daec3776090be87b69688dfeeea2fbacd (patch)
tree8de84e250af486a92259c9135522a8ddc56fe752 /initd
parent387532c3572824333550880d7b73d879ceb6a871 (diff)
Move rest of initd supervisor code into main.c
Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
Diffstat (limited to 'initd')
-rw-r--r--initd/Makemodule.am1
-rw-r--r--initd/init.h10
-rw-r--r--initd/main.c240
-rw-r--r--initd/supervisor.c242
4 files changed, 240 insertions, 253 deletions
diff --git a/initd/Makemodule.am b/initd/Makemodule.am
index 294b2ee..9f4b872 100644
--- a/initd/Makemodule.am
+++ b/initd/Makemodule.am
@@ -1,5 +1,4 @@
init_SOURCES = initd/main.c initd/init.h initd/runsvc.c
-init_SOURCES += initd/supervisor.c
init_CPPFLAGS = $(AM_CPPFLAGS)
init_CFLAGS = $(AM_CFLAGS)
init_LDFLAGS = $(AM_LDFLAGS)
diff --git a/initd/init.h b/initd/init.h
index bfc1f62..2c2adb1 100644
--- a/initd/init.h
+++ b/initd/init.h
@@ -54,14 +54,4 @@ typedef struct {
*/
pid_t runsvc(service_t *svc);
-/********** supervisor.c **********/
-
-void supervisor_handle_exited(pid_t pid, int status);
-
-void supervisor_set_target(int next);
-
-void supervisor_init(void);
-
-void supervisor_process_queues(void);
-
#endif /* INIT_H */
diff --git a/initd/main.c b/initd/main.c
index 446553c..e40fc32 100644
--- a/initd/main.c
+++ b/initd/main.c
@@ -1,6 +1,246 @@
/* 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,
+ [STATE_RUNNING] ="\033[22;33m UP \033[0m",
+ [STATE_COMPLETED] = "\033[22;32mDONE\033[0m",
+ [STATE_FAILED] ="\033[22;31mFAIL\033[0m",
+};
+
+static void print_status(const char *msg, int type)
+{
+ printf("[%s] %s\n", status_str[type], msg);
+ fflush(stdout);
+}
+
+static void respawn(svc_run_data_t *rt)
+{
+ if (rt->svc->rspwn_limit > 0) {
+ rt->rspwn_count += 1;
+
+ if (rt->rspwn_count >= rt->svc->rspwn_limit)
+ goto fail;
+ }
+
+ rt->pid = runsvc(rt->svc);
+ if (rt->pid == -1)
+ goto fail;
+
+ rt->state = STATE_RUNNING;
+ return;
+fail:
+ rt->state = STATE_FAILED;
+ print_status(rt->svc->desc, rt->state);
+ return;
+}
+
+static void check_target_completion(void)
+{
+ if (singleshot > 0 || queue_idx < queue_count[target])
+ return;
+
+ switch (target) {
+ case TGT_BOOT:
+ break;
+ case TGT_SHUTDOWN:
+ for (;;)
+ reboot(RB_POWER_OFF);
+ break;
+ case TGT_REBOOT:
+ for (;;)
+ reboot(RB_AUTOBOOT);
+ break;
+ }
+}
+
+static void supervisor_handle_exited(pid_t pid, int status)
+{
+ svc_run_data_t *rt;
+ service_t *svc;
+ size_t i;
+
+ for (i = 0; i < rt_count; ++i) {
+ if (rt_data[i].pid == pid)
+ break;
+ }
+
+ if (i >= rt_count)
+ return;
+
+ rt = rt_data + i;
+ svc = rt->svc;
+ rt->status = status;
+ rt->pid = -1;
+
+ if (svc->type == SVC_RESPAWN) {
+ if (target != TGT_REBOOT && target != TGT_SHUTDOWN)
+ respawn(rt);
+ } else {
+ if (rt->status == EXIT_SUCCESS) {
+ rt->state = STATE_COMPLETED;
+ } else {
+ rt->state = STATE_FAILED;
+ }
+
+ print_status(svc->desc, rt->state);
+
+ if (svc->type == SVC_ONCE)
+ singleshot -= 1;
+
+ check_target_completion();
+ }
+}
+
+static void supervisor_set_target(int next)
+{
+ if (target == TGT_REBOOT || target == TGT_SHUTDOWN || next == target)
+ return;
+
+ if (queue_idx < queue_count[target]) {
+ if (next != TGT_REBOOT && next != TGT_SHUTDOWN)
+ return;
+ }
+
+ target = next;
+ queue_idx = 0;
+}
+
+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 pid_t wait_for_process(int *status)
+{
+ pid_t pid = wait(status);
+
+ if (pid == -1 || !WIFEXITED(*status)) {
+ *status = EXIT_FAILURE;
+ } else {
+ *status = WEXITSTATUS(*status);
+ }
+ return pid;
+}
+
+static void supervisor_process_queues(void)
+{
+ svc_run_data_t *rt;
+ service_t *svc;
+ size_t count;
+ int status;
+ pid_t pid;
+
+ count = queue_count[target];
+
+ if (queue_idx >= count) {
+ pid = wait_for_process(&status);
+ supervisor_handle_exited(pid, status);
+ return;
+ }
+
+ rt = rt_data + queue_start[target] + queue_idx++;
+ svc = rt->svc;
+
+ if (svc->flags & SVC_FLAG_HAS_EXEC) {
+ rt->pid = runsvc(rt->svc);
+
+ if (rt->pid == -1) {
+ rt->state = STATE_FAILED;
+ print_status(svc->desc, rt->state);
+ } else {
+ rt->state = STATE_RUNNING;
+ print_status(svc->desc, rt->state);
+
+ switch (svc->type) {
+ case SVC_WAIT:
+ for (;;) {
+ pid = wait_for_process(&status);
+ if (pid == rt->pid)
+ break;
+ supervisor_handle_exited(pid, status);
+ }
+
+ rt->state = status == EXIT_SUCCESS ?
+ STATE_COMPLETED : STATE_FAILED;
+ print_status(svc->desc, rt->state);
+ break;
+ case SVC_ONCE:
+ singleshot += 1;
+ break;
+ }
+ }
+ } else {
+ rt->status = EXIT_SUCCESS;
+ rt->state = STATE_COMPLETED;
+ print_status(svc->desc, rt->state);
+ }
+
+ check_target_completion();
+}
+
static void handle_signal(int signo)
{
switch (signo) {
diff --git a/initd/supervisor.c b/initd/supervisor.c
deleted file mode 100644
index d54b9ca..0000000
--- a/initd/supervisor.c
+++ /dev/null
@@ -1,242 +0,0 @@
-/* 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,
- [STATE_RUNNING] ="\033[22;33m UP \033[0m",
- [STATE_COMPLETED] = "\033[22;32mDONE\033[0m",
- [STATE_FAILED] ="\033[22;31mFAIL\033[0m",
-};
-
-static void print_status(const char *msg, int type)
-{
- printf("[%s] %s\n", status_str[type], msg);
- fflush(stdout);
-}
-
-static void respawn(svc_run_data_t *rt)
-{
- if (rt->svc->rspwn_limit > 0) {
- rt->rspwn_count += 1;
-
- if (rt->rspwn_count >= rt->svc->rspwn_limit)
- goto fail;
- }
-
- rt->pid = runsvc(rt->svc);
- if (rt->pid == -1)
- goto fail;
-
- rt->state = STATE_RUNNING;
- return;
-fail:
- rt->state = STATE_FAILED;
- print_status(rt->svc->desc, rt->state);
- return;
-}
-
-static void check_target_completion(void)
-{
- if (singleshot > 0 || queue_idx < queue_count[target])
- return;
-
- switch (target) {
- case TGT_BOOT:
- break;
- case TGT_SHUTDOWN:
- for (;;)
- reboot(RB_POWER_OFF);
- break;
- case TGT_REBOOT:
- for (;;)
- reboot(RB_AUTOBOOT);
- break;
- }
-}
-
-void supervisor_handle_exited(pid_t pid, int status)
-{
- svc_run_data_t *rt;
- service_t *svc;
- size_t i;
-
- for (i = 0; i < rt_count; ++i) {
- if (rt_data[i].pid == pid)
- break;
- }
-
- if (i >= rt_count)
- return;
-
- rt = rt_data + i;
- svc = rt->svc;
- rt->status = status;
- rt->pid = -1;
-
- if (svc->type == SVC_RESPAWN) {
- if (target != TGT_REBOOT && target != TGT_SHUTDOWN)
- respawn(rt);
- } else {
- if (rt->status == EXIT_SUCCESS) {
- rt->state = STATE_COMPLETED;
- } else {
- rt->state = STATE_FAILED;
- }
-
- print_status(svc->desc, rt->state);
-
- if (svc->type == SVC_ONCE)
- singleshot -= 1;
-
- check_target_completion();
- }
-}
-
-void supervisor_set_target(int next)
-{
- if (target == TGT_REBOOT || target == TGT_SHUTDOWN || next == target)
- return;
-
- if (queue_idx < queue_count[target]) {
- if (next != TGT_REBOOT && next != TGT_SHUTDOWN)
- return;
- }
-
- target = next;
- queue_idx = 0;
-}
-
-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 pid_t wait_for_process(int *status)
-{
- pid_t pid = wait(status);
-
- if (pid == -1 || !WIFEXITED(*status)) {
- *status = EXIT_FAILURE;
- } else {
- *status = WEXITSTATUS(*status);
- }
- return pid;
-}
-
-void supervisor_process_queues(void)
-{
- svc_run_data_t *rt;
- service_t *svc;
- size_t count;
- int status;
- pid_t pid;
-
- count = queue_count[target];
-
- if (queue_idx >= count) {
- pid = wait_for_process(&status);
- supervisor_handle_exited(pid, status);
- return;
- }
-
- rt = rt_data + queue_start[target] + queue_idx++;
- svc = rt->svc;
-
- if (svc->flags & SVC_FLAG_HAS_EXEC) {
- rt->pid = runsvc(rt->svc);
-
- if (rt->pid == -1) {
- rt->state = STATE_FAILED;
- print_status(svc->desc, rt->state);
- } else {
- rt->state = STATE_RUNNING;
- print_status(svc->desc, rt->state);
-
- switch (svc->type) {
- case SVC_WAIT:
- for (;;) {
- pid = wait_for_process(&status);
- if (pid == rt->pid)
- break;
- supervisor_handle_exited(pid, status);
- }
-
- rt->state = status == EXIT_SUCCESS ?
- STATE_COMPLETED : STATE_FAILED;
- print_status(svc->desc, rt->state);
- break;
- case SVC_ONCE:
- singleshot += 1;
- break;
- }
- }
- } else {
- rt->status = EXIT_SUCCESS;
- rt->state = STATE_COMPLETED;
- print_status(svc->desc, rt->state);
- }
-
- check_target_completion();
-}