mirror of
https://dev.lirent.ru/Vatrog/vm-automation-signaling.git
synced 2026-06-26 04:36:37 +03:00
vmsig: management daemon, runtime endpoint lifecycle, roster, discovery, in-tree drivers, packaging
- core: runtime attach/detach of a per-endpoint adapter trio (runtime-safe add_adapter + vmsig_core_detach_endpoint, deferred reap) - roster: VMSIG_EV_ROSTER + CAP_ROSTER, retained per-endpoint and replayed to late subscribers - discovery: inotify trigger dir, vmid/endpoint slot allocator, host probe; vmsigd daemon with config + per-uid admission - input driver and vgpu perception built in-tree; vgpu perception as a separate library - memctx: own the supplied ro_fd (closed at detach) - deb packaging: install rules, systemd unit, tmpfiles, default config
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
/* 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);
|
||||
}
|
||||
Reference in New Issue
Block a user