diff --git a/src/xenxs/xen_sxpr.c b/src/xenxs/xen_sxpr.c index aac2585b3a..3a412a68e8 100644 --- a/src/xenxs/xen_sxpr.c +++ b/src/xenxs/xen_sxpr.c @@ -177,6 +177,9 @@ xenParseSxprChar(const char *value, if (value[0] == '/') { def->source.type = VIR_DOMAIN_CHR_TYPE_DEV; + def->source.data.file.path = strdup(value); + if (!def->source.data.file.path) + goto no_memory; } else { if ((tmp = strchr(value, ':')) != NULL) { *tmp = '\0'; @@ -1280,18 +1283,55 @@ xenParseSxpr(const struct sexpr *root, /* Character device config */ if (hvm) { - tmp = sexpr_node(root, "domain/image/hvm/serial"); - if (tmp && STRNEQ(tmp, "none")) { - virDomainChrDefPtr chr; - if ((chr = xenParseSxprChar(tmp, tty)) == NULL) - goto error; - if (VIR_REALLOC_N(def->serials, def->nserials+1) < 0) { - virDomainChrDefFree(chr); - goto no_memory; + const struct sexpr *serial_root; + bool have_multiple_serials = false; + + serial_root = sexpr_lookup(root, "domain/image/hvm/serial"); + if (serial_root) { + const struct sexpr *cur, *node, *cur2; + int ports_skipped = 0; + + for (cur = serial_root; cur->kind == SEXPR_CONS; cur = cur->u.s.cdr) { + node = cur->u.s.car; + + for (cur2 = node; cur2->kind == SEXPR_CONS; cur2 = cur2->u.s.cdr) { + tmp = cur2->u.s.car->u.value; + + if (tmp && STRNEQ(tmp, "none")) { + virDomainChrDefPtr chr; + if ((chr = xenParseSxprChar(tmp, tty)) == NULL) + goto error; + if (VIR_REALLOC_N(def->serials, def->nserials+1) < 0) { + virDomainChrDefFree(chr); + goto no_memory; + } + chr->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL; + chr->target.port = def->nserials + ports_skipped; + def->serials[def->nserials++] = chr; + } + else + ports_skipped++; + + have_multiple_serials = true; + } } - chr->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL; - def->serials[def->nserials++] = chr; } + + if (!have_multiple_serials) { + tmp = sexpr_node(root, "domain/image/hvm/serial"); + if (tmp && STRNEQ(tmp, "none")) { + virDomainChrDefPtr chr; + if ((chr = xenParseSxprChar(tmp, tty)) == NULL) + goto error; + if (VIR_REALLOC_N(def->serials, def->nserials+1) < 0) { + virDomainChrDefFree(chr); + goto no_memory; + } + chr->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL; + def->serials[def->nserials++] = chr; + } + } + tmp = sexpr_node(root, "domain/image/hvm/parallel"); if (tmp && STRNEQ(tmp, "none")) { virDomainChrDefPtr chr; @@ -2121,10 +2161,41 @@ xenFormatSxpr(virConnectPtr conn, virBufferAddLit(&buf, "(parallel none)"); } if (def->serials) { - virBufferAddLit(&buf, "(serial "); - if (xenFormatSxprChr(def->serials[0], &buf) < 0) - goto error; - virBufferAddLit(&buf, ")"); + if ((def->nserials > 1) || (def->serials[0]->target.port != 0)) { + int maxport = -1; + int j = 0; + + virBufferAddLit(&buf, "(serial ("); + for (i = 0; i < def->nserials; i++) + if (def->serials[i]->target.port > maxport) + maxport = def->serials[i]->target.port; + + for (i = 0; i <= maxport; i++) { + virDomainChrDefPtr chr = NULL; + + if (i) + virBufferAddLit(&buf, " "); + for (j = 0; j < def->nserials; j++) { + if (def->serials[j]->target.port == i) { + chr = def->serials[j]; + break; + } + } + if (chr) { + if (xenFormatSxprChr(chr, &buf) < 0) + goto error; + } else { + virBufferAddLit(&buf, "none"); + } + } + virBufferAddLit(&buf, "))"); + } + else { + virBufferAddLit(&buf, "(serial "); + if (xenFormatSxprChr(def->serials[0], &buf) < 0) + goto error; + virBufferAddLit(&buf, ")"); + } } else { virBufferAddLit(&buf, "(serial none)"); } diff --git a/src/xenxs/xen_xm.c b/src/xenxs/xen_xm.c index ce590b9493..0acd12016b 100644 --- a/src/xenxs/xen_xm.c +++ b/src/xenxs/xen_xm.c @@ -965,20 +965,57 @@ xenParseXM(virConfPtr conf, int xendConfigVersion, chr = NULL; } - if (xenXMConfigGetString(conf, "serial", &str, NULL) < 0) - goto cleanup; - if (str && STRNEQ(str, "none") && - !(chr = xenParseSxprChar(str, NULL))) - goto cleanup; + /* Try to get the list of values to support multiple serial ports */ + list = virConfGetValue(conf, "serial"); + if (list && list->type == VIR_CONF_LIST) { + int portnum = -1; - if (chr) { - if (VIR_ALLOC_N(def->serials, 1) < 0) { - virDomainChrDefFree(chr); - goto no_memory; + list = list->list; + while (list) { + char *port = NULL; + + if ((list->type != VIR_CONF_STRING) || (list->str == NULL)) + goto cleanup; + + port = list->str; + portnum++; + if (STREQ(port, "none")) { + list = list->next; + continue; + } + + if (VIR_ALLOC(chr) < 0) + goto no_memory; + if (!(chr = xenParseSxprChar(port, NULL))) + goto cleanup; + + if (VIR_REALLOC_N(def->serials, def->nserials+1) < 0) + goto no_memory; + + chr->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL; + chr->target.port = portnum; + + def->serials[def->nserials++] = chr; + chr = NULL; + + list = list->next; + } + } else { + /* If domain is not using multiple serial ports we parse data old way */ + if (xenXMConfigGetString(conf, "serial", &str, NULL) < 0) + goto cleanup; + if (str && STRNEQ(str, "none") && + !(chr = xenParseSxprChar(str, NULL))) + goto cleanup; + if (chr) { + if (VIR_ALLOC_N(def->serials, 1) < 0) { + virDomainChrDefFree(chr); + goto no_memory; + } + chr->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL; + def->serials[0] = chr; + def->nserials++; } - chr->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL; - def->serials[0] = chr; - def->nserials++; } } else { if (!(def->console = xenParseSxprChar("pty", NULL))) @@ -1120,6 +1157,49 @@ cleanup: return -1; } +static int xenFormatXMSerial(virConfValuePtr list, + virDomainChrDefPtr serial) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + virConfValuePtr val, tmp; + int ret; + + if (serial) { + ret = xenFormatSxprChr(serial, &buf); + if (ret < 0) { + virReportOOMError(); + goto cleanup; + } + } else { + virBufferAddLit(&buf, "none"); + } + if (virBufferError(&buf)) { + virReportOOMError(); + goto cleanup; + } + + if (VIR_ALLOC(val) < 0) { + virReportOOMError(); + goto cleanup; + } + + val->type = VIR_CONF_STRING; + val->str = virBufferContentAndReset(&buf); + tmp = list->list; + while (tmp && tmp->next) + tmp = tmp->next; + if (tmp) + tmp->next = val; + else + list->list = val; + + return 0; + +cleanup: + virBufferFreeAndReset(&buf); + return -1; +} + static int xenFormatXMNet(virConnectPtr conn, virConfValuePtr list, virDomainNetDefPtr net, @@ -1678,17 +1758,52 @@ virConfPtr xenFormatXM(virConnectPtr conn, } if (def->nserials) { - virBuffer buf = VIR_BUFFER_INITIALIZER; - char *str; - int ret; + if ((def->nserials == 1) && (def->serials[0]->target.port == 0)) { + virBuffer buf = VIR_BUFFER_INITIALIZER; + char *str; + int ret; - ret = xenFormatSxprChr(def->serials[0], &buf); - str = virBufferContentAndReset(&buf); - if (ret == 0) - ret = xenXMConfigSetString(conf, "serial", str); - VIR_FREE(str); - if (ret < 0) - goto no_memory; + ret = xenFormatSxprChr(def->serials[0], &buf); + str = virBufferContentAndReset(&buf); + if (ret == 0) + ret = xenXMConfigSetString(conf, "serial", str); + VIR_FREE(str); + if (ret < 0) + goto no_memory; + } else { + int j = 0; + int maxport = -1; + virConfValuePtr serialVal = NULL; + + if (VIR_ALLOC(serialVal) < 0) + goto no_memory; + serialVal->type = VIR_CONF_LIST; + serialVal->list = NULL; + + for (i = 0; i < def->nserials; i++) + if (def->serials[i]->target.port > maxport) + maxport = def->serials[i]->target.port; + + for (i = 0; i <= maxport; i++) { + virDomainChrDefPtr chr = NULL; + for (j = 0; j < def->nserials; j++) { + if (def->serials[j]->target.port == i) { + chr = def->serials[j]; + break; + } + } + if (xenFormatXMSerial(serialVal, chr) < 0) + goto cleanup; + } + + if (serialVal->list != NULL) { + int ret = virConfSetValue(conf, "serial", serialVal); + serialVal = NULL; + if (ret < 0) + goto no_memory; + } + VIR_FREE(serialVal); + } } else { if (xenXMConfigSetString(conf, "serial", "none") < 0) goto no_memory; @@ -1721,4 +1836,4 @@ cleanup: if (conf) virConfFree(conf); return (NULL); -} \ No newline at end of file +} diff --git a/tests/sexpr2xmldata/sexpr2xml-fv-serial-dev-2-ports.sexpr b/tests/sexpr2xmldata/sexpr2xml-fv-serial-dev-2-ports.sexpr new file mode 100644 index 0000000000..e709eb0c9e --- /dev/null +++ b/tests/sexpr2xmldata/sexpr2xml-fv-serial-dev-2-ports.sexpr @@ -0,0 +1 @@ +(domain (domid 1)(name 'fvtest')(memory 400)(maxmem 400)(vcpus 1)(uuid 'b5d70dd275cdaca517769660b059d8ff')(on_poweroff 'destroy')(on_reboot 'restart')(on_crash 'restart')(image (hvm (kernel '/usr/lib/xen/boot/hvmloader')(vcpus 1)(boot c)(cdrom '/root/boot.iso')(acpi 1)(usb 1)(parallel none)(serial (/dev/ttyS0 /dev/ttyS1))(device_model '/usr/lib64/xen/bin/qemu-dm')(vnc 1)))(device (vbd (dev 'ioemu:hda')(uname 'file:/root/foo.img')(mode 'w')))(device (vif (mac '00:16:3e:1b:b1:47')(bridge 'xenbr0')(script 'vif-bridge')(type ioemu)))) diff --git a/tests/sexpr2xmldata/sexpr2xml-fv-serial-dev-2-ports.xml b/tests/sexpr2xmldata/sexpr2xml-fv-serial-dev-2-ports.xml new file mode 100644 index 0000000000..5e085f96c9 --- /dev/null +++ b/tests/sexpr2xmldata/sexpr2xml-fv-serial-dev-2-ports.xml @@ -0,0 +1,53 @@ + + fvtest + b5d70dd2-75cd-aca5-1776-9660b059d8ff + 409600 + 409600 + 1 + + hvm + /usr/lib/xen/boot/hvmloader + + + + + + + destroy + restart + restart + + /usr/lib64/xen/bin/qemu-dm + + + + + + + + + + + + + + +