diff options
Diffstat (limited to 'initd/config.c')
-rw-r--r-- | initd/config.c | 131 |
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--; +} |