services: herdd: implement scanning and parsing of runlevel and service config files
This commit is contained in:
@@ -0,0 +1,154 @@
|
||||
#include "runlevel.h"
|
||||
|
||||
#include "log.h"
|
||||
#include "service.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fx/core/stringstream.h>
|
||||
#include <fx/ds/array.h>
|
||||
#include <fx/ds/dict.h>
|
||||
#include <fx/serial.h>
|
||||
#include <mango/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)
|
||||
{
|
||||
if (!fx_object_is_type(in, FX_TYPE_DICT)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
fx_dict *in_runlevel = fx_dict_at(in, "runlevel");
|
||||
if (!in_runlevel || !fx_object_is_type(in_runlevel, FX_TYPE_DICT)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
fx_string *name = fx_dict_at(in_runlevel, "name");
|
||||
if (!name || !fx_object_is_type(name, FX_TYPE_STRING)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
fx_string *description = fx_dict_at(in_runlevel, "description");
|
||||
if (!description || !fx_object_is_type(description, FX_TYPE_STRING)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
fx_array *deps = fx_dict_at(in_runlevel, "requires");
|
||||
if (deps && !fx_object_is_type(deps, FX_TYPE_ARRAY)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ret = 0;
|
||||
size_t dep_count = fx_array_size(deps);
|
||||
fx_iterator *it = fx_iterator_begin(deps);
|
||||
fx_foreach_ptr(fx_string, dep, it)
|
||||
{
|
||||
if (!fx_object_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_ptr(fx_string, dep, it)
|
||||
{
|
||||
out->rl_requires[i++] = fx_string_steal(dep);
|
||||
}
|
||||
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_object *data;
|
||||
fx_status status = fx_serial_ctx_deserialise(ctx, in, &data, 0);
|
||||
if (!FX_OK(status)) {
|
||||
free(rl);
|
||||
errno = EFTYPE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (parse_runlevel_data(data, rl) != 0) {
|
||||
free(rl);
|
||||
errno = EFTYPE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
fx_stream_unref(in);
|
||||
fx_object_unref(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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user