aboutsummaryrefslogtreecommitdiff
path: root/initd/config.c
diff options
context:
space:
mode:
Diffstat (limited to 'initd/config.c')
-rw-r--r--initd/config.c131
1 files changed, 131 insertions, 0 deletions
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--;
+}