]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
Get QEMU pty paths from the monitor
authorMatthew Booth <mbooth@redhat.com>
Mon, 14 Dec 2009 09:50:01 +0000 (10:50 +0100)
committerDaniel Veillard <veillard@redhat.com>
Mon, 14 Dec 2009 09:50:01 +0000 (10:50 +0100)
This change makes the QEMU driver get pty paths from the output of the
monitor 'info chardev' command. This output is structured, and contains
both the name of the device and the path on the same line. This is
considerably more reliable than parsing the startup log output, which
requires the parsing code to know which order QEMU will print pty
information in.

Note that we still need to parse the log output as the monitor itself
may be on a pty. This should be rare, however, and the new code will
replace all pty paths parsed by the log output method once the monitor
is available.

* src/qemu/qemu_monitor.(c|h) src/qemu_monitor_text.(c|h): Implement
  qemuMonitorGetPtyPaths().
* src/qemu/qemu_driver.c: Get pty path information using
  qemuMonitorGetPtyPaths().

src/qemu/qemu_driver.c
src/qemu/qemu_monitor.c
src/qemu/qemu_monitor.h
src/qemu/qemu_monitor_text.c
src/qemu/qemu_monitor_text.h

index c5aa2db4fe8ff325268f080f647b4811907992a8..7b8c4475b4eceb3b7f4037758ca836ef6b8eeebd 100644 (file)
@@ -1406,6 +1406,40 @@ qemudExtractTTYPath(virConnectPtr conn,
     return 1;
 }
 
+static int
+qemudFindCharDevicePTYsMonitor(virConnectPtr conn,
+                               virDomainObjPtr vm,
+                               virHashTablePtr paths)
+{
+    int i;
+
+#define LOOKUP_PTYS(array, arraylen, idprefix)                            \
+    for (i = 0 ; i < (arraylen) ; i++) {                                  \
+        virDomainChrDefPtr chr = (array)[i];                              \
+        if (chr->type == VIR_DOMAIN_CHR_TYPE_PTY) {                       \
+            char id[16];                                                  \
+                                                                          \
+            if (snprintf(id, sizeof(id), idprefix "%i", i) >= sizeof(id)) \
+                return -1;                                                \
+                                                                          \
+            const char *path = (const char *) virHashLookup(paths, id);   \
+            if (path == NULL) {                                           \
+                qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,\
+                                 _("no assigned pty for device %s"), id); \
+                return -1;                                                \
+            }                                                             \
+                                                                          \
+            chr->data.file.path = strdup(path);                           \
+        }                                                                 \
+    }
+
+    LOOKUP_PTYS(vm->def->serials,   vm->def->nserials,   "serial");
+    LOOKUP_PTYS(vm->def->parallels, vm->def->nparallels, "parallel");
+    LOOKUP_PTYS(vm->def->channels,  vm->def->nchannels,  "channel");
+
+    return 0;
+}
+
 static int
 qemudFindCharDevicePTYs(virConnectPtr conn,
                         virDomainObjPtr vm,
@@ -1452,6 +1486,11 @@ qemudFindCharDevicePTYs(virConnectPtr conn,
     return 0;
 }
 
+static void qemudFreePtyPath(void *payload, const char *name ATTRIBUTE_UNUSED)
+{
+    VIR_FREE(payload);
+}
+
 static int
 qemudWaitForMonitor(virConnectPtr conn,
                     struct qemud_driver* driver,
@@ -1459,7 +1498,7 @@ qemudWaitForMonitor(virConnectPtr conn,
 {
     char buf[4096]; /* Plenty of space to get startup greeting */
     int logfd;
-    int ret;
+    int ret = -1;
 
     if ((logfd = qemudLogReadFD(conn, driver->logDir, vm->def->name, pos))
         < 0)
@@ -1485,7 +1524,32 @@ qemudWaitForMonitor(virConnectPtr conn,
     if (qemuConnectMonitor(vm) < 0)
         return -1;
 
-    return 0;
+    /* Try to get the pty path mappings again via the monitor. This is much more
+     * reliable if it's available.
+     * Note that the monitor itself can be on a pty, so we still need to try the
+     * log output method. */
+    virHashTablePtr paths = virHashCreate(0);
+    if (paths == NULL) {
+        virReportOOMError(NULL);
+        goto cleanup;
+    }
+
+    qemuDomainObjEnterMonitor(vm);
+    qemuDomainObjPrivatePtr priv = vm->privateData;
+    ret = qemuMonitorGetPtyPaths(priv->mon, paths);
+    qemuDomainObjExitMonitor(vm);
+
+    VIR_DEBUG("qemuMonitorGetPtyPaths returned %i", ret);
+    if (ret == 0) {
+        ret = qemudFindCharDevicePTYsMonitor(conn, vm, paths);
+    }
+
+cleanup:
+    if (paths) {
+        virHashFree(paths, qemudFreePtyPath);
+    }
+
+    return ret;
 }
 
 static int
index 103cf28fee0290f53ce934e19ed63cf63031e116..750e3e60a36ec321354cf4cb194ce3fa0504532e 100644 (file)
@@ -1267,3 +1267,12 @@ int qemuMonitorRemoveHostNetwork(qemuMonitorPtr mon,
         ret = qemuMonitorTextRemoveHostNetwork(mon, vlan, netname);
     return ret;
 }
+
+int qemuMonitorGetPtyPaths(qemuMonitorPtr mon,
+                           virHashTablePtr paths)
+{
+    DEBUG("mon=%p, fd=%d",
+          mon, mon->fd);
+
+    return qemuMonitorTextGetPtyPaths(mon, paths);
+}
index 8b1e3a3872d492e170b378a178111f0f964d974c..db00b26918fa2880f9de401550971b84bd12e189 100644 (file)
@@ -28,6 +28,7 @@
 #include "internal.h"
 
 #include "domain_conf.h"
+#include "hash.h"
 
 typedef struct _qemuMonitor qemuMonitor;
 typedef qemuMonitor *qemuMonitorPtr;
@@ -272,5 +273,7 @@ int qemuMonitorRemoveHostNetwork(qemuMonitorPtr mon,
                                  int vlan,
                                  const char *netname);
 
+int qemuMonitorGetPtyPaths(qemuMonitorPtr mon,
+                           virHashTablePtr paths);
 
 #endif /* QEMU_MONITOR_H */
index 72cb2bb5a850161b79f0cc4b14dea80b05d523fd..3ed45bafa4da116bb9cdf626acfd09a69571c476 100644 (file)
@@ -1594,3 +1594,74 @@ cleanup:
     VIR_FREE(reply);
     return ret;
 }
+
+
+/* Parse the output of "info chardev" and return a hash of pty paths.
+ *
+ * Output is:
+ * foo: filename=pty:/dev/pts/7
+ * monitor: filename=stdio
+ * serial0: filename=vc
+ * parallel0: filename=vc
+ *
+ * Non-pty lines are ignored. In the above example, key is 'foo', value is
+ * '/dev/pty/7'. The hash will contain only a single value.
+ */
+
+int qemuMonitorTextGetPtyPaths(qemuMonitorPtr mon,
+                               virHashTablePtr paths)
+{
+    const char *cmd = "info chardev";
+    char *reply = NULL;
+    int ret = -1;
+
+    if (qemuMonitorCommand(mon, cmd, &reply) < 0) {
+        qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED,
+                         _("failed to retrieve chardev info in qemu with '%s'"),
+                         cmd);
+        goto cleanup;
+    }
+
+    char *pos = reply;                  /* The current start of searching */
+    char *end = pos + strlen(reply);    /* The end of the reply string */
+    char *eol;                   /* The character which ends the current line */
+
+    while (pos < end) {
+        /* Split the output into lines */
+        eol = memchr(pos, '\n', end - pos);
+        if (eol == NULL)
+            eol = end;
+
+        /* Look for 'filename=pty:' */
+#define NEEDLE "filename=pty:"
+        char *needle = memmem(pos, eol - pos, NEEDLE, strlen(NEEDLE));
+
+        /* If it's not there we can ignore this line */
+        if (!needle)
+            goto next;
+
+        /* id is everthing from the beginning of the line to the ':'
+         * find ':' and turn it into a terminator */
+        char *colon = memchr(pos, ':', needle - pos);
+        if (colon == NULL)
+            goto next;
+        *colon = '\0';
+        char *id = pos;
+
+        /* Path is everything after needle to the end of the line */
+        *eol = '\0';
+        char *path = needle + strlen(NEEDLE);
+
+        virHashAddEntry(paths, id, strdup(path));
+#undef NEEDLE
+
+    next:
+        pos = eol + 1;
+    }
+
+    ret = 0;
+
+cleanup:
+    VIR_FREE(reply);
+    return ret;
+}
index bc52ad232ec862c719b0faf3bbe0ad32e4ce0d73..519edf4e4d87803f582654a8b763f61374670326 100644 (file)
@@ -28,6 +28,7 @@
 #include "internal.h"
 
 #include "qemu_monitor.h"
+#include "hash.h"
 
 int qemuMonitorTextIOProcess(qemuMonitorPtr mon,
                              const char *data,
@@ -153,4 +154,7 @@ int qemuMonitorTextRemoveHostNetwork(qemuMonitorPtr mon,
                                      int vlan,
                                      const char *netname);
 
+int qemuMonitorTextGetPtyPaths(qemuMonitorPtr mon,
+                               virHashTablePtr paths);
+
 #endif /* QEMU_MONITOR_TEXT_H */