From 49956f046907035d9b43ed3462beb78c9b3d621e Mon Sep 17 00:00:00 2001
From: "Daniel P. Berrange" <berrange@redhat.com>
Date: Fri, 25 Apr 2008 20:46:13 +0000
Subject: [PATCH] Implement serial & parallel device support for QEMU driver

---
 ChangeLog                                     |  14 +-
 src/internal.h                                |   4 +
 src/qemu_conf.c                               | 648 +++++++++++++++++-
 src/qemu_conf.h                               |  60 +-
 src/qemu_driver.c                             |  77 ++-
 .../qemuxml2argv-boot-cdrom.args              |   2 +-
 .../qemuxml2argv-boot-floppy.args             |   2 +-
 .../qemuxml2argv-boot-network.args            |   2 +-
 .../qemuxml2argv-clock-localtime.args         |   2 +-
 .../qemuxml2argv-clock-utc.args               |   2 +-
 .../qemuxml2argv-console-compat.args          |   1 +
 .../qemuxml2argv-console-compat.xml           |  28 +
 .../qemuxml2argv-disk-cdrom.args              |   2 +-
 .../qemuxml2argv-disk-floppy.args             |   2 +-
 .../qemuxml2argv-disk-many.args               |   2 +-
 .../qemuxml2argv-graphics-sdl.args            |   2 +-
 .../qemuxml2argv-graphics-vnc.args            |   2 +-
 .../qemuxml2argv-input-usbmouse.args          |   2 +-
 .../qemuxml2argv-input-usbtablet.args         |   2 +-
 .../qemuxml2argv-minimal.args                 |   2 +-
 .../qemuxml2argv-misc-acpi.args               |   2 +-
 .../qemuxml2argv-misc-no-reboot.args          |   2 +-
 .../qemuxml2argv-net-user.args                |   2 +-
 .../qemuxml2argv-parallel-tcp.args            |   1 +
 .../qemuxml2argv-parallel-tcp.xml             |  27 +
 .../qemuxml2argv-serial-dev.args              |   1 +
 .../qemuxml2argv-serial-dev.xml               |  30 +
 .../qemuxml2argv-serial-file.args             |   1 +
 .../qemuxml2argv-serial-file.xml              |  30 +
 .../qemuxml2argv-serial-many.args             |   1 +
 .../qemuxml2argv-serial-many.xml              |  32 +
 .../qemuxml2argv-serial-pty.args              |   1 +
 .../qemuxml2argv-serial-pty.xml               |  28 +
 .../qemuxml2argv-serial-tcp-telnet.args       |   1 +
 .../qemuxml2argv-serial-tcp-telnet.xml        |  32 +
 .../qemuxml2argv-serial-tcp.args              |   1 +
 .../qemuxml2argv-serial-tcp.xml               |  32 +
 .../qemuxml2argv-serial-udp.args              |   1 +
 .../qemuxml2argv-serial-udp.xml               |  32 +
 .../qemuxml2argv-serial-unix.args             |   1 +
 .../qemuxml2argv-serial-unix.xml              |  30 +
 .../qemuxml2argv-serial-vc.args               |   1 +
 .../qemuxml2argv-serial-vc.xml                |  28 +
 tests/qemuxml2argvtest.c                      | 117 ++--
 tests/qemuxml2xmltest.c                       | 113 ++-
 45 files changed, 1212 insertions(+), 193 deletions(-)
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-console-compat.args
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-console-compat.xml
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-parallel-tcp.args
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-parallel-tcp.xml
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-dev.args
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-dev.xml
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-file.args
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-file.xml
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-many.args
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-many.xml
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-pty.args
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-pty.xml
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-telnet.args
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-telnet.xml
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-tcp.args
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-tcp.xml
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-udp.args
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-udp.xml
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-unix.args
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-unix.xml
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-vc.args
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-vc.xml

diff --git a/ChangeLog b/ChangeLog
index 74d0b80c55..7247f9a6af 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,16 @@
-Fri Apr 25 12:21:28 EST 2008 Daniel P. Berrange <berrange@redhat.coM>
+Fri Apr 25 16:45:28 EST 2008 Daniel P. Berrange <berrange@redhat.com>
+
+	* src/internal.c: Convenience macros for fixed arrays
+	* src/qemu_driver.c: Extract TTY paths for serial and parallel
+	devices too
+	* src/qemu_conf.c, src/qemu_conf.h: Support arbitrary serial
+	and parallel devices.
+	* tests/qemuxml2argvtest.c, tests/qemuxml2xmltest.c: Add tests
+	for serial and parallel devices
+	* tests/qemuxml2argvdata/*: Updated and added data files for
+	new test cases
+
+Fri Apr 25 12:21:28 EST 2008 Daniel P. Berrange <berrange@redhat.com>
 
 	* docs/page.xsl, docs/libvir.css: Re-arrange layout to workaround
 	IE6 bugs
diff --git a/src/internal.h b/src/internal.h
index 6bed4770d2..67d31b3639 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -66,6 +66,10 @@ extern "C" {
 #define STRNEQLEN(a,b,n) (strncmp((a),(b),(n)) != 0)
 #define STRCASENEQLEN(a,b,n) (strncasecmp((a),(b),(n)) != 0)
 
+
+#define NUL_TERMINATE(buf) do { (buf)[sizeof(buf)-1] = '\0'; } while (0)
+#define ARRAY_CARDINALITY(Array) (sizeof (Array) / sizeof *(Array))
+
 /* If configured with --enable-debug=yes then library calls
  * are printed to stderr for debugging.
  */
diff --git a/src/qemu_conf.c b/src/qemu_conf.c
index d9b82b205b..2d048d36ff 100644
--- a/src/qemu_conf.c
+++ b/src/qemu_conf.c
@@ -205,6 +205,8 @@ void qemudFreeVMDef(struct qemud_vm_def *def) {
     struct qemud_vm_disk_def *disk = def->disks;
     struct qemud_vm_net_def *net = def->nets;
     struct qemud_vm_input_def *input = def->inputs;
+    struct qemud_vm_chr_def *serial = def->serials;
+    struct qemud_vm_chr_def *parallel = def->parallels;
 
     while (disk) {
         struct qemud_vm_disk_def *prev = disk;
@@ -221,6 +223,16 @@ void qemudFreeVMDef(struct qemud_vm_def *def) {
         input = input->next;
         free(prev);
     }
+    while (serial) {
+        struct qemud_vm_chr_def *prev = serial;
+        serial = serial->next;
+        free(prev);
+    }
+    while (parallel) {
+        struct qemud_vm_chr_def *prev = parallel;
+        parallel = parallel->next;
+        free(prev);
+    }
     xmlFree(def->keymap);
     free(def);
 }
@@ -945,6 +957,333 @@ static int qemudParseInterfaceXML(virConnectPtr conn,
 }
 
 
+/* Parse the XML definition for a character device
+ * @param net pre-allocated & zero'd net record
+ * @param node XML nodeset to parse for net definition
+ * @return 0 on success, -1 on failure
+ *
+ * The XML we're dealing with looks like
+ *
+ * <serial type="pty">
+ *   <source path="/dev/pts/3"/>
+ *   <target port="1"/>
+ * </serial>
+ *
+ * <serial type="dev">
+ *   <source path="/dev/ttyS0"/>
+ *   <target port="1"/>
+ * </serial>
+ *
+ * <serial type="tcp">
+ *   <source mode="connect" host="0.0.0.0" service="2445"/>
+ *   <target port="1"/>
+ * </serial>
+ *
+ * <serial type="tcp">
+ *   <source mode="bind" host="0.0.0.0" service="2445"/>
+ *   <target port="1"/>
+ * </serial>
+ *
+ * <serial type="udp">
+ *   <source mode="bind" host="0.0.0.0" service="2445"/>
+ *   <source mode="connect" host="0.0.0.0" service="2445"/>
+ *   <target port="1"/>
+ * </serial>
+ *
+ * <serial type="unix">
+ *   <source mode="bind" path="/tmp/foo"/>
+ *   <target port="1"/>
+ * </serial>
+ *
+ */
+static int qemudParseCharXML(virConnectPtr conn,
+                             struct qemud_vm_chr_def *chr,
+                             int portNum,
+                             xmlNodePtr node) {
+    xmlNodePtr cur;
+    xmlChar *type = NULL;
+    xmlChar *bindHost = NULL;
+    xmlChar *bindService = NULL;
+    xmlChar *connectHost = NULL;
+    xmlChar *connectService = NULL;
+    xmlChar *path = NULL;
+    xmlChar *mode = NULL;
+    xmlChar *protocol = NULL;
+    int ret = -1;
+
+    chr->srcType = QEMUD_CHR_SRC_TYPE_PTY;
+    type = xmlGetProp(node, BAD_CAST "type");
+    if (type != NULL) {
+        if (xmlStrEqual(type, BAD_CAST "null"))
+            chr->srcType = QEMUD_CHR_SRC_TYPE_NULL;
+        else if (xmlStrEqual(type, BAD_CAST "vc"))
+            chr->srcType = QEMUD_CHR_SRC_TYPE_VC;
+        else if (xmlStrEqual(type, BAD_CAST "pty"))
+            chr->srcType = QEMUD_CHR_SRC_TYPE_PTY;
+        else if (xmlStrEqual(type, BAD_CAST "dev"))
+            chr->srcType = QEMUD_CHR_SRC_TYPE_DEV;
+        else if (xmlStrEqual(type, BAD_CAST "file"))
+            chr->srcType = QEMUD_CHR_SRC_TYPE_FILE;
+        else if (xmlStrEqual(type, BAD_CAST "pipe"))
+            chr->srcType = QEMUD_CHR_SRC_TYPE_PIPE;
+        else if (xmlStrEqual(type, BAD_CAST "stdio"))
+            chr->srcType = QEMUD_CHR_SRC_TYPE_STDIO;
+        else if (xmlStrEqual(type, BAD_CAST "udp"))
+            chr->srcType = QEMUD_CHR_SRC_TYPE_UDP;
+        else if (xmlStrEqual(type, BAD_CAST "tcp"))
+            chr->srcType = QEMUD_CHR_SRC_TYPE_TCP;
+        else if (xmlStrEqual(type, BAD_CAST "unix"))
+            chr->srcType = QEMUD_CHR_SRC_TYPE_UNIX;
+        else
+            chr->srcType = QEMUD_CHR_SRC_TYPE_NULL;
+    }
+
+    cur = node->children;
+    while (cur != NULL) {
+        if (cur->type == XML_ELEMENT_NODE) {
+            if (xmlStrEqual(cur->name, BAD_CAST "source")) {
+                if (mode == NULL)
+                    mode = xmlGetProp(cur, BAD_CAST "mode");
+
+                switch (chr->srcType) {
+                case QEMUD_CHR_SRC_TYPE_PTY:
+                case QEMUD_CHR_SRC_TYPE_DEV:
+                case QEMUD_CHR_SRC_TYPE_FILE:
+                case QEMUD_CHR_SRC_TYPE_PIPE:
+                case QEMUD_CHR_SRC_TYPE_UNIX:
+                    if (path == NULL)
+                        path = xmlGetProp(cur, BAD_CAST "path");
+
+                    break;
+
+                case QEMUD_CHR_SRC_TYPE_UDP:
+                case QEMUD_CHR_SRC_TYPE_TCP:
+                    if (mode == NULL ||
+                        STREQ((const char *)mode, "connect")) {
+
+                        if (connectHost == NULL)
+                            connectHost = xmlGetProp(cur, BAD_CAST "host");
+                        if (connectService == NULL)
+                            connectService = xmlGetProp(cur, BAD_CAST "service");
+                    } else {
+                        if (bindHost == NULL)
+                            bindHost = xmlGetProp(cur, BAD_CAST "host");
+                        if (bindService == NULL)
+                            bindService = xmlGetProp(cur, BAD_CAST "service");
+                    }
+
+                    if (chr->srcType == QEMUD_CHR_SRC_TYPE_UDP) {
+                        xmlFree(mode);
+                        mode = NULL;
+                    }
+                }
+            } else if (xmlStrEqual(cur->name, BAD_CAST "protocol")) {
+                if (protocol == NULL)
+                    protocol = xmlGetProp(cur, BAD_CAST "type");
+            }
+        }
+        cur = cur->next;
+    }
+
+
+    chr->dstPort = portNum;
+
+    switch (chr->srcType) {
+    case QEMUD_CHR_SRC_TYPE_NULL:
+        /* Nada */
+        break;
+
+    case QEMUD_CHR_SRC_TYPE_VC:
+        break;
+
+    case QEMUD_CHR_SRC_TYPE_PTY:
+        /* @path attribute is an output only property - pty is auto-allocted */
+        break;
+
+    case QEMUD_CHR_SRC_TYPE_DEV:
+    case QEMUD_CHR_SRC_TYPE_FILE:
+    case QEMUD_CHR_SRC_TYPE_PIPE:
+        if (path == NULL) {
+            qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                             "%s", _("Missing source path attribute for char device"));
+            goto cleanup;
+        }
+
+        strncpy(chr->srcData.file.path, (const char *)path,
+                sizeof(chr->srcData.file.path));
+        NUL_TERMINATE(chr->srcData.file.path);
+        break;
+
+    case QEMUD_CHR_SRC_TYPE_STDIO:
+        /* Nada */
+        break;
+
+    case QEMUD_CHR_SRC_TYPE_TCP:
+        if (mode == NULL ||
+            STREQ((const char *)mode, "connect")) {
+            if (connectHost == NULL) {
+                qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                                 "%s", _("Missing source host attribute for char device"));
+                goto cleanup;
+            }
+            if (connectService == NULL) {
+                qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                                 "%s", _("Missing source service attribute for char device"));
+                goto cleanup;
+            }
+
+            strncpy(chr->srcData.tcp.host, (const char *)connectHost,
+                    sizeof(chr->srcData.tcp.host));
+            NUL_TERMINATE(chr->srcData.tcp.host);
+            strncpy(chr->srcData.tcp.service, (const char *)connectService,
+                    sizeof(chr->srcData.tcp.service));
+            NUL_TERMINATE(chr->srcData.tcp.service);
+
+            chr->srcData.tcp.listen = 0;
+        } else {
+            if (bindHost == NULL) {
+                qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                                 "%s", _("Missing source host attribute for char device"));
+                goto cleanup;
+            }
+            if (bindService == NULL) {
+                qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                                 "%s", _("Missing source service attribute for char device"));
+                goto cleanup;
+            }
+
+            strncpy(chr->srcData.tcp.host, (const char *)bindHost,
+                    sizeof(chr->srcData.tcp.host));
+            NUL_TERMINATE(chr->srcData.tcp.host);
+            strncpy(chr->srcData.tcp.service, (const char *)bindService,
+                    sizeof(chr->srcData.tcp.service));
+            NUL_TERMINATE(chr->srcData.tcp.service);
+
+            chr->srcData.tcp.listen = 1;
+        }
+        if (protocol != NULL &&
+            STREQ((const char *)protocol, "telnet"))
+            chr->srcData.tcp.protocol = QEMUD_CHR_SRC_TCP_PROTOCOL_TELNET;
+        else
+            chr->srcData.tcp.protocol = QEMUD_CHR_SRC_TCP_PROTOCOL_RAW;
+        break;
+
+    case QEMUD_CHR_SRC_TYPE_UDP:
+        if (connectService == NULL) {
+            qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                             "%s", _("Missing source service attribute for char device"));
+            goto cleanup;
+        }
+
+        if (connectHost != NULL) {
+            strncpy(chr->srcData.udp.connectHost, (const char *)connectHost,
+                    sizeof(chr->srcData.udp.connectHost));
+            NUL_TERMINATE(chr->srcData.udp.connectHost);
+        }
+        strncpy(chr->srcData.udp.connectService, (const char *)connectService,
+                sizeof(chr->srcData.udp.connectService));
+        NUL_TERMINATE(chr->srcData.udp.connectService);
+
+        if (bindHost != NULL) {
+            strncpy(chr->srcData.udp.bindHost, (const char *)bindHost,
+                    sizeof(chr->srcData.udp.bindHost));
+            NUL_TERMINATE(chr->srcData.udp.bindHost);
+        }
+        if (bindService != NULL) {
+            strncpy(chr->srcData.udp.bindService, (const char *)bindService,
+                    sizeof(chr->srcData.udp.bindService));
+            NUL_TERMINATE(chr->srcData.udp.bindService);
+        }
+        break;
+
+    case QEMUD_CHR_SRC_TYPE_UNIX:
+        if (path == NULL) {
+            qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                             "%s", _("Missing source path attribute for char device"));
+            goto cleanup;
+        }
+
+        if (mode != NULL &&
+            STRNEQ((const char *)mode, "connect"))
+            chr->srcData.nix.listen = 1;
+        else
+            chr->srcData.nix.listen = 0;
+
+        strncpy(chr->srcData.nix.path, (const char *)path,
+                sizeof(chr->srcData.nix.path));
+        NUL_TERMINATE(chr->srcData.nix.path);
+        break;
+    }
+
+    ret = 0;
+
+cleanup:
+    xmlFree(mode);
+    xmlFree(protocol);
+    xmlFree(type);
+    xmlFree(bindHost);
+    xmlFree(bindService);
+    xmlFree(connectHost);
+    xmlFree(connectService);
+    xmlFree(path);
+
+    return ret;
+}
+
+
+static int qemudParseCharXMLDevices(virConnectPtr conn,
+                                    xmlXPathContextPtr ctxt,
+                                    const char *xpath,
+                                    unsigned int *ndevs,
+                                    struct qemud_vm_chr_def **devs)
+{
+    xmlXPathObjectPtr obj;
+    int i, ret = -1;
+
+    obj = xmlXPathEval(BAD_CAST xpath, ctxt);
+    if ((obj != NULL) && (obj->type == XPATH_NODESET) &&
+        (obj->nodesetval != NULL) && (obj->nodesetval->nodeNr >= 0)) {
+        struct qemud_vm_chr_def *prev = *devs;
+        if (ndevs == NULL &&
+            obj->nodesetval->nodeNr > 1) {
+            qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                             "%s", _("too many character devices"));
+            goto cleanup;
+        }
+
+        for (i = 0; i < obj->nodesetval->nodeNr; i++) {
+            struct qemud_vm_chr_def *chr = calloc(1, sizeof(*chr));
+            if (!chr) {
+                qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY,
+                                 "%s",
+                                 _("failed to allocate space for char device"));
+                goto cleanup;
+            }
+
+            if (qemudParseCharXML(conn, chr, i, obj->nodesetval->nodeTab[i]) < 0) {
+                free(chr);
+                goto cleanup;
+            }
+            if (ndevs)
+                (*ndevs)++;
+            chr->next = NULL;
+            if (i == 0) {
+                *devs = chr;
+            } else {
+                prev->next = chr;
+            }
+            prev = chr;
+        }
+    }
+
+    ret = 0;
+
+cleanup:
+    xmlXPathFreeObject(obj);
+    return ret;
+}
+
+
 /* Parse the XML definition for a network interface */
 static int qemudParseInputXML(virConnectPtr conn,
                               struct qemud_vm_input_def *input,
@@ -1423,6 +1762,45 @@ static struct qemud_vm_def *qemudParseXML(virConnectPtr conn,
         }
     }
     xmlXPathFreeObject(obj);
+    obj = NULL;
+
+    /* analysis of the character devices */
+    if (qemudParseCharXMLDevices(conn, ctxt,
+                                 "/domain/devices/parallel",
+                                 &def->nparallels,
+                                 &def->parallels) < 0)
+        goto error;
+    if (qemudParseCharXMLDevices(conn, ctxt,
+                                 "/domain/devices/serial",
+                                 &def->nserials,
+                                 &def->serials) < 0)
+        goto error;
+
+    /*
+     * If no serial devices were listed, then look for console
+     * devices which is the legacy syntax for the same thing
+     */
+    if (def->nserials == 0) {
+        obj = xmlXPathEval(BAD_CAST "/domain/devices/console", ctxt);
+        if ((obj != NULL) && (obj->type == XPATH_NODESET) &&
+            (obj->nodesetval != NULL) && (obj->nodesetval->nodeNr == 1)) {
+            struct qemud_vm_chr_def *chr = calloc(1, sizeof(*chr));
+            if (!chr) {
+                qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY,
+                                 "%s",
+                                 _("failed to allocate space for char device"));
+                goto error;
+            }
+
+            if (qemudParseCharXML(conn, chr, 0, obj->nodesetval->nodeTab[0]) < 0) {
+                free(chr);
+                goto error;
+            }
+            def->nserials = 1;
+            def->serials = chr;
+        }
+        xmlXPathFreeObject(obj);
+    }
 
 
     /* analysis of the network devices */
@@ -1617,6 +1995,78 @@ qemudNetworkIfaceConnect(virConnectPtr conn,
     return NULL;
 }
 
+static int qemudBuildCommandLineChrDevStr(struct qemud_vm_chr_def *dev,
+                                          char *buf,
+                                          int buflen)
+{
+    switch (dev->srcType) {
+    case QEMUD_CHR_SRC_TYPE_NULL:
+        strncpy(buf, "null", buflen);
+        buf[buflen-1] = '\0';
+        break;
+
+    case QEMUD_CHR_SRC_TYPE_VC:
+        strncpy(buf, "vc", buflen);
+        buf[buflen-1] = '\0';
+        break;
+
+    case QEMUD_CHR_SRC_TYPE_PTY:
+        strncpy(buf, "pty", buflen);
+        buf[buflen-1] = '\0';
+        break;
+
+    case QEMUD_CHR_SRC_TYPE_DEV:
+        if (snprintf(buf, buflen, "%s",
+                     dev->srcData.file.path) >= buflen)
+            return -1;
+        break;
+
+    case QEMUD_CHR_SRC_TYPE_FILE:
+        if (snprintf(buf, buflen, "file:%s",
+                     dev->srcData.file.path) >= buflen)
+            return -1;
+        break;
+
+    case QEMUD_CHR_SRC_TYPE_PIPE:
+        if (snprintf(buf, buflen, "pipe:%s",
+                     dev->srcData.file.path) >= buflen)
+            return -1;
+        break;
+
+    case QEMUD_CHR_SRC_TYPE_STDIO:
+        strncpy(buf, "stdio", buflen);
+        buf[buflen-1] = '\0';
+        break;
+
+    case QEMUD_CHR_SRC_TYPE_UDP:
+        if (snprintf(buf, buflen, "udp:%s:%s@%s:%s",
+                     dev->srcData.udp.connectHost,
+                     dev->srcData.udp.connectService,
+                     dev->srcData.udp.bindHost,
+                     dev->srcData.udp.bindService) >= buflen)
+            return -1;
+        break;
+
+    case QEMUD_CHR_SRC_TYPE_TCP:
+        if (snprintf(buf, buflen, "%s:%s:%s%s",
+                     dev->srcData.tcp.protocol == QEMUD_CHR_SRC_TCP_PROTOCOL_TELNET ? "telnet" : "tcp",
+                     dev->srcData.tcp.host,
+                     dev->srcData.tcp.service,
+                     dev->srcData.tcp.listen ? ",listen" : "") >= buflen)
+            return -1;
+        break;
+
+    case QEMUD_CHR_SRC_TYPE_UNIX:
+        if (snprintf(buf, buflen, "unix:%s%s",
+                     dev->srcData.nix.path,
+                     dev->srcData.nix.listen ? ",listen" : "") >= buflen)
+            return -1;
+        break;
+    }
+
+    return 0;
+}
+
 /*
  * Constructs a argv suitable for launching qemu with config defined
  * for a given virtual machine.
@@ -1633,6 +2083,8 @@ int qemudBuildCommandLine(virConnectPtr conn,
     struct qemud_vm_disk_def *disk = vm->def->disks;
     struct qemud_vm_net_def *net = vm->def->nets;
     struct qemud_vm_input_def *input = vm->def->inputs;
+    struct qemud_vm_chr_def *serial = vm->def->serials;
+    struct qemud_vm_chr_def *parallel = vm->def->parallels;
     struct utsname ut;
     int disableKQEMU = 0;
 
@@ -1681,6 +2133,8 @@ int qemudBuildCommandLine(virConnectPtr conn,
         (vm->def->nnets > 0 ? (4 * vm->def->nnets) : 2) + /* networks */
         1 + /* usb */
         2 * vm->def->ninputs + /* input devices */
+        (vm->def->nserials > 0 ? (2 * vm->def->nserials) : 2) + /* character devices */
+        (vm->def->nparallels > 0 ? (2 * vm->def->nparallels) : 2) + /* character devices */
         2 + /* memory*/
         2 + /* cpus */
         2 + /* boot device */
@@ -1913,6 +2367,48 @@ int qemudBuildCommandLine(virConnectPtr conn,
         }
     }
 
+    if (!serial) {
+        if (!((*argv)[++n] = strdup("-serial")))
+            goto no_memory;
+        if (!((*argv)[++n] = strdup("none")))
+            goto no_memory;
+    } else {
+        while (serial) {
+            char buf[4096];
+
+            if (qemudBuildCommandLineChrDevStr(serial, buf, sizeof(buf)) < 0)
+                goto error;
+
+            if (!((*argv)[++n] = strdup("-serial")))
+                goto no_memory;
+            if (!((*argv)[++n] = strdup(buf)))
+                goto no_memory;
+
+            serial = serial->next;
+        }
+    }
+
+    if (!parallel) {
+        if (!((*argv)[++n] = strdup("-parallel")))
+            goto no_memory;
+        if (!((*argv)[++n] = strdup("none")))
+            goto no_memory;
+    } else {
+        while (parallel) {
+            char buf[4096];
+
+            if (qemudBuildCommandLineChrDevStr(parallel, buf, sizeof(buf)) < 0)
+                goto error;
+
+            if (!((*argv)[++n] = strdup("-parallel")))
+                goto no_memory;
+            if (!((*argv)[++n] = strdup(buf)))
+                goto no_memory;
+
+            parallel = parallel->next;
+        }
+    }
+
     if (!((*argv)[++n] = strdup("-usb")))
         goto no_memory;
     while (input) {
@@ -2838,6 +3334,127 @@ int qemudScanConfigs(struct qemud_driver *driver) {
     return 0;
 }
 
+static int qemudGenerateXMLChar(virBufferPtr buf,
+                                const struct qemud_vm_chr_def *dev,
+                                const char *type)
+{
+    const char *const types[] = {
+        "null",
+        "vc",
+        "pty",
+        "dev",
+        "file",
+        "pipe",
+        "stdio",
+        "udp",
+        "tcp",
+        "unix"
+    };
+    /*verify(ARRAY_CARDINALITY(types) == QEMUD_CHR_SRC_TYPE_LAST);*/
+
+    if (dev->srcType < 0 || dev->srcType >= QEMUD_CHR_SRC_TYPE_LAST)
+        return -1;
+
+    /* Compat with legacy  <console tty='/dev/pts/5'/> syntax */
+    if (STREQ(type, "console") &&
+        dev->srcType == QEMUD_CHR_SRC_TYPE_PTY &&
+        dev->srcData.file.path[0] != '\0') {
+        if (virBufferVSprintf(buf, "    <%s type='%s' tty='%s'>\n",
+                              type, types[dev->srcType],
+                              dev->srcData.file.path) < 0)
+            return -1;
+    } else {
+        if (virBufferVSprintf(buf, "    <%s type='%s'>\n",
+                              type, types[dev->srcType]) < 0)
+            return -1;
+    }
+
+    switch (dev->srcType) {
+    case QEMUD_CHR_SRC_TYPE_NULL:
+    case QEMUD_CHR_SRC_TYPE_VC:
+    case QEMUD_CHR_SRC_TYPE_STDIO:
+        /* nada */
+        break;
+
+    case QEMUD_CHR_SRC_TYPE_PTY:
+    case QEMUD_CHR_SRC_TYPE_DEV:
+    case QEMUD_CHR_SRC_TYPE_FILE:
+    case QEMUD_CHR_SRC_TYPE_PIPE:
+        if (dev->srcType != QEMUD_CHR_SRC_TYPE_PTY ||
+            dev->srcData.file.path[0]) {
+            if (virBufferVSprintf(buf, "      <source path='%s'/>\n",
+                                  dev->srcData.file.path) < 0)
+                return -1;
+        }
+        break;
+
+    case QEMUD_CHR_SRC_TYPE_UDP:
+        if (dev->srcData.udp.bindService[0] != '\0' &&
+            dev->srcData.udp.bindHost[0] != '\0') {
+            if (virBufferVSprintf(buf, "      <source mode='bind' host='%s' service='%s'/>\n",
+                                  dev->srcData.udp.bindHost,
+                                  dev->srcData.udp.bindService) < 0)
+                return -1;
+        } else if (dev->srcData.udp.bindHost[0] !='\0') {
+            if (virBufferVSprintf(buf, "      <source mode='bind' host='%s'/>\n",
+                                  dev->srcData.udp.bindHost) < 0)
+                return -1;
+        } else if (dev->srcData.udp.bindService[0] != '\0') {
+            if (virBufferVSprintf(buf, "      <source mode='bind' service='%s'/>\n",
+                                  dev->srcData.udp.bindService) < 0)
+                return -1;
+        }
+
+        if (dev->srcData.udp.connectService[0] != '\0' &&
+            dev->srcData.udp.connectHost[0] != '\0') {
+            if (virBufferVSprintf(buf, "      <source mode='connect' host='%s' service='%s'/>\n",
+                                  dev->srcData.udp.connectHost,
+                                  dev->srcData.udp.connectService) < 0)
+                return -1;
+        } else if (dev->srcData.udp.connectHost[0] != '\0') {
+            if (virBufferVSprintf(buf, "      <source mode='connect' host='%s'/>\n",
+                                  dev->srcData.udp.connectHost) < 0)
+                return -1;
+        } else if (dev->srcData.udp.connectService[0] != '\0') {
+            if (virBufferVSprintf(buf, "      <source mode='connect' service='%s'/>\n",
+                                  dev->srcData.udp.connectService) < 0)
+                return -1;
+        }
+
+        break;
+
+    case QEMUD_CHR_SRC_TYPE_TCP:
+        if (virBufferVSprintf(buf, "      <source mode='%s' host='%s' service='%s'/>\n",
+                              dev->srcData.tcp.listen ? "bind" : "connect",
+                              dev->srcData.tcp.host,
+                              dev->srcData.tcp.service) < 0)
+            return -1;
+        if (virBufferVSprintf(buf, "      <protocol type='%s'/>\n",
+                              dev->srcData.tcp.protocol == QEMUD_CHR_SRC_TCP_PROTOCOL_TELNET
+                              ? "telnet" : "raw") < 0)
+            return -1;
+        break;
+
+    case QEMUD_CHR_SRC_TYPE_UNIX:
+        if (virBufferVSprintf(buf, "      <source mode='%s' path='%s'/>\n",
+                              dev->srcData.nix.listen ? "bind" : "connect",
+                              dev->srcData.nix.path) < 0)
+            return -1;
+        break;
+    }
+
+    if (virBufferVSprintf(buf, "      <target port='%d'/>\n",
+                          dev->dstPort) < 0)
+        return -1;
+
+    if (virBufferVSprintf(buf, "    </%s>\n",
+                          type) < 0)
+        return -1;
+
+    return 0;
+}
+
+
 /* Generate an XML document describing the guest's configuration */
 char *qemudGenerateXML(virConnectPtr conn,
                        struct qemud_driver *driver ATTRIBUTE_UNUSED,
@@ -2847,9 +3464,10 @@ char *qemudGenerateXML(virConnectPtr conn,
     virBufferPtr buf = 0;
     unsigned char *uuid;
     char uuidstr[VIR_UUID_STRING_BUFLEN];
-    struct qemud_vm_disk_def *disk;
-    struct qemud_vm_net_def *net;
-    struct qemud_vm_input_def *input;
+    const struct qemud_vm_disk_def *disk;
+    const struct qemud_vm_net_def *net;
+    const struct qemud_vm_input_def *input;
+    const struct qemud_vm_chr_def *chr;
     const char *type = NULL;
     int n;
 
@@ -3078,6 +3696,27 @@ char *qemudGenerateXML(virConnectPtr conn,
         net = net->next;
     }
 
+    chr = def->serials;
+    while (chr) {
+        if (qemudGenerateXMLChar(buf, chr, "serial") < 0)
+            goto no_memory;
+
+        chr = chr->next;
+    }
+
+    chr = def->parallels;
+    while (chr) {
+        if (qemudGenerateXMLChar(buf, chr, "parallel") < 0)
+            goto no_memory;
+
+        chr = chr->next;
+    }
+
+    /* First serial device is the primary console */
+    if (def->nserials > 0 &&
+        qemudGenerateXMLChar(buf, def->serials, "console") < 0)
+        goto no_memory;
+
     input = def->inputs;
     while (input) {
         if (input->bus != QEMU_INPUT_BUS_PS2 &&
@@ -3125,9 +3764,6 @@ char *qemudGenerateXML(virConnectPtr conn,
         break;
     }
 
-    if (def->graphicsType == QEMUD_GRAPHICS_VNC) {
-    }
-
     if (virBufferAddLit(buf, "  </devices>\n") < 0)
         goto no_memory;
 
diff --git a/src/qemu_conf.h b/src/qemu_conf.h
index c59b1faebd..8a367e3eca 100644
--- a/src/qemu_conf.h
+++ b/src/qemu_conf.h
@@ -119,6 +119,54 @@ struct qemud_vm_net_def {
     struct qemud_vm_net_def *next;
 };
 
+enum qemu_vm_chr_dst_type {
+    QEMUD_CHR_SRC_TYPE_NULL,
+    QEMUD_CHR_SRC_TYPE_VC,
+    QEMUD_CHR_SRC_TYPE_PTY,
+    QEMUD_CHR_SRC_TYPE_DEV,
+    QEMUD_CHR_SRC_TYPE_FILE,
+    QEMUD_CHR_SRC_TYPE_PIPE,
+    QEMUD_CHR_SRC_TYPE_STDIO,
+    QEMUD_CHR_SRC_TYPE_UDP,
+    QEMUD_CHR_SRC_TYPE_TCP,
+    QEMUD_CHR_SRC_TYPE_UNIX,
+
+    QEMUD_CHR_SRC_TYPE_LAST,
+};
+
+enum {
+    QEMUD_CHR_SRC_TCP_PROTOCOL_RAW,
+    QEMUD_CHR_SRC_TCP_PROTOCOL_TELNET,
+};
+
+struct qemud_vm_chr_def {
+    int dstPort;
+
+    int srcType;
+    union {
+        struct {
+            char path[PATH_MAX];
+        } file; /* pty, file, pipe, or device */
+        struct {
+            char host[BR_INET_ADDR_MAXLEN];
+            char service[BR_INET_ADDR_MAXLEN];
+            int listen;
+            int protocol;
+        } tcp;
+        struct {
+            char bindHost[BR_INET_ADDR_MAXLEN];
+            char bindService[BR_INET_ADDR_MAXLEN];
+            char connectHost[BR_INET_ADDR_MAXLEN];
+            char connectService[BR_INET_ADDR_MAXLEN];
+        } udp;
+        struct {
+            char path[PATH_MAX];
+            int listen;
+        } nix;
+    } srcData;
+
+    struct qemud_vm_chr_def *next;
+};
 
 enum qemu_vm_input_type {
     QEMU_INPUT_TYPE_MOUSE,
@@ -215,14 +263,20 @@ struct qemud_vm_def {
     char vncListen[BR_INET_ADDR_MAXLEN];
     char *keymap;
 
-    int ndisks;
+    unsigned int ndisks;
     struct qemud_vm_disk_def *disks;
 
-    int nnets;
+    unsigned int nnets;
     struct qemud_vm_net_def *nets;
 
-    int ninputs;
+    unsigned int ninputs;
     struct qemud_vm_input_def *inputs;
+
+    unsigned int nserials;
+    struct qemud_vm_chr_def *serials;
+
+    unsigned int nparallels;
+    struct qemud_vm_chr_def *parallels;
 };
 
 /* Guest VM runtime state */
diff --git a/src/qemu_driver.c b/src/qemu_driver.c
index eb2f6e8903..e9246336c5 100644
--- a/src/qemu_driver.c
+++ b/src/qemu_driver.c
@@ -381,7 +381,6 @@ qemudReadMonitorOutput(virConnectPtr conn,
                        const char *what)
 {
 #define MONITOR_TIMEOUT 3000
-
     int got = 0;
     buf[0] = '\0';
 
@@ -498,48 +497,88 @@ static int qemudOpenMonitor(virConnectPtr conn,
     return ret;
 }
 
-static int qemudExtractMonitorPath(const char *haystack, char *path, int pathmax) {
+static int qemudExtractMonitorPath(const char *haystack,
+                                   size_t *offset,
+                                   char *path, int pathmax) {
     static const char needle[] = "char device redirected to";
     char *tmp;
 
-    if (!(tmp = strstr(haystack, needle)))
+    /* First look for our magic string */
+    if (!(tmp = strstr(haystack + *offset, needle)))
         return -1;
 
+    /* Grab all the trailing data */
     strncpy(path, tmp+sizeof(needle), pathmax-1);
     path[pathmax-1] = '\0';
 
-    while (*path) {
-        /*
-         * The monitor path ends at first whitespace char
-         * so lets search for it & NULL terminate it there
-         */
-        if (isspace(to_uchar(*path))) {
-            *path = '\0';
+    /*
+     * And look for first whitespace character and nul terminate
+     * to mark end of the pty path
+     */
+    tmp = path;
+    while (*tmp) {
+        if (isspace(to_uchar(*tmp))) {
+            *tmp = '\0';
+            *offset += (sizeof(needle)-1) + strlen(path);
             return 0;
         }
-        path++;
+        tmp++;
     }
 
     /*
      * We found a path, but didn't find any whitespace,
      * so it must be still incomplete - we should at
-     * least see a \n
+     * least see a \n - indicate that we want to carry
+     * on trying again
      */
     return -1;
 }
 
 static int
-qemudOpenMonitorPath(virConnectPtr conn,
-                     struct qemud_driver *driver,
-                     struct qemud_vm *vm,
-                     const char *output,
-                     int fd ATTRIBUTE_UNUSED)
+qemudFindCharDevicePTYs(virConnectPtr conn,
+                        struct qemud_driver *driver,
+                        struct qemud_vm *vm,
+                        const char *output,
+                        int fd ATTRIBUTE_UNUSED)
 {
     char monitor[PATH_MAX];
+    size_t offset = 0;
+    struct qemud_vm_chr_def *chr;
 
-    if (qemudExtractMonitorPath(output, monitor, sizeof(monitor)) < 0)
+    /* The order in which QEMU prints out the PTY paths is
+       the order in which it procsses its monitor, serial
+       and parallel device args. This code must match that
+       ordering.... */
+
+    /* So first comes the monitor device */
+    if (qemudExtractMonitorPath(output, &offset, monitor, sizeof(monitor)) < 0)
         return 1; /* keep reading */
 
+    /* then the serial devices */
+    chr = vm->def->serials;
+    while (chr) {
+        if (chr->srcType == QEMUD_CHR_SRC_TYPE_PTY) {
+            if (qemudExtractMonitorPath(output, &offset,
+                                        chr->srcData.file.path,
+                                        sizeof(chr->srcData.file.path)) < 0)
+                return 1; /* keep reading */
+        }
+        chr = chr->next;
+    }
+
+    /* and finally the parallel devices */
+    chr = vm->def->parallels;
+    while (chr) {
+        if (chr->srcType == QEMUD_CHR_SRC_TYPE_PTY) {
+            if (qemudExtractMonitorPath(output, &offset,
+                                        chr->srcData.file.path,
+                                        sizeof(chr->srcData.file.path)) < 0)
+                return 1; /* keep reading */
+        }
+        chr = chr->next;
+    }
+
+    /* Got them all, so now open the monitor console */
     return qemudOpenMonitor(conn, driver, vm, monitor);
 }
 
@@ -550,7 +589,7 @@ static int qemudWaitForMonitor(virConnectPtr conn,
     int ret = qemudReadMonitorOutput(conn,
                                      driver, vm, vm->stderr,
                                      buf, sizeof(buf),
-                                     qemudOpenMonitorPath,
+                                     qemudFindCharDevicePTYs,
                                      "console");
 
     buf[sizeof(buf)-1] = '\0';
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-boot-cdrom.args b/tests/qemuxml2argvdata/qemuxml2argv-boot-cdrom.args
index cf4a92815b..fe29e97c12 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-boot-cdrom.args
+++ b/tests/qemuxml2argvdata/qemuxml2argv-boot-cdrom.args
@@ -1 +1 @@
-/usr/bin/qemu -M pc -m 214 -smp 1 -nographic -monitor pty -no-acpi -boot d -cdrom /dev/cdrom -net none -usb
\ No newline at end of file
+/usr/bin/qemu -M pc -m 214 -smp 1 -nographic -monitor pty -no-acpi -boot d -cdrom /dev/cdrom -net none -serial none -parallel none -usb
\ No newline at end of file
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-boot-floppy.args b/tests/qemuxml2argvdata/qemuxml2argv-boot-floppy.args
index 70d96dee84..9141ef299d 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-boot-floppy.args
+++ b/tests/qemuxml2argvdata/qemuxml2argv-boot-floppy.args
@@ -1 +1 @@
-/usr/bin/qemu -M pc -m 214 -smp 1 -nographic -monitor pty -no-acpi -boot a -hda /dev/HostVG/QEMUGuest1 -fda /tmp/firmware.img -net none -usb
\ No newline at end of file
+/usr/bin/qemu -M pc -m 214 -smp 1 -nographic -monitor pty -no-acpi -boot a -hda /dev/HostVG/QEMUGuest1 -fda /tmp/firmware.img -net none -serial none -parallel none -usb
\ No newline at end of file
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-boot-network.args b/tests/qemuxml2argvdata/qemuxml2argv-boot-network.args
index 991f2f9917..fdef4608d4 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-boot-network.args
+++ b/tests/qemuxml2argvdata/qemuxml2argv-boot-network.args
@@ -1 +1 @@
-/usr/bin/qemu -M pc -m 214 -smp 1 -nographic -monitor pty -no-acpi -boot n -hda /dev/HostVG/QEMUGuest1 -net none -usb
\ No newline at end of file
+/usr/bin/qemu -M pc -m 214 -smp 1 -nographic -monitor pty -no-acpi -boot n -hda /dev/HostVG/QEMUGuest1 -net none -serial none -parallel none -usb
\ No newline at end of file
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-clock-localtime.args b/tests/qemuxml2argvdata/qemuxml2argv-clock-localtime.args
index c7ef740256..9e2f9706ed 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-clock-localtime.args
+++ b/tests/qemuxml2argvdata/qemuxml2argv-clock-localtime.args
@@ -1 +1 @@
-/usr/bin/qemu -M pc -m 214 -smp 1 -nographic -monitor pty -localtime -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -usb
\ No newline at end of file
+/usr/bin/qemu -M pc -m 214 -smp 1 -nographic -monitor pty -localtime -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -serial none -parallel none -usb
\ No newline at end of file
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-clock-utc.args b/tests/qemuxml2argvdata/qemuxml2argv-clock-utc.args
index 08b55b8846..69b1e7a421 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-clock-utc.args
+++ b/tests/qemuxml2argvdata/qemuxml2argv-clock-utc.args
@@ -1 +1 @@
-/usr/bin/qemu -M pc -m 214 -smp 1 -nographic -monitor pty -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -usb
\ No newline at end of file
+/usr/bin/qemu -M pc -m 214 -smp 1 -nographic -monitor pty -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -serial none -parallel none -usb
\ No newline at end of file
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-console-compat.args b/tests/qemuxml2argvdata/qemuxml2argv-console-compat.args
new file mode 100644
index 0000000000..541b7194ef
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-console-compat.args
@@ -0,0 +1 @@
+/usr/bin/qemu -M pc -m 214 -smp 1 -nographic -monitor pty -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -serial pty -parallel none -usb
\ No newline at end of file
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-console-compat.xml b/tests/qemuxml2argvdata/qemuxml2argv-console-compat.xml
new file mode 100644
index 0000000000..7752c02357
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-console-compat.xml
@@ -0,0 +1,28 @@
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory>219200</memory>
+  <currentMemory>219200</currentMemory>
+  <vcpu>1</vcpu>
+  <os>
+    <type arch='i686' machine='pc'>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+    <emulator>/usr/bin/qemu</emulator>
+    <disk type='block' device='disk'>
+      <source dev='/dev/HostVG/QEMUGuest1'/>
+      <target dev='hda'/>
+    </disk>
+    <serial type='pty'>
+      <target port='0'/>
+    </serial>
+    <console type='pty'>
+      <target port='0'/>
+    </console>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-disk-cdrom.args b/tests/qemuxml2argvdata/qemuxml2argv-disk-cdrom.args
index 86964c1a07..8f0cdf8dad 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-disk-cdrom.args
+++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-cdrom.args
@@ -1 +1 @@
-/usr/bin/qemu -M pc -m 214 -smp 1 -nographic -monitor pty -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -cdrom /root/boot.iso -net none -usb
\ No newline at end of file
+/usr/bin/qemu -M pc -m 214 -smp 1 -nographic -monitor pty -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -cdrom /root/boot.iso -net none -serial none -parallel none -usb
\ No newline at end of file
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-disk-floppy.args b/tests/qemuxml2argvdata/qemuxml2argv-disk-floppy.args
index 87c579c294..10b72d7d99 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-disk-floppy.args
+++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-floppy.args
@@ -1 +1 @@
-/usr/bin/qemu -M pc -m 214 -smp 1 -nographic -monitor pty -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -fda /dev/fd0 -fdb /tmp/firmware.img -net none -usb
\ No newline at end of file
+/usr/bin/qemu -M pc -m 214 -smp 1 -nographic -monitor pty -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -fda /dev/fd0 -fdb /tmp/firmware.img -net none -serial none -parallel none -usb
\ No newline at end of file
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-disk-many.args b/tests/qemuxml2argvdata/qemuxml2argv-disk-many.args
index 0534d6195e..899b35b226 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-disk-many.args
+++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-many.args
@@ -1 +1 @@
-/usr/bin/qemu -M pc -m 214 -smp 1 -nographic -monitor pty -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -hdb /dev/HostVG/QEMUGuest2 -hdc /tmp/data.img -hdd /tmp/logs.img -net none -usb
\ No newline at end of file
+/usr/bin/qemu -M pc -m 214 -smp 1 -nographic -monitor pty -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -hdb /dev/HostVG/QEMUGuest2 -hdc /tmp/data.img -hdd /tmp/logs.img -net none -serial none -parallel none -usb
\ No newline at end of file
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-graphics-sdl.args b/tests/qemuxml2argvdata/qemuxml2argv-graphics-sdl.args
index 6163ba6dc2..b2faaabffd 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-graphics-sdl.args
+++ b/tests/qemuxml2argvdata/qemuxml2argv-graphics-sdl.args
@@ -1 +1 @@
-/usr/bin/qemu -M pc -m 214 -smp 1 -monitor pty -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -usb
\ No newline at end of file
+/usr/bin/qemu -M pc -m 214 -smp 1 -monitor pty -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -serial none -parallel none -usb
\ No newline at end of file
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-graphics-vnc.args b/tests/qemuxml2argvdata/qemuxml2argv-graphics-vnc.args
index 42a33a47bb..f8a98cd1cd 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-graphics-vnc.args
+++ b/tests/qemuxml2argvdata/qemuxml2argv-graphics-vnc.args
@@ -1 +1 @@
-/usr/bin/qemu -M pc -m 214 -smp 1 -monitor pty -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -usb -vnc 127.0.0.1:3
\ No newline at end of file
+/usr/bin/qemu -M pc -m 214 -smp 1 -monitor pty -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -serial none -parallel none -usb -vnc 127.0.0.1:3
\ No newline at end of file
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-input-usbmouse.args b/tests/qemuxml2argvdata/qemuxml2argv-input-usbmouse.args
index 0e27138ce1..8552d308cb 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-input-usbmouse.args
+++ b/tests/qemuxml2argvdata/qemuxml2argv-input-usbmouse.args
@@ -1 +1 @@
-/usr/bin/qemu -M pc -m 214 -smp 1 -nographic -monitor pty -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -usb -usbdevice mouse
\ No newline at end of file
+/usr/bin/qemu -M pc -m 214 -smp 1 -nographic -monitor pty -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -serial none -parallel none -usb -usbdevice mouse
\ No newline at end of file
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-input-usbtablet.args b/tests/qemuxml2argvdata/qemuxml2argv-input-usbtablet.args
index 2c9652b20d..790bc1b324 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-input-usbtablet.args
+++ b/tests/qemuxml2argvdata/qemuxml2argv-input-usbtablet.args
@@ -1 +1 @@
-/usr/bin/qemu -M pc -m 214 -smp 1 -nographic -monitor pty -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -usb -usbdevice tablet
\ No newline at end of file
+/usr/bin/qemu -M pc -m 214 -smp 1 -nographic -monitor pty -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -serial none -parallel none -usb -usbdevice tablet
\ No newline at end of file
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-minimal.args b/tests/qemuxml2argvdata/qemuxml2argv-minimal.args
index 08b55b8846..69b1e7a421 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-minimal.args
+++ b/tests/qemuxml2argvdata/qemuxml2argv-minimal.args
@@ -1 +1 @@
-/usr/bin/qemu -M pc -m 214 -smp 1 -nographic -monitor pty -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -usb
\ No newline at end of file
+/usr/bin/qemu -M pc -m 214 -smp 1 -nographic -monitor pty -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -serial none -parallel none -usb
\ No newline at end of file
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-misc-acpi.args b/tests/qemuxml2argvdata/qemuxml2argv-misc-acpi.args
index b4e8f6804c..ba87bfbafb 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-misc-acpi.args
+++ b/tests/qemuxml2argvdata/qemuxml2argv-misc-acpi.args
@@ -1 +1 @@
-/usr/bin/qemu -M pc -m 214 -smp 1 -nographic -monitor pty -boot c -hda /dev/HostVG/QEMUGuest1 -net none -usb
\ No newline at end of file
+/usr/bin/qemu -M pc -m 214 -smp 1 -nographic -monitor pty -boot c -hda /dev/HostVG/QEMUGuest1 -net none -serial none -parallel none -usb
\ No newline at end of file
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-misc-no-reboot.args b/tests/qemuxml2argvdata/qemuxml2argv-misc-no-reboot.args
index 0135d5e6c4..7461c957c7 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-misc-no-reboot.args
+++ b/tests/qemuxml2argvdata/qemuxml2argv-misc-no-reboot.args
@@ -1 +1 @@
-/usr/bin/qemu -M pc -m 214 -smp 1 -nographic -monitor pty -no-reboot -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -usb
\ No newline at end of file
+/usr/bin/qemu -M pc -m 214 -smp 1 -nographic -monitor pty -no-reboot -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -serial none -parallel none -usb
\ No newline at end of file
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-net-user.args b/tests/qemuxml2argvdata/qemuxml2argv-net-user.args
index 5c218610ed..fce8a215d5 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-net-user.args
+++ b/tests/qemuxml2argvdata/qemuxml2argv-net-user.args
@@ -1 +1 @@
-/usr/bin/qemu -M pc -m 214 -smp 1 -nographic -monitor pty -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net nic,macaddr=00:11:22:33:44:55,vlan=0 -net user,vlan=0 -usb
\ No newline at end of file
+/usr/bin/qemu -M pc -m 214 -smp 1 -nographic -monitor pty -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net nic,macaddr=00:11:22:33:44:55,vlan=0 -net user,vlan=0 -serial none -parallel none -usb
\ No newline at end of file
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-parallel-tcp.args b/tests/qemuxml2argvdata/qemuxml2argv-parallel-tcp.args
new file mode 100644
index 0000000000..31c482ee0a
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-parallel-tcp.args
@@ -0,0 +1 @@
+/usr/bin/qemu -M pc -m 214 -smp 1 -nographic -monitor pty -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -serial none -parallel tcp:127.0.0.1:9999,listen -usb
\ No newline at end of file
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-parallel-tcp.xml b/tests/qemuxml2argvdata/qemuxml2argv-parallel-tcp.xml
new file mode 100644
index 0000000000..e0fd51383e
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-parallel-tcp.xml
@@ -0,0 +1,27 @@
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory>219200</memory>
+  <currentMemory>219200</currentMemory>
+  <vcpu>1</vcpu>
+  <os>
+    <type arch='i686' machine='pc'>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+    <emulator>/usr/bin/qemu</emulator>
+    <disk type='block' device='disk'>
+      <source dev='/dev/HostVG/QEMUGuest1'/>
+      <target dev='hda'/>
+    </disk>
+    <parallel type='tcp'>
+      <source mode='bind' host='127.0.0.1' service='9999'/>
+      <protocol type='raw'/>
+      <target port='0'/>
+    </parallel>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-dev.args b/tests/qemuxml2argvdata/qemuxml2argv-serial-dev.args
new file mode 100644
index 0000000000..9c6262b057
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-dev.args
@@ -0,0 +1 @@
+/usr/bin/qemu -M pc -m 214 -smp 1 -nographic -monitor pty -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -serial /dev/ttyS2 -parallel none -usb
\ No newline at end of file
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-dev.xml b/tests/qemuxml2argvdata/qemuxml2argv-serial-dev.xml
new file mode 100644
index 0000000000..fa371cc0ee
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-dev.xml
@@ -0,0 +1,30 @@
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory>219200</memory>
+  <currentMemory>219200</currentMemory>
+  <vcpu>1</vcpu>
+  <os>
+    <type arch='i686' machine='pc'>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+    <emulator>/usr/bin/qemu</emulator>
+    <disk type='block' device='disk'>
+      <source dev='/dev/HostVG/QEMUGuest1'/>
+      <target dev='hda'/>
+    </disk>
+    <serial type='dev'>
+      <source path='/dev/ttyS2'/>
+      <target port='0'/>
+    </serial>
+    <console type='dev'>
+      <source path='/dev/ttyS2'/>
+      <target port='0'/>
+    </console>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-file.args b/tests/qemuxml2argvdata/qemuxml2argv-serial-file.args
new file mode 100644
index 0000000000..a373db29c1
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-file.args
@@ -0,0 +1 @@
+/usr/bin/qemu -M pc -m 214 -smp 1 -nographic -monitor pty -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -serial file:/tmp/serial.log -parallel none -usb
\ No newline at end of file
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-file.xml b/tests/qemuxml2argvdata/qemuxml2argv-serial-file.xml
new file mode 100644
index 0000000000..4a1bdc5df4
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-file.xml
@@ -0,0 +1,30 @@
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory>219200</memory>
+  <currentMemory>219200</currentMemory>
+  <vcpu>1</vcpu>
+  <os>
+    <type arch='i686' machine='pc'>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+    <emulator>/usr/bin/qemu</emulator>
+    <disk type='block' device='disk'>
+      <source dev='/dev/HostVG/QEMUGuest1'/>
+      <target dev='hda'/>
+    </disk>
+    <serial type='file'>
+      <source path='/tmp/serial.log'/>
+      <target port='0'/>
+    </serial>
+    <console type='file'>
+      <source path='/tmp/serial.log'/>
+      <target port='0'/>
+    </console>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-many.args b/tests/qemuxml2argvdata/qemuxml2argv-serial-many.args
new file mode 100644
index 0000000000..d3e26867fd
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-many.args
@@ -0,0 +1 @@
+/usr/bin/qemu -M pc -m 214 -smp 1 -nographic -monitor pty -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -serial pty -serial file:/tmp/serial.log -parallel none -usb
\ No newline at end of file
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-many.xml b/tests/qemuxml2argvdata/qemuxml2argv-serial-many.xml
new file mode 100644
index 0000000000..3b9f124d2f
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-many.xml
@@ -0,0 +1,32 @@
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory>219200</memory>
+  <currentMemory>219200</currentMemory>
+  <vcpu>1</vcpu>
+  <os>
+    <type arch='i686' machine='pc'>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+    <emulator>/usr/bin/qemu</emulator>
+    <disk type='block' device='disk'>
+      <source dev='/dev/HostVG/QEMUGuest1'/>
+      <target dev='hda'/>
+    </disk>
+    <serial type='pty'>
+      <target port='0'/>
+    </serial>
+    <serial type='file'>
+      <source path='/tmp/serial.log'/>
+      <target port='1'/>
+    </serial>
+    <console type='pty'>
+      <target port='0'/>
+    </console>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-pty.args b/tests/qemuxml2argvdata/qemuxml2argv-serial-pty.args
new file mode 100644
index 0000000000..541b7194ef
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-pty.args
@@ -0,0 +1 @@
+/usr/bin/qemu -M pc -m 214 -smp 1 -nographic -monitor pty -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -serial pty -parallel none -usb
\ No newline at end of file
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-pty.xml b/tests/qemuxml2argvdata/qemuxml2argv-serial-pty.xml
new file mode 100644
index 0000000000..7752c02357
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-pty.xml
@@ -0,0 +1,28 @@
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory>219200</memory>
+  <currentMemory>219200</currentMemory>
+  <vcpu>1</vcpu>
+  <os>
+    <type arch='i686' machine='pc'>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+    <emulator>/usr/bin/qemu</emulator>
+    <disk type='block' device='disk'>
+      <source dev='/dev/HostVG/QEMUGuest1'/>
+      <target dev='hda'/>
+    </disk>
+    <serial type='pty'>
+      <target port='0'/>
+    </serial>
+    <console type='pty'>
+      <target port='0'/>
+    </console>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-telnet.args b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-telnet.args
new file mode 100644
index 0000000000..9613919971
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-telnet.args
@@ -0,0 +1 @@
+/usr/bin/qemu -M pc -m 214 -smp 1 -nographic -monitor pty -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -serial telnet:127.0.0.1:9999,listen -parallel none -usb
\ No newline at end of file
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-telnet.xml b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-telnet.xml
new file mode 100644
index 0000000000..77ac6a3f65
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-telnet.xml
@@ -0,0 +1,32 @@
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory>219200</memory>
+  <currentMemory>219200</currentMemory>
+  <vcpu>1</vcpu>
+  <os>
+    <type arch='i686' machine='pc'>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+    <emulator>/usr/bin/qemu</emulator>
+    <disk type='block' device='disk'>
+      <source dev='/dev/HostVG/QEMUGuest1'/>
+      <target dev='hda'/>
+    </disk>
+    <serial type='tcp'>
+      <source mode='bind' host='127.0.0.1' service='9999'/>
+      <protocol type='telnet'/>
+      <target port='0'/>
+    </serial>
+    <console type='tcp'>
+      <source mode='bind' host='127.0.0.1' service='9999'/>
+      <protocol type='telnet'/>
+      <target port='0'/>
+    </console>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp.args b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp.args
new file mode 100644
index 0000000000..c82ef995ed
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp.args
@@ -0,0 +1 @@
+/usr/bin/qemu -M pc -m 214 -smp 1 -nographic -monitor pty -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -serial tcp:127.0.0.1:9999 -parallel none -usb
\ No newline at end of file
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp.xml b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp.xml
new file mode 100644
index 0000000000..fe80d2d481
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp.xml
@@ -0,0 +1,32 @@
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory>219200</memory>
+  <currentMemory>219200</currentMemory>
+  <vcpu>1</vcpu>
+  <os>
+    <type arch='i686' machine='pc'>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+    <emulator>/usr/bin/qemu</emulator>
+    <disk type='block' device='disk'>
+      <source dev='/dev/HostVG/QEMUGuest1'/>
+      <target dev='hda'/>
+    </disk>
+    <serial type='tcp'>
+      <source mode='connect' host='127.0.0.1' service='9999'/>
+      <protocol type='raw'/>
+      <target port='0'/>
+    </serial>
+    <console type='tcp'>
+      <source mode='connect' host='127.0.0.1' service='9999'/>
+      <protocol type='raw'/>
+      <target port='0'/>
+    </console>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-udp.args b/tests/qemuxml2argvdata/qemuxml2argv-serial-udp.args
new file mode 100644
index 0000000000..e376ffc9e4
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-udp.args
@@ -0,0 +1 @@
+/usr/bin/qemu -M pc -m 214 -smp 1 -nographic -monitor pty -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -serial udp:127.0.0.1:9998@127.0.0.1:9999 -parallel none -usb
\ No newline at end of file
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-udp.xml b/tests/qemuxml2argvdata/qemuxml2argv-serial-udp.xml
new file mode 100644
index 0000000000..bdab917bbd
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-udp.xml
@@ -0,0 +1,32 @@
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory>219200</memory>
+  <currentMemory>219200</currentMemory>
+  <vcpu>1</vcpu>
+  <os>
+    <type arch='i686' machine='pc'>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+    <emulator>/usr/bin/qemu</emulator>
+    <disk type='block' device='disk'>
+      <source dev='/dev/HostVG/QEMUGuest1'/>
+      <target dev='hda'/>
+    </disk>
+    <serial type='udp'>
+      <source mode='bind' host='127.0.0.1' service='9999'/>
+      <source mode='connect' host='127.0.0.1' service='9998'/>
+      <target port='0'/>
+    </serial>
+    <console type='udp'>
+      <source mode='bind' host='127.0.0.1' service='9999'/>
+      <source mode='connect' host='127.0.0.1' service='9998'/>
+      <target port='0'/>
+    </console>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-unix.args b/tests/qemuxml2argvdata/qemuxml2argv-serial-unix.args
new file mode 100644
index 0000000000..1ce9aee7c1
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-unix.args
@@ -0,0 +1 @@
+/usr/bin/qemu -M pc -m 214 -smp 1 -nographic -monitor pty -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -serial unix:/tmp/serial.sock -parallel none -usb
\ No newline at end of file
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-unix.xml b/tests/qemuxml2argvdata/qemuxml2argv-serial-unix.xml
new file mode 100644
index 0000000000..cc9626998b
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-unix.xml
@@ -0,0 +1,30 @@
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory>219200</memory>
+  <currentMemory>219200</currentMemory>
+  <vcpu>1</vcpu>
+  <os>
+    <type arch='i686' machine='pc'>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+    <emulator>/usr/bin/qemu</emulator>
+    <disk type='block' device='disk'>
+      <source dev='/dev/HostVG/QEMUGuest1'/>
+      <target dev='hda'/>
+    </disk>
+    <serial type='unix'>
+      <source mode='connect' path='/tmp/serial.sock'/>
+      <target port='0'/>
+    </serial>
+    <console type='unix'>
+      <source mode='connect' path='/tmp/serial.sock'/>
+      <target port='0'/>
+    </console>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-vc.args b/tests/qemuxml2argvdata/qemuxml2argv-serial-vc.args
new file mode 100644
index 0000000000..93f331f015
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-vc.args
@@ -0,0 +1 @@
+/usr/bin/qemu -M pc -m 214 -smp 1 -nographic -monitor pty -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -serial vc -parallel none -usb
\ No newline at end of file
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-vc.xml b/tests/qemuxml2argvdata/qemuxml2argv-serial-vc.xml
new file mode 100644
index 0000000000..b5d6d178d8
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-vc.xml
@@ -0,0 +1,28 @@
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory>219200</memory>
+  <currentMemory>219200</currentMemory>
+  <vcpu>1</vcpu>
+  <os>
+    <type arch='i686' machine='pc'>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+    <emulator>/usr/bin/qemu</emulator>
+    <disk type='block' device='disk'>
+      <source dev='/dev/HostVG/QEMUGuest1'/>
+      <target dev='hda'/>
+    </disk>
+    <serial type='vc'>
+      <target port='0'/>
+    </serial>
+    <console type='vc'>
+      <target port='0'/>
+    </console>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index 59ea21dab4..093ff87407 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -15,7 +15,7 @@
 #include "qemu_conf.h"
 
 static char *progname;
-static char *abs_top_srcdir;
+static char *abs_srcdir;
 static struct qemud_driver driver;
 
 #define MAX_FILE 4096
@@ -71,11 +71,8 @@ static int testCompareXMLToArgvFiles(const char *xml, const char *cmd) {
         tmp++;
     }
 
-    if (strcmp(expectargv, actualargv)) {
-        if (getenv("DEBUG_TESTS")) {
-            printf("Expect %4d '%s'\n", (int)strlen(expectargv), expectargv);
-            printf("Actual %4d '%s'\n", (int)strlen(actualargv), actualargv);
-        }
+    if (STRNEQ(expectargv, actualargv)) {
+        virtTestDifference(stderr, expectargv, actualargv);
         goto fail;
     }
 
@@ -100,10 +97,10 @@ static int testCompareXMLToArgvFiles(const char *xml, const char *cmd) {
 static int testCompareXMLToArgvHelper(const void *data) {
     char xml[PATH_MAX];
     char args[PATH_MAX];
-    snprintf(xml, PATH_MAX, "%s/tests/qemuxml2argvdata/qemuxml2argv-%s.xml",
-             abs_top_srcdir, (const char*)data);
-    snprintf(args, PATH_MAX, "%s/tests/qemuxml2argvdata/qemuxml2argv-%s.args",
-             abs_top_srcdir, (const char*)data);
+    snprintf(xml, PATH_MAX, "%s/qemuxml2argvdata/qemuxml2argv-%s.xml",
+             abs_srcdir, (const char*)data);
+    snprintf(args, PATH_MAX, "%s/qemuxml2argvdata/qemuxml2argv-%s.args",
+             abs_srcdir, (const char*)data);
     return testCompareXMLToArgvFiles(xml, args);
 }
 
@@ -113,6 +110,7 @@ int
 main(int argc, char **argv)
 {
     int ret = 0;
+    char cwd[PATH_MAX];
 
     progname = argv[0];
 
@@ -121,76 +119,45 @@ main(int argc, char **argv)
         exit(EXIT_FAILURE);
     }
 
-    abs_top_srcdir = getenv("abs_top_srcdir");
-    if (!abs_top_srcdir)
-      return 1;
+    abs_srcdir = getenv("abs_srcdir");
+    if (!abs_srcdir)
+        abs_srcdir = getcwd(cwd, sizeof(cwd));
 
     driver.caps = qemudCapsInit();
 
-    if (virtTestRun("QEMU XML-2-ARGV minimal",
-                    1, testCompareXMLToArgvHelper, "minimal") < 0)
-        ret = -1;
+#define DO_TEST(name) \
+    if (virtTestRun("QEMU XML-2-ARGV " name, \
+                    1, testCompareXMLToArgvHelper, (name)) < 0) \
+        ret = -1
 
-    if (virtTestRun("QEMU XML-2-ARGV Boot CDROM",
-                    1, testCompareXMLToArgvHelper, "boot-cdrom") < 0)
-        ret = -1;
-
-    if (virtTestRun("QEMU XML-2-ARGV Boot Network",
-                    1, testCompareXMLToArgvHelper, "boot-network") < 0)
-        ret = -1;
-
-    if (virtTestRun("QEMU XML-2-ARGV Boot Floppy",
-                    1, testCompareXMLToArgvHelper, "boot-floppy") < 0)
-        ret = -1;
-
-    if (virtTestRun("QEMU XML-2-ARGV Clock UTC",
-                    1, testCompareXMLToArgvHelper, "clock-utc") < 0)
-        ret = -1;
-
-    if (virtTestRun("QEMU XML-2-ARGV Clock Localtime",
-                    1, testCompareXMLToArgvHelper, "clock-localtime") < 0)
-        ret = -1;
-
-    if (virtTestRun("QEMU XML-2-ARGV Disk CDROM",
-                    1, testCompareXMLToArgvHelper, "disk-cdrom") < 0)
-        ret = -1;
-
-    if (virtTestRun("QEMU XML-2-ARGV Disk Floppy",
-                    1, testCompareXMLToArgvHelper, "disk-floppy") < 0)
-        ret = -1;
-
-    if (virtTestRun("QEMU XML-2-ARGV Disk Many",
-                    1, testCompareXMLToArgvHelper, "disk-many") < 0)
-        ret = -1;
-
-    if (virtTestRun("QEMU XML-2-ARGV Graphics VNC",
-                    1, testCompareXMLToArgvHelper, "graphics-vnc") < 0)
-        ret = -1;
-
-    if (virtTestRun("QEMU XML-2-ARGV Graphics SDL",
-                    1, testCompareXMLToArgvHelper, "graphics-sdl") < 0)
-        ret = -1;
-
-    if (virtTestRun("QEMU XML-2-ARGV Input USB Mouse",
-                    1, testCompareXMLToArgvHelper, "input-usbmouse") < 0)
-        ret = -1;
-
-    if (virtTestRun("QEMU XML-2-ARGV Input USB Tablet",
-                    1, testCompareXMLToArgvHelper, "input-usbtablet") < 0)
-        ret = -1;
-
-    if (virtTestRun("QEMU XML-2-ARGV Misc ACPI",
-                    1, testCompareXMLToArgvHelper, "misc-acpi") < 0)
-        ret = -1;
-
-    if (virtTestRun("QEMU XML-2-ARGV Misc No Reboot",
-                    1, testCompareXMLToArgvHelper, "misc-no-reboot") < 0)
-        ret = -1;
-
-    if (virtTestRun("QEMU XML-2-ARGV Net User",
-                    1, testCompareXMLToArgvHelper, "net-user") < 0)
-        ret = -1;
+    DO_TEST("minimal");
+    DO_TEST("boot-cdrom");
+    DO_TEST("boot-network");
+    DO_TEST("boot-floppy");
+    DO_TEST("clock-utc");
+    DO_TEST("clock-localtime");
+    DO_TEST("disk-cdrom");
+    DO_TEST("disk-floppy");
+    DO_TEST("disk-many");
+    DO_TEST("graphics-vnc");
+    DO_TEST("graphics-sdl");
+    DO_TEST("input-usbmouse");
+    DO_TEST("input-usbtablet");
+    DO_TEST("misc-acpi");
+    DO_TEST("misc-no-reboot");
+    DO_TEST("net-user");
 
+    DO_TEST("serial-vc");
+    DO_TEST("serial-pty");
+    DO_TEST("serial-dev");
+    DO_TEST("serial-file");
+    DO_TEST("serial-unix");
+    DO_TEST("serial-tcp");
+    DO_TEST("serial-udp");
+    DO_TEST("serial-tcp-telnet");
+    DO_TEST("serial-many");
+    DO_TEST("parallel-tcp");
+    DO_TEST("console-compat");
 
     virCapabilitiesFree(driver.caps);
 
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
index 69cf77b825..156d5093c6 100644
--- a/tests/qemuxml2xmltest.c
+++ b/tests/qemuxml2xmltest.c
@@ -15,7 +15,7 @@
 #include "qemu_conf.h"
 
 static char *progname;
-static char *abs_top_srcdir;
+static char *abs_srcdir;
 static struct qemud_driver driver;
 
 #define MAX_FILE 4096
@@ -47,11 +47,8 @@ static int testCompareXMLToXMLFiles(const char *xml) {
     if (!(actual = qemudGenerateXML(NULL, &driver, &vm, vmdef, 0)))
         goto fail;
 
-    if (strcmp(xmlData, actual)) {
-        if (getenv("DEBUG_TESTS")) {
-            printf("Expect %4d '%s'\n", (int)strlen(xmlData), xmlData);
-            printf("Actual %4d '%s'\n", (int)strlen(actual), actual);
-        }
+    if (STRNEQ(xmlData, actual)) {
+        virtTestDifference(stderr, xmlData, actual);
         goto fail;
     }
 
@@ -66,8 +63,8 @@ static int testCompareXMLToXMLFiles(const char *xml) {
 
 static int testCompareXMLToXMLHelper(const void *data) {
     char xml[PATH_MAX];
-    snprintf(xml, PATH_MAX, "%s/tests/qemuxml2argvdata/qemuxml2argv-%s.xml",
-             abs_top_srcdir, (const char*)data);
+    snprintf(xml, PATH_MAX, "%s/qemuxml2argvdata/qemuxml2argv-%s.xml",
+             abs_srcdir, (const char*)data);
     return testCompareXMLToXMLFiles(xml);
 }
 
@@ -76,6 +73,7 @@ int
 main(int argc, char **argv)
 {
     int ret = 0;
+    char cwd[PATH_MAX];
 
     progname = argv[0];
 
@@ -84,76 +82,45 @@ main(int argc, char **argv)
         exit(EXIT_FAILURE);
     }
 
-    abs_top_srcdir = getenv("abs_top_srcdir");
-    if (!abs_top_srcdir)
-      return 1;
-
+    abs_srcdir = getenv("abs_srcdir");
+    if (!abs_srcdir)
+        abs_srcdir = getcwd(cwd, sizeof(cwd));
 
     driver.caps = qemudCapsInit();
 
-    if (virtTestRun("QEMU XML-2-ARGV minimal",
-                    1, testCompareXMLToXMLHelper, "minimal") < 0)
-        ret = -1;
+#define DO_TEST(name) \
+    if (virtTestRun("QEMU XML-2-XML " name, \
+                    1, testCompareXMLToXMLHelper, (name)) < 0) \
+        ret = -1
 
-    if (virtTestRun("QEMU XML-2-ARGV Boot CDROM",
-                    1, testCompareXMLToXMLHelper, "boot-cdrom") < 0)
-        ret = -1;
+    DO_TEST("minimal");
+    DO_TEST("boot-cdrom");
+    DO_TEST("boot-network");
+    DO_TEST("boot-floppy");
+    DO_TEST("clock-utc");
+    DO_TEST("clock-localtime");
+    DO_TEST("disk-cdrom");
+    DO_TEST("disk-floppy");
+    DO_TEST("disk-many");
+    DO_TEST("graphics-vnc");
+    DO_TEST("graphics-sdl");
+    DO_TEST("input-usbmouse");
+    DO_TEST("input-usbtablet");
+    DO_TEST("misc-acpi");
+    DO_TEST("misc-no-reboot");
+    DO_TEST("net-user");
 
-    if (virtTestRun("QEMU XML-2-ARGV Boot Network",
-                    1, testCompareXMLToXMLHelper, "boot-network") < 0)
-        ret = -1;
-
-    if (virtTestRun("QEMU XML-2-ARGV Boot Floppy",
-                    1, testCompareXMLToXMLHelper, "boot-floppy") < 0)
-        ret = -1;
-
-    if (virtTestRun("QEMU XML-2-ARGV Clock UTC",
-                    1, testCompareXMLToXMLHelper, "clock-utc") < 0)
-        ret = -1;
-
-    if (virtTestRun("QEMU XML-2-ARGV Clock Localtime",
-                    1, testCompareXMLToXMLHelper, "clock-localtime") < 0)
-        ret = -1;
-
-    if (virtTestRun("QEMU XML-2-ARGV Disk CDROM",
-                    1, testCompareXMLToXMLHelper, "disk-cdrom") < 0)
-        ret = -1;
-
-    if (virtTestRun("QEMU XML-2-ARGV Disk Floppy",
-                    1, testCompareXMLToXMLHelper, "disk-floppy") < 0)
-        ret = -1;
-
-    if (virtTestRun("QEMU XML-2-ARGV Disk Many",
-                    1, testCompareXMLToXMLHelper, "disk-many") < 0)
-        ret = -1;
-
-    if (virtTestRun("QEMU XML-2-ARGV Graphics VNC",
-                    1, testCompareXMLToXMLHelper, "graphics-vnc") < 0)
-        ret = -1;
-
-    if (virtTestRun("QEMU XML-2-ARGV Graphics SDL",
-                    1, testCompareXMLToXMLHelper, "graphics-sdl") < 0)
-        ret = -1;
-
-    if (virtTestRun("QEMU XML-2-ARGV Input USB Mouse",
-                    1, testCompareXMLToXMLHelper, "input-usbmouse") < 0)
-        ret = -1;
-
-    if (virtTestRun("QEMU XML-2-ARGV Input USB Tablet",
-                    1, testCompareXMLToXMLHelper, "input-usbtablet") < 0)
-        ret = -1;
-
-    if (virtTestRun("QEMU XML-2-ARGV Misc ACPI",
-                    1, testCompareXMLToXMLHelper, "misc-acpi") < 0)
-        ret = -1;
-
-    if (virtTestRun("QEMU XML-2-ARGV Misc No Reboot",
-                    1, testCompareXMLToXMLHelper, "misc-no-reboot") < 0)
-        ret = -1;
-
-    if (virtTestRun("QEMU XML-2-ARGV Net User",
-                    1, testCompareXMLToXMLHelper, "net-user") < 0)
-        ret = -1;
+    DO_TEST("serial-vc");
+    DO_TEST("serial-pty");
+    DO_TEST("serial-dev");
+    DO_TEST("serial-file");
+    DO_TEST("serial-unix");
+    DO_TEST("serial-tcp");
+    DO_TEST("serial-udp");
+    DO_TEST("serial-tcp-telnet");
+    DO_TEST("serial-many");
+    DO_TEST("parallel-tcp");
+    DO_TEST("console-compat");
 
     virCapabilitiesFree(driver.caps);