#include "runlevel.h" #include "log.h" #include "service.h" #include #include #include #include #include #include #include #include #include #include static struct queue runlevels = QUEUE_INIT; struct queue *global_runlevels(void) { return &runlevels; } static int parse_runlevel_data(fx_object *in, struct runlevel *out) { if (!fx_object_is_type(in, FX_TYPE_HASHTABLE)) { return -1; } 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; } fx_hashtable *in_runlevel = NULL; fx_value_get_object(runlevel_v, &in_runlevel); 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; } fx_string *name = NULL; fx_value_get_object(name_v, &name); 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; } fx_string *description = NULL; fx_value_get_object(description_v, &description); 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; } fx_array *deps = NULL; fx_value_get_object(deps_v, &deps); int ret = 0; size_t dep_count = fx_array_get_size(deps); const fx_iterator *it = fx_iterator_begin(deps); fx_foreach(dep, it) { 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; fx_foreach(dep, it) { 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(); fx_value data; 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; } 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); 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; }