Files
vatrog-vm-signaling/src/daemon/config.c
T

127 lines
4.8 KiB
C
Raw Normal View History

/* config.c — vmsigd config parser (see vmsigd.h). INI-ish: `key = value` globals + repeated
* `[grant uid=N]` stanzas. Pure libc; no core/vmie dependency (unit-testable in any build). */
#define _GNU_SOURCE
#include "vmsigd.h"
#include "vmsig_control.h" /* VMSIG_CAP_* */
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
void vmsigd_config_defaults(vmsigd_config* c) {
memset(c, 0, sizeof *c);
snprintf(c->socket, sizeof c->socket, "%s", "/run/vmsig/vmsigd.sock");
snprintf(c->watch, sizeof c->watch, "%s", "/dev/shm/vmsig");
snprintf(c->pve_conf, sizeof c->pve_conf, "%s", "/etc/pve/qemu-server");
snprintf(c->qmp_dir, sizeof c->qmp_dir, "%s", "/var/run/qemu-server");
snprintf(c->slots, sizeof c->slots, "%s", "/dev/shm/vmsig/.slots");
}
uint32_t vmsigd_caps_from_str(const char* s) {
static const struct { const char* k; uint32_t bit; } map[] = {
{ "observe", VMSIG_CAP_OBSERVE },
{ "input", VMSIG_CAP_INPUT },
{ "lifecycle", VMSIG_CAP_LIFECYCLE },
{ "power", VMSIG_CAP_POWER },
{ "vm", VMSIG_CAP_VM },
{ "memctx", VMSIG_CAP_MEMCTX },
{ "memwrite", VMSIG_CAP_MEMWRITE },
{ "roster", VMSIG_CAP_ROSTER },
};
uint32_t mask = 0;
while (s && *s) {
while (*s == ',' || *s == ' ' || *s == '\t') s++;
const char* w = s;
while (*s && *s != ',' && *s != ' ' && *s != '\t') s++;
size_t len = (size_t)(s - w);
for (size_t i = 0; i < sizeof map / sizeof map[0]; i++)
if (len == strlen(map[i].k) && strncmp(w, map[i].k, len) == 0) { mask |= map[i].bit; break; }
}
return mask;
}
/* Trim leading/trailing whitespace in place; returns the trimmed start. */
static char* trim(char* s) {
while (*s == ' ' || *s == '\t' || *s == '\r') s++;
char* e = s + strlen(s);
while (e > s && (e[-1] == ' ' || e[-1] == '\t' || e[-1] == '\r' || e[-1] == '\n')) *--e = 0;
return s;
}
static void set_path(char* dst, size_t cap, const char* v) { snprintf(dst, cap, "%s", v); }
static void parse_vmids(vmsigd_grant_rule* g, const char* v) {
g->all_vms = 0; g->nvmids = 0;
if (strchr(v, '*')) { g->all_vms = 1; return; }
while (*v) {
while (*v == ',' || *v == ' ' || *v == '\t') v++;
if (*v < '0' || *v > '9') { if (*v) v++; continue; }
uint32_t id = (uint32_t)strtoul(v, NULL, 10);
while (*v >= '0' && *v <= '9') v++;
if (id && g->nvmids < VMSIGD_MAX_VMIDS) g->vmids[g->nvmids++] = id;
}
}
int vmsigd_config_parse_buf(vmsigd_config* c, const char* buf) {
if (!c || !buf) return -1;
char* copy = strdup(buf);
if (!copy) return -1;
vmsigd_grant_rule* cur = NULL; /* current [grant] stanza, or NULL for globals */
char* save = NULL;
for (char* line = strtok_r(copy, "\n", &save); line; line = strtok_r(NULL, "\n", &save)) {
char* p = trim(line);
if (!*p || *p == '#' || *p == ';') continue;
if (*p == '[') {
cur = NULL;
/* [grant uid=N] */
char* u = strstr(p, "uid=");
if (u && c->ngrants < VMSIGD_MAX_GRANTS) {
cur = &c->grants[c->ngrants++];
memset(cur, 0, sizeof *cur);
cur->uid = (uint32_t)strtoul(u + 4, NULL, 10);
}
continue;
}
char* eq = strchr(p, '=');
if (!eq) continue;
*eq = 0;
char* key = trim(p);
char* val = trim(eq + 1);
if (cur) {
if (!strcmp(key, "vmids")) parse_vmids(cur, val);
else if (!strcmp(key, "caps")) cur->cap_mask = vmsigd_caps_from_str(val);
else if (!strcmp(key, "arb_prio")) cur->arb_prio = (uint32_t)strtoul(val, NULL, 10);
} else {
if (!strcmp(key, "socket")) set_path(c->socket, sizeof c->socket, val);
else if (!strcmp(key, "watch")) set_path(c->watch, sizeof c->watch, val);
else if (!strcmp(key, "pve_conf")) set_path(c->pve_conf, sizeof c->pve_conf, val);
else if (!strcmp(key, "qmp_dir")) set_path(c->qmp_dir, sizeof c->qmp_dir, val);
else if (!strcmp(key, "slots")) set_path(c->slots, sizeof c->slots, val);
}
}
free(copy);
return 0;
}
int vmsigd_config_parse_file(vmsigd_config* c, const char* path) {
int fd = open(path, O_RDONLY | O_CLOEXEC);
if (fd < 0) return -1;
char buf[16 * 1024];
size_t got = 0;
for (;;) {
ssize_t n = read(fd, buf + got, sizeof buf - 1 - got);
if (n < 0) { close(fd); return -1; }
if (n == 0) break;
got += (size_t)n;
if (got >= sizeof buf - 1) break;
}
close(fd);
buf[got] = 0;
return vmsigd_config_parse_buf(c, buf);
}