Files
rosetta/services/herdd/runlevel.c
T

177 lines
3.6 KiB
C
Raw Normal View History

#include "runlevel.h"
#include "log.h"
#include "service.h"
#include <errno.h>
2026-05-30 10:19:33 +01:00
#include <fx/collections/array.h>
#include <fx/collections/hashtable.h>
#include <fx/serial.h>
2026-05-30 10:19:33 +01:00
#include <fx/string.h>
#include <fx/stringstream.h>
#include <magenta/log.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static struct queue runlevels = QUEUE_INIT;
struct queue *global_runlevels(void)
{
return &runlevels;
}
static int parse_runlevel_data(fx_object *in, struct runlevel *out)
{
2026-05-30 10:19:33 +01:00
if (!fx_object_is_type(in, FX_TYPE_HASHTABLE)) {
return -1;
}
2026-05-30 10:19:33 +01:00
const fx_value *runlevel_v = fx_hashtable_get(in, &FX_CSTR("runlevel"));
if (!runlevel_v || !fx_value_is_type(runlevel_v, FX_TYPE_HASHTABLE)) {
return -1;
}
2026-05-30 10:19:33 +01:00
fx_hashtable *in_runlevel = NULL;
fx_value_get_object(runlevel_v, &in_runlevel);
2026-05-30 10:19:33 +01:00
const fx_value *name_v
= fx_hashtable_get(in_runlevel, &FX_CSTR("name"));
if (!name_v || !fx_value_is_type(name_v, FX_TYPE_STRING)) {
return -1;
}
2026-05-30 10:19:33 +01:00
fx_string *name = NULL;
fx_value_get_object(name_v, &name);
2026-05-30 10:19:33 +01:00
const fx_value *description_v
= fx_hashtable_get(in_runlevel, &FX_CSTR("description"));
if (!description_v
|| !fx_value_is_type(description_v, FX_TYPE_STRING)) {
return -1;
}
2026-05-30 10:19:33 +01:00
fx_string *description = NULL;
fx_value_get_object(description_v, &description);
2026-05-30 10:19:33 +01:00
const fx_value *deps_v
= fx_hashtable_get(in_runlevel, &FX_CSTR("requires"));
if (deps_v && !fx_value_is_type(deps_v, FX_TYPE_ARRAY)) {
return -1;
}
2026-05-30 10:19:33 +01:00
fx_array *deps = NULL;
fx_value_get_object(deps_v, &deps);
int ret = 0;
2026-05-30 10:19:33 +01:00
size_t dep_count = fx_array_get_size(deps);
const fx_iterator *it = fx_iterator_begin(deps);
fx_foreach(dep, it)
{
2026-05-30 10:19:33 +01:00
if (!fx_value_is_type(dep, FX_TYPE_STRING)) {
ret = -1;
break;
}
}
fx_iterator_unref(it);
if (ret != 0) {
return ret;
}
out->rl_requires_count = dep_count;
out->rl_requires = calloc(dep_count, sizeof(char *));
it = fx_iterator_begin(deps);
size_t i = 0;
2026-05-30 10:19:33 +01:00
fx_foreach(dep, it)
{
2026-05-30 10:19:33 +01:00
fx_string *str = NULL;
fx_value_get_object(dep, &str);
out->rl_requires[i++] = fx_string_steal(str);
}
fx_iterator_unref(it);
out->rl_name = fx_string_steal(name);
out->rl_description = fx_string_steal(description);
return 0;
}
int runlevel_load(const char *path, struct runlevel **out)
{
struct runlevel *rl = malloc(sizeof *rl);
if (!rl) {
errno = ENOMEM;
return -1;
}
FILE *fp = fopen(path, "r");
if (!fp) {
free(rl);
return -1;
}
fx_stream *in = fx_stream_open_fp(fp);
fx_serial_ctx *ctx = fx_toml_serial_ctx_create();
2026-05-30 10:19:33 +01:00
fx_value data;
2026-04-20 22:17:28 +01:00
fx_result result = fx_serial_ctx_deserialise(ctx, in, &data, 0);
if (fx_result_is_error(result)) {
fx_throw(result);
free(rl);
errno = EFTYPE;
return -1;
}
2026-05-30 10:19:33 +01:00
if (!fx_value_is_type(&data, FX_TYPE_HASHTABLE)) {
free(rl);
errno = EFTYPE;
return -1;
}
if (parse_runlevel_data(data.v_object, rl) != 0) {
free(rl);
errno = EFTYPE;
return -1;
}
fx_stream_unref(in);
2026-05-30 10:19:33 +01:00
fx_value_unset(&data);
fclose(fp);
*out = rl;
return 0;
}
struct runlevel *runlevel_find(const char *name)
{
struct queue_entry *cur = queue_first(&runlevels);
while (cur) {
struct runlevel *rl
= QUEUE_CONTAINER(struct runlevel, rl_entry, cur);
if (!strcmp(rl->rl_name, name)) {
return rl;
}
cur = queue_next(cur);
}
return NULL;
}
int runlevel_activate(struct runlevel *rl)
{
for (size_t i = 0; i < rl->rl_requires_count; i++) {
const char *svc_name = rl->rl_requires[i];
struct service *svc = service_find(svc_name);
if (!svc) {
log_fail("Cannot find service %s.", svc_name);
return -1;
}
int ret = service_start(svc);
if (ret != 0) {
return ret;
}
}
log_ok("Reached runlevel %s.", rl->rl_description);
return 0;
}