mirror of
https://github.com/libvirt/libvirt.git
synced 2025-02-20 11:48:28 -06:00
qemu_monitor: Introduce qemuMonitorAttachCharDev
The function being introduced is responsible for preparing and executing 'chardev-add' qemu monitor command. Moreover, in case of PTY chardev, the corresponding pty path is updated.
This commit is contained in:
parent
41e826d539
commit
4a51447abe
@ -3622,3 +3622,24 @@ int qemuMonitorGetTPMTypes(qemuMonitorPtr mon,
|
||||
|
||||
return qemuMonitorJSONGetTPMTypes(mon, tpmtypes);
|
||||
}
|
||||
|
||||
int qemuMonitorAttachCharDev(qemuMonitorPtr mon,
|
||||
const char *chrID,
|
||||
virDomainChrSourceDefPtr chr)
|
||||
{
|
||||
VIR_DEBUG("mon=%p chrID=%s chr=%p", mon, chrID, chr);
|
||||
|
||||
if (!mon) {
|
||||
virReportError(VIR_ERR_INVALID_ARG, "%s",
|
||||
_("monitor must not be NULL"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!mon->json) {
|
||||
virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
|
||||
_("JSON monitor is required"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return qemuMonitorJSONAttachCharDev(mon, chrID, chr);
|
||||
}
|
||||
|
@ -701,6 +701,9 @@ int qemuMonitorGetTPMModels(qemuMonitorPtr mon,
|
||||
int qemuMonitorGetTPMTypes(qemuMonitorPtr mon,
|
||||
char ***tpmtypes);
|
||||
|
||||
int qemuMonitorAttachCharDev(qemuMonitorPtr mon,
|
||||
const char *chrID,
|
||||
virDomainChrSourceDefPtr chr);
|
||||
/**
|
||||
* When running two dd process and using <> redirection, we need a
|
||||
* shell that will not truncate files. These two strings serve that
|
||||
|
@ -4766,6 +4766,29 @@ error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static virJSONValuePtr
|
||||
qemuMonitorJSONBuildUnixSocketAddress(const char *path)
|
||||
{
|
||||
virJSONValuePtr addr = NULL;
|
||||
virJSONValuePtr data = NULL;
|
||||
|
||||
if (!(data = virJSONValueNewObject()) ||
|
||||
!(addr = virJSONValueNewObject()))
|
||||
goto error;
|
||||
|
||||
if (virJSONValueObjectAppendString(data, "path", path) < 0 ||
|
||||
virJSONValueObjectAppendString(addr, "type", "unix") < 0 ||
|
||||
virJSONValueObjectAppend(addr, "data", data) < 0)
|
||||
goto error;
|
||||
|
||||
return addr;
|
||||
error:
|
||||
virReportOOMError();
|
||||
virJSONValueFree(data);
|
||||
virJSONValueFree(addr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
qemuMonitorJSONNBDServerStart(qemuMonitorPtr mon,
|
||||
const char *host,
|
||||
@ -4941,3 +4964,162 @@ int qemuMonitorJSONGetTPMTypes(qemuMonitorPtr mon,
|
||||
{
|
||||
return qemuMonitorJSONGetStringArray(mon, "query-tpm-types", tpmtypes);
|
||||
}
|
||||
|
||||
static virJSONValuePtr
|
||||
qemuMonitorJSONAttachCharDevCommand(const char *chrID,
|
||||
const virDomainChrSourceDefPtr chr)
|
||||
{
|
||||
virJSONValuePtr ret;
|
||||
virJSONValuePtr backend;
|
||||
virJSONValuePtr data = NULL;
|
||||
virJSONValuePtr addr = NULL;
|
||||
const char *backend_type = NULL;
|
||||
bool telnet;
|
||||
|
||||
if (!(backend = virJSONValueNewObject()) ||
|
||||
!(data = virJSONValueNewObject())) {
|
||||
goto no_memory;
|
||||
}
|
||||
|
||||
switch ((enum virDomainChrType) chr->type) {
|
||||
case VIR_DOMAIN_CHR_TYPE_NULL:
|
||||
case VIR_DOMAIN_CHR_TYPE_VC:
|
||||
backend_type = "null";
|
||||
break;
|
||||
|
||||
case VIR_DOMAIN_CHR_TYPE_PTY:
|
||||
backend_type = "pty";
|
||||
break;
|
||||
|
||||
case VIR_DOMAIN_CHR_TYPE_FILE:
|
||||
backend_type = "file";
|
||||
if (virJSONValueObjectAppendString(data, "out", chr->data.file.path) < 0)
|
||||
goto no_memory;
|
||||
break;
|
||||
|
||||
case VIR_DOMAIN_CHR_TYPE_DEV:
|
||||
backend_type = STRPREFIX(chrID, "parallel") ? "parallel" : "serial";
|
||||
if (virJSONValueObjectAppendString(data, "device",
|
||||
chr->data.file.path) < 0)
|
||||
goto no_memory;
|
||||
break;
|
||||
|
||||
case VIR_DOMAIN_CHR_TYPE_TCP:
|
||||
backend_type = "socket";
|
||||
addr = qemuMonitorJSONBuildInetSocketAddress(chr->data.tcp.host,
|
||||
chr->data.tcp.service);
|
||||
if (!addr ||
|
||||
virJSONValueObjectAppend(data, "addr", addr) < 0)
|
||||
goto no_memory;
|
||||
addr = NULL;
|
||||
|
||||
telnet = chr->data.tcp.protocol == VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET;
|
||||
|
||||
if (virJSONValueObjectAppendBoolean(data, "wait", false) < 0 ||
|
||||
virJSONValueObjectAppendBoolean(data, "telnet", telnet) < 0 ||
|
||||
virJSONValueObjectAppendBoolean(data, "server", chr->data.tcp.listen) < 0)
|
||||
goto no_memory;
|
||||
break;
|
||||
|
||||
case VIR_DOMAIN_CHR_TYPE_UDP:
|
||||
backend_type = "socket";
|
||||
addr = qemuMonitorJSONBuildInetSocketAddress(chr->data.udp.connectHost,
|
||||
chr->data.udp.connectService);
|
||||
if (!addr ||
|
||||
virJSONValueObjectAppend(data, "addr", addr) < 0)
|
||||
goto no_memory;
|
||||
addr = NULL;
|
||||
break;
|
||||
|
||||
case VIR_DOMAIN_CHR_TYPE_UNIX:
|
||||
backend_type = "socket";
|
||||
addr = qemuMonitorJSONBuildUnixSocketAddress(chr->data.nix.path);
|
||||
|
||||
if (!addr ||
|
||||
virJSONValueObjectAppend(data, "addr", addr) < 0)
|
||||
goto no_memory;
|
||||
addr = NULL;
|
||||
|
||||
if (virJSONValueObjectAppendBoolean(data, "wait", false) < 0 ||
|
||||
virJSONValueObjectAppendBoolean(data, "server", chr->data.nix.listen) < 0)
|
||||
goto no_memory;
|
||||
break;
|
||||
|
||||
case VIR_DOMAIN_CHR_TYPE_SPICEVMC:
|
||||
case VIR_DOMAIN_CHR_TYPE_PIPE:
|
||||
case VIR_DOMAIN_CHR_TYPE_STDIO:
|
||||
case VIR_DOMAIN_CHR_TYPE_LAST:
|
||||
virReportError(VIR_ERR_OPERATION_FAILED,
|
||||
_("Unsupported char device type '%d'"),
|
||||
chr->type);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (virJSONValueObjectAppendString(backend, "type", backend_type) < 0 ||
|
||||
virJSONValueObjectAppend(backend, "data", data) < 0)
|
||||
goto no_memory;
|
||||
data = NULL;
|
||||
|
||||
if (!(ret = qemuMonitorJSONMakeCommand("chardev-add",
|
||||
"s:id", chrID,
|
||||
"a:backend", backend,
|
||||
NULL)))
|
||||
goto error;
|
||||
|
||||
return ret;
|
||||
|
||||
no_memory:
|
||||
virReportOOMError();
|
||||
error:
|
||||
virJSONValueFree(addr);
|
||||
virJSONValueFree(data);
|
||||
virJSONValueFree(backend);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
qemuMonitorJSONAttachCharDev(qemuMonitorPtr mon,
|
||||
const char *chrID,
|
||||
virDomainChrSourceDefPtr chr)
|
||||
{
|
||||
int ret = -1;
|
||||
virJSONValuePtr cmd;
|
||||
virJSONValuePtr reply = NULL;
|
||||
|
||||
if (!(cmd = qemuMonitorJSONAttachCharDevCommand(chrID, chr)))
|
||||
return ret;
|
||||
|
||||
if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (qemuMonitorJSONCheckError(cmd, reply) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (chr->type == VIR_DOMAIN_CHR_TYPE_PTY) {
|
||||
virJSONValuePtr data;
|
||||
const char *path;
|
||||
|
||||
if (!(data = virJSONValueObjectGet(reply, "return"))) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||
_("chardev-add reply was missing return data"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!(path = virJSONValueObjectGetString(data, "pty"))) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||
_("chardev-add reply was missing pty path"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (VIR_STRDUP(chr->data.file.path, path) < 0)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
virJSONValueFree(cmd);
|
||||
virJSONValueFree(reply);
|
||||
return ret;
|
||||
}
|
||||
|
@ -353,4 +353,7 @@ int qemuMonitorJSONGetTPMTypes(qemuMonitorPtr mon,
|
||||
char ***tpmtypes)
|
||||
ATTRIBUTE_NONNULL(2);
|
||||
|
||||
int qemuMonitorJSONAttachCharDev(qemuMonitorPtr mon,
|
||||
const char *chrID,
|
||||
virDomainChrSourceDefPtr chr);
|
||||
#endif /* QEMU_MONITOR_JSON_H */
|
||||
|
@ -594,6 +594,86 @@ cleanup:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
testQemuMonitorJSONAttachChardev(const void *data)
|
||||
{
|
||||
const virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data;
|
||||
qemuMonitorTestPtr test = qemuMonitorTestNew(true, xmlopt);
|
||||
virDomainChrSourceDef chr;
|
||||
int ret = 0;
|
||||
|
||||
if (!test)
|
||||
return -1;
|
||||
|
||||
#define DO_CHECK(chrID, reply, fail) \
|
||||
if (qemuMonitorTestAddItem(test, "chardev-add", reply) < 0) \
|
||||
goto cleanup; \
|
||||
if (qemuMonitorAttachCharDev(qemuMonitorTestGetMonitor(test), \
|
||||
chrID, &chr) < 0) \
|
||||
ret = fail ? ret : -1; \
|
||||
else \
|
||||
ret = fail ? -1 : ret; \
|
||||
|
||||
#define CHECK(chrID, reply) \
|
||||
DO_CHECK(chrID, reply, false)
|
||||
|
||||
#define CHECK_FAIL(chrID, reply) \
|
||||
DO_CHECK(chrID, reply, true)
|
||||
|
||||
chr = (virDomainChrSourceDef) { .type = VIR_DOMAIN_CHR_TYPE_NULL };
|
||||
CHECK("chr_null", "{\"return\": {}}");
|
||||
|
||||
chr = (virDomainChrSourceDef) { .type =VIR_DOMAIN_CHR_TYPE_VC };
|
||||
CHECK("chr_vc", "{\"return\": {}}");
|
||||
|
||||
#define PTY_PATH "/dev/ttyS0"
|
||||
chr = (virDomainChrSourceDef) { .type = VIR_DOMAIN_CHR_TYPE_PTY };
|
||||
CHECK("chr_pty", "{\"return\": {\"pty\" : \"" PTY_PATH "\"}}");
|
||||
if (STRNEQ_NULLABLE(PTY_PATH, chr.data.file.path)) {
|
||||
VIR_FREE(chr.data.file.path);
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
"expected PTY path: %s got: %s",
|
||||
PTY_PATH, NULLSTR(chr.data.file.path));
|
||||
ret = -1;
|
||||
}
|
||||
VIR_FREE(chr.data.file.path);
|
||||
|
||||
chr = (virDomainChrSourceDef) { .type = VIR_DOMAIN_CHR_TYPE_PTY };
|
||||
CHECK_FAIL("chr_pty_fail", "{\"return\": {}}");
|
||||
#undef PTY_PATH
|
||||
|
||||
chr = (virDomainChrSourceDef) { .type = VIR_DOMAIN_CHR_TYPE_FILE };
|
||||
CHECK("chr_file", "{\"return\": {}}");
|
||||
|
||||
chr = (virDomainChrSourceDef) { .type = VIR_DOMAIN_CHR_TYPE_DEV };
|
||||
CHECK("chr_dev", "{\"return\": {}}");
|
||||
|
||||
chr = (virDomainChrSourceDef) { .type = VIR_DOMAIN_CHR_TYPE_TCP };
|
||||
CHECK("chr_tcp", "{\"return\": {}}");
|
||||
|
||||
chr = (virDomainChrSourceDef) { .type = VIR_DOMAIN_CHR_TYPE_UDP };
|
||||
CHECK("chr_udp", "{\"return\": {}}");
|
||||
|
||||
chr = (virDomainChrSourceDef) { .type = VIR_DOMAIN_CHR_TYPE_UNIX };
|
||||
CHECK("chr_unix", "{\"return\": {}}");
|
||||
|
||||
chr = (virDomainChrSourceDef) { .type = VIR_DOMAIN_CHR_TYPE_SPICEVMC };
|
||||
CHECK_FAIL("chr_spicevmc", "{\"return\": {}}");
|
||||
|
||||
chr = (virDomainChrSourceDef) { .type = VIR_DOMAIN_CHR_TYPE_PIPE };
|
||||
CHECK_FAIL("chr_pipe", "{\"return\": {}}");
|
||||
|
||||
chr = (virDomainChrSourceDef) { .type = VIR_DOMAIN_CHR_TYPE_STDIO };
|
||||
CHECK_FAIL("chr_stdio", "{\"return\": {}}");
|
||||
|
||||
#undef CHECK
|
||||
#undef CHECK_FAIL
|
||||
#undef DO_CHECK
|
||||
|
||||
cleanup:
|
||||
qemuMonitorTestFree(test);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
mymain(void)
|
||||
@ -623,6 +703,7 @@ mymain(void)
|
||||
DO_TEST(GetCommands);
|
||||
DO_TEST(GetTPMModels);
|
||||
DO_TEST(GetCommandLineOptionParameters);
|
||||
DO_TEST(AttachChardev);
|
||||
|
||||
virObjectUnref(xmlopt);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user