]> xenbits.xensource.com Git - libvirt.git/commitdiff
qemu_monitor: Introduce qemuMonitorAttachCharDev
authorMichal Privoznik <mprivozn@redhat.com>
Tue, 12 Mar 2013 18:48:04 +0000 (19:48 +0100)
committerMichal Privoznik <mprivozn@redhat.com>
Fri, 12 Jul 2013 09:00:01 +0000 (11:00 +0200)
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.

src/qemu/qemu_monitor.c
src/qemu/qemu_monitor.h
src/qemu/qemu_monitor_json.c
src/qemu/qemu_monitor_json.h
tests/qemumonitorjsontest.c

index 6f9a8fc0bde8df063d046b04f0b0337cce23a708..de0079eb18d4120ed2823e99aeabda43a80f6429 100644 (file)
@@ -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);
+}
index 78011ee73fd798f485ac9da7f0368c2c59fbcf3e..734e09bc6db94bfdb5d66fe22cb71314c3156d87 100644 (file)
@@ -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
index bff46a5b664bdeec3f819879b568f4f2a6e74b38..b06429e20013af056f9e2cd1d15aab627af7a9d7 100644 (file)
@@ -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;
+}
index d79b86b2496e2ac8ab996e5412f89c09310925a8..e0a48835e18ccd02c9aaf44410265395ab68defe 100644 (file)
@@ -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 */
index 14d37000b0637b10a360598970b47a062dd9538c..1b3b9f83c876ccfbe40ab430e8dfb8a0c31cdd89 100644 (file)
@@ -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);