Files
rosetta/services/herdd/service.c
T

191 lines
3.8 KiB
C
Raw Normal View History

#include "service.h"
#include "log.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 <launch.h>
2026-05-30 10:19:33 +01:00
#include <magenta/log.h>
#include <rosetta/bootstrap.h>
#include <spawn.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static struct queue services = QUEUE_INIT;
struct queue *global_services(void)
{
return &services;
}
static int parse_service_data(fx_object *in, struct service *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 *service_v = fx_hashtable_get(in, &FX_CSTR("service"));
if (!service_v || !fx_value_is_type(service_v, FX_TYPE_HASHTABLE)) {
return -1;
}
2026-05-30 10:19:33 +01:00
fx_hashtable *in_service = NULL;
fx_value_get_object(service_v, &in_service);
2026-05-30 10:19:33 +01:00
const fx_value *unit_v = fx_hashtable_get(in, &FX_CSTR("unit"));
if (!unit_v || !fx_value_is_type(unit_v, FX_TYPE_HASHTABLE)) {
return -1;
}
2026-05-30 10:19:33 +01:00
fx_hashtable *in_unit = NULL;
fx_value_get_object(unit_v, &in_unit);
2026-05-30 10:19:33 +01:00
const fx_value *description_v
= fx_hashtable_get(in_unit, &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 *exec_v = fx_hashtable_get(in_service, &FX_CSTR("exec"));
if (!exec_v || !fx_value_is_type(exec_v, FX_TYPE_STRING)) {
return -1;
}
2026-05-30 10:19:33 +01:00
fx_string *exec = NULL;
fx_value_get_object(exec_v, &exec);
2026-05-30 10:19:33 +01:00
const fx_value *roles_v
= fx_hashtable_get(in_service, &FX_CSTR("roles"));
if (roles_v && !fx_value_is_type(roles_v, FX_TYPE_ARRAY)) {
return -1;
}
2026-05-30 10:19:33 +01:00
fx_array *roles = NULL;
fx_value_get_object(roles_v, &roles);
int ret = 0;
2026-05-30 10:19:33 +01:00
const fx_iterator *it = fx_iterator_begin(roles);
fx_foreach(v, it)
{
2026-05-30 10:19:33 +01:00
if (!fx_value_is_type(v, FX_TYPE_STRING)) {
ret = -1;
break;
}
}
fx_iterator_unref(it);
if (ret != 0) {
return ret;
}
it = fx_iterator_begin(roles);
size_t i = 0;
2026-05-30 10:19:33 +01:00
fx_foreach(role, it)
{
2026-05-30 10:19:33 +01:00
const char *role_cstr = NULL;
fx_value_get_cstr(role, &role_cstr);
if (!strcmp(role_cstr, "NamespaceProvider")) {
out->s_roles |= SVC_ROLE_NAMESPACE_PROVIDER;
}
}
fx_iterator_unref(it);
out->s_description = fx_string_steal(description);
out->s_exec = fx_string_steal(exec);
return 0;
}
2026-05-30 19:47:49 +01:00
int service_load(const char *name, const char *path, struct service **out)
{
2026-05-30 19:47:49 +01:00
struct service *svc = malloc(sizeof *svc);
if (!svc) {
errno = ENOMEM;
return -1;
}
FILE *fp = fopen(path, "r");
if (!fp) {
2026-05-30 19:47:49 +01:00
free(svc);
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);
2026-05-30 19:47:49 +01:00
free(svc);
errno = EFTYPE;
return -1;
}
2026-05-30 10:19:33 +01:00
if (!fx_value_is_type(&data, FX_TYPE_HASHTABLE)) {
fx_value_unset(&data);
2026-05-30 19:47:49 +01:00
free(svc);
2026-05-30 10:19:33 +01:00
errno = EFTYPE;
return -1;
}
2026-05-30 19:47:49 +01:00
if (parse_service_data(data.v_object, svc) != 0) {
free(svc);
errno = EFTYPE;
return -1;
}
2026-05-30 19:47:49 +01:00
svc->s_name = fx_strdup(name);
fx_stream_unref(in);
2026-05-30 10:19:33 +01:00
fx_value_unset(&data);
fclose(fp);
2026-05-30 19:47:49 +01:00
*out = svc;
return 0;
}
struct service *service_find(const char *name)
{
struct queue_entry *cur = queue_first(&services);
while (cur) {
struct service *s
= QUEUE_CONTAINER(struct service, s_entry, cur);
if (!strcmp(s->s_name, name)) {
return s;
}
cur = queue_next(cur);
}
return NULL;
}
int service_start(struct service *svc)
{
log("Starting %s...", svc->s_description);
pid_t child = 0;
char *const argv[] = {
svc->s_name,
NULL,
};
int err = posix_spawn(&child, svc->s_exec, NULL, NULL, argv, NULL);
if (err == 0) {
log_ok("Started %s.", svc->s_description);
} else {
log_fail(
"Failed to start %s (%s)",
svc->s_description,
strerror(errno));
}
return err;
}