From e6f112381924d98d4846e4e1e79a3b1550653f3b Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Sat, 26 Apr 2008 14:22:02 +0000 Subject: [PATCH] Added full support for serial and parallel devices to Xen drivers --- ChangeLog | 10 + src/internal.h | 2 +- src/xend_internal.c | 267 ++++++++++++- src/xend_internal.h | 9 +- src/xm_internal.c | 55 ++- src/xml.c | 217 ++++++++++- src/xml.h | 4 + tests/sexpr2xmldata/sexpr2xml-curmem.xml | 3 + .../sexpr2xml-disk-block-shareable.xml | 3 + tests/sexpr2xmldata/sexpr2xml-disk-block.xml | 3 + .../sexpr2xml-disk-drv-blktap-qcow.xml | 3 + .../sexpr2xml-disk-drv-blktap-raw.xml | 3 + tests/sexpr2xmldata/sexpr2xml-disk-file.xml | 3 + tests/sexpr2xmldata/sexpr2xml-fv-kernel.xml | 6 + .../sexpr2xml-fv-parallel-tcp.sexpr | 1 + .../sexpr2xml-fv-parallel-tcp.xml | 45 +++ .../sexpr2xml-fv-serial-file.sexpr | 1 + .../sexpr2xml-fv-serial-file.xml | 48 +++ .../sexpr2xml-fv-serial-null.sexpr | 1 + .../sexpr2xml-fv-serial-null.xml | 46 +++ .../sexpr2xml-fv-serial-pipe.sexpr | 1 + .../sexpr2xml-fv-serial-pipe.xml | 48 +++ .../sexpr2xml-fv-serial-pty.sexpr | 1 + .../sexpr2xmldata/sexpr2xml-fv-serial-pty.xml | 46 +++ .../sexpr2xml-fv-serial-stdio.sexpr | 1 + .../sexpr2xml-fv-serial-stdio.xml | 46 +++ .../sexpr2xml-fv-serial-tcp-telnet.sexpr | 1 + .../sexpr2xml-fv-serial-tcp-telnet.xml | 50 +++ .../sexpr2xml-fv-serial-tcp.sexpr | 1 + .../sexpr2xmldata/sexpr2xml-fv-serial-tcp.xml | 50 +++ .../sexpr2xml-fv-serial-udp.sexpr | 1 + .../sexpr2xmldata/sexpr2xml-fv-serial-udp.xml | 50 +++ .../sexpr2xml-fv-serial-unix.sexpr | 1 + .../sexpr2xml-fv-serial-unix.xml | 48 +++ tests/sexpr2xmldata/sexpr2xml-net-bridged.xml | 3 + tests/sexpr2xmldata/sexpr2xml-net-routed.xml | 3 + .../sexpr2xml-no-source-cdrom.xml | 6 + .../sexpr2xmldata/sexpr2xml-pv-bootloader.xml | 3 + tests/sexpr2xmldata/sexpr2xml-pv-vfb-new.xml | 3 + tests/sexpr2xmldata/sexpr2xml-pv-vfb-orig.xml | 3 + tests/sexpr2xmldata/sexpr2xml-pv.xml | 3 + tests/sexpr2xmltest.c | 307 ++++----------- .../xmconfigdata/test-fullvirt-localtime.cfg | 2 + .../xmconfigdata/test-fullvirt-new-cdrom.cfg | 2 + .../xmconfigdata/test-fullvirt-old-cdrom.cfg | 2 + .../test-fullvirt-parallel-tcp.cfg | 25 ++ .../test-fullvirt-parallel-tcp.xml | 46 +++ .../test-fullvirt-serial-file.cfg | 25 ++ .../test-fullvirt-serial-file.xml | 49 +++ .../test-fullvirt-serial-null.cfg | 25 ++ .../test-fullvirt-serial-null.xml | 47 +++ .../test-fullvirt-serial-pipe.cfg | 25 ++ .../test-fullvirt-serial-pipe.xml | 49 +++ .../xmconfigdata/test-fullvirt-serial-pty.cfg | 25 ++ .../xmconfigdata/test-fullvirt-serial-pty.xml | 47 +++ .../test-fullvirt-serial-stdio.cfg | 25 ++ .../test-fullvirt-serial-stdio.xml | 47 +++ .../test-fullvirt-serial-tcp-telnet.cfg | 25 ++ .../test-fullvirt-serial-tcp-telnet.xml | 51 +++ .../xmconfigdata/test-fullvirt-serial-tcp.cfg | 25 ++ .../xmconfigdata/test-fullvirt-serial-tcp.xml | 51 +++ .../xmconfigdata/test-fullvirt-serial-udp.cfg | 25 ++ .../xmconfigdata/test-fullvirt-serial-udp.xml | 51 +++ .../test-fullvirt-serial-unix.cfg | 25 ++ .../test-fullvirt-serial-unix.xml | 49 +++ tests/xmconfigdata/test-fullvirt-usbmouse.cfg | 2 + .../xmconfigdata/test-fullvirt-usbtablet.cfg | 2 + tests/xmconfigdata/test-fullvirt-utc.cfg | 2 + tests/xmconfigdata/test-paravirt-new-pvfb.xml | 4 +- tests/xmconfigdata/test-paravirt-old-pvfb.xml | 4 +- tests/xmconfigtest.c | 18 +- tests/xml2sexprdata/xml2sexpr-fv-kernel.sexpr | 2 +- .../xml2sexpr-fv-localtime.sexpr | 2 +- .../xml2sexpr-fv-parallel-tcp.sexpr | 1 + .../xml2sexpr-fv-parallel-tcp.xml | 40 ++ .../xml2sexpr-fv-serial-file.sexpr | 1 + .../xml2sexpr-fv-serial-file.xml | 40 ++ .../xml2sexpr-fv-serial-null.sexpr | 1 + .../xml2sexpr-fv-serial-null.xml | 39 ++ .../xml2sexpr-fv-serial-pipe.sexpr | 1 + .../xml2sexpr-fv-serial-pipe.xml | 40 ++ .../xml2sexpr-fv-serial-pty.sexpr | 1 + .../xml2sexprdata/xml2sexpr-fv-serial-pty.xml | 39 ++ .../xml2sexpr-fv-serial-stdio.sexpr | 1 + .../xml2sexpr-fv-serial-stdio.xml | 39 ++ .../xml2sexpr-fv-serial-tcp-telnet.sexpr | 1 + .../xml2sexpr-fv-serial-tcp-telnet.xml | 41 ++ .../xml2sexpr-fv-serial-tcp.sexpr | 1 + .../xml2sexprdata/xml2sexpr-fv-serial-tcp.xml | 40 ++ .../xml2sexpr-fv-serial-udp.sexpr | 1 + .../xml2sexprdata/xml2sexpr-fv-serial-udp.xml | 41 ++ .../xml2sexpr-fv-serial-unix.sexpr | 1 + .../xml2sexpr-fv-serial-unix.xml | 40 ++ .../xml2sexprdata/xml2sexpr-fv-usbmouse.sexpr | 2 +- .../xml2sexpr-fv-usbtablet.sexpr | 2 +- tests/xml2sexprdata/xml2sexpr-fv-utc.sexpr | 2 +- tests/xml2sexprdata/xml2sexpr-fv-v2.sexpr | 2 +- .../xml2sexpr-fv-vncunused.sexpr | 2 +- tests/xml2sexprdata/xml2sexpr-fv.sexpr | 2 +- .../xml2sexpr-no-source-cdrom.sexpr | 2 +- tests/xml2sexprtest.c | 354 ++++-------------- 101 files changed, 2402 insertions(+), 560 deletions(-) create mode 100644 tests/sexpr2xmldata/sexpr2xml-fv-parallel-tcp.sexpr create mode 100644 tests/sexpr2xmldata/sexpr2xml-fv-parallel-tcp.xml create mode 100644 tests/sexpr2xmldata/sexpr2xml-fv-serial-file.sexpr create mode 100644 tests/sexpr2xmldata/sexpr2xml-fv-serial-file.xml create mode 100644 tests/sexpr2xmldata/sexpr2xml-fv-serial-null.sexpr create mode 100644 tests/sexpr2xmldata/sexpr2xml-fv-serial-null.xml create mode 100644 tests/sexpr2xmldata/sexpr2xml-fv-serial-pipe.sexpr create mode 100644 tests/sexpr2xmldata/sexpr2xml-fv-serial-pipe.xml create mode 100644 tests/sexpr2xmldata/sexpr2xml-fv-serial-pty.sexpr create mode 100644 tests/sexpr2xmldata/sexpr2xml-fv-serial-pty.xml create mode 100644 tests/sexpr2xmldata/sexpr2xml-fv-serial-stdio.sexpr create mode 100644 tests/sexpr2xmldata/sexpr2xml-fv-serial-stdio.xml create mode 100644 tests/sexpr2xmldata/sexpr2xml-fv-serial-tcp-telnet.sexpr create mode 100644 tests/sexpr2xmldata/sexpr2xml-fv-serial-tcp-telnet.xml create mode 100644 tests/sexpr2xmldata/sexpr2xml-fv-serial-tcp.sexpr create mode 100644 tests/sexpr2xmldata/sexpr2xml-fv-serial-tcp.xml create mode 100644 tests/sexpr2xmldata/sexpr2xml-fv-serial-udp.sexpr create mode 100644 tests/sexpr2xmldata/sexpr2xml-fv-serial-udp.xml create mode 100644 tests/sexpr2xmldata/sexpr2xml-fv-serial-unix.sexpr create mode 100644 tests/sexpr2xmldata/sexpr2xml-fv-serial-unix.xml create mode 100755 tests/xmconfigdata/test-fullvirt-parallel-tcp.cfg create mode 100644 tests/xmconfigdata/test-fullvirt-parallel-tcp.xml create mode 100755 tests/xmconfigdata/test-fullvirt-serial-file.cfg create mode 100644 tests/xmconfigdata/test-fullvirt-serial-file.xml create mode 100755 tests/xmconfigdata/test-fullvirt-serial-null.cfg create mode 100644 tests/xmconfigdata/test-fullvirt-serial-null.xml create mode 100755 tests/xmconfigdata/test-fullvirt-serial-pipe.cfg create mode 100644 tests/xmconfigdata/test-fullvirt-serial-pipe.xml create mode 100755 tests/xmconfigdata/test-fullvirt-serial-pty.cfg create mode 100644 tests/xmconfigdata/test-fullvirt-serial-pty.xml create mode 100755 tests/xmconfigdata/test-fullvirt-serial-stdio.cfg create mode 100644 tests/xmconfigdata/test-fullvirt-serial-stdio.xml create mode 100755 tests/xmconfigdata/test-fullvirt-serial-tcp-telnet.cfg create mode 100644 tests/xmconfigdata/test-fullvirt-serial-tcp-telnet.xml create mode 100755 tests/xmconfigdata/test-fullvirt-serial-tcp.cfg create mode 100644 tests/xmconfigdata/test-fullvirt-serial-tcp.xml create mode 100755 tests/xmconfigdata/test-fullvirt-serial-udp.cfg create mode 100644 tests/xmconfigdata/test-fullvirt-serial-udp.xml create mode 100755 tests/xmconfigdata/test-fullvirt-serial-unix.cfg create mode 100644 tests/xmconfigdata/test-fullvirt-serial-unix.xml create mode 100644 tests/xml2sexprdata/xml2sexpr-fv-parallel-tcp.sexpr create mode 100644 tests/xml2sexprdata/xml2sexpr-fv-parallel-tcp.xml create mode 100644 tests/xml2sexprdata/xml2sexpr-fv-serial-file.sexpr create mode 100644 tests/xml2sexprdata/xml2sexpr-fv-serial-file.xml create mode 100644 tests/xml2sexprdata/xml2sexpr-fv-serial-null.sexpr create mode 100644 tests/xml2sexprdata/xml2sexpr-fv-serial-null.xml create mode 100644 tests/xml2sexprdata/xml2sexpr-fv-serial-pipe.sexpr create mode 100644 tests/xml2sexprdata/xml2sexpr-fv-serial-pipe.xml create mode 100644 tests/xml2sexprdata/xml2sexpr-fv-serial-pty.sexpr create mode 100644 tests/xml2sexprdata/xml2sexpr-fv-serial-pty.xml create mode 100644 tests/xml2sexprdata/xml2sexpr-fv-serial-stdio.sexpr create mode 100644 tests/xml2sexprdata/xml2sexpr-fv-serial-stdio.xml create mode 100644 tests/xml2sexprdata/xml2sexpr-fv-serial-tcp-telnet.sexpr create mode 100644 tests/xml2sexprdata/xml2sexpr-fv-serial-tcp-telnet.xml create mode 100644 tests/xml2sexprdata/xml2sexpr-fv-serial-tcp.sexpr create mode 100644 tests/xml2sexprdata/xml2sexpr-fv-serial-tcp.xml create mode 100644 tests/xml2sexprdata/xml2sexpr-fv-serial-udp.sexpr create mode 100644 tests/xml2sexprdata/xml2sexpr-fv-serial-udp.xml create mode 100644 tests/xml2sexprdata/xml2sexpr-fv-serial-unix.sexpr create mode 100644 tests/xml2sexprdata/xml2sexpr-fv-serial-unix.xml diff --git a/ChangeLog b/ChangeLog index 7247f9a6af..0bf674c3d1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +Sat Apr 26 10:21:28 EST 2008 Daniel P. Berrange + + * src/xm_internal.c, src/xml.c, src/xml.h, src/xend_internal.c, + src/xend_internal.h: Added support for serial and parallel + devices + * tests/sexpr2xmltest.c, tests/xml2sexprtest.c, tests/xmconfigtest.c: + added tests for serial and parallel devices + * tests/sexpr2xmldata/*, tests/xml2sexprdata/*, tests/xmconfigdata/*: + updated for new test cases + Fri Apr 25 16:45:28 EST 2008 Daniel P. Berrange * src/internal.c: Convenience macros for fixed arrays diff --git a/src/internal.h b/src/internal.h index 67d31b3639..02cd3584a1 100644 --- a/src/internal.h +++ b/src/internal.h @@ -65,7 +65,7 @@ extern "C" { #define STRCASEEQLEN(a,b,n) (strncasecmp((a),(b),(n)) == 0) #define STRNEQLEN(a,b,n) (strncmp((a),(b),(n)) != 0) #define STRCASENEQLEN(a,b,n) (strncasecmp((a),(b),(n)) != 0) - +#define STRPREFIX(a,b) (strncmp((a),(b),strlen((b))) == 0) #define NUL_TERMINATE(buf) do { (buf)[sizeof(buf)-1] = '\0'; } while (0) #define ARRAY_CARDINALITY(Array) (sizeof (Array) / sizeof *(Array)) diff --git a/src/xend_internal.c b/src/xend_internal.c index 6ba4571db6..7eb4877e10 100644 --- a/src/xend_internal.c +++ b/src/xend_internal.c @@ -1376,6 +1376,244 @@ xend_parse_sexp_desc_os(virConnectPtr xend, struct sexpr *node, virBufferPtr buf return(0); } + +int +xend_parse_sexp_desc_char(virConnectPtr conn, + virBufferPtr buf, + const char *devtype, + int portNum, + const char *value, + const char *tty) +{ + const char *type; + int telnet = 0; + char *bindPort = NULL; + char *bindHost = NULL; + char *connectPort = NULL; + char *connectHost = NULL; + char *path = NULL; + int ret = -1; + + if (value[0] == '/') { + type = "dev"; + } else if (STRPREFIX(value, "null")) { + type = "null"; + value = NULL; + } else if (STRPREFIX(value, "vc")) { + type = "vc"; + value = NULL; + } else if (STRPREFIX(value, "pty")) { + type = "pty"; + value = NULL; + } else if (STRPREFIX(value, "stdio")) { + type = "stdio"; + value = NULL; + } else if (STRPREFIX(value, "file:")) { + type = "file"; + value += sizeof("file:")-1; + } else if (STRPREFIX(value, "pipe:")) { + type = "pipe"; + value += sizeof("pipe:")-1; + } else if (STRPREFIX(value, "tcp:")) { + type = "tcp"; + value += sizeof("tcp:")-1; + } else if (STRPREFIX(value, "telnet:")) { + type = "tcp"; + value += sizeof("telnet:")-1; + telnet = 1; + } else if (STRPREFIX(value, "udp:")) { + type = "udp"; + value += sizeof("udp:")-1; + } else if (STRPREFIX(value, "unix:")) { + type = "unix"; + value += sizeof("unix:")-1; + } else { + virXendError(conn, VIR_ERR_INTERNAL_ERROR, + _("Unknown char device type")); + return -1; + } + + /* Compat with legacy syntax */ + if (STREQ(devtype, "console") && + STREQ(type, "pty") && + tty != NULL) { + if (virBufferVSprintf(buf, " <%s type='%s' tty='%s'>\n", + devtype, type, tty) < 0) + goto no_memory; + } else { + if (virBufferVSprintf(buf, " <%s type='%s'>\n", + devtype, type) < 0) + goto no_memory; + } + + if (STREQ(type, "null") || + STREQ(type, "vc") || + STREQ(type, "stdio")) { + /* no source needed */ + } else if (STREQ(type, "pty")) { + if (tty && + virBufferVSprintf(buf, " \n", + tty) < 0) + goto no_memory; + } else if (STREQ(type, "file") || + STREQ(type, "pipe")) { + if (virBufferVSprintf(buf, " \n", + value) < 0) + goto no_memory; + } else if (STREQ(type, "tcp")) { + const char *offset = strchr(value, ':'); + const char *offset2; + const char *mode, *protocol; + + if (offset == NULL) { + virXendError(conn, VIR_ERR_INTERNAL_ERROR, + _("malformed char device string")); + goto error; + } + + if (offset != value && + (bindHost = strndup(value, offset - value)) == NULL) + goto no_memory; + + offset2 = strchr(offset, ','); + if (offset2 == NULL) + bindPort = strdup(offset+1); + else + bindPort = strndup(offset+1, offset2-(offset+1)); + if (bindPort == NULL) + goto no_memory; + + if (offset2 && strstr(offset2, ",listen")) + mode = "bind"; + else + mode = "connect"; + protocol = telnet ? "telnet":"raw"; + + if (bindHost) { + if (virBufferVSprintf(buf, + " \n", + mode, bindHost, bindPort) < 0) + goto no_memory; + } else { + if (virBufferVSprintf(buf, + " \n", + mode, bindPort) < 0) + goto no_memory; + } + if (virBufferVSprintf(buf, + " \n", + protocol) < 0) + goto no_memory; + } else if (STREQ(type, "udp")) { + const char *offset = strchr(value, ':'); + const char *offset2, *offset3; + + if (offset == NULL) { + virXendError(conn, VIR_ERR_INTERNAL_ERROR, + _("malformed char device string")); + goto error; + } + + if (offset != value && + (connectHost = strndup(value, offset - value)) == NULL) + goto no_memory; + + offset2 = strchr(offset, '@'); + if (offset2 != NULL) { + if ((connectPort = strndup(offset + 1, offset2-(offset+1))) == NULL) + goto no_memory; + + offset3 = strchr(offset2, ':'); + if (offset3 == NULL) { + virXendError(conn, VIR_ERR_INTERNAL_ERROR, + _("malformed char device string")); + goto error; + } + + if (offset3 > (offset2 + 1) && + (bindHost = strndup(offset2 + 1, offset3 - (offset2+1))) == NULL) + goto no_memory; + + if ((bindPort = strdup(offset3 + 1)) == NULL) + goto no_memory; + } else { + if ((connectPort = strdup(offset + 1)) == NULL) + goto no_memory; + } + + if (connectPort) { + if (connectHost) { + if (virBufferVSprintf(buf, + " \n", + connectHost, connectPort) < 0) + goto no_memory; + } else { + if (virBufferVSprintf(buf, + " \n", + connectPort) < 0) + goto no_memory; + } + } + if (bindPort) { + if (bindHost) { + if (virBufferVSprintf(buf, + " \n", + bindHost, bindPort) < 0) + goto no_memory; + } else { + if (virBufferVSprintf(buf, + " \n", + bindPort) < 0) + goto no_memory; + } + } + + } else if (STREQ(type, "unix")) { + const char *offset = strchr(value, ','); + int dolisten = 0; + if (offset) + path = strndup(value, (offset - value)); + else + path = strdup(value); + if (path == NULL) + goto no_memory; + + if (offset != NULL && + strstr(offset, ",listen") != NULL) + dolisten = 1; + + if (virBufferVSprintf(buf, " \n", + dolisten ? "bind" : "connect", path) < 0) + goto no_memory; + } + + if (virBufferVSprintf(buf, " \n", + portNum) < 0) + goto no_memory; + + if (virBufferVSprintf(buf, " \n", + devtype) < 0) + goto no_memory; + + ret = 0; + + if (ret == -1) { +no_memory: + virXendError(conn, VIR_ERR_NO_MEMORY, + _("no memory for char device config")); + } + +error: + + free(path); + free(bindHost); + free(bindPort); + free(connectHost); + free(connectPort); + + return ret; +} + /** * xend_parse_sexp_desc: * @conn: the connection associated with the XML @@ -1828,10 +2066,33 @@ xend_parse_sexp_desc(virConnectPtr conn, struct sexpr *root, } tty = xenStoreDomainGetConsolePath(conn, domid); - if (tty) { - virBufferVSprintf(&buf, " \n", tty); - free(tty); + if (hvm) { + tmp = sexpr_node(root, "domain/image/hvm/serial"); + if (tmp && STRNEQ(tmp, "none")) { + if (xend_parse_sexp_desc_char(conn, &buf, "serial", 0, tmp, tty) < 0) + goto error; + /* Add back-compat tag for primary console */ + if (xend_parse_sexp_desc_char(conn, &buf, "console", 0, tmp, tty) < 0) + goto error; + } + tmp = sexpr_node(root, "domain/image/hvm/parallel"); + if (tmp && STRNEQ(tmp, "none")) { + /* XXX does XenD stuff parallel port tty info into xenstore somewhere ? */ + if (xend_parse_sexp_desc_char(conn, &buf, "parallel", 0, tmp, NULL) < 0) + goto error; + } + } else { + /* Paravirt always has a console */ + if (tty) { + virBufferVSprintf(&buf, " \n", tty); + virBufferVSprintf(&buf, " \n", tty); + } else { + virBufferAddLit(&buf, " \n"); + } + virBufferAddLit(&buf, " \n"); + virBufferAddLit(&buf, " \n"); } + free(tty); virBufferAddLit(&buf, " \n"); virBufferAddLit(&buf, "\n"); diff --git a/src/xend_internal.h b/src/xend_internal.h index e157e88b5e..d56d73d60d 100644 --- a/src/xend_internal.h +++ b/src/xend_internal.h @@ -20,12 +20,12 @@ #include "libvirt/libvirt.h" #include "capabilities.h" +#include "buf.h" #ifdef __cplusplus extern "C" { #endif - /** * \brief Setup the connection to a xend instance via TCP * \param host The host name to connect to @@ -180,6 +180,13 @@ char *xenDaemonDomainDumpXMLByName(virConnectPtr xend, */ int xend_log(virConnectPtr xend, char *buffer, size_t n_buffer); + int xend_parse_sexp_desc_char(virConnectPtr conn, + virBufferPtr buf, + const char *devtype, + int portNum, + const char *value, + const char *tty); + char *xend_parse_domain_sexp(virConnectPtr conn, char *root, int xendConfigVersion); /* refactored ones */ diff --git a/src/xm_internal.c b/src/xm_internal.c index 3d845dcd57..811a62bdee 100644 --- a/src/xm_internal.c +++ b/src/xm_internal.c @@ -1025,11 +1025,22 @@ char *xenXMDomainFormatXML(virConnectPtr conn, virConfPtr conf) { } if (hvm) { - if (xenXMConfigGetString(conf, "serial", &str) == 0 && !strcmp(str, "pty")) { - virBufferAddLit(buf, " \n"); + if (xenXMConfigGetString(conf, "parallel", &str) == 0) { + if (STRNEQ(str, "none")) + xend_parse_sexp_desc_char(conn, buf, "parallel", 0, str, NULL); } - } else { /* Paravirt implicitly always has a console */ - virBufferAddLit(buf, " \n"); + if (xenXMConfigGetString(conf, "serial", &str) == 0) { + if (STRNEQ(str, "none")) { + xend_parse_sexp_desc_char(conn, buf, "serial", 0, str, NULL); + /* Add back-compat console tag for primary console */ + xend_parse_sexp_desc_char(conn, buf, "console", 0, str, NULL); + } + } + } else { + /* Paravirt implicitly always has a single console */ + virBufferAddLit(buf, " \n"); + virBufferAddLit(buf, " \n"); + virBufferAddLit(buf, " \n"); } virBufferAddLit(buf, " \n"); @@ -2267,14 +2278,38 @@ virConfPtr xenXMParseXMLToConfig(virConnectPtr conn, const char *xml) { obj = NULL; if (hvm) { - obj = xmlXPathEval(BAD_CAST "count(/domain/devices/console) > 0", ctxt); - if ((obj != NULL) && (obj->type == XPATH_BOOLEAN) && - (obj->boolval)) { - if (xenXMConfigSetString(conf, "serial", "pty") < 0) + xmlNodePtr cur; + cur = virXPathNode("/domain/devices/parallel[1]", ctxt); + if (cur != NULL) { + char scratch[PATH_MAX]; + + if (virDomainParseXMLOSDescHVMChar(conn, scratch, sizeof(scratch), cur) < 0) { + goto error; + } + + if (xenXMConfigSetString(conf, "parallel", scratch) < 0) + goto error; + } else { + if (xenXMConfigSetString(conf, "parallel", "none") < 0) goto error; } - xmlXPathFreeObject(obj); - obj = NULL; + + cur = virXPathNode("/domain/devices/serial[1]", ctxt); + if (cur != NULL) { + char scratch[PATH_MAX]; + if (virDomainParseXMLOSDescHVMChar(conn, scratch, sizeof(scratch), cur) < 0) + goto error; + if (xenXMConfigSetString(conf, "serial", scratch) < 0) + goto error; + } else { + if (virXPathBoolean("count(/domain/devices/console) > 0", ctxt)) { + if (xenXMConfigSetString(conf, "serial", "pty") < 0) + goto error; + } else { + if (xenXMConfigSetString(conf, "serial", "none") < 0) + goto error; + } + } } xmlFreeDoc(doc); diff --git a/src/xml.c b/src/xml.c index 8e95103b19..ceea987219 100644 --- a/src/xml.c +++ b/src/xml.c @@ -673,6 +673,178 @@ virDomainParseXMLGraphicsDescVFB(virConnectPtr conn ATTRIBUTE_UNUSED, } +int +virDomainParseXMLOSDescHVMChar(virConnectPtr conn, + char *buf, + size_t buflen, + xmlNodePtr node) +{ + xmlChar *type = NULL; + xmlChar *path = NULL; + xmlChar *bindHost = NULL; + xmlChar *bindService = NULL; + xmlChar *connectHost = NULL; + xmlChar *connectService = NULL; + xmlChar *mode = NULL; + xmlChar *protocol = NULL; + xmlNodePtr cur; + + type = xmlGetProp(node, BAD_CAST "type"); + + if (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"); + + if (STREQ((const char *)type, "dev") || + STREQ((const char *)type, "file") || + STREQ((const char *)type, "pipe") || + STREQ((const char *)type, "unix")) { + if (path == NULL) + path = xmlGetProp(cur, BAD_CAST "path"); + + } else if (STREQ((const char *)type, "udp") || + STREQ((const char *)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 (STREQ((const char*)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; + } + } + + if (type == NULL || + STREQ((const char *)type, "pty")) { + strncpy(buf, "pty", buflen); + } else if (STREQ((const char *)type, "null") || + STREQ((const char *)type, "stdio") || + STREQ((const char *)type, "vc")) { + snprintf(buf, buflen, "%s", type); + } else if (STREQ((const char *)type, "file") || + STREQ((const char *)type, "dev") || + STREQ((const char *)type, "pipe")) { + if (path == NULL) { + virXMLError(conn, VIR_ERR_XML_ERROR, + _("Missing source path attribute for char device"), 0); + goto cleanup; + } + + if (STREQ((const char *)type, "dev")) + strncpy(buf, (const char *)path, buflen); + else + snprintf(buf, buflen, "%s:%s", type, path); + } else if (STREQ((const char *)type, "tcp")) { + int telnet = 0; + if (protocol != NULL && + STREQ((const char *)protocol, "telnet")) + telnet = 1; + + if (mode == NULL || + STREQ((const char *)mode, "connect")) { + if (connectHost == NULL) { + virXMLError(conn, VIR_ERR_INTERNAL_ERROR, + _("Missing source host attribute for char device"), 0); + goto cleanup; + } + if (connectService == NULL) { + virXMLError(conn, VIR_ERR_INTERNAL_ERROR, + _("Missing source service attribute for char device"), 0); + goto cleanup; + } + + snprintf(buf, buflen, "%s:%s:%s", + (telnet ? "telnet" : "tcp"), + connectHost, connectService); + } else { + if (bindHost == NULL) { + virXMLError(conn, VIR_ERR_INTERNAL_ERROR, + _("Missing source host attribute for char device"), 0); + goto cleanup; + } + if (bindService == NULL) { + virXMLError(conn, VIR_ERR_INTERNAL_ERROR, + _("Missing source service attribute for char device"), 0); + goto cleanup; + } + + snprintf(buf, buflen, "%s:%s:%s,listen", + (telnet ? "telnet" : "tcp"), + bindHost, bindService); + } + } else if (STREQ((const char *)type, "udp")) { + if (connectService == NULL) { + virXMLError(conn, VIR_ERR_XML_ERROR, + _("Missing source service attribute for char device"), 0); + goto cleanup; + } + + snprintf(buf, buflen, "udp:%s:%s@%s:%s", + connectHost ? (const char *)connectHost : "", + connectService, + bindHost ? (const char *)bindHost : "", + bindService ? (const char *)bindService : ""); + } else if (STREQ((const char *)type, "unix")) { + if (path == NULL) { + virXMLError(conn, VIR_ERR_XML_ERROR, + _("Missing source path attribute for char device"), 0); + goto cleanup; + } + + if (mode == NULL || + STREQ((const char *)mode, "connect")) { + snprintf(buf, buflen, "%s:%s", type, path); + } else { + snprintf(buf, buflen, "%s:%s,listen", type, path); + } + } + buf[buflen-1] = '\0'; + + xmlFree(mode); + xmlFree(protocol); + xmlFree(type); + xmlFree(bindHost); + xmlFree(bindService); + xmlFree(connectHost); + xmlFree(connectService); + xmlFree(path); + + return 0; + +cleanup: + xmlFree(mode); + xmlFree(protocol); + xmlFree(type); + xmlFree(bindHost); + xmlFree(bindService); + xmlFree(connectHost); + xmlFree(connectService); + xmlFree(path); + return -1; +} + /** * virDomainParseXMLOSDescHVM: * @conn: pointer to the hypervisor connection @@ -877,24 +1049,53 @@ virDomainParseXMLOSDescHVM(virConnectPtr conn, xmlNodePtr node, nodes = NULL; } - - res = virXPathBoolean("count(domain/devices/console) > 0", ctxt); - if (res < 0) { - virXMLError(conn, VIR_ERR_XML_ERROR, NULL, 0); - goto error; + cur = virXPathNode("/domain/devices/parallel[1]", ctxt); + if (cur != NULL) { + char scratch[PATH_MAX]; + if (virDomainParseXMLOSDescHVMChar(conn, scratch, sizeof(scratch), cur) < 0) + goto error; + if (virBufferVSprintf(buf, "(parallel %s)", scratch) < 0) + goto no_memory; + } else { + if (virBufferAddLit(buf, "(parallel none)") < 0) + goto no_memory; } - if (res) { - virBufferAddLit(buf, "(serial pty)"); + + cur = virXPathNode("/domain/devices/serial[1]", ctxt); + if (cur != NULL) { + char scratch[PATH_MAX]; + if (virDomainParseXMLOSDescHVMChar(conn, scratch, sizeof(scratch), cur) < 0) + goto error; + if (virBufferVSprintf(buf, "(serial %s)", scratch) < 0) + goto no_memory; + } else { + res = virXPathBoolean("count(domain/devices/console) > 0", ctxt); + if (res < 0) { + virXMLError(conn, VIR_ERR_XML_ERROR, NULL, 0); + goto error; + } + if (res) { + if (virBufferAddLit(buf, "(serial pty)") < 0) + goto no_memory; + } else { + if (virBufferAddLit(buf, "(serial none)") < 0) + goto no_memory; + } } str = virXPathString("string(/domain/clock/@offset)", ctxt); if (str != NULL && !strcmp(str, "localtime")) { - virBufferAddLit(buf, "(localtime 1)"); + if (virBufferAddLit(buf, "(localtime 1)") < 0) + goto no_memory; } free(str); return (0); +no_memory: + virXMLError(conn, VIR_ERR_XML_ERROR, + _("cannot allocate memory for buffer"), 0); + error: free(nodes); return (-1); diff --git a/src/xml.h b/src/xml.h index 2d30b6576f..d91a1b0e7b 100644 --- a/src/xml.h +++ b/src/xml.h @@ -44,6 +44,10 @@ char * virSaveCpuSet (virConnectPtr conn, char * virConvertCpuSet(virConnectPtr conn, const char *str, int maxcpu); +int virDomainParseXMLOSDescHVMChar(virConnectPtr conn, + char *buf, + size_t buflen, + xmlNodePtr node); char * virDomainParseXMLDesc(virConnectPtr conn, const char *xmldesc, char **name, diff --git a/tests/sexpr2xmldata/sexpr2xml-curmem.xml b/tests/sexpr2xmldata/sexpr2xml-curmem.xml index 15853cd827..a609f97e83 100644 --- a/tests/sexpr2xmldata/sexpr2xml-curmem.xml +++ b/tests/sexpr2xmldata/sexpr2xml-curmem.xml @@ -28,5 +28,8 @@ + + + diff --git a/tests/sexpr2xmldata/sexpr2xml-disk-block-shareable.xml b/tests/sexpr2xmldata/sexpr2xml-disk-block-shareable.xml index 9c2f19dcc9..35735399f1 100644 --- a/tests/sexpr2xmldata/sexpr2xml-disk-block-shareable.xml +++ b/tests/sexpr2xmldata/sexpr2xml-disk-block-shareable.xml @@ -21,5 +21,8 @@