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:
2026-06-22 17:25:06 +03:00
parent 0d387a4249
commit 9bde398b6c
55 changed files with 4703 additions and 61 deletions
+113
View File
@@ -0,0 +1,113 @@
/* qmp.c — AF_UNIX QMP client: connect + capability handshake, line-based recv
* with a poll timeout, and synchronous command execution. */
#include "qmp.h"
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <poll.h>
#define QMP_TIMEOUT_MS 5000
#define QMP_BUF_SIZE 4096
struct qmp_conn {
int fd;
};
static int recv_line(int fd, char* buf, size_t cap) {
size_t n = 0;
while (n + 1 < cap) {
struct pollfd pfd = { .fd = fd, .events = POLLIN };
if (poll(&pfd, 1, QMP_TIMEOUT_MS) <= 0) return -1;
char c;
if (read(fd, &c, 1) != 1) return -1;
buf[n++] = c;
if (c == '\n') break;
}
buf[n] = '\0';
return (int)n;
}
static int send_all(int fd, const char* s, size_t len) {
while (len > 0) {
ssize_t w = write(fd, s, len);
if (w <= 0) return -1;
s += w;
len -= (size_t)w;
}
return 0;
}
qmp_conn* qmp_connect(const char* sock_path) {
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (fd < 0) return NULL;
struct sockaddr_un addr;
memset(&addr, 0, sizeof addr);
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, sock_path, sizeof addr.sun_path - 1);
if (connect(fd, (struct sockaddr*)&addr, sizeof addr) < 0) {
close(fd);
return NULL;
}
char buf[QMP_BUF_SIZE];
if (recv_line(fd, buf, sizeof buf) < 0) {
close(fd);
return NULL;
}
const char* cap_cmd = "{\"execute\":\"qmp_capabilities\"}\r\n";
if (send_all(fd, cap_cmd, strlen(cap_cmd)) < 0) {
close(fd);
return NULL;
}
if (recv_line(fd, buf, sizeof buf) < 0) {
close(fd);
return NULL;
}
qmp_conn* c = malloc(sizeof *c);
if (!c) {
close(fd);
return NULL;
}
c->fd = fd;
return c;
}
void qmp_disconnect(qmp_conn* c) {
if (!c) return;
close(c->fd);
free(c);
}
int qmp_exec(qmp_conn* c, const char* cmd, char* resp, size_t cap) {
size_t cmdlen = strlen(cmd);
if (send_all(c->fd, cmd, cmdlen) < 0) return -1;
if (send_all(c->fd, "\r\n", 2) < 0) return -1;
char line[QMP_BUF_SIZE];
for (;;) {
if (recv_line(c->fd, line, sizeof line) < 0) return -1;
if (strstr(line, "\"return\"")) {
if (resp && cap > 0) {
strncpy(resp, line, cap - 1);
resp[cap - 1] = '\0';
}
return 0;
}
if (strstr(line, "\"error\"")) {
if (resp && cap > 0) {
strncpy(resp, line, cap - 1);
resp[cap - 1] = '\0';
}
return -1;
}
}
}