diff --git a/po/POTFILES.in b/po/POTFILES.in index 2256cb29c79c490b2a3de3cd5da6fd3dfd8f1570..7fbbe8f370ebfa4e7c75bf53b9d61f618079d1c3 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -119,6 +119,7 @@ src/xen/xm_internal.c src/xen/xs_internal.c src/xenapi/xenapi_driver.c src/xenapi/xenapi_utils.c +src/xenxs/xen_sxpr.c tools/console.c tools/libvirt-guests.init.sh tools/virsh.c diff --git a/src/Makefile.am b/src/Makefile.am index 5c9b019c9b9918d338459edf4d7d528969bf492a..4a64eb1b2c945f5e49f9e2dee595127e11e55a16 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -423,6 +423,10 @@ CPU_SOURCES = \ VMX_SOURCES = \ vmx/vmx.c vmx/vmx.h +XENXS_SOURCES = \ + xenxs/xenxs_private.h \ + xenxs/xen_sxpr.c xenxs/xen_sxpr.h + pkgdata_DATA = cpu/cpu_map.xml EXTRA_DIST += $(pkgdata_DATA) @@ -464,6 +468,14 @@ libvirt_vmx_la_CFLAGS = \ libvirt_vmx_la_SOURCES = $(VMX_SOURCES) endif +if WITH_XEN +noinst_LTLIBRARIES += libvirt_xenxs.la +libvirt_la_BUILT_LIBADD += libvirt_xenxs.la +libvirt_xenxs_la_CFLAGS = \ + -I@top_srcdir@/src/conf $(AM_CFLAGS) +libvirt_xenxs_la_SOURCES = $(XENXS_SOURCES) +endif + noinst_LTLIBRARIES += libvirt_driver.la libvirt_la_BUILT_LIBADD += libvirt_driver.la @@ -583,6 +595,7 @@ endif libvirt_driver_xen_la_CFLAGS = \ $(XEN_CFLAGS) \ -I@top_srcdir@/src/conf \ + -I@top_srcdir@/src/xenxs \ $(AM_CFLAGS) libvirt_driver_xen_la_LDFLAGS = $(AM_LDFLAGS) libvirt_driver_xen_la_LIBADD = $(XEN_LIBS) @@ -995,7 +1008,8 @@ EXTRA_DIST += \ $(SECURITY_DRIVER_APPARMOR_SOURCES) \ $(SECRET_DRIVER_SOURCES) \ $(VBOX_DRIVER_EXTRA_DIST) \ - $(VMWARE_DRIVER_SOURCES) + $(VMWARE_DRIVER_SOURCES) \ + $(XENXS_SOURCES) check-local: augeas-check diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c index f6d281e49ae572c816d8ed2baf9ed3dd57d5f318..4bb549ae2c3babb749e0ebca2614c24473394196 100644 --- a/src/xen/xen_driver.c +++ b/src/xen/xen_driver.c @@ -33,6 +33,7 @@ #include "datatypes.h" #include "xen_driver.h" +#include "xen_sxpr.h" #include "xen_hypervisor.h" #include "xend_internal.h" #include "xs_internal.h" @@ -1198,6 +1199,9 @@ xenUnifiedDomainXMLFromNative(virConnectPtr conn, virDomainDefPtr def = NULL; char *ret = NULL; virConfPtr conf = NULL; + int id; + char * tty; + int vncport; GET_PRIVATE(conn); if (STRNEQ(format, XEN_CONFIG_FORMAT_XM) && @@ -1214,7 +1218,13 @@ xenUnifiedDomainXMLFromNative(virConnectPtr conn, def = xenXMDomainConfigParse(conn, conf); } else if (STREQ(format, XEN_CONFIG_FORMAT_SEXPR)) { - def = xenDaemonParseSxprString(conn, config, priv->xendConfigVersion); + id = xenGetDomIdFromSxprString(config, priv->xendConfigVersion); + xenUnifiedLock(priv); + tty = xenStoreDomainGetConsolePath(conn, id); + vncport = xenStoreDomainGetVNCPort(conn, id); + xenUnifiedUnlock(priv); + def = xenDaemonParseSxprString(config, priv->xendConfigVersion, tty, + vncport); } if (!def) goto cleanup; diff --git a/src/xen/xend_internal.c b/src/xen/xend_internal.c index 346fb8f9a7537b29bb68f3ba5e3f56fe65182788..466c749ce8def34f2c7db96f5f76e8b8525e28c7 100644 --- a/src/xen/xend_internal.c +++ b/src/xen/xend_internal.c @@ -38,6 +38,7 @@ #include "driver.h" #include "util.h" #include "sexpr.h" +#include "xen_sxpr.h" #include "buf.h" #include "uuid.h" #include "xen_driver.h" @@ -1040,1307 +1041,6 @@ xend_detect_config_version(virConnectPtr conn) { } -/***************************************************************** - ****** - ****** Parsing of SEXPR into virDomainDef objects - ****** - *****************************************************************/ - -/** - * xenDaemonParseSxprOS - * @node: the root of the parsed S-Expression - * @def: the domain config - * @hvm: true or 1 if no contains HVM S-Expression - * @bootloader: true or 1 if a bootloader is defined - * - * Parse the xend sexp for description of os and append it to buf. - * - * Returns 0 in case of success and -1 in case of error - */ -static int -xenDaemonParseSxprOS(const struct sexpr *node, - virDomainDefPtr def, - int hvm) -{ - if (hvm) { - if (sexpr_node_copy(node, "domain/image/hvm/loader", &def->os.loader) < 0) - goto no_memory; - if (def->os.loader == NULL) { - if (sexpr_node_copy(node, "domain/image/hvm/kernel", &def->os.loader) < 0) - goto no_memory; - - if (def->os.loader == NULL) { - virXendError(VIR_ERR_INTERNAL_ERROR, - "%s", _("domain information incomplete, missing HVM loader")); - return(-1); - } - } else { - if (sexpr_node_copy(node, "domain/image/hvm/kernel", &def->os.kernel) < 0) - goto no_memory; - if (sexpr_node_copy(node, "domain/image/hvm/ramdisk", &def->os.initrd) < 0) - goto no_memory; - if (sexpr_node_copy(node, "domain/image/hvm/args", &def->os.cmdline) < 0) - goto no_memory; - if (sexpr_node_copy(node, "domain/image/hvm/root", &def->os.root) < 0) - goto no_memory; - } - } else { - if (sexpr_node_copy(node, "domain/image/linux/kernel", &def->os.kernel) < 0) - goto no_memory; - if (sexpr_node_copy(node, "domain/image/linux/ramdisk", &def->os.initrd) < 0) - goto no_memory; - if (sexpr_node_copy(node, "domain/image/linux/args", &def->os.cmdline) < 0) - goto no_memory; - if (sexpr_node_copy(node, "domain/image/linux/root", &def->os.root) < 0) - goto no_memory; - } - - /* If HVM kenrel == loader, then old xend, so kill off kernel */ - if (hvm && - def->os.kernel && - STREQ(def->os.kernel, def->os.loader)) { - VIR_FREE(def->os.kernel); - } - - if (!def->os.kernel && - hvm) { - const char *boot = sexpr_node(node, "domain/image/hvm/boot"); - if ((boot != NULL) && (boot[0] != 0)) { - while (*boot && - def->os.nBootDevs < VIR_DOMAIN_BOOT_LAST) { - if (*boot == 'a') - def->os.bootDevs[def->os.nBootDevs++] = VIR_DOMAIN_BOOT_FLOPPY; - else if (*boot == 'c') - def->os.bootDevs[def->os.nBootDevs++] = VIR_DOMAIN_BOOT_DISK; - else if (*boot == 'd') - def->os.bootDevs[def->os.nBootDevs++] = VIR_DOMAIN_BOOT_CDROM; - else if (*boot == 'n') - def->os.bootDevs[def->os.nBootDevs++] = VIR_DOMAIN_BOOT_NET; - boot++; - } - } - } - - if (!hvm && - !def->os.kernel && - !def->os.bootloader) { - virXendError(VIR_ERR_INTERNAL_ERROR, - "%s", _("domain information incomplete, missing kernel & bootloader")); - return -1; - } - - return 0; - -no_memory: - virReportOOMError(); - return -1; -} - -virDomainChrDefPtr -xenDaemonParseSxprChar(const char *value, - const char *tty) -{ - const char *prefix; - char *tmp; - virDomainChrDefPtr def; - - if (VIR_ALLOC(def) < 0) { - virReportOOMError(); - return NULL; - } - - prefix = value; - - if (value[0] == '/') { - def->source.type = VIR_DOMAIN_CHR_TYPE_DEV; - } else { - if ((tmp = strchr(value, ':')) != NULL) { - *tmp = '\0'; - value = tmp + 1; - } - - if (STRPREFIX(prefix, "telnet")) { - def->source.type = VIR_DOMAIN_CHR_TYPE_TCP; - def->source.data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET; - } else { - if ((def->source.type = virDomainChrTypeFromString(prefix)) < 0) { - virXendError(VIR_ERR_INTERNAL_ERROR, - _("unknown chr device type '%s'"), prefix); - goto error; - } - } - } - - /* Compat with legacy syntax */ - switch (def->source.type) { - case VIR_DOMAIN_CHR_TYPE_PTY: - if (tty != NULL && - !(def->source.data.file.path = strdup(tty))) - goto no_memory; - break; - - case VIR_DOMAIN_CHR_TYPE_FILE: - case VIR_DOMAIN_CHR_TYPE_PIPE: - if (!(def->source.data.file.path = strdup(value))) - goto no_memory; - break; - - case VIR_DOMAIN_CHR_TYPE_TCP: - { - const char *offset = strchr(value, ':'); - const char *offset2; - - if (offset == NULL) { - virXendError(VIR_ERR_INTERNAL_ERROR, - "%s", _("malformed char device string")); - goto error; - } - - if (offset != value && - (def->source.data.tcp.host = strndup(value, - offset - value)) == NULL) - goto no_memory; - - offset2 = strchr(offset, ','); - if (offset2 == NULL) - def->source.data.tcp.service = strdup(offset+1); - else - def->source.data.tcp.service = strndup(offset+1, - offset2-(offset+1)); - if (def->source.data.tcp.service == NULL) - goto no_memory; - - if (offset2 && strstr(offset2, ",server")) - def->source.data.tcp.listen = true; - } - break; - - case VIR_DOMAIN_CHR_TYPE_UDP: - { - const char *offset = strchr(value, ':'); - const char *offset2, *offset3; - - if (offset == NULL) { - virXendError(VIR_ERR_INTERNAL_ERROR, - "%s", _("malformed char device string")); - goto error; - } - - if (offset != value && - (def->source.data.udp.connectHost - = strndup(value, offset - value)) == NULL) - goto no_memory; - - offset2 = strchr(offset, '@'); - if (offset2 != NULL) { - if ((def->source.data.udp.connectService - = strndup(offset + 1, offset2-(offset+1))) == NULL) - goto no_memory; - - offset3 = strchr(offset2, ':'); - if (offset3 == NULL) { - virXendError(VIR_ERR_INTERNAL_ERROR, - "%s", _("malformed char device string")); - goto error; - } - - if (offset3 > (offset2 + 1) && - (def->source.data.udp.bindHost - = strndup(offset2 + 1, offset3 - (offset2+1))) == NULL) - goto no_memory; - - if ((def->source.data.udp.bindService - = strdup(offset3 + 1)) == NULL) - goto no_memory; - } else { - if ((def->source.data.udp.connectService - = strdup(offset + 1)) == NULL) - goto no_memory; - } - } - break; - - case VIR_DOMAIN_CHR_TYPE_UNIX: - { - const char *offset = strchr(value, ','); - if (offset) - def->source.data.nix.path = strndup(value, (offset - value)); - else - def->source.data.nix.path = strdup(value); - if (def->source.data.nix.path == NULL) - goto no_memory; - - if (offset != NULL && - strstr(offset, ",server") != NULL) - def->source.data.nix.listen = true; - } - break; - } - - return def; - -no_memory: - virReportOOMError(); -error: - virDomainChrDefFree(def); - return NULL; -} - -/** - * xend_parse_sexp_desc_disks - * @conn: connection - * @root: root sexpr - * @xendConfigVersion: version of xend - * - * This parses out block devices from the domain sexpr - * - * Returns 0 if successful or -1 if failed. - */ -static int -xenDaemonParseSxprDisks(virDomainDefPtr def, - const struct sexpr *root, - int hvm, - int xendConfigVersion) -{ - const struct sexpr *cur, *node; - virDomainDiskDefPtr disk = NULL; - - for (cur = root; cur->kind == SEXPR_CONS; cur = cur->u.s.cdr) { - node = cur->u.s.car; - /* Normally disks are in a (device (vbd ...)) block - but blktap disks ended up in a differently named - (device (tap ....)) block.... */ - if (sexpr_lookup(node, "device/vbd") || - sexpr_lookup(node, "device/tap") || - sexpr_lookup(node, "device/tap2")) { - char *offset; - const char *src = NULL; - const char *dst = NULL; - const char *mode = NULL; - - /* Again dealing with (vbd...) vs (tap ...) differences */ - if (sexpr_lookup(node, "device/vbd")) { - src = sexpr_node(node, "device/vbd/uname"); - dst = sexpr_node(node, "device/vbd/dev"); - mode = sexpr_node(node, "device/vbd/mode"); - } else if (sexpr_lookup(node, "device/tap2")) { - src = sexpr_node(node, "device/tap2/uname"); - dst = sexpr_node(node, "device/tap2/dev"); - mode = sexpr_node(node, "device/tap2/mode"); - } else { - src = sexpr_node(node, "device/tap/uname"); - dst = sexpr_node(node, "device/tap/dev"); - mode = sexpr_node(node, "device/tap/mode"); - } - - if (VIR_ALLOC(disk) < 0) - goto no_memory; - - if (dst == NULL) { - virXendError(VIR_ERR_INTERNAL_ERROR, - "%s", _("domain information incomplete, vbd has no dev")); - goto error; - } - - if (src == NULL) { - /* There is a case without the uname to the CD-ROM device */ - offset = strchr(dst, ':'); - if (!offset || - !hvm || - STRNEQ(offset, ":cdrom")) { - virXendError(VIR_ERR_INTERNAL_ERROR, - "%s", _("domain information incomplete, vbd has no src")); - goto error; - } - } - - if (src != NULL) { - offset = strchr(src, ':'); - if (!offset) { - virXendError(VIR_ERR_INTERNAL_ERROR, - "%s", _("cannot parse vbd filename, missing driver name")); - goto error; - } - - if (VIR_ALLOC_N(disk->driverName, (offset-src)+1) < 0) - goto no_memory; - if (virStrncpy(disk->driverName, src, offset-src, - (offset-src)+1) == NULL) { - virXendError(VIR_ERR_INTERNAL_ERROR, - _("Driver name %s too big for destination"), - src); - goto error; - } - - src = offset + 1; - - if (STREQ (disk->driverName, "tap") || - STREQ (disk->driverName, "tap2")) { - offset = strchr(src, ':'); - if (!offset) { - virXendError(VIR_ERR_INTERNAL_ERROR, - "%s", _("cannot parse vbd filename, missing driver type")); - goto error; - } - - if (VIR_ALLOC_N(disk->driverType, (offset-src)+1)< 0) - goto no_memory; - if (virStrncpy(disk->driverType, src, offset-src, - (offset-src)+1) == NULL) { - virXendError(VIR_ERR_INTERNAL_ERROR, - _("Driver type %s too big for destination"), - src); - goto error; - } - - src = offset + 1; - /* Its possible to use blktap driver for block devs - too, but kinda pointless because blkback is better, - so we assume common case here. If blktap becomes - omnipotent, we can revisit this, perhaps stat()'ing - the src file in question */ - disk->type = VIR_DOMAIN_DISK_TYPE_FILE; - } else if (STREQ(disk->driverName, "phy")) { - disk->type = VIR_DOMAIN_DISK_TYPE_BLOCK; - } else if (STREQ(disk->driverName, "file")) { - disk->type = VIR_DOMAIN_DISK_TYPE_FILE; - } - } else { - /* No CDROM media so can't really tell. We'll just - call if a FILE for now and update when media - is inserted later */ - disk->type = VIR_DOMAIN_DISK_TYPE_FILE; - } - - if (STREQLEN (dst, "ioemu:", 6)) - dst += 6; - - disk->device = VIR_DOMAIN_DISK_DEVICE_DISK; - /* New style disk config from Xen >= 3.0.3 */ - if (xendConfigVersion > 1) { - offset = strrchr(dst, ':'); - if (offset) { - if (STREQ (offset, ":cdrom")) { - disk->device = VIR_DOMAIN_DISK_DEVICE_CDROM; - } else if (STREQ (offset, ":disk")) { - /* The default anyway */ - } else { - /* Unknown, lets pretend its a disk too */ - } - offset[0] = '\0'; - } - } - - if (!(disk->dst = strdup(dst))) - goto no_memory; - if (src && - !(disk->src = strdup(src))) - goto no_memory; - - if (STRPREFIX(disk->dst, "xvd")) - disk->bus = VIR_DOMAIN_DISK_BUS_XEN; - else if (STRPREFIX(disk->dst, "hd")) - disk->bus = VIR_DOMAIN_DISK_BUS_IDE; - else if (STRPREFIX(disk->dst, "sd")) - disk->bus = VIR_DOMAIN_DISK_BUS_SCSI; - else - disk->bus = VIR_DOMAIN_DISK_BUS_IDE; - - if (mode && - strchr(mode, 'r')) - disk->readonly = 1; - if (mode && - strchr(mode, '!')) - disk->shared = 1; - - if (VIR_REALLOC_N(def->disks, def->ndisks+1) < 0) - goto no_memory; - - def->disks[def->ndisks++] = disk; - disk = NULL; - } - } - - return 0; - -no_memory: - virReportOOMError(); - -error: - virDomainDiskDefFree(disk); - return -1; -} - - -static int -xenDaemonParseSxprNets(virDomainDefPtr def, - const struct sexpr *root) -{ - virDomainNetDefPtr net = NULL; - const struct sexpr *cur, *node; - const char *tmp; - int vif_index = 0; - - for (cur = root; cur->kind == SEXPR_CONS; cur = cur->u.s.cdr) { - node = cur->u.s.car; - if (sexpr_lookup(node, "device/vif")) { - const char *tmp2, *model, *type; - char buf[50]; - tmp2 = sexpr_node(node, "device/vif/script"); - tmp = sexpr_node(node, "device/vif/bridge"); - model = sexpr_node(node, "device/vif/model"); - type = sexpr_node(node, "device/vif/type"); - - if (VIR_ALLOC(net) < 0) - goto no_memory; - - if (tmp != NULL || - (tmp2 != NULL && STREQ(tmp2, DEFAULT_VIF_SCRIPT))) { - net->type = VIR_DOMAIN_NET_TYPE_BRIDGE; - /* XXX virtual network reverse resolve */ - - if (tmp && - !(net->data.bridge.brname = strdup(tmp))) - goto no_memory; - if (tmp2 && - net->type == VIR_DOMAIN_NET_TYPE_BRIDGE && - !(net->data.bridge.script = strdup(tmp2))) - goto no_memory; - tmp = sexpr_node(node, "device/vif/ip"); - if (tmp && - !(net->data.bridge.ipaddr = strdup(tmp))) - goto no_memory; - } else { - net->type = VIR_DOMAIN_NET_TYPE_ETHERNET; - if (tmp2 && - !(net->data.ethernet.script = strdup(tmp2))) - goto no_memory; - tmp = sexpr_node(node, "device/vif/ip"); - if (tmp && - !(net->data.ethernet.ipaddr = strdup(tmp))) - goto no_memory; - } - - tmp = sexpr_node(node, "device/vif/vifname"); - if (!tmp) { - snprintf(buf, sizeof(buf), "vif%d.%d", def->id, vif_index); - tmp = buf; - } - if (!(net->ifname = strdup(tmp))) - goto no_memory; - - tmp = sexpr_node(node, "device/vif/mac"); - if (tmp) { - if (virParseMacAddr(tmp, net->mac) < 0) { - virXendError(VIR_ERR_INTERNAL_ERROR, - _("malformed mac address '%s'"), tmp); - goto cleanup; - } - } - - if (model && - !(net->model = strdup(model))) - goto no_memory; - - if (!model && type && - STREQ(type, "netfront") && - !(net->model = strdup("netfront"))) - goto no_memory; - - if (VIR_REALLOC_N(def->nets, def->nnets + 1) < 0) - goto no_memory; - - def->nets[def->nnets++] = net; - vif_index++; - } - } - - return 0; - -no_memory: - virReportOOMError(); -cleanup: - virDomainNetDefFree(net); - return -1; -} - - -int -xenDaemonParseSxprSound(virDomainDefPtr def, - const char *str) -{ - if (STREQ(str, "all")) { - int i; - - /* - * Special compatability code for Xen with a bogus - * sound=all in config. - * - * NB delibrately, don't include all possible - * sound models anymore, just the 2 that were - * historically present in Xen's QEMU. - * - * ie just es1370 + sb16. - * - * Hence use of MODEL_ES1370 + 1, instead of MODEL_LAST - */ - - if (VIR_ALLOC_N(def->sounds, - VIR_DOMAIN_SOUND_MODEL_ES1370 + 1) < 0) - goto no_memory; - - - for (i = 0 ; i < (VIR_DOMAIN_SOUND_MODEL_ES1370 + 1) ; i++) { - virDomainSoundDefPtr sound; - if (VIR_ALLOC(sound) < 0) - goto no_memory; - sound->model = i; - def->sounds[def->nsounds++] = sound; - } - } else { - char model[10]; - const char *offset = str, *offset2; - - do { - int len; - virDomainSoundDefPtr sound; - offset2 = strchr(offset, ','); - if (offset2) - len = (offset2 - offset); - else - len = strlen(offset); - if (virStrncpy(model, offset, len, sizeof(model)) == NULL) { - virXendError(VIR_ERR_INTERNAL_ERROR, - _("Sound model %s too big for destination"), - offset); - goto error; - } - - if (VIR_ALLOC(sound) < 0) - goto no_memory; - - if ((sound->model = virDomainSoundModelTypeFromString(model)) < 0) { - VIR_FREE(sound); - goto error; - } - - if (VIR_REALLOC_N(def->sounds, def->nsounds+1) < 0) { - virDomainSoundDefFree(sound); - goto no_memory; - } - - def->sounds[def->nsounds++] = sound; - offset = offset2 ? offset2 + 1 : NULL; - } while (offset); - } - - return 0; - -no_memory: - virReportOOMError(); -error: - return -1; -} - - -static int -xenDaemonParseSxprUSB(virDomainDefPtr def, - const struct sexpr *root) -{ - struct sexpr *cur, *node; - const char *tmp; - - for (cur = sexpr_lookup(root, "domain/image/hvm"); cur && cur->kind == SEXPR_CONS; cur = cur->u.s.cdr) { - node = cur->u.s.car; - if (sexpr_lookup(node, "usbdevice")) { - tmp = sexpr_node(node, "usbdevice"); - if (tmp && *tmp) { - if (STREQ(tmp, "tablet") || - STREQ(tmp, "mouse")) { - virDomainInputDefPtr input; - if (VIR_ALLOC(input) < 0) - goto no_memory; - input->bus = VIR_DOMAIN_INPUT_BUS_USB; - if (STREQ(tmp, "tablet")) - input->type = VIR_DOMAIN_INPUT_TYPE_TABLET; - else - input->type = VIR_DOMAIN_INPUT_TYPE_MOUSE; - - if (VIR_REALLOC_N(def->inputs, def->ninputs+1) < 0) { - VIR_FREE(input); - goto no_memory; - } - def->inputs[def->ninputs++] = input; - } else { - /* XXX Handle other non-input USB devices later */ - } - } - } - } - return 0; - -no_memory: - virReportOOMError(); - return -1; -} - -static int -xenDaemonParseSxprGraphicsOld(virConnectPtr conn, - virDomainDefPtr def, - const struct sexpr *root, - int hvm, - int xendConfigVersion) -{ - xenUnifiedPrivatePtr priv = conn->privateData; - const char *tmp; - virDomainGraphicsDefPtr graphics = NULL; - - if ((tmp = sexpr_fmt_node(root, "domain/image/%s/vnc", hvm ? "hvm" : "linux")) && - tmp[0] == '1') { - /* Graphics device (HVM, or old (pre-3.0.4) style PV VNC config) */ - int port; - const char *listenAddr = sexpr_fmt_node(root, "domain/image/%s/vnclisten", hvm ? "hvm" : "linux"); - const char *vncPasswd = sexpr_fmt_node(root, "domain/image/%s/vncpasswd", hvm ? "hvm" : "linux"); - const char *keymap = sexpr_fmt_node(root, "domain/image/%s/keymap", hvm ? "hvm" : "linux"); - const char *unused = sexpr_fmt_node(root, "domain/image/%s/vncunused", hvm ? "hvm" : "linux"); - - xenUnifiedLock(priv); - port = xenStoreDomainGetVNCPort(conn, def->id); - xenUnifiedUnlock(priv); - - if (VIR_ALLOC(graphics) < 0) - goto no_memory; - - graphics->type = VIR_DOMAIN_GRAPHICS_TYPE_VNC; - /* For Xen >= 3.0.3, don't generate a fixed port mapping - * because it will almost certainly be wrong ! Just leave - * it as -1 which lets caller see that the VNC server isn't - * present yet. Subsquent dumps of the XML will eventually - * find the port in XenStore once VNC server has started - */ - if (port == -1 && xendConfigVersion < 2) - port = 5900 + def->id; - - if ((unused && STREQ(unused, "1")) || port == -1) - graphics->data.vnc.autoport = 1; - graphics->data.vnc.port = port; - - if (listenAddr && - !(graphics->data.vnc.listenAddr = strdup(listenAddr))) - goto no_memory; - - if (vncPasswd && - !(graphics->data.vnc.auth.passwd = strdup(vncPasswd))) - goto no_memory; - - if (keymap && - !(graphics->data.vnc.keymap = strdup(keymap))) - goto no_memory; - - if (VIR_ALLOC_N(def->graphics, 1) < 0) - goto no_memory; - def->graphics[0] = graphics; - def->ngraphics = 1; - graphics = NULL; - } else if ((tmp = sexpr_fmt_node(root, "domain/image/%s/sdl", hvm ? "hvm" : "linux")) && - tmp[0] == '1') { - /* Graphics device (HVM, or old (pre-3.0.4) style PV sdl config) */ - const char *display = sexpr_fmt_node(root, "domain/image/%s/display", hvm ? "hvm" : "linux"); - const char *xauth = sexpr_fmt_node(root, "domain/image/%s/xauthority", hvm ? "hvm" : "linux"); - - if (VIR_ALLOC(graphics) < 0) - goto no_memory; - - graphics->type = VIR_DOMAIN_GRAPHICS_TYPE_SDL; - if (display && - !(graphics->data.sdl.display = strdup(display))) - goto no_memory; - if (xauth && - !(graphics->data.sdl.xauth = strdup(xauth))) - goto no_memory; - - if (VIR_ALLOC_N(def->graphics, 1) < 0) - goto no_memory; - def->graphics[0] = graphics; - def->ngraphics = 1; - graphics = NULL; - } - - return 0; - -no_memory: - virReportOOMError(); - virDomainGraphicsDefFree(graphics); - return -1; -} - - -static int -xenDaemonParseSxprGraphicsNew(virConnectPtr conn, - virDomainDefPtr def, - const struct sexpr *root) -{ - xenUnifiedPrivatePtr priv = conn->privateData; - virDomainGraphicsDefPtr graphics = NULL; - const struct sexpr *cur, *node; - const char *tmp; - - /* append network devices and framebuffer */ - for (cur = root; cur->kind == SEXPR_CONS; cur = cur->u.s.cdr) { - node = cur->u.s.car; - if (sexpr_lookup(node, "device/vfb")) { - /* New style graphics config for PV guests in >= 3.0.4, - * or for HVM guests in >= 3.0.5 */ - if (sexpr_node(node, "device/vfb/type")) { - tmp = sexpr_node(node, "device/vfb/type"); - } else if (sexpr_node(node, "device/vfb/vnc")) { - tmp = "vnc"; - } else if (sexpr_node(node, "device/vfb/sdl")) { - tmp = "sdl"; - } else { - tmp = "unknown"; - } - - if (VIR_ALLOC(graphics) < 0) - goto no_memory; - - if ((graphics->type = virDomainGraphicsTypeFromString(tmp)) < 0) { - virXendError(VIR_ERR_INTERNAL_ERROR, - _("unknown graphics type '%s'"), tmp); - goto error; - } - - if (graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) { - const char *display = sexpr_node(node, "device/vfb/display"); - const char *xauth = sexpr_node(node, "device/vfb/xauthority"); - if (display && - !(graphics->data.sdl.display = strdup(display))) - goto no_memory; - if (xauth && - !(graphics->data.sdl.xauth = strdup(xauth))) - goto no_memory; - } else { - int port; - const char *listenAddr = sexpr_node(node, "device/vfb/vnclisten"); - const char *vncPasswd = sexpr_node(node, "device/vfb/vncpasswd"); - const char *keymap = sexpr_node(node, "device/vfb/keymap"); - const char *unused = sexpr_node(node, "device/vfb/vncunused"); - - xenUnifiedLock(priv); - port = xenStoreDomainGetVNCPort(conn, def->id); - xenUnifiedUnlock(priv); - - /* Didn't find port entry in xenstore */ - if (port == -1) { - const char *str = sexpr_node(node, "device/vfb/vncdisplay"); - int val; - if (str != NULL && virStrToLong_i(str, NULL, 0, &val) == 0) - port = val; - } - - if ((unused && STREQ(unused, "1")) || port == -1) - graphics->data.vnc.autoport = 1; - - if (port >= 0 && port < 5900) - port += 5900; - graphics->data.vnc.port = port; - - if (listenAddr && - !(graphics->data.vnc.listenAddr = strdup(listenAddr))) - goto no_memory; - - if (vncPasswd && - !(graphics->data.vnc.auth.passwd = strdup(vncPasswd))) - goto no_memory; - - if (keymap && - !(graphics->data.vnc.keymap = strdup(keymap))) - goto no_memory; - } - - if (VIR_ALLOC_N(def->graphics, 1) < 0) - goto no_memory; - def->graphics[0] = graphics; - def->ngraphics = 1; - graphics = NULL; - break; - } - } - - return 0; - -no_memory: - virReportOOMError(); -error: - virDomainGraphicsDefFree(graphics); - return -1; -} - -/** - * xenDaemonParseSxprPCI - * @root: root sexpr - * - * This parses out block devices from the domain sexpr - * - * Returns 0 if successful or -1 if failed. - */ -static int -xenDaemonParseSxprPCI(virDomainDefPtr def, - const struct sexpr *root) -{ - const struct sexpr *cur, *tmp = NULL, *node; - virDomainHostdevDefPtr dev = NULL; - - /* - * With the (domain ...) block we have the following odd setup - * - * (device - * (pci - * (dev (domain 0x0000) (bus 0x00) (slot 0x1b) (func 0x0)) - * (dev (domain 0x0000) (bus 0x00) (slot 0x13) (func 0x0)) - * ) - * ) - * - * Normally there is one (device ...) block per device, but in - * wierd world of Xen PCI, once (device ...) covers multiple - * devices. - */ - - for (cur = root; cur->kind == SEXPR_CONS; cur = cur->u.s.cdr) { - node = cur->u.s.car; - if ((tmp = sexpr_lookup(node, "device/pci")) != NULL) - break; - } - - if (!tmp) - return 0; - - for (cur = tmp; cur->kind == SEXPR_CONS; cur = cur->u.s.cdr) { - const char *domain = NULL; - const char *bus = NULL; - const char *slot = NULL; - const char *func = NULL; - int domainID; - int busID; - int slotID; - int funcID; - - node = cur->u.s.car; - if (!sexpr_lookup(node, "dev")) - continue; - - if (!(domain = sexpr_node(node, "dev/domain"))) { - virXendError(VIR_ERR_INTERNAL_ERROR, - "%s", _("missing PCI domain")); - goto error; - } - if (!(bus = sexpr_node(node, "dev/bus"))) { - virXendError(VIR_ERR_INTERNAL_ERROR, - "%s", _("missing PCI bus")); - goto error; - } - if (!(slot = sexpr_node(node, "dev/slot"))) { - virXendError(VIR_ERR_INTERNAL_ERROR, - "%s", _("missing PCI slot")); - goto error; - } - if (!(func = sexpr_node(node, "dev/func"))) { - virXendError(VIR_ERR_INTERNAL_ERROR, - "%s", _("missing PCI func")); - goto error; - } - - if (virStrToLong_i(domain, NULL, 0, &domainID) < 0) { - virXendError(VIR_ERR_INTERNAL_ERROR, - _("cannot parse PCI domain '%s'"), domain); - goto error; - } - if (virStrToLong_i(bus, NULL, 0, &busID) < 0) { - virXendError(VIR_ERR_INTERNAL_ERROR, - _("cannot parse PCI bus '%s'"), bus); - goto error; - } - if (virStrToLong_i(slot, NULL, 0, &slotID) < 0) { - virXendError(VIR_ERR_INTERNAL_ERROR, - _("cannot parse PCI slot '%s'"), slot); - goto error; - } - if (virStrToLong_i(func, NULL, 0, &funcID) < 0) { - virXendError(VIR_ERR_INTERNAL_ERROR, - _("cannot parse PCI func '%s'"), func); - goto error; - } - - if (VIR_ALLOC(dev) < 0) - goto no_memory; - - dev->mode = VIR_DOMAIN_HOSTDEV_MODE_SUBSYS; - dev->managed = 0; - dev->source.subsys.type = VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI; - dev->source.subsys.u.pci.domain = domainID; - dev->source.subsys.u.pci.bus = busID; - dev->source.subsys.u.pci.slot = slotID; - dev->source.subsys.u.pci.function = funcID; - - if (VIR_REALLOC_N(def->hostdevs, def->nhostdevs+1) < 0) { - goto no_memory; - } - - def->hostdevs[def->nhostdevs++] = dev; - } - - return 0; - -no_memory: - virReportOOMError(); - -error: - virDomainHostdevDefFree(dev); - return -1; -} - - -/** - * xenDaemonParseSxpr: - * @conn: the connection associated with the XML - * @root: the root of the parsed S-Expression - * @xendConfigVersion: version of xend - * @cpus: set of cpus the domain may be pinned to - * - * Parse the xend sexp description and turn it into the XML format similar - * to the one unsed for creation. - * - * Returns the 0 terminated XML string or NULL in case of error. - * the caller must free() the returned value. - */ -static virDomainDefPtr -xenDaemonParseSxpr(virConnectPtr conn, - const struct sexpr *root, - int xendConfigVersion, - const char *cpus) -{ - xenUnifiedPrivatePtr priv = conn->privateData; - const char *tmp; - virDomainDefPtr def; - int hvm = 0; - char *tty = NULL; - - if (VIR_ALLOC(def) < 0) - goto no_memory; - - tmp = sexpr_node(root, "domain/domid"); - if (tmp == NULL && xendConfigVersion < 3) { /* Old XenD, domid was mandatory */ - virXendError(VIR_ERR_INTERNAL_ERROR, - "%s", _("domain information incomplete, missing id")); - goto error; - } - def->virtType = VIR_DOMAIN_VIRT_XEN; - if (tmp) - def->id = sexpr_int(root, "domain/domid"); - else - def->id = -1; - - if (sexpr_node_copy(root, "domain/name", &def->name) < 0) - goto no_memory; - if (def->name == NULL) { - virXendError(VIR_ERR_INTERNAL_ERROR, - "%s", _("domain information incomplete, missing name")); - goto error; - } - - tmp = sexpr_node(root, "domain/uuid"); - if (tmp == NULL) { - virXendError(VIR_ERR_INTERNAL_ERROR, - "%s", _("domain information incomplete, missing name")); - goto error; - } - virUUIDParse(tmp, def->uuid); - - if (sexpr_node_copy(root, "domain/description", &def->description) < 0) - goto no_memory; - - hvm = sexpr_lookup(root, "domain/image/hvm") ? 1 : 0; - if (!hvm) { - if (sexpr_node_copy(root, "domain/bootloader", - &def->os.bootloader) < 0) - goto no_memory; - - if (!def->os.bootloader && - sexpr_has(root, "domain/bootloader") && - (def->os.bootloader = strdup("")) == NULL) - goto no_memory; - - if (def->os.bootloader && - sexpr_node_copy(root, "domain/bootloader_args", - &def->os.bootloaderArgs) < 0) - goto no_memory; - } - - if (!(def->os.type = strdup(hvm ? "hvm" : "linux"))) - goto no_memory; - - if (def->id != 0) { - if (sexpr_lookup(root, "domain/image")) { - if (xenDaemonParseSxprOS(root, def, hvm) < 0) - goto error; - } - } - - def->mem.max_balloon = (unsigned long) - (sexpr_u64(root, "domain/maxmem") << 10); - def->mem.cur_balloon = (unsigned long) - (sexpr_u64(root, "domain/memory") << 10); - if (def->mem.cur_balloon > def->mem.max_balloon) - def->mem.cur_balloon = def->mem.max_balloon; - - if (cpus != NULL) { - def->cpumasklen = VIR_DOMAIN_CPUMASK_LEN; - if (VIR_ALLOC_N(def->cpumask, def->cpumasklen) < 0) { - virReportOOMError(); - goto error; - } - - if (virDomainCpuSetParse(&cpus, - 0, def->cpumask, - def->cpumasklen) < 0) { - virXendError(VIR_ERR_INTERNAL_ERROR, - _("invalid CPU mask %s"), cpus); - goto error; - } - } - - def->maxvcpus = sexpr_int(root, "domain/vcpus"); - def->vcpus = count_one_bits_l(sexpr_u64(root, "domain/vcpu_avail")); - if (!def->vcpus || def->maxvcpus < def->vcpus) - def->vcpus = def->maxvcpus; - - tmp = sexpr_node(root, "domain/on_poweroff"); - if (tmp != NULL) { - if ((def->onPoweroff = virDomainLifecycleTypeFromString(tmp)) < 0) { - virXendError(VIR_ERR_INTERNAL_ERROR, - _("unknown lifecycle type %s"), tmp); - goto error; - } - } else - def->onPoweroff = VIR_DOMAIN_LIFECYCLE_DESTROY; - - tmp = sexpr_node(root, "domain/on_reboot"); - if (tmp != NULL) { - if ((def->onReboot = virDomainLifecycleTypeFromString(tmp)) < 0) { - virXendError(VIR_ERR_INTERNAL_ERROR, - _("unknown lifecycle type %s"), tmp); - goto error; - } - } else - def->onReboot = VIR_DOMAIN_LIFECYCLE_RESTART; - - tmp = sexpr_node(root, "domain/on_crash"); - if (tmp != NULL) { - if ((def->onCrash = virDomainLifecycleCrashTypeFromString(tmp)) < 0) { - virXendError(VIR_ERR_INTERNAL_ERROR, - _("unknown lifecycle type %s"), tmp); - goto error; - } - } else - def->onCrash = VIR_DOMAIN_LIFECYCLE_DESTROY; - - def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_UTC; - if (hvm) { - if (sexpr_int(root, "domain/image/hvm/acpi")) - def->features |= (1 << VIR_DOMAIN_FEATURE_ACPI); - if (sexpr_int(root, "domain/image/hvm/apic")) - def->features |= (1 << VIR_DOMAIN_FEATURE_APIC); - if (sexpr_int(root, "domain/image/hvm/pae")) - def->features |= (1 << VIR_DOMAIN_FEATURE_PAE); - if (sexpr_int(root, "domain/image/hvm/hap")) - def->features |= (1 << VIR_DOMAIN_FEATURE_HAP); - - /* Old XenD only allows localtime here for HVM */ - if (sexpr_int(root, "domain/image/hvm/localtime")) - def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME; - } - - /* Current XenD allows localtime here, for PV and HVM */ - if (sexpr_int(root, "domain/localtime")) - def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME; - - if (sexpr_node_copy(root, hvm ? - "domain/image/hvm/device_model" : - "domain/image/linux/device_model", - &def->emulator) < 0) - goto no_memory; - - /* append block devices */ - if (xenDaemonParseSxprDisks(def, root, hvm, xendConfigVersion) < 0) - goto error; - - if (xenDaemonParseSxprNets(def, root) < 0) - goto error; - - if (xenDaemonParseSxprPCI(def, root) < 0) - goto error; - - /* New style graphics device config */ - if (xenDaemonParseSxprGraphicsNew(conn, def, root) < 0) - goto error; - - /* Graphics device (HVM <= 3.0.4, or PV <= 3.0.3) vnc config */ - if ((def->ngraphics == 0) && - xenDaemonParseSxprGraphicsOld(conn, def, root, hvm, xendConfigVersion) < 0) - goto error; - - - /* Old style cdrom config from Xen <= 3.0.2 */ - if (hvm && - xendConfigVersion == 1) { - tmp = sexpr_node(root, "domain/image/hvm/cdrom"); - if ((tmp != NULL) && (tmp[0] != 0)) { - virDomainDiskDefPtr disk; - if (VIR_ALLOC(disk) < 0) - goto no_memory; - if (!(disk->src = strdup(tmp))) { - virDomainDiskDefFree(disk); - goto no_memory; - } - disk->type = VIR_DOMAIN_DISK_TYPE_FILE; - disk->device = VIR_DOMAIN_DISK_DEVICE_CDROM; - if (!(disk->dst = strdup("hdc"))) { - virDomainDiskDefFree(disk); - goto no_memory; - } - if (!(disk->driverName = strdup("file"))) { - virDomainDiskDefFree(disk); - goto no_memory; - } - disk->bus = VIR_DOMAIN_DISK_BUS_IDE; - disk->readonly = 1; - - if (VIR_REALLOC_N(def->disks, def->ndisks+1) < 0) { - virDomainDiskDefFree(disk); - goto no_memory; - } - def->disks[def->ndisks++] = disk; - } - } - - - /* Floppy disk config */ - if (hvm) { - const char *const fds[] = { "fda", "fdb" }; - int i; - for (i = 0 ; i < ARRAY_CARDINALITY(fds) ; i++) { - tmp = sexpr_fmt_node(root, "domain/image/hvm/%s", fds[i]); - if ((tmp != NULL) && (tmp[0] != 0)) { - virDomainDiskDefPtr disk; - if (VIR_ALLOC(disk) < 0) - goto no_memory; - if (!(disk->src = strdup(tmp))) { - VIR_FREE(disk); - goto no_memory; - } - disk->type = VIR_DOMAIN_DISK_TYPE_FILE; - disk->device = VIR_DOMAIN_DISK_DEVICE_FLOPPY; - if (!(disk->dst = strdup(fds[i]))) { - virDomainDiskDefFree(disk); - goto no_memory; - } - if (!(disk->driverName = strdup("file"))) { - virDomainDiskDefFree(disk); - goto no_memory; - } - disk->bus = VIR_DOMAIN_DISK_BUS_FDC; - - if (VIR_REALLOC_N(def->disks, def->ndisks+1) < 0) { - virDomainDiskDefFree(disk); - goto no_memory; - } - def->disks[def->ndisks++] = disk; - } - } - } - - /* in case of HVM we have USB device emulation */ - if (hvm && - xenDaemonParseSxprUSB(def, root) < 0) - goto error; - - /* Character device config */ - xenUnifiedLock(priv); - tty = xenStoreDomainGetConsolePath(conn, def->id); - xenUnifiedUnlock(priv); - if (hvm) { - tmp = sexpr_node(root, "domain/image/hvm/serial"); - if (tmp && STRNEQ(tmp, "none")) { - virDomainChrDefPtr chr; - if ((chr = xenDaemonParseSxprChar(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; - /* XXX does XenD stuff parallel port tty info into xenstore somewhere ? */ - if ((chr = xenDaemonParseSxprChar(tmp, NULL)) == NULL) - goto error; - if (VIR_REALLOC_N(def->parallels, def->nparallels+1) < 0) { - virDomainChrDefFree(chr); - goto no_memory; - } - chr->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL; - def->parallels[def->nparallels++] = chr; - } - } else { - /* Fake a paravirt console, since that's not in the sexpr */ - if (!(def->console = xenDaemonParseSxprChar("pty", tty))) - goto error; - def->console->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE; - def->console->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_XEN; - } - VIR_FREE(tty); - - - /* Sound device config */ - if (hvm && - (tmp = sexpr_node(root, "domain/image/hvm/soundhw")) != NULL && - *tmp) { - if (xenDaemonParseSxprSound(def, tmp) < 0) - goto error; - } - - return def; - -no_memory: - virReportOOMError(); -error: - VIR_FREE(tty); - virDomainDefFree(def); - return NULL; -} - -virDomainDefPtr -xenDaemonParseSxprString(virConnectPtr conn, - const char *sexpr, - int xendConfigVersion) -{ - struct sexpr *root = string2sexpr(sexpr); - virDomainDefPtr def; - - if (!root) - return NULL; - - def = xenDaemonParseSxpr(conn, root, xendConfigVersion, NULL); - - sexpr_free(root); - - return def; -} - - /** * sexpr_to_xend_domain_info: * @root: an S-Expression describing a domain @@ -3098,6 +1798,9 @@ xenDaemonDomainFetch(virConnectPtr conn, struct sexpr *root; xenUnifiedPrivatePtr priv; virDomainDefPtr def; + int id; + char * tty; + int vncport; if (name) root = sexpr_get(conn, "/xend/domain/%s?detail=1", name); @@ -3112,10 +1815,16 @@ xenDaemonDomainFetch(virConnectPtr conn, priv = (xenUnifiedPrivatePtr) conn->privateData; - if (!(def = xenDaemonParseSxpr(conn, - root, + id = xenGetDomIdFromSxpr(root, priv->xendConfigVersion); + xenUnifiedLock(priv); + tty = xenStoreDomainGetConsolePath(conn, id); + vncport = xenStoreDomainGetVNCPort(conn, id); + xenUnifiedUnlock(priv); + if (!(def = xenDaemonParseSxpr(root, priv->xendConfigVersion, - cpus))) + cpus, + tty, + vncport))) goto cleanup; cleanup: @@ -5043,6 +3752,9 @@ xenDaemonDomainBlockPeek (virDomainPtr domain, const char *path, int fd = -1, ret = -1; int found = 0, i; virDomainDefPtr def; + int id; + char * tty; + int vncport; priv = (xenUnifiedPrivatePtr) domain->conn->privateData; @@ -5068,7 +3780,14 @@ xenDaemonDomainBlockPeek (virDomainPtr domain, const char *path, return -1; } - if (!(def = xenDaemonParseSxpr(domain->conn, root, priv->xendConfigVersion, NULL))) + id = xenGetDomIdFromSxpr(root, priv->xendConfigVersion); + xenUnifiedLock(priv); + tty = xenStoreDomainGetConsolePath(domain->conn, id); + vncport = xenStoreDomainGetVNCPort(domain->conn, id); + xenUnifiedUnlock(priv); + + if (!(def = xenDaemonParseSxpr(root, priv->xendConfigVersion, NULL, tty, + vncport))) goto cleanup; for (i = 0 ; i < def->ndisks ; i++) { diff --git a/src/xen/xend_internal.h b/src/xen/xend_internal.h index 53f5d2c0be813883c684c967261f681ac68e2b29..8603a082ffe973667cf50c77c741b9788db84220 100644 --- a/src/xen/xend_internal.h +++ b/src/xen/xend_internal.h @@ -27,12 +27,6 @@ # include "driver.h" # include "buf.h" -# ifdef __sun -# define DEFAULT_VIF_SCRIPT "vif-vnic" -# else -# define DEFAULT_VIF_SCRIPT "vif-bridge" -# endif - int xenDaemonOpen_unix(virConnectPtr conn, const char *path); @@ -96,18 +90,6 @@ xenDaemonDomainFetch(virConnectPtr xend, const char *name, const char *cpus); -virDomainDefPtr -xenDaemonParseSxprString(virConnectPtr conn, - const char *sexpr, - int xendConfigVersion); - -int -xenDaemonParseSxprSound(virDomainDefPtr def, - const char *str); - -virDomainChrDefPtr -xenDaemonParseSxprChar(const char *value, - const char *tty); int xenDaemonFormatSxprChr(virDomainChrDefPtr def, diff --git a/src/xen/xm_internal.c b/src/xen/xm_internal.c index bc304f077a284071b03eeda591df0151cb7dd146..ba30ffb9e818d4730d452978f496cf0e988ce0be 100644 --- a/src/xen/xm_internal.c +++ b/src/xen/xm_internal.c @@ -40,6 +40,7 @@ #include "xm_internal.h" #include "xen_driver.h" #include "xend_internal.h" +#include "xen_sxpr.h" #include "hash.h" #include "buf.h" #include "uuid.h" diff --git a/src/xenxs/xen_sxpr.c b/src/xenxs/xen_sxpr.c new file mode 100644 index 0000000000000000000000000000000000000000..edd0fb41b9fb1cf74a73dc0afef4676d61aa495d --- /dev/null +++ b/src/xenxs/xen_sxpr.c @@ -0,0 +1,1351 @@ +/* + * xen_sxpr.c: Xen SEXPR parsing functions + * + * Copyright (C) 2011 Univention GmbH + * Copyright (C) 2010-2011 Red Hat, Inc. + * Copyright (C) 2005 Anthony Liguori + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Anthony Liguori + * Author: Daniel Veillard + * Author: Markus Groß + */ + +#include + +#include "internal.h" +#include "virterror_internal.h" +#include "conf.h" +#include "memory.h" +#include "verify.h" +#include "uuid.h" +#include "logging.h" +#include "count-one-bits.h" +#include "xenxs_private.h" +#include "xen_sxpr.h" + +/* Get a domain id from a sexpr string */ +int xenGetDomIdFromSxprString(const char *sexpr, int xendConfigVersion) +{ + struct sexpr *root = string2sexpr(sexpr); + + if (!root) + return -1; + + int id = xenGetDomIdFromSxpr(root, xendConfigVersion); + sexpr_free(root); + return id; +} + +/* Get a domain id from a sexpr */ +int xenGetDomIdFromSxpr(const struct sexpr *root, int xendConfigVersion) +{ + int id = -1; + const char * tmp = sexpr_node(root, "domain/domid"); + if (tmp == NULL && xendConfigVersion < 3) { /* Old XenD, domid was mandatory */ + XENXS_ERROR(VIR_ERR_INTERNAL_ERROR, + "%s", _("domain information incomplete, missing id")); + } else { + id = tmp ? sexpr_int(root, "domain/domid") : -1; + } + return id; +} + +/***************************************************************** + ****** + ****** Parsing of SEXPR into virDomainDef objects + ****** + *****************************************************************/ + +/** + * xenDaemonParseSxprOS + * @node: the root of the parsed S-Expression + * @def: the domain config + * @hvm: true or 1 if no contains HVM S-Expression + * @bootloader: true or 1 if a bootloader is defined + * + * Parse the xend sexp for description of os and append it to buf. + * + * Returns 0 in case of success and -1 in case of error + */ +static int +xenDaemonParseSxprOS(const struct sexpr *node, + virDomainDefPtr def, + int hvm) +{ + if (hvm) { + if (sexpr_node_copy(node, "domain/image/hvm/loader", &def->os.loader) < 0) + goto no_memory; + if (def->os.loader == NULL) { + if (sexpr_node_copy(node, "domain/image/hvm/kernel", &def->os.loader) < 0) + goto no_memory; + + if (def->os.loader == NULL) { + XENXS_ERROR(VIR_ERR_INTERNAL_ERROR, + "%s", _("domain information incomplete, missing HVM loader")); + return(-1); + } + } else { + if (sexpr_node_copy(node, "domain/image/hvm/kernel", &def->os.kernel) < 0) + goto no_memory; + if (sexpr_node_copy(node, "domain/image/hvm/ramdisk", &def->os.initrd) < 0) + goto no_memory; + if (sexpr_node_copy(node, "domain/image/hvm/args", &def->os.cmdline) < 0) + goto no_memory; + if (sexpr_node_copy(node, "domain/image/hvm/root", &def->os.root) < 0) + goto no_memory; + } + } else { + if (sexpr_node_copy(node, "domain/image/linux/kernel", &def->os.kernel) < 0) + goto no_memory; + if (sexpr_node_copy(node, "domain/image/linux/ramdisk", &def->os.initrd) < 0) + goto no_memory; + if (sexpr_node_copy(node, "domain/image/linux/args", &def->os.cmdline) < 0) + goto no_memory; + if (sexpr_node_copy(node, "domain/image/linux/root", &def->os.root) < 0) + goto no_memory; + } + + /* If HVM kenrel == loader, then old xend, so kill off kernel */ + if (hvm && + def->os.kernel && + STREQ(def->os.kernel, def->os.loader)) { + VIR_FREE(def->os.kernel); + } + + if (!def->os.kernel && + hvm) { + const char *boot = sexpr_node(node, "domain/image/hvm/boot"); + if ((boot != NULL) && (boot[0] != 0)) { + while (*boot && + def->os.nBootDevs < VIR_DOMAIN_BOOT_LAST) { + if (*boot == 'a') + def->os.bootDevs[def->os.nBootDevs++] = VIR_DOMAIN_BOOT_FLOPPY; + else if (*boot == 'c') + def->os.bootDevs[def->os.nBootDevs++] = VIR_DOMAIN_BOOT_DISK; + else if (*boot == 'd') + def->os.bootDevs[def->os.nBootDevs++] = VIR_DOMAIN_BOOT_CDROM; + else if (*boot == 'n') + def->os.bootDevs[def->os.nBootDevs++] = VIR_DOMAIN_BOOT_NET; + boot++; + } + } + } + + if (!hvm && + !def->os.kernel && + !def->os.bootloader) { + XENXS_ERROR(VIR_ERR_INTERNAL_ERROR, + "%s", _("domain information incomplete, missing kernel & bootloader")); + return -1; + } + + return 0; + +no_memory: + virReportOOMError(); + return -1; +} + +virDomainChrDefPtr +xenDaemonParseSxprChar(const char *value, + const char *tty) +{ + const char *prefix; + char *tmp; + virDomainChrDefPtr def; + + if (VIR_ALLOC(def) < 0) { + virReportOOMError(); + return NULL; + } + + prefix = value; + + if (value[0] == '/') { + def->source.type = VIR_DOMAIN_CHR_TYPE_DEV; + } else { + if ((tmp = strchr(value, ':')) != NULL) { + *tmp = '\0'; + value = tmp + 1; + } + + if (STRPREFIX(prefix, "telnet")) { + def->source.type = VIR_DOMAIN_CHR_TYPE_TCP; + def->source.data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET; + } else { + if ((def->source.type = virDomainChrTypeFromString(prefix)) < 0) { + XENXS_ERROR(VIR_ERR_INTERNAL_ERROR, + _("unknown chr device type '%s'"), prefix); + goto error; + } + } + } + + /* Compat with legacy syntax */ + switch (def->source.type) { + case VIR_DOMAIN_CHR_TYPE_PTY: + if (tty != NULL && + !(def->source.data.file.path = strdup(tty))) + goto no_memory; + break; + + case VIR_DOMAIN_CHR_TYPE_FILE: + case VIR_DOMAIN_CHR_TYPE_PIPE: + if (!(def->source.data.file.path = strdup(value))) + goto no_memory; + break; + + case VIR_DOMAIN_CHR_TYPE_TCP: + { + const char *offset = strchr(value, ':'); + const char *offset2; + + if (offset == NULL) { + XENXS_ERROR(VIR_ERR_INTERNAL_ERROR, + "%s", _("malformed char device string")); + goto error; + } + + if (offset != value && + (def->source.data.tcp.host = strndup(value, + offset - value)) == NULL) + goto no_memory; + + offset2 = strchr(offset, ','); + if (offset2 == NULL) + def->source.data.tcp.service = strdup(offset+1); + else + def->source.data.tcp.service = strndup(offset+1, + offset2-(offset+1)); + if (def->source.data.tcp.service == NULL) + goto no_memory; + + if (offset2 && strstr(offset2, ",server")) + def->source.data.tcp.listen = true; + } + break; + + case VIR_DOMAIN_CHR_TYPE_UDP: + { + const char *offset = strchr(value, ':'); + const char *offset2, *offset3; + + if (offset == NULL) { + XENXS_ERROR(VIR_ERR_INTERNAL_ERROR, + "%s", _("malformed char device string")); + goto error; + } + + if (offset != value && + (def->source.data.udp.connectHost + = strndup(value, offset - value)) == NULL) + goto no_memory; + + offset2 = strchr(offset, '@'); + if (offset2 != NULL) { + if ((def->source.data.udp.connectService + = strndup(offset + 1, offset2-(offset+1))) == NULL) + goto no_memory; + + offset3 = strchr(offset2, ':'); + if (offset3 == NULL) { + XENXS_ERROR(VIR_ERR_INTERNAL_ERROR, + "%s", _("malformed char device string")); + goto error; + } + + if (offset3 > (offset2 + 1) && + (def->source.data.udp.bindHost + = strndup(offset2 + 1, offset3 - (offset2+1))) == NULL) + goto no_memory; + + if ((def->source.data.udp.bindService + = strdup(offset3 + 1)) == NULL) + goto no_memory; + } else { + if ((def->source.data.udp.connectService + = strdup(offset + 1)) == NULL) + goto no_memory; + } + } + break; + + case VIR_DOMAIN_CHR_TYPE_UNIX: + { + const char *offset = strchr(value, ','); + if (offset) + def->source.data.nix.path = strndup(value, (offset - value)); + else + def->source.data.nix.path = strdup(value); + if (def->source.data.nix.path == NULL) + goto no_memory; + + if (offset != NULL && + strstr(offset, ",server") != NULL) + def->source.data.nix.listen = true; + } + break; + } + + return def; + +no_memory: + virReportOOMError(); +error: + virDomainChrDefFree(def); + return NULL; +} + +/** + * xend_parse_sexp_desc_disks + * @conn: connection + * @root: root sexpr + * @xendConfigVersion: version of xend + * + * This parses out block devices from the domain sexpr + * + * Returns 0 if successful or -1 if failed. + */ +static int +xenDaemonParseSxprDisks(virDomainDefPtr def, + const struct sexpr *root, + int hvm, + int xendConfigVersion) +{ + const struct sexpr *cur, *node; + virDomainDiskDefPtr disk = NULL; + + for (cur = root; cur->kind == SEXPR_CONS; cur = cur->u.s.cdr) { + node = cur->u.s.car; + /* Normally disks are in a (device (vbd ...)) block + but blktap disks ended up in a differently named + (device (tap ....)) block.... */ + if (sexpr_lookup(node, "device/vbd") || + sexpr_lookup(node, "device/tap") || + sexpr_lookup(node, "device/tap2")) { + char *offset; + const char *src = NULL; + const char *dst = NULL; + const char *mode = NULL; + + /* Again dealing with (vbd...) vs (tap ...) differences */ + if (sexpr_lookup(node, "device/vbd")) { + src = sexpr_node(node, "device/vbd/uname"); + dst = sexpr_node(node, "device/vbd/dev"); + mode = sexpr_node(node, "device/vbd/mode"); + } else if (sexpr_lookup(node, "device/tap2")) { + src = sexpr_node(node, "device/tap2/uname"); + dst = sexpr_node(node, "device/tap2/dev"); + mode = sexpr_node(node, "device/tap2/mode"); + } else { + src = sexpr_node(node, "device/tap/uname"); + dst = sexpr_node(node, "device/tap/dev"); + mode = sexpr_node(node, "device/tap/mode"); + } + + if (VIR_ALLOC(disk) < 0) + goto no_memory; + + if (dst == NULL) { + XENXS_ERROR(VIR_ERR_INTERNAL_ERROR, + "%s", _("domain information incomplete, vbd has no dev")); + goto error; + } + + if (src == NULL) { + /* There is a case without the uname to the CD-ROM device */ + offset = strchr(dst, ':'); + if (!offset || + !hvm || + STRNEQ(offset, ":cdrom")) { + XENXS_ERROR(VIR_ERR_INTERNAL_ERROR, + "%s", _("domain information incomplete, vbd has no src")); + goto error; + } + } + + if (src != NULL) { + offset = strchr(src, ':'); + if (!offset) { + XENXS_ERROR(VIR_ERR_INTERNAL_ERROR, + "%s", _("cannot parse vbd filename, missing driver name")); + goto error; + } + + if (VIR_ALLOC_N(disk->driverName, (offset-src)+1) < 0) + goto no_memory; + if (virStrncpy(disk->driverName, src, offset-src, + (offset-src)+1) == NULL) { + XENXS_ERROR(VIR_ERR_INTERNAL_ERROR, + _("Driver name %s too big for destination"), + src); + goto error; + } + + src = offset + 1; + + if (STREQ (disk->driverName, "tap") || + STREQ (disk->driverName, "tap2")) { + offset = strchr(src, ':'); + if (!offset) { + XENXS_ERROR(VIR_ERR_INTERNAL_ERROR, + "%s", _("cannot parse vbd filename, missing driver type")); + goto error; + } + + if (VIR_ALLOC_N(disk->driverType, (offset-src)+1)< 0) + goto no_memory; + if (virStrncpy(disk->driverType, src, offset-src, + (offset-src)+1) == NULL) { + XENXS_ERROR(VIR_ERR_INTERNAL_ERROR, + _("Driver type %s too big for destination"), + src); + goto error; + } + + src = offset + 1; + /* Its possible to use blktap driver for block devs + too, but kinda pointless because blkback is better, + so we assume common case here. If blktap becomes + omnipotent, we can revisit this, perhaps stat()'ing + the src file in question */ + disk->type = VIR_DOMAIN_DISK_TYPE_FILE; + } else if (STREQ(disk->driverName, "phy")) { + disk->type = VIR_DOMAIN_DISK_TYPE_BLOCK; + } else if (STREQ(disk->driverName, "file")) { + disk->type = VIR_DOMAIN_DISK_TYPE_FILE; + } + } else { + /* No CDROM media so can't really tell. We'll just + call if a FILE for now and update when media + is inserted later */ + disk->type = VIR_DOMAIN_DISK_TYPE_FILE; + } + + if (STREQLEN (dst, "ioemu:", 6)) + dst += 6; + + disk->device = VIR_DOMAIN_DISK_DEVICE_DISK; + /* New style disk config from Xen >= 3.0.3 */ + if (xendConfigVersion > 1) { + offset = strrchr(dst, ':'); + if (offset) { + if (STREQ (offset, ":cdrom")) { + disk->device = VIR_DOMAIN_DISK_DEVICE_CDROM; + } else if (STREQ (offset, ":disk")) { + /* The default anyway */ + } else { + /* Unknown, lets pretend its a disk too */ + } + offset[0] = '\0'; + } + } + + if (!(disk->dst = strdup(dst))) + goto no_memory; + if (src && + !(disk->src = strdup(src))) + goto no_memory; + + if (STRPREFIX(disk->dst, "xvd")) + disk->bus = VIR_DOMAIN_DISK_BUS_XEN; + else if (STRPREFIX(disk->dst, "hd")) + disk->bus = VIR_DOMAIN_DISK_BUS_IDE; + else if (STRPREFIX(disk->dst, "sd")) + disk->bus = VIR_DOMAIN_DISK_BUS_SCSI; + else + disk->bus = VIR_DOMAIN_DISK_BUS_IDE; + + if (mode && + strchr(mode, 'r')) + disk->readonly = 1; + if (mode && + strchr(mode, '!')) + disk->shared = 1; + + if (VIR_REALLOC_N(def->disks, def->ndisks+1) < 0) + goto no_memory; + + def->disks[def->ndisks++] = disk; + disk = NULL; + } + } + + return 0; + +no_memory: + virReportOOMError(); + +error: + virDomainDiskDefFree(disk); + return -1; +} + + +static int +xenDaemonParseSxprNets(virDomainDefPtr def, + const struct sexpr *root) +{ + virDomainNetDefPtr net = NULL; + const struct sexpr *cur, *node; + const char *tmp; + int vif_index = 0; + + for (cur = root; cur->kind == SEXPR_CONS; cur = cur->u.s.cdr) { + node = cur->u.s.car; + if (sexpr_lookup(node, "device/vif")) { + const char *tmp2, *model, *type; + char buf[50]; + tmp2 = sexpr_node(node, "device/vif/script"); + tmp = sexpr_node(node, "device/vif/bridge"); + model = sexpr_node(node, "device/vif/model"); + type = sexpr_node(node, "device/vif/type"); + + if (VIR_ALLOC(net) < 0) + goto no_memory; + + if (tmp != NULL || + (tmp2 != NULL && STREQ(tmp2, DEFAULT_VIF_SCRIPT))) { + net->type = VIR_DOMAIN_NET_TYPE_BRIDGE; + /* XXX virtual network reverse resolve */ + + if (tmp && + !(net->data.bridge.brname = strdup(tmp))) + goto no_memory; + if (tmp2 && + net->type == VIR_DOMAIN_NET_TYPE_BRIDGE && + !(net->data.bridge.script = strdup(tmp2))) + goto no_memory; + tmp = sexpr_node(node, "device/vif/ip"); + if (tmp && + !(net->data.bridge.ipaddr = strdup(tmp))) + goto no_memory; + } else { + net->type = VIR_DOMAIN_NET_TYPE_ETHERNET; + if (tmp2 && + !(net->data.ethernet.script = strdup(tmp2))) + goto no_memory; + tmp = sexpr_node(node, "device/vif/ip"); + if (tmp && + !(net->data.ethernet.ipaddr = strdup(tmp))) + goto no_memory; + } + + tmp = sexpr_node(node, "device/vif/vifname"); + if (!tmp) { + snprintf(buf, sizeof(buf), "vif%d.%d", def->id, vif_index); + tmp = buf; + } + if (!(net->ifname = strdup(tmp))) + goto no_memory; + + tmp = sexpr_node(node, "device/vif/mac"); + if (tmp) { + if (virParseMacAddr(tmp, net->mac) < 0) { + XENXS_ERROR(VIR_ERR_INTERNAL_ERROR, + _("malformed mac address '%s'"), tmp); + goto cleanup; + } + } + + if (model && + !(net->model = strdup(model))) + goto no_memory; + + if (!model && type && + STREQ(type, "netfront") && + !(net->model = strdup("netfront"))) + goto no_memory; + + if (VIR_REALLOC_N(def->nets, def->nnets + 1) < 0) + goto no_memory; + + def->nets[def->nnets++] = net; + vif_index++; + } + } + + return 0; + +no_memory: + virReportOOMError(); +cleanup: + virDomainNetDefFree(net); + return -1; +} + + +int +xenDaemonParseSxprSound(virDomainDefPtr def, + const char *str) +{ + if (STREQ(str, "all")) { + int i; + + /* + * Special compatability code for Xen with a bogus + * sound=all in config. + * + * NB delibrately, don't include all possible + * sound models anymore, just the 2 that were + * historically present in Xen's QEMU. + * + * ie just es1370 + sb16. + * + * Hence use of MODEL_ES1370 + 1, instead of MODEL_LAST + */ + + if (VIR_ALLOC_N(def->sounds, + VIR_DOMAIN_SOUND_MODEL_ES1370 + 1) < 0) + goto no_memory; + + + for (i = 0 ; i < (VIR_DOMAIN_SOUND_MODEL_ES1370 + 1) ; i++) { + virDomainSoundDefPtr sound; + if (VIR_ALLOC(sound) < 0) + goto no_memory; + sound->model = i; + def->sounds[def->nsounds++] = sound; + } + } else { + char model[10]; + const char *offset = str, *offset2; + + do { + int len; + virDomainSoundDefPtr sound; + offset2 = strchr(offset, ','); + if (offset2) + len = (offset2 - offset); + else + len = strlen(offset); + if (virStrncpy(model, offset, len, sizeof(model)) == NULL) { + XENXS_ERROR(VIR_ERR_INTERNAL_ERROR, + _("Sound model %s too big for destination"), + offset); + goto error; + } + + if (VIR_ALLOC(sound) < 0) + goto no_memory; + + if ((sound->model = virDomainSoundModelTypeFromString(model)) < 0) { + VIR_FREE(sound); + goto error; + } + + if (VIR_REALLOC_N(def->sounds, def->nsounds+1) < 0) { + virDomainSoundDefFree(sound); + goto no_memory; + } + + def->sounds[def->nsounds++] = sound; + offset = offset2 ? offset2 + 1 : NULL; + } while (offset); + } + + return 0; + +no_memory: + virReportOOMError(); +error: + return -1; +} + + +static int +xenDaemonParseSxprUSB(virDomainDefPtr def, + const struct sexpr *root) +{ + struct sexpr *cur, *node; + const char *tmp; + + for (cur = sexpr_lookup(root, "domain/image/hvm"); cur && cur->kind == SEXPR_CONS; cur = cur->u.s.cdr) { + node = cur->u.s.car; + if (sexpr_lookup(node, "usbdevice")) { + tmp = sexpr_node(node, "usbdevice"); + if (tmp && *tmp) { + if (STREQ(tmp, "tablet") || + STREQ(tmp, "mouse")) { + virDomainInputDefPtr input; + if (VIR_ALLOC(input) < 0) + goto no_memory; + input->bus = VIR_DOMAIN_INPUT_BUS_USB; + if (STREQ(tmp, "tablet")) + input->type = VIR_DOMAIN_INPUT_TYPE_TABLET; + else + input->type = VIR_DOMAIN_INPUT_TYPE_MOUSE; + + if (VIR_REALLOC_N(def->inputs, def->ninputs+1) < 0) { + VIR_FREE(input); + goto no_memory; + } + def->inputs[def->ninputs++] = input; + } else { + /* XXX Handle other non-input USB devices later */ + } + } + } + } + return 0; + +no_memory: + virReportOOMError(); + return -1; +} + +static int +xenDaemonParseSxprGraphicsOld(virDomainDefPtr def, + const struct sexpr *root, + int hvm, + int xendConfigVersion, int vncport) +{ + const char *tmp; + virDomainGraphicsDefPtr graphics = NULL; + + if ((tmp = sexpr_fmt_node(root, "domain/image/%s/vnc", hvm ? "hvm" : "linux")) && + tmp[0] == '1') { + /* Graphics device (HVM, or old (pre-3.0.4) style PV VNC config) */ + int port; + const char *listenAddr = sexpr_fmt_node(root, "domain/image/%s/vnclisten", hvm ? "hvm" : "linux"); + const char *vncPasswd = sexpr_fmt_node(root, "domain/image/%s/vncpasswd", hvm ? "hvm" : "linux"); + const char *keymap = sexpr_fmt_node(root, "domain/image/%s/keymap", hvm ? "hvm" : "linux"); + const char *unused = sexpr_fmt_node(root, "domain/image/%s/vncunused", hvm ? "hvm" : "linux"); + + port = vncport; + + if (VIR_ALLOC(graphics) < 0) + goto no_memory; + + graphics->type = VIR_DOMAIN_GRAPHICS_TYPE_VNC; + /* For Xen >= 3.0.3, don't generate a fixed port mapping + * because it will almost certainly be wrong ! Just leave + * it as -1 which lets caller see that the VNC server isn't + * present yet. Subsquent dumps of the XML will eventually + * find the port in XenStore once VNC server has started + */ + if (port == -1 && xendConfigVersion < 2) + port = 5900 + def->id; + + if ((unused && STREQ(unused, "1")) || port == -1) + graphics->data.vnc.autoport = 1; + graphics->data.vnc.port = port; + + if (listenAddr && + !(graphics->data.vnc.listenAddr = strdup(listenAddr))) + goto no_memory; + + if (vncPasswd && + !(graphics->data.vnc.auth.passwd = strdup(vncPasswd))) + goto no_memory; + + if (keymap && + !(graphics->data.vnc.keymap = strdup(keymap))) + goto no_memory; + + if (VIR_ALLOC_N(def->graphics, 1) < 0) + goto no_memory; + def->graphics[0] = graphics; + def->ngraphics = 1; + graphics = NULL; + } else if ((tmp = sexpr_fmt_node(root, "domain/image/%s/sdl", hvm ? "hvm" : "linux")) && + tmp[0] == '1') { + /* Graphics device (HVM, or old (pre-3.0.4) style PV sdl config) */ + const char *display = sexpr_fmt_node(root, "domain/image/%s/display", hvm ? "hvm" : "linux"); + const char *xauth = sexpr_fmt_node(root, "domain/image/%s/xauthority", hvm ? "hvm" : "linux"); + + if (VIR_ALLOC(graphics) < 0) + goto no_memory; + + graphics->type = VIR_DOMAIN_GRAPHICS_TYPE_SDL; + if (display && + !(graphics->data.sdl.display = strdup(display))) + goto no_memory; + if (xauth && + !(graphics->data.sdl.xauth = strdup(xauth))) + goto no_memory; + + if (VIR_ALLOC_N(def->graphics, 1) < 0) + goto no_memory; + def->graphics[0] = graphics; + def->ngraphics = 1; + graphics = NULL; + } + + return 0; + +no_memory: + virReportOOMError(); + virDomainGraphicsDefFree(graphics); + return -1; +} + + +static int +xenDaemonParseSxprGraphicsNew(virDomainDefPtr def, + const struct sexpr *root, int vncport) +{ + virDomainGraphicsDefPtr graphics = NULL; + const struct sexpr *cur, *node; + const char *tmp; + + /* append network devices and framebuffer */ + for (cur = root; cur->kind == SEXPR_CONS; cur = cur->u.s.cdr) { + node = cur->u.s.car; + if (sexpr_lookup(node, "device/vfb")) { + /* New style graphics config for PV guests in >= 3.0.4, + * or for HVM guests in >= 3.0.5 */ + if (sexpr_node(node, "device/vfb/type")) { + tmp = sexpr_node(node, "device/vfb/type"); + } else if (sexpr_node(node, "device/vfb/vnc")) { + tmp = "vnc"; + } else if (sexpr_node(node, "device/vfb/sdl")) { + tmp = "sdl"; + } else { + tmp = "unknown"; + } + + if (VIR_ALLOC(graphics) < 0) + goto no_memory; + + if ((graphics->type = virDomainGraphicsTypeFromString(tmp)) < 0) { + XENXS_ERROR(VIR_ERR_INTERNAL_ERROR, + _("unknown graphics type '%s'"), tmp); + goto error; + } + + if (graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) { + const char *display = sexpr_node(node, "device/vfb/display"); + const char *xauth = sexpr_node(node, "device/vfb/xauthority"); + if (display && + !(graphics->data.sdl.display = strdup(display))) + goto no_memory; + if (xauth && + !(graphics->data.sdl.xauth = strdup(xauth))) + goto no_memory; + } else { + int port; + const char *listenAddr = sexpr_node(node, "device/vfb/vnclisten"); + const char *vncPasswd = sexpr_node(node, "device/vfb/vncpasswd"); + const char *keymap = sexpr_node(node, "device/vfb/keymap"); + const char *unused = sexpr_node(node, "device/vfb/vncunused"); + + port = vncport; + + /* Didn't find port entry in xenstore */ + if (port == -1) { + const char *str = sexpr_node(node, "device/vfb/vncdisplay"); + int val; + if (str != NULL && virStrToLong_i(str, NULL, 0, &val) == 0) + port = val; + } + + if ((unused && STREQ(unused, "1")) || port == -1) + graphics->data.vnc.autoport = 1; + + if (port >= 0 && port < 5900) + port += 5900; + graphics->data.vnc.port = port; + + if (listenAddr && + !(graphics->data.vnc.listenAddr = strdup(listenAddr))) + goto no_memory; + + if (vncPasswd && + !(graphics->data.vnc.auth.passwd = strdup(vncPasswd))) + goto no_memory; + + if (keymap && + !(graphics->data.vnc.keymap = strdup(keymap))) + goto no_memory; + } + + if (VIR_ALLOC_N(def->graphics, 1) < 0) + goto no_memory; + def->graphics[0] = graphics; + def->ngraphics = 1; + graphics = NULL; + break; + } + } + + return 0; + +no_memory: + virReportOOMError(); +error: + virDomainGraphicsDefFree(graphics); + return -1; +} + +/** + * xenDaemonParseSxprPCI + * @root: root sexpr + * + * This parses out block devices from the domain sexpr + * + * Returns 0 if successful or -1 if failed. + */ +static int +xenDaemonParseSxprPCI(virDomainDefPtr def, + const struct sexpr *root) +{ + const struct sexpr *cur, *tmp = NULL, *node; + virDomainHostdevDefPtr dev = NULL; + + /* + * With the (domain ...) block we have the following odd setup + * + * (device + * (pci + * (dev (domain 0x0000) (bus 0x00) (slot 0x1b) (func 0x0)) + * (dev (domain 0x0000) (bus 0x00) (slot 0x13) (func 0x0)) + * ) + * ) + * + * Normally there is one (device ...) block per device, but in + * wierd world of Xen PCI, once (device ...) covers multiple + * devices. + */ + + for (cur = root; cur->kind == SEXPR_CONS; cur = cur->u.s.cdr) { + node = cur->u.s.car; + if ((tmp = sexpr_lookup(node, "device/pci")) != NULL) + break; + } + + if (!tmp) + return 0; + + for (cur = tmp; cur->kind == SEXPR_CONS; cur = cur->u.s.cdr) { + const char *domain = NULL; + const char *bus = NULL; + const char *slot = NULL; + const char *func = NULL; + int domainID; + int busID; + int slotID; + int funcID; + + node = cur->u.s.car; + if (!sexpr_lookup(node, "dev")) + continue; + + if (!(domain = sexpr_node(node, "dev/domain"))) { + XENXS_ERROR(VIR_ERR_INTERNAL_ERROR, + "%s", _("missing PCI domain")); + goto error; + } + if (!(bus = sexpr_node(node, "dev/bus"))) { + XENXS_ERROR(VIR_ERR_INTERNAL_ERROR, + "%s", _("missing PCI bus")); + goto error; + } + if (!(slot = sexpr_node(node, "dev/slot"))) { + XENXS_ERROR(VIR_ERR_INTERNAL_ERROR, + "%s", _("missing PCI slot")); + goto error; + } + if (!(func = sexpr_node(node, "dev/func"))) { + XENXS_ERROR(VIR_ERR_INTERNAL_ERROR, + "%s", _("missing PCI func")); + goto error; + } + + if (virStrToLong_i(domain, NULL, 0, &domainID) < 0) { + XENXS_ERROR(VIR_ERR_INTERNAL_ERROR, + _("cannot parse PCI domain '%s'"), domain); + goto error; + } + if (virStrToLong_i(bus, NULL, 0, &busID) < 0) { + XENXS_ERROR(VIR_ERR_INTERNAL_ERROR, + _("cannot parse PCI bus '%s'"), bus); + goto error; + } + if (virStrToLong_i(slot, NULL, 0, &slotID) < 0) { + XENXS_ERROR(VIR_ERR_INTERNAL_ERROR, + _("cannot parse PCI slot '%s'"), slot); + goto error; + } + if (virStrToLong_i(func, NULL, 0, &funcID) < 0) { + XENXS_ERROR(VIR_ERR_INTERNAL_ERROR, + _("cannot parse PCI func '%s'"), func); + goto error; + } + + if (VIR_ALLOC(dev) < 0) + goto no_memory; + + dev->mode = VIR_DOMAIN_HOSTDEV_MODE_SUBSYS; + dev->managed = 0; + dev->source.subsys.type = VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI; + dev->source.subsys.u.pci.domain = domainID; + dev->source.subsys.u.pci.bus = busID; + dev->source.subsys.u.pci.slot = slotID; + dev->source.subsys.u.pci.function = funcID; + + if (VIR_REALLOC_N(def->hostdevs, def->nhostdevs+1) < 0) { + goto no_memory; + } + + def->hostdevs[def->nhostdevs++] = dev; + } + + return 0; + +no_memory: + virReportOOMError(); + +error: + virDomainHostdevDefFree(dev); + return -1; +} + + +/** + * xenDaemonParseSxpr: + * @conn: the connection associated with the XML + * @root: the root of the parsed S-Expression + * @xendConfigVersion: version of xend + * @cpus: set of cpus the domain may be pinned to + * + * Parse the xend sexp description and turn it into the XML format similar + * to the one unsed for creation. + * + * Returns the 0 terminated XML string or NULL in case of error. + * the caller must free() the returned value. + */ +virDomainDefPtr +xenDaemonParseSxpr(const struct sexpr *root, + int xendConfigVersion, + const char *cpus, char *tty, int vncport) +{ + const char *tmp; + virDomainDefPtr def; + int hvm = 0; + + if (VIR_ALLOC(def) < 0) + goto no_memory; + + tmp = sexpr_node(root, "domain/domid"); + if (tmp == NULL && xendConfigVersion < 3) { /* Old XenD, domid was mandatory */ + XENXS_ERROR(VIR_ERR_INTERNAL_ERROR, + "%s", _("domain information incomplete, missing id")); + goto error; + } + def->virtType = VIR_DOMAIN_VIRT_XEN; + if (tmp) + def->id = sexpr_int(root, "domain/domid"); + else + def->id = -1; + + if (sexpr_node_copy(root, "domain/name", &def->name) < 0) + goto no_memory; + if (def->name == NULL) { + XENXS_ERROR(VIR_ERR_INTERNAL_ERROR, + "%s", _("domain information incomplete, missing name")); + goto error; + } + + tmp = sexpr_node(root, "domain/uuid"); + if (tmp == NULL) { + XENXS_ERROR(VIR_ERR_INTERNAL_ERROR, + "%s", _("domain information incomplete, missing name")); + goto error; + } + virUUIDParse(tmp, def->uuid); + + if (sexpr_node_copy(root, "domain/description", &def->description) < 0) + goto no_memory; + + hvm = sexpr_lookup(root, "domain/image/hvm") ? 1 : 0; + if (!hvm) { + if (sexpr_node_copy(root, "domain/bootloader", + &def->os.bootloader) < 0) + goto no_memory; + + if (!def->os.bootloader && + sexpr_has(root, "domain/bootloader") && + (def->os.bootloader = strdup("")) == NULL) + goto no_memory; + + if (def->os.bootloader && + sexpr_node_copy(root, "domain/bootloader_args", + &def->os.bootloaderArgs) < 0) + goto no_memory; + } + + if (!(def->os.type = strdup(hvm ? "hvm" : "linux"))) + goto no_memory; + + if (def->id != 0) { + if (sexpr_lookup(root, "domain/image")) { + if (xenDaemonParseSxprOS(root, def, hvm) < 0) + goto error; + } + } + + def->mem.max_balloon = (unsigned long) + (sexpr_u64(root, "domain/maxmem") << 10); + def->mem.cur_balloon = (unsigned long) + (sexpr_u64(root, "domain/memory") << 10); + if (def->mem.cur_balloon > def->mem.max_balloon) + def->mem.cur_balloon = def->mem.max_balloon; + + if (cpus != NULL) { + def->cpumasklen = VIR_DOMAIN_CPUMASK_LEN; + if (VIR_ALLOC_N(def->cpumask, def->cpumasklen) < 0) { + virReportOOMError(); + goto error; + } + + if (virDomainCpuSetParse(&cpus, + 0, def->cpumask, + def->cpumasklen) < 0) { + XENXS_ERROR(VIR_ERR_INTERNAL_ERROR, + _("invalid CPU mask %s"), cpus); + goto error; + } + } + + def->maxvcpus = sexpr_int(root, "domain/vcpus"); + def->vcpus = count_one_bits_l(sexpr_u64(root, "domain/vcpu_avail")); + if (!def->vcpus || def->maxvcpus < def->vcpus) + def->vcpus = def->maxvcpus; + + tmp = sexpr_node(root, "domain/on_poweroff"); + if (tmp != NULL) { + if ((def->onPoweroff = virDomainLifecycleTypeFromString(tmp)) < 0) { + XENXS_ERROR(VIR_ERR_INTERNAL_ERROR, + _("unknown lifecycle type %s"), tmp); + goto error; + } + } else + def->onPoweroff = VIR_DOMAIN_LIFECYCLE_DESTROY; + + tmp = sexpr_node(root, "domain/on_reboot"); + if (tmp != NULL) { + if ((def->onReboot = virDomainLifecycleTypeFromString(tmp)) < 0) { + XENXS_ERROR(VIR_ERR_INTERNAL_ERROR, + _("unknown lifecycle type %s"), tmp); + goto error; + } + } else + def->onReboot = VIR_DOMAIN_LIFECYCLE_RESTART; + + tmp = sexpr_node(root, "domain/on_crash"); + if (tmp != NULL) { + if ((def->onCrash = virDomainLifecycleCrashTypeFromString(tmp)) < 0) { + XENXS_ERROR(VIR_ERR_INTERNAL_ERROR, + _("unknown lifecycle type %s"), tmp); + goto error; + } + } else + def->onCrash = VIR_DOMAIN_LIFECYCLE_DESTROY; + + def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_UTC; + if (hvm) { + if (sexpr_int(root, "domain/image/hvm/acpi")) + def->features |= (1 << VIR_DOMAIN_FEATURE_ACPI); + if (sexpr_int(root, "domain/image/hvm/apic")) + def->features |= (1 << VIR_DOMAIN_FEATURE_APIC); + if (sexpr_int(root, "domain/image/hvm/pae")) + def->features |= (1 << VIR_DOMAIN_FEATURE_PAE); + if (sexpr_int(root, "domain/image/hvm/hap")) + def->features |= (1 << VIR_DOMAIN_FEATURE_HAP); + + /* Old XenD only allows localtime here for HVM */ + if (sexpr_int(root, "domain/image/hvm/localtime")) + def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME; + } + + /* Current XenD allows localtime here, for PV and HVM */ + if (sexpr_int(root, "domain/localtime")) + def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME; + + if (sexpr_node_copy(root, hvm ? + "domain/image/hvm/device_model" : + "domain/image/linux/device_model", + &def->emulator) < 0) + goto no_memory; + + /* append block devices */ + if (xenDaemonParseSxprDisks(def, root, hvm, xendConfigVersion) < 0) + goto error; + + if (xenDaemonParseSxprNets(def, root) < 0) + goto error; + + if (xenDaemonParseSxprPCI(def, root) < 0) + goto error; + + /* New style graphics device config */ + if (xenDaemonParseSxprGraphicsNew(def, root, vncport) < 0) + goto error; + + /* Graphics device (HVM <= 3.0.4, or PV <= 3.0.3) vnc config */ + if ((def->ngraphics == 0) && + xenDaemonParseSxprGraphicsOld(def, root, hvm, xendConfigVersion, + vncport) < 0) + goto error; + + + /* Old style cdrom config from Xen <= 3.0.2 */ + if (hvm && + xendConfigVersion == 1) { + tmp = sexpr_node(root, "domain/image/hvm/cdrom"); + if ((tmp != NULL) && (tmp[0] != 0)) { + virDomainDiskDefPtr disk; + if (VIR_ALLOC(disk) < 0) + goto no_memory; + if (!(disk->src = strdup(tmp))) { + virDomainDiskDefFree(disk); + goto no_memory; + } + disk->type = VIR_DOMAIN_DISK_TYPE_FILE; + disk->device = VIR_DOMAIN_DISK_DEVICE_CDROM; + if (!(disk->dst = strdup("hdc"))) { + virDomainDiskDefFree(disk); + goto no_memory; + } + if (!(disk->driverName = strdup("file"))) { + virDomainDiskDefFree(disk); + goto no_memory; + } + disk->bus = VIR_DOMAIN_DISK_BUS_IDE; + disk->readonly = 1; + + if (VIR_REALLOC_N(def->disks, def->ndisks+1) < 0) { + virDomainDiskDefFree(disk); + goto no_memory; + } + def->disks[def->ndisks++] = disk; + } + } + + + /* Floppy disk config */ + if (hvm) { + const char *const fds[] = { "fda", "fdb" }; + int i; + for (i = 0 ; i < ARRAY_CARDINALITY(fds) ; i++) { + tmp = sexpr_fmt_node(root, "domain/image/hvm/%s", fds[i]); + if ((tmp != NULL) && (tmp[0] != 0)) { + virDomainDiskDefPtr disk; + if (VIR_ALLOC(disk) < 0) + goto no_memory; + if (!(disk->src = strdup(tmp))) { + VIR_FREE(disk); + goto no_memory; + } + disk->type = VIR_DOMAIN_DISK_TYPE_FILE; + disk->device = VIR_DOMAIN_DISK_DEVICE_FLOPPY; + if (!(disk->dst = strdup(fds[i]))) { + virDomainDiskDefFree(disk); + goto no_memory; + } + if (!(disk->driverName = strdup("file"))) { + virDomainDiskDefFree(disk); + goto no_memory; + } + disk->bus = VIR_DOMAIN_DISK_BUS_FDC; + + if (VIR_REALLOC_N(def->disks, def->ndisks+1) < 0) { + virDomainDiskDefFree(disk); + goto no_memory; + } + def->disks[def->ndisks++] = disk; + } + } + } + + /* in case of HVM we have USB device emulation */ + if (hvm && + xenDaemonParseSxprUSB(def, root) < 0) + goto error; + + /* Character device config */ + if (hvm) { + tmp = sexpr_node(root, "domain/image/hvm/serial"); + if (tmp && STRNEQ(tmp, "none")) { + virDomainChrDefPtr chr; + if ((chr = xenDaemonParseSxprChar(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; + /* XXX does XenD stuff parallel port tty info into xenstore somewhere ? */ + if ((chr = xenDaemonParseSxprChar(tmp, NULL)) == NULL) + goto error; + if (VIR_REALLOC_N(def->parallels, def->nparallels+1) < 0) { + virDomainChrDefFree(chr); + goto no_memory; + } + chr->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL; + def->parallels[def->nparallels++] = chr; + } + } else { + /* Fake a paravirt console, since that's not in the sexpr */ + if (!(def->console = xenDaemonParseSxprChar("pty", tty))) + goto error; + def->console->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE; + def->console->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_XEN; + } + VIR_FREE(tty); + + + /* Sound device config */ + if (hvm && + (tmp = sexpr_node(root, "domain/image/hvm/soundhw")) != NULL && + *tmp) { + if (xenDaemonParseSxprSound(def, tmp) < 0) + goto error; + } + + return def; + +no_memory: + virReportOOMError(); +error: + VIR_FREE(tty); + virDomainDefFree(def); + return NULL; +} + +virDomainDefPtr +xenDaemonParseSxprString(const char *sexpr, + int xendConfigVersion, char *tty, int vncport) +{ + struct sexpr *root = string2sexpr(sexpr); + virDomainDefPtr def; + + if (!root) + return NULL; + + def = xenDaemonParseSxpr(root, xendConfigVersion, NULL, tty, vncport); + + sexpr_free(root); + + return def; +} \ No newline at end of file diff --git a/src/xenxs/xen_sxpr.h b/src/xenxs/xen_sxpr.h new file mode 100644 index 0000000000000000000000000000000000000000..c0c6a53b51cedb121b0031c9a9a633851aac8613 --- /dev/null +++ b/src/xenxs/xen_sxpr.h @@ -0,0 +1,62 @@ +/* + * xen_sxpr.h: Xen SEXPR parsing functions + * + * Copyright (C) 2011 Univention GmbH + * Copyright (C) 2006-2008, 2010 Red Hat, Inc. + * Copyright (C) 2005,2006 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Anthony Liguori + * Author: Daniel Veillard + * Author: Markus Groß + */ + +#ifndef __VIR_XEN_SXPR_H__ +# define __VIR_XEN_SXPR_H__ + +# include "internal.h" +# include "conf.h" +# include "domain_conf.h" +# include "sexpr.h" + +# ifdef __sun +# define DEFAULT_VIF_SCRIPT "vif-vnic" +# else +# define DEFAULT_VIF_SCRIPT "vif-bridge" +# endif + +/* helper functions to get the dom id from a sexpr */ +int xenGetDomIdFromSxprString(const char *sexpr, int xendConfigVersion); +int xenGetDomIdFromSxpr(const struct sexpr *root, int xendConfigVersion); + +virDomainDefPtr +xenDaemonParseSxprString(const char *sexpr, + int xendConfigVersion, char *tty, int vncport); + +virDomainDefPtr +xenDaemonParseSxpr(const struct sexpr *root, + int xendConfigVersion, + const char *cpus, char *tty, int vncport); + +int +xenDaemonParseSxprSound(virDomainDefPtr def, + const char *str); + +virDomainChrDefPtr +xenDaemonParseSxprChar(const char *value, + const char *tty); + +#endif /* __VIR_XEN_SXPR_H__ */ diff --git a/src/xenxs/xenxs_private.h b/src/xenxs/xenxs_private.h new file mode 100644 index 0000000000000000000000000000000000000000..1acabfbcd8c92b877e798f6319c89a6cecc59f50 --- /dev/null +++ b/src/xenxs/xenxs_private.h @@ -0,0 +1,37 @@ +/* + * xenxs_private.h: Private definitions for Xen parsing + * + * Copyright (C) 2011 Univention GmbH + * Copyright (C) 2007, 2010 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Richard W.M. Jones + * Author: Markus Groß + */ + +#ifndef __VIR_XENXS_PRIVATE_H__ +# define __VIR_XENXS_PRIVATE_H__ + +# include "internal.h" + + +# define VIR_FROM_THIS VIR_FROM_NONE + +# define XENXS_ERROR(code, ...) \ + virReportErrorHelper(NULL, VIR_FROM_NONE, code, __FILE__, __FUNCTION__, \ + __LINE__, __VA_ARGS__) + +#endif /* __VIR_XENXS_PRIVATE_H__ */ diff --git a/tests/sexpr2xmltest.c b/tests/sexpr2xmltest.c index f100dd87ce52ed17ff52b55d0b7d51682db46461..cf3e5bcd3d9fc8b8b006c00548e8c39db8b86ba0 100644 --- a/tests/sexpr2xmltest.c +++ b/tests/sexpr2xmltest.c @@ -9,6 +9,7 @@ #include "datatypes.h" #include "xen/xen_driver.h" #include "xen/xend_internal.h" +#include "xenxs/xen_sxpr.h" #include "testutils.h" #include "testutilsxen.h" @@ -25,6 +26,9 @@ static int testCompareFiles(const char *xml, const char *sexpr, char *gotxml = NULL; char *xmlPtr = &(xmlData[0]); char *sexprPtr = &(sexprData[0]); + int id; + char * tty; + int vncport; int ret = -1; virDomainDefPtr def = NULL; virConnectPtr conn; @@ -48,7 +52,14 @@ static int testCompareFiles(const char *xml, const char *sexpr, if (virMutexInit(&priv.lock) < 0) goto fail; - if (!(def = xenDaemonParseSxprString(conn, sexprData, xendConfigVersion))) + id = xenGetDomIdFromSxprString(sexprData, xendConfigVersion); + xenUnifiedLock(&priv); + tty = xenStoreDomainGetConsolePath(conn, id); + vncport = xenStoreDomainGetVNCPort(conn, id); + xenUnifiedUnlock(&priv); + + if (!(def = xenDaemonParseSxprString(sexprData, xendConfigVersion, tty, + vncport))) goto fail; if (!(gotxml = virDomainDefFormat(def, 0)))