Blob Blame History Raw
From ec6edfd4fa89b918348318eeb3bca982a9f39ba2 Mon Sep 17 00:00:00 2001
Message-Id: <ec6edfd4fa89b918348318eeb3bca982a9f39ba2@dist-git>
From: Peter Krempa <pkrempa@redhat.com>
Date: Mon, 24 Nov 2014 17:51:16 +0100
Subject: [PATCH] qemu: chardev: Extract more information about character
 devices

https://bugzilla.redhat.com/show_bug.cgi?id=1146944

Improve the monitor function to also retrieve the guest state of
character device (if provided) so that we can refresh the state of
virtio-serial channels and perhaps react to changes in the state in
future patches.

This patch changes the returned data from qemuMonitorGetChardevInfo to
return a structure containing the pty path and the state for all the
character devices.

The change to the testsuite makes sure that the data is parsed
correctly.

(cherry picked from commit 4d7eb903119ef61b58ced29432f4933b372e00ab)

Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
---
 src/qemu/qemu_monitor.c      | 13 ++++++++++-
 src/qemu/qemu_monitor.h      |  6 ++++++
 src/qemu/qemu_monitor_json.c | 51 +++++++++++++++++++++++++++++---------------
 src/qemu/qemu_monitor_text.c | 17 ++++++++++-----
 src/qemu/qemu_process.c      |  8 +++----
 tests/qemumonitorjsontest.c  | 41 +++++++++++++++++++++++++++++------
 6 files changed, 103 insertions(+), 33 deletions(-)

diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 55a0542..38399ba 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -2986,6 +2986,17 @@ qemuMonitorQueryRxFilter(qemuMonitorPtr mon, const char *alias,
 }
 
 
+static void
+qemuMonitorChardevInfoFree(void *data,
+                           const void *name ATTRIBUTE_UNUSED)
+{
+    qemuMonitorChardevInfoPtr info = data;
+
+    VIR_FREE(info->ptyPath);
+    VIR_FREE(info);
+}
+
+
 int
 qemuMonitorGetChardevInfo(qemuMonitorPtr mon,
                           virHashTablePtr *retinfo)
@@ -3001,7 +3012,7 @@ qemuMonitorGetChardevInfo(qemuMonitorPtr mon,
         goto error;
     }
 
-    if (!(info = virHashCreate(10, virHashValueFree)))
+    if (!(info = virHashCreate(10, qemuMonitorChardevInfoFree)))
         goto error;
 
     if (mon->json)
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 8ae0dbe..d1dc242 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -649,6 +649,12 @@ int qemuMonitorRemoveNetdev(qemuMonitorPtr mon,
 int qemuMonitorQueryRxFilter(qemuMonitorPtr mon, const char *alias,
                              virNetDevRxFilterPtr *filter);
 
+typedef struct _qemuMonitorChardevInfo qemuMonitorChardevInfo;
+typedef qemuMonitorChardevInfo *qemuMonitorChardevInfoPtr;
+struct _qemuMonitorChardevInfo {
+    char *ptyPath;
+    virDomainChrDeviceState state;
+};
 int qemuMonitorGetChardevInfo(qemuMonitorPtr mon,
                               virHashTablePtr *retinfo);
 
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index e5f49ef..34fb91f 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -3557,7 +3557,7 @@ qemuMonitorJSONQueryRxFilter(qemuMonitorPtr mon, const char *alias,
  *
  * {"return": [
  *      {"filename": "stdio", "label": "monitor"},
- *      {"filename": "pty:/dev/pts/6", "label": "serial0"},
+ *      {"filename": "pty:/dev/pts/6", "label": "serial0", "frontend-open": true},
  *      {"filename": "pty:/dev/pts/7", "label": "parallel0"}
  * ]}
  *
@@ -3569,6 +3569,7 @@ qemuMonitorJSONExtractChardevInfo(virJSONValuePtr reply,
     virJSONValuePtr data;
     int ret = -1;
     size_t i;
+    qemuMonitorChardevInfoPtr entry = NULL;
 
     if (!(data = virJSONValueObjectGet(reply, "return"))) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
@@ -3583,44 +3584,60 @@ qemuMonitorJSONExtractChardevInfo(virJSONValuePtr reply,
     }
 
     for (i = 0; i < virJSONValueArraySize(data); i++) {
-        virJSONValuePtr entry = virJSONValueArrayGet(data, i);
+        virJSONValuePtr chardev = virJSONValueArrayGet(data, i);
         const char *type;
-        const char *id;
-        if (!entry) {
+        const char *alias;
+        bool connected;
+
+        if (!chardev) {
             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                            _("character device information was missing array element"));
             goto cleanup;
         }
 
-        if (!(type = virJSONValueObjectGetString(entry, "filename"))) {
+        if (!(alias = virJSONValueObjectGetString(chardev, "label"))) {
             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                           _("character device information was missing filename"));
+                           _("character device information was missing label"));
             goto cleanup;
         }
 
-        if (!(id = virJSONValueObjectGetString(entry, "label"))) {
+        if (!(type = virJSONValueObjectGetString(chardev, "filename"))) {
             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                            _("character device information was missing filename"));
             goto cleanup;
         }
 
-        if (STRPREFIX(type, "pty:")) {
-            char *path;
-            if (VIR_STRDUP(path, type + strlen("pty:")) < 0)
-                goto cleanup;
+        if (VIR_ALLOC(entry) < 0)
+            goto cleanup;
+
+        if (STRPREFIX(type, "pty:") &&
+            VIR_STRDUP(entry->ptyPath, type + strlen("pty:")) < 0)
+            goto cleanup;
+
+        if (virJSONValueObjectGetBoolean(chardev, "frontend-open", &connected) == 0) {
+            if (connected)
+                entry->state = VIR_DOMAIN_CHR_DEVICE_STATE_CONNECTED;
+            else
+                entry->state = VIR_DOMAIN_CHR_DEVICE_STATE_DISCONNECTED;
+        }
 
-            if (virHashAddEntry(info, id, path) < 0) {
-                virReportError(VIR_ERR_OPERATION_FAILED,
-                               _("failed to save chardev path '%s'"), path);
-                VIR_FREE(path);
-                goto cleanup;
-            }
+        if (virHashAddEntry(info, alias, entry) < 0) {
+            virReportError(VIR_ERR_OPERATION_FAILED,
+                           _("failed to add chardev '%s' info"), alias);
+            goto cleanup;
         }
+
+        entry = NULL;
     }
 
     ret = 0;
 
  cleanup:
+    if (entry) {
+        VIR_FREE(entry->ptyPath);
+        VIR_FREE(entry);
+    }
+
     return ret;
 }
 
diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c
index 634f9f3..aee9f35 100644
--- a/src/qemu/qemu_monitor_text.c
+++ b/src/qemu/qemu_monitor_text.c
@@ -2176,6 +2176,7 @@ int qemuMonitorTextGetChardevInfo(qemuMonitorPtr mon,
                                   virHashTablePtr info)
 {
     char *reply = NULL;
+    qemuMonitorChardevInfoPtr entry = NULL;
     int ret = -1;
 
     if (qemuMonitorHMPCommand(mon, "info chardev", &reply) < 0)
@@ -2220,17 +2221,22 @@ int qemuMonitorTextGetChardevInfo(qemuMonitorPtr mon,
 
         /* Path is everything after needle to the end of the line */
         *eol = '\0';
-        char *path;
-        if (VIR_STRDUP(path, needle + strlen(NEEDLE)) < 0)
+
+        if (VIR_ALLOC(entry) < 0)
+            goto cleanup;
+
+        if (VIR_STRDUP(entry->ptyPath, needle + strlen(NEEDLE)) < 0)
             goto cleanup;
 
-        if (virHashAddEntry(info, id, path) < 0) {
+        if (virHashAddEntry(info, id, entry) < 0) {
             virReportError(VIR_ERR_OPERATION_FAILED,
                            _("failed to save chardev path '%s'"),
-                           path);
-            VIR_FREE(path);
+                           entry->ptyPath);
+            VIR_FREE(entry->ptyPath);
             goto cleanup;
         }
+
+        entry = NULL;
 #undef NEEDLE
     }
 
@@ -2238,6 +2244,7 @@ int qemuMonitorTextGetChardevInfo(qemuMonitorPtr mon,
 
  cleanup:
     VIR_FREE(reply);
+    VIR_FREE(entry);
     return ret;
 }
 
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 7e1b9a2..ebcd5e8 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -1919,15 +1919,15 @@ qemuProcessLookupPTYs(virDomainDefPtr def,
 
         if (chr->source.type == VIR_DOMAIN_CHR_TYPE_PTY) {
             char id[32];
-            const char *path;
+            qemuMonitorChardevInfoPtr entry;
 
             if (snprintf(id, sizeof(id), "%s%s",
                          chardevfmt ? "char" : "",
                          chr->info.alias) >= sizeof(id))
                 return -1;
 
-            path = (const char *) virHashLookup(info, id);
-            if (path == NULL) {
+            entry = virHashLookup(info, id);
+            if (!entry || !entry->ptyPath) {
                 if (chr->source.data.file.path == NULL) {
                     /* neither the log output nor 'info chardev' had a
                      * pty path for this chardev, report an error
@@ -1944,7 +1944,7 @@ qemuProcessLookupPTYs(virDomainDefPtr def,
             }
 
             VIR_FREE(chr->source.data.file.path);
-            if (VIR_STRDUP(chr->source.data.file.path, path) < 0)
+            if (VIR_STRDUP(chr->source.data.file.path, entry->ptyPath) < 0)
                 return -1;
         }
     }
diff --git a/tests/qemumonitorjsontest.c b/tests/qemumonitorjsontest.c
index afa2561..46c5f40 100644
--- a/tests/qemumonitorjsontest.c
+++ b/tests/qemumonitorjsontest.c
@@ -1759,11 +1759,28 @@ testQemuMonitorJSONqemuMonitorJSONGetSpiceMigrationStatus(const void *data)
 }
 
 static int
-testHashEqualString(const void *value1, const void *value2)
+testHashEqualChardevInfo(const void *value1, const void *value2)
 {
-    return strcmp(value1, value2);
+    const qemuMonitorChardevInfo *info1 = value1;
+    const qemuMonitorChardevInfo *info2 = value2;
+
+    if (info1->state != info2->state)
+        goto error;
+
+    if (STRNEQ_NULLABLE(info1->ptyPath, info2->ptyPath))
+        goto error;
+
+    return 0;
+
+ error:
+    fprintf(stderr, "\n"
+            "info1->state: %d info2->state: %d\n"
+            "info1->ptyPath: %s info2->ptyPath: %s\n",
+            info1->state, info2->state, info1->ptyPath, info2->ptyPath);
+    return -1;
 }
 
+
 static int
 testQemuMonitorJSONqemuMonitorJSONGetChardevInfo(const void *data)
 {
@@ -1771,6 +1788,10 @@ testQemuMonitorJSONqemuMonitorJSONGetChardevInfo(const void *data)
     qemuMonitorTestPtr test = qemuMonitorTestNewSimple(true, xmlopt);
     int ret = -1;
     virHashTablePtr info = NULL, expectedInfo = NULL;
+    qemuMonitorChardevInfo info0 = { NULL, VIR_DOMAIN_CHR_DEVICE_STATE_DEFAULT };
+    qemuMonitorChardevInfo info1 = { (char *) "/dev/pts/21", VIR_DOMAIN_CHR_DEVICE_STATE_CONNECTED };
+    qemuMonitorChardevInfo info2 = { (char *) "/dev/pts/20", VIR_DOMAIN_CHR_DEVICE_STATE_DEFAULT };
+    qemuMonitorChardevInfo info3 = { NULL, VIR_DOMAIN_CHR_DEVICE_STATE_DISCONNECTED };
 
     if (!test)
         return -1;
@@ -1779,8 +1800,10 @@ testQemuMonitorJSONqemuMonitorJSONGetChardevInfo(const void *data)
         !(expectedInfo = virHashCreate(32, NULL)))
         goto cleanup;
 
-    if (virHashAddEntry(expectedInfo, "charserial1", (void *) "/dev/pts/21") < 0 ||
-        virHashAddEntry(expectedInfo, "charserial0", (void *) "/dev/pts/20") < 0) {
+    if (virHashAddEntry(expectedInfo, "charserial1", &info1) < 0 ||
+        virHashAddEntry(expectedInfo, "charserial0", &info2) < 0 ||
+        virHashAddEntry(expectedInfo, "charmonitor", &info0) < 0 ||
+        virHashAddEntry(expectedInfo, "charserial2", &info3) < 0) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                        "Unable to create expectedInfo hash table");
         goto cleanup;
@@ -1791,7 +1814,8 @@ testQemuMonitorJSONqemuMonitorJSONGetChardevInfo(const void *data)
                                "    \"return\": ["
                                "        {"
                                "            \"filename\": \"pty:/dev/pts/21\","
-                               "            \"label\": \"charserial1\""
+                               "            \"label\": \"charserial1\","
+                               "            \"frontend-open\": true"
                                "        },"
                                "        {"
                                "            \"filename\": \"pty:/dev/pts/20\","
@@ -1800,6 +1824,11 @@ testQemuMonitorJSONqemuMonitorJSONGetChardevInfo(const void *data)
                                "        {"
                                "            \"filename\": \"unix:/var/lib/libvirt/qemu/gentoo.monitor,server\","
                                "            \"label\": \"charmonitor\""
+                               "        },"
+                               "        {"
+                               "            \"filename\": \"unix:/path/to/socket,server\","
+                               "            \"label\": \"charserial2\","
+                               "            \"frontend-open\": false"
                                "        }"
                                "    ],"
                                "    \"id\": \"libvirt-15\""
@@ -1810,7 +1839,7 @@ testQemuMonitorJSONqemuMonitorJSONGetChardevInfo(const void *data)
                                       info) < 0)
         goto cleanup;
 
-    if (!virHashEqual(info, expectedInfo, testHashEqualString)) {
+    if (!virHashEqual(info, expectedInfo, testHashEqualChardevInfo)) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                        "Hashtable is different to the expected one");
         goto cleanup;
-- 
2.1.3