mirror of
https://dev.lirent.ru/Vatrog/vm-automation-signaling.git
synced 2026-06-25 20:36:36 +03:00
127 lines
4.8 KiB
C
127 lines
4.8 KiB
C
|
|
/* 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);
|
||
|
|
}
|