From 594af3eb226c51d6c0f4136ab78fd41b9e0758ce Mon Sep 17 00:00:00 2001 From: Daniel Veillard Date: Wed, 6 Feb 2008 17:57:10 +0000 Subject: [PATCH] add/change/delete a Disk/NIC of an inactive domains * src/xm_internal.[ch]: applied patch from Shigeki Sakamoto to add/change/delete a Disk/NIC of an inactive domains Daniel --- ChangeLog | 5 + NEWS | 28 +- src/xm_internal.c | 640 +++++++++++++++++++++++++++++++++++++++++++++- src/xm_internal.h | 3 + 4 files changed, 660 insertions(+), 16 deletions(-) diff --git a/ChangeLog b/ChangeLog index 74ebae5761..b761bf0172 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +Wed Feb 6 18:55:37 CET 2008 Daniel Veillard + + * src/xm_internal.[ch]: applied patch from Shigeki Sakamoto to + add/change/delete a Disk/NIC of an inactive domains + Wed Feb 6 17:22:34 CET 2008 Daniel Veillard * src/qemu_conf.c: applied 2 patches from Guido Guenther to avoid diff --git a/NEWS b/NEWS index fb4878f68f..581acb6aeb 100644 --- a/NEWS +++ b/NEWS @@ -17,7 +17,7 @@ Releases various english fixes (Bruce Montague), OCaml docs links (Richard Jones), describe the various bindings add Ruby link, Windows support page (Richard Jones), authentication documentation updates (Daniel Berrange) - + - Bug fixes: NUMA topology error handling (Beth Kon), NUMA topology cells without CPU (Beth Kon), XML to/from XM bridge config (Daniel Berrange), XM processing of vnc parameters (Daniel Berrange), Reset @@ -42,7 +42,7 @@ Releases parameter setting in XM config (Saori Fukuta), credential handling fixes (Daniel Berrange), fix compatibility with Xen 3.2.0 (Daniel Berrange) - + - Improvements: /etc/libvirt/qemu.conf configuration for QEMU driver (Daniel Berrange), NUMA cpu pinning in config files (DV and Saori Fukuta), CDRom media change in KVM/QEMU (Daniel Berrange), tests for @@ -51,7 +51,7 @@ Releases --without-libvirtd config option (Richard Jones), Python bindings for NUMA, add extra utility functions to buffer (Richard Jones), separate qparams module for handling query parameters (Richard Jones) - + - Code cleanups: remove virDomainRestart from API as it was never used (Richard Jones), constify params for attach/detach APIs (Daniel Berrange), gcc printf attribute checkings (Jim Meyering), refactoring of device @@ -72,13 +72,13 @@ Releases port (Richard Jones), disable the proxy if using PolicyKit, readline availability detection, test libvirtd's config-processing code (Jim Meyering), use a variable name as sizeof argument (Jim Meyering) - + 0.3.3: Sep 30 2007: - New features: Avahi mDNS daemon export (Daniel Berrange), - NUMA support (Beth Kan) - - Documentation: cleanups (Toth Istvan), typos (Eduardo Pereira), + NUMA support (Beth Kan) + - Documentation: cleanups (Toth Istvan), typos (Eduardo Pereira), - Bug fixes: memory corruption on large dumps (Masayuki Sunou), fix virsh vncdisplay command exit (Masayuki Sunou), Fix network stats TX/RX result (Richard Jones), warning on Xen 3.0.3 (Richard Jones), @@ -124,10 +124,10 @@ Releases speedup of domain queries on Xen (Daniel berrange), augment XML dumps with interface devices names (Richard Jones), internal API to query drivers for features (Richard Jones). - + - Cleanups: Improve virNodeGetInfo implentation (Daniel berrange), general UUID code cleanup (Daniel berrange), fix API generator - file selection. + file selection. 0.3.1: Jul 24 2007: @@ -161,7 +161,7 @@ Releases - Secure Remote support (Richard Jones). See the remote page of the documentation - + - Documentation: remote support (Richard Jones), description of the URI connection strings (Richard Jones), update of virsh man page, matrix of libvirt API/hypervisor support with version @@ -202,7 +202,7 @@ Releases 0.2.3: Jun 8 2007: - Documentation: documentation for upcoming remote access (Richard Jones), virConnectNumOfDefinedDomains doc (Jan Michael), virsh help messages - for dumpxml and net-dumpxml (Chris Wright), + for dumpxml and net-dumpxml (Chris Wright), - Bug fixes: RelaxNG schemas regexp fix (Robin Green), RelaxNG arch bug (Mark McLoughlin), large buffers bug fixes (Shigeki Sakamoto), error on out of memory condition (Shigeki Sakamoto), virshStrdup fix, non-root @@ -262,7 +262,7 @@ Releases signal handler error cleanup (Richard Jones), iptables internal code claenup (Mark McLoughlin), unified Xen driver (Richard Jones), cleanup XPath libxml2 calls, IPTables rules tightening (Daniel - Berrange), + Berrange), - Improvements: more regression tests on XML (Daniel Berrange), Python bindings now generate exception in error cases (Richard Jones), Python bindings for vir*GetAutoStart (Daniel Berrange), @@ -270,7 +270,7 @@ Releases fix hypervisor call to work with Xen 3.0.5 (Daniel Berrange), DomainGetOSType for inactive domains (Daniel Berrange), multiple boot devices for HVM (Daniel Berrange), - + 0.2.1: Mar 16 2007: @@ -375,7 +375,7 @@ Releases - Support for localization of strings using gettext (Daniel Berrange) - Support for new Xen-3.0.3 cdrom and disk configuration (Daniel Berrange) - Support for setting VNC port when creating domains with new - xend config files (Daniel Berrange) + xend config files (Daniel Berrange) - Fix bug when running against xen-3.0.2 hypercalls (Jim Fehlig) - Fix reconnection problem when talking directly to http xend @@ -409,7 +409,7 @@ Releases floppy and cdrom (Daniel Berrange), features block in XML to report/ask PAE, ACPI, APIC for HVM domains (Daniel Berrange), fail saide-effect operations when using read-only connection, large improvements to test - driver (Daniel Berrange) + driver (Daniel Berrange) - documentation: spelling (Daniel Berrange), test driver examples. diff --git a/src/xm_internal.c b/src/xm_internal.c index ccd3d83742..b3a9f3a285 100644 --- a/src/xm_internal.c +++ b/src/xm_internal.c @@ -72,6 +72,12 @@ static virHashTablePtr nameConfigMap = NULL; static int nconnections = 0; static time_t lastRefresh = 0; +char * xenXMAutoAssignMac(void); +static int xenXMAttachDisk(virDomainPtr domain, xmlXPathContextPtr ctxt, int hvm, + xmlNodePtr node, xenXMConfCachePtr entry); +static int xenXMAttachInterface(virDomainPtr domain, xmlXPathContextPtr ctxt, int hvm, + xmlNodePtr node, xenXMConfCachePtr entry); + #define XM_REFRESH_INTERVAL 10 #define XM_CONFIG_DIR "/etc/xen" @@ -79,6 +85,7 @@ static time_t lastRefresh = 0; #define XEND_CONFIG_FILE "xend-config.sxp" #define XEND_PCI_CONFIG_PREFIX "xend-pci-" #define QEMU_IF_SCRIPT "qemu-ifup" +#define XM_XML_ERROR "Invalid xml" struct xenUnifiedDriver xenXMDriver = { xenXMOpen, /* open */ @@ -113,8 +120,8 @@ struct xenUnifiedDriver xenXMDriver = { xenXMDomainCreate, /* domainCreate */ xenXMDomainDefineXML, /* domainDefineXML */ xenXMDomainUndefine, /* domainUndefine */ - NULL, /* domainAttachDevice */ - NULL, /* domainDetachDevice */ + xenXMDomainAttachDevice, /* domainAttachDevice */ + xenXMDomainDetachDevice, /* domainDetachDevice */ NULL, /* domainGetAutostart */ NULL, /* domainSetAutostart */ NULL, /* domainGetSchedulerType */ @@ -2515,6 +2522,635 @@ int xenXMNumOfDefinedDomains(virConnectPtr conn) { return virHashSize(nameConfigMap); } +/** + * xenXMDomainAttachDevice: + * @domain: pointer to domain object + * @xml: pointer to XML description of device + * + * Create a virtual device attachment to backend. + * XML description is translated into config file. + * + * Returns 0 in case of success, -1 in case of failure. + */ +static int +xenXMDomainAttachDevice(virDomainPtr domain, const char *xml) { + const char *filename = NULL; + xenXMConfCachePtr entry = NULL; + xmlDocPtr doc = NULL; + xmlNodePtr node = NULL; + xmlXPathContextPtr ctxt = NULL; + xmlXPathObjectPtr obj = NULL; + char *domxml = NULL; + int ret = -1, hvm = 0; + + if ((!domain) || (!domain->conn) || (!domain->name) || (!xml)) { + xenXMError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG, + __FUNCTION__); + goto cleanup; + } + if (domain->conn->flags & VIR_CONNECT_RO) + goto cleanup; + if (domain->id != -1) + goto cleanup; + if (!(filename = virHashLookup(nameConfigMap, domain->name))) + goto cleanup; + if (!(entry = virHashLookup(configCache, filename))) + goto cleanup; + if (!(entry->conf)) + goto cleanup; + + if (!(domxml = xenXMDomainDumpXML(domain, 0))) + goto cleanup; + + doc = xmlReadDoc((const xmlChar *) domxml, "domain.xml", NULL, + XML_PARSE_NOENT | XML_PARSE_NONET | + XML_PARSE_NOERROR | XML_PARSE_NOWARNING); + if (!doc) { + xenXMError(domain->conn, VIR_ERR_XML_ERROR, "cannot read XML domain definition"); + goto cleanup; + } + if (!(ctxt = xmlXPathNewContext(doc))) { + xenXMError(domain->conn, VIR_ERR_INTERNAL_ERROR, "cannot create XPath context"); + goto cleanup; + } + obj = xmlXPathEval(BAD_CAST "string(/domain/os/type)", ctxt); + if ((obj != NULL) && (obj->type == XPATH_STRING) && + (obj->stringval) && (STREQ((char *)obj->stringval, "hvm"))) + hvm = 1; + + if (ctxt) + xmlXPathFreeContext(ctxt); + ctxt = NULL; + if (doc) + xmlFreeDoc(doc); + doc = xmlReadDoc((const xmlChar *) xml, "device.xml", NULL, + XML_PARSE_NOENT | XML_PARSE_NONET | + XML_PARSE_NOERROR | XML_PARSE_NOWARNING); + if (!doc) { + xenXMError(domain->conn, VIR_ERR_XML_ERROR, + "cannot read XML domain definition"); + goto cleanup; + } + if (!(ctxt = xmlXPathNewContext(doc))) { + xenXMError(domain->conn, VIR_ERR_INTERNAL_ERROR, + "cannot create XPath context"); + goto cleanup; + } + + if ((node = virXPathNode("/disk", ctxt))) { + if (xenXMAttachDisk(domain, ctxt, hvm, node, entry)) + goto cleanup; + } else if ((node = virXPathNode("/interface", ctxt))) { + if (xenXMAttachInterface(domain, ctxt, hvm, node, entry)) + goto cleanup; + } else { + xenXMError(domain->conn, VIR_ERR_XML_ERROR, "unknown device"); + goto cleanup; + } + + /* If this fails, should we try to undo our changes to the + * in-memory representation of the config file. I say not! + */ + if (virConfWriteFile(entry->filename, entry->conf) < 0) + goto cleanup; + + ret = 0; + + cleanup: + if (domxml) + free(domxml); + if (obj) + xmlXPathFreeObject(obj); + if (ctxt) + xmlXPathFreeContext(ctxt); + if (doc) + xmlFreeDoc(doc); + + return ret; +} + +static int +xenXMAttachDisk(virDomainPtr domain, xmlXPathContextPtr ctxt, int hvm, + xmlNodePtr node, xenXMConfCachePtr entry) { + virConfValuePtr list_item = NULL, list_val = NULL, prev = NULL; + xenUnifiedPrivatePtr priv = NULL; + xmlChar *type = NULL, *source = NULL, *target = NULL; + int ret = -1; + char *dev; + + priv = (xenUnifiedPrivatePtr) domain->conn->privateData; + xenXMParseXMLDisk(node, hvm, ((xenUnifiedPrivatePtr) domain->conn->privateData)->xendConfigVersion, &dev); + if (!dev) + goto cleanup; + + if (!(type = xmlGetProp(node, BAD_CAST "type"))) { + xenXMError(domain->conn, VIR_ERR_XML_ERROR, XM_XML_ERROR); + goto cleanup; + } + if (!(node = virXPathNode("/disk/source", ctxt))) { + xenXMError(domain->conn, VIR_ERR_XML_ERROR, XM_XML_ERROR); + goto cleanup; + } + if (!strcmp((const char *) type, "block")) + source = xmlGetProp(node, BAD_CAST "dev"); + else if (!strcmp((const char *) type, "file")) + source = xmlGetProp(node, BAD_CAST "file"); + else { + xenXMError(domain->conn, VIR_ERR_XML_ERROR, XM_XML_ERROR); + goto cleanup; + } + if (!(node = virXPathNode("/disk/target", ctxt))) { + xenXMError(domain->conn, VIR_ERR_XML_ERROR, XM_XML_ERROR); + goto cleanup; + } + target = xmlGetProp(node, BAD_CAST "dev"); + + list_item = virConfGetValue(entry->conf, "disk"); + if (list_item && list_item->type == VIR_CONF_LIST) { + prev = list_item; + list_val = list_item->list; + while (list_val) { + if ((list_val->type != VIR_CONF_STRING) || (!list_val->str)) + goto skip; + char domdev[NAME_MAX]; + char *head; + char *offset; + char *tmp; + + head = list_val->str; + + /* Extract the source */ + if (!(offset = strchr(head, ',')) || offset[0] == '\0') + goto skip; + if ((offset - head) >= (PATH_MAX-1)) + goto skip; + head = offset + 1; + + /* Extract the dest */ + if (!(offset = strchr(head, ',')) || offset[0] == '\0') + goto skip; + if ((offset - head) >= (PATH_MAX-1)) + goto skip; + strncpy(domdev, head, (offset - head)); + domdev[(offset-head)] = '\0'; + head = offset + 1; + + /* Remove legacy ioemu: junk */ + if (!strncmp(domdev, "ioemu:", 6)) { + memmove(domdev, domdev+6, strlen(domdev)-5); + } + + /* Check for a :cdrom/:disk postfix */ + if ((tmp = strchr(domdev, ':'))) + tmp[0] = '\0'; + + if (!(strcmp(domdev, (const char *) target))) + break; + skip: + prev = list_val; + list_val = list_val->next; + } + } else if (!list_item) { + if (!(list_item = calloc(1, sizeof(virConfValue)))) + goto cleanup; + list_item->type = VIR_CONF_LIST; + if(virConfSetValue(entry->conf, "disk", list_item)) { + free(list_item); + goto cleanup; + } + list_val = NULL; + prev = list_item; + } else + goto cleanup; + + if (!list_val) { + /* insert */ + if (!(list_val = malloc(sizeof(virConfValue)))) + goto cleanup; + list_val->type = VIR_CONF_STRING; + list_val->next = NULL; + list_val->str = dev; + if (prev->type == VIR_CONF_LIST) + prev->list = list_val; + else + prev->next = list_val; + } else { + /* configure */ + if (list_val->str) + free(list_val->str); + list_val->str = dev; + } + + ret = 0; + goto cleanup; + + cleanup: + if (type) + free(type); + if (source) + free(source); + if (target) + free(target); + + return (ret); +} + +static int +xenXMAttachInterface(virDomainPtr domain, xmlXPathContextPtr ctxt, int hvm, + xmlNodePtr node, xenXMConfCachePtr entry) { + virConfValuePtr list_item = NULL, list_val = NULL, prev = NULL; + xmlChar *type = NULL, *source = NULL, *mac = NULL; + int ret = -1, autoassign = 0; + char *dev; + + xmlNodePtr node_cur = NULL, node_tmp = NULL; + xmlAttrPtr attr_node = NULL; + xmlNodePtr text_node = NULL; + + if(!(type = xmlGetProp(node, BAD_CAST "type"))) { + xenXMError(domain->conn, VIR_ERR_XML_ERROR, XM_XML_ERROR); + goto cleanup; + } + + if (!(node = virXPathNode("/interface/source", ctxt))) { + xenXMError(domain->conn, VIR_ERR_XML_ERROR, XM_XML_ERROR); + goto cleanup; + } + source = xmlGetProp(node, BAD_CAST type); + + if (!(node = virXPathNode("/interface/mac", ctxt))) { + if (!(mac = (xmlChar *)xenXMAutoAssignMac())) + goto cleanup; + autoassign = 1; + } else + mac = xmlGetProp(node, BAD_CAST "address"); + + list_item = virConfGetValue(entry->conf, "vif"); + if (list_item && list_item->type == VIR_CONF_LIST) { + prev = list_item; + list_val = list_item->list; + while (list_val) { + if ((list_val->type != VIR_CONF_STRING) || (!list_val->str)) + goto skip; + char dommac[18]; + char *key; + + dommac[0] = '\0'; + + key = list_val->str; + while (key) { + char *data; + char *nextkey = strchr(key, ','); + + if (!(data = strchr(key, '=')) || (data[0] == '\0')) + goto skip; + data++; + + if (!strncmp(key, "mac=", 4)) { + int len = nextkey ? (nextkey - data) : 17; + if (len > 17) + len = 17; + strncpy(dommac, data, len); + dommac[len] = '\0'; + } + + while (nextkey && (nextkey[0] == ',' || + nextkey[0] == ' ' || + nextkey[0] == '\t')) + nextkey++; + key = nextkey; + } + + if (!(strcmp(dommac, (const char *) mac))) { + if (autoassign) { + if (mac) + free(mac); + mac = NULL; + if (!(mac = (xmlChar *)xenXMAutoAssignMac())) + goto cleanup; + /* initialize the list */ + list_item = virConfGetValue(entry->conf, "vif"); + prev = list_item; + list_val = list_item->list; + continue; + } else + break; + } + skip: + prev = list_val; + list_val = list_val->next; + } + } else if (!list_item) { + if (!(list_item = calloc(1, sizeof(virConfValue)))) + goto cleanup; + list_item->type = VIR_CONF_LIST; + if(virConfSetValue(entry->conf, "vif", list_item)) { + free(list_item); + goto cleanup; + } + list_val = NULL; + prev = list_item; + } else + goto cleanup; + + if ((node = virXPathNode("/interface", ctxt))) { + if (autoassign) { + node_cur = node->children; + + while (node_cur->next) + node_cur = node_cur->next; + + if (!(node_tmp = calloc(1, sizeof(xmlNode)))) + goto node_cleanup; + node_tmp->type = XML_ELEMENT_NODE; + if (!(node_tmp->name = malloc(4))) + goto node_cleanup; + strcpy((char *)node_tmp->name, "mac"); + node_tmp->children = NULL; + + if (!(attr_node = calloc(1, sizeof(xmlAttr)))) + goto node_cleanup; + attr_node->type = XML_ATTRIBUTE_NODE; + attr_node->ns = NULL; + if (!(attr_node->name = malloc(8))) + goto node_cleanup; + strcpy((char *) attr_node->name, "address"); + node_tmp->properties = attr_node; + + if (!(text_node = calloc(1, sizeof(xmlNode)))) + goto node_cleanup; + text_node->type = XML_TEXT_NODE; + text_node->_private = NULL; + if (!(text_node->name = malloc(8))) + goto node_cleanup; + strcpy((char *) text_node->name, "text"); + text_node->children = NULL; + text_node->parent = (xmlNodePtr)attr_node; + text_node->content = mac; + mac = NULL; + attr_node->children = text_node; + attr_node->last = text_node; + attr_node->parent = node_tmp; + + node_cur->next = node_tmp; + } + if (!(dev = xenXMParseXMLVif(domain->conn, node, hvm))) + goto cleanup; + } else + goto cleanup; + + if (!list_val) { + /* insert */ + if (!(list_val = malloc(sizeof(virConfValue)))) + goto cleanup; + list_val->type = VIR_CONF_STRING; + list_val->next = NULL; + list_val->str = dev; + if (prev->type == VIR_CONF_LIST) + prev->list = list_val; + else + prev->next = list_val; + } else { + /* configure */ + if (list_val->str) + free(list_val->str); + list_val->str = dev; + } + + ret = 0; + goto cleanup; + + node_cleanup: + if (node_tmp) + xmlFree(node_tmp); + if (attr_node) + xmlFree(attr_node); + if (text_node) + xmlFree(text_node); + cleanup: + if (type) + free(type); + if (source) + free(source); + if (mac) + free(mac); + + return (ret); +} + +/** + * xenXMAutoAssignMac: + * @mac: pointer to Mac String + * + * a mac is assigned automatically. + * + * Returns 0 in case of success, -1 in case of failure. + */ +char * +xenXMAutoAssignMac() { + char *buf; + + if (!(buf = malloc(18))) + return 0; + srand((unsigned)time(NULL)); + sprintf(buf, "00:16:3e:%02x:%02x:%02x" + ,1 + (int)(256*(rand()/(RAND_MAX+1.0))) + ,1 + (int)(256*(rand()/(RAND_MAX+1.0))) + ,1 + (int)(256*(rand()/(RAND_MAX+1.0)))); + return buf; +} + +/** + * xenXMDomainDetachDevice: + * @domain: pointer to domain object + * @xml: pointer to XML description of device + * + * Destroy a virtual device attachment to backend. + * + * Returns 0 in case of success, -1 in case of failure. + */ +static int +xenXMDomainDetachDevice(virDomainPtr domain, const char *xml) { + const char *filename = NULL; + char device[8], *domdevice = NULL; + xenXMConfCachePtr entry = NULL; + virConfValuePtr prev = NULL, list_ptr = NULL, list_val = NULL; + xmlDocPtr doc = NULL; + xmlNodePtr node = NULL; + xmlXPathContextPtr ctxt = NULL; + xmlChar *key = NULL; + int ret = -1; + + if ((!domain) || (!domain->conn) || (!domain->name) || (!xml)) { + xenXMError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG, + __FUNCTION__); + goto cleanup; + } + if (domain->conn->flags & VIR_CONNECT_RO) + goto cleanup; + if (domain->id != -1) + goto cleanup; + if (!(filename = virHashLookup(nameConfigMap, domain->name))) + goto cleanup; + + doc = xmlReadDoc((const xmlChar *) xml, "device.xml", NULL, + XML_PARSE_NOENT | XML_PARSE_NONET | + XML_PARSE_NOERROR | XML_PARSE_NOWARNING); + if (!doc) { + xenXMError(domain->conn, VIR_ERR_XML_ERROR, "cannot read XML domain definition"); + goto cleanup; + } + if (!(ctxt = xmlXPathNewContext(doc))) { + xenXMError(domain->conn, VIR_ERR_INTERNAL_ERROR, "cannot create XPath context"); + goto cleanup; + } + + if ((node = virXPathNode("/disk", ctxt))) { + strcpy(device, "disk"); + if (!(node = virXPathNode("/disk/target", ctxt))) + goto cleanup; + key = xmlGetProp(node, BAD_CAST "dev"); + } else if ((node = virXPathNode("/interface", ctxt))) { + strcpy(device, "vif"); + if (!(node = virXPathNode("/interface/mac", ctxt))) + goto cleanup; + key = xmlGetProp(node, BAD_CAST "address"); + } else + goto cleanup; + if (!key || (strlen((char *)key) == 0)) + goto cleanup; + + if (!(entry = virHashLookup(configCache, filename))) + goto cleanup; + if (!entry->conf) + goto cleanup; + + list_ptr = virConfGetValue(entry->conf, device); + if (!list_ptr) + goto cleanup; + else if (list_ptr && list_ptr->type == VIR_CONF_LIST) { + list_val = list_ptr->list; + while (list_val) { + if (!(strcmp(device, "disk"))) { + char domdev[NAME_MAX]; + char *head; + char *offset; + char *tmp; + + if ((list_val->type != VIR_CONF_STRING) || (!list_val->str)) + goto skip; + head = list_val->str; + + /* Extract the source */ + if (!(offset = strchr(head, ',')) || offset[0] == '\0') + goto skip; + if ((offset - head) >= (PATH_MAX-1)) + goto skip; + head = offset + 1; + + /* Extract the dest */ + if (!(offset = strchr(head, ',')) || offset[0] == '\0') + goto skip; + if ((offset - head) >= (PATH_MAX-1)) + goto skip; + strncpy(domdev, head, (offset - head)); + domdev[(offset-head)] = '\0'; + head = offset + 1; + + /* Remove legacy ioemu: junk */ + if (!strncmp(domdev, "ioemu:", 6)) { + memmove(domdev, domdev+6, strlen(domdev)-5); + } + + /* Check for a :cdrom/:disk postfix */ + if ((tmp = strchr(domdev, ':'))) + tmp[0] = '\0'; + + if (!(strcmp(domdev, (const char *) key))) + break; + } else { + char dommac[18]; + char *mac; + + dommac[0] = '\0'; + + if ((list_val->type != VIR_CONF_STRING) || (!list_val->str)) + goto skip; + + mac = list_val->str; + while (mac) { + char *data; + char *nextmac = strchr(mac, ','); + + if (!(data = strchr(mac, '=')) || (data[0] == '\0')) + goto skip; + data++; + + if (!strncmp(mac, "mac=", 4)) { + int len = nextmac ? (nextmac - data) : 17; + if (len > 17) + len = 17; + strncpy(dommac, data, len); + dommac[len] = '\0'; + } + + while (nextmac && (nextmac[0] == ',' || + nextmac[0] == ' ' || + nextmac[0] == '\t')) + nextmac++; + mac = nextmac; + } + + if (!(strcmp(dommac, (const char *) key))) + break; + } + skip: + prev = list_val; + list_val = list_val->next; + } + } + + if (!list_val) + goto cleanup; + else { + if (!prev) { + virConfValuePtr value; + if (!(value = calloc(1, sizeof(virConfValue)))) + goto cleanup; + value->type = VIR_CONF_LIST; + value->list = list_val->next; + list_val->next = NULL; + if (virConfSetValue(entry->conf, device, value)) { + free(value); + goto cleanup; + } + } else + prev->next = list_val->next; + } + + /* If this fails, should we try to undo our changes to the + * in-memory representation of the config file. I say not! + */ + if (virConfWriteFile(entry->filename, entry->conf) < 0) + goto cleanup; + + ret = 0; + + cleanup: + if (ctxt) + xmlXPathFreeContext(ctxt); + if (doc) + xmlFreeDoc(doc); + if (domdevice) + free(domdevice); + if (key) + free(key); + if (list_val) + free(list_val); + + return (ret); +} + #endif /* WITH_XEN */ /* * Local variables: diff --git a/src/xm_internal.h b/src/xm_internal.h index bdb5bb768e..b7b5599b9e 100644 --- a/src/xm_internal.h +++ b/src/xm_internal.h @@ -61,6 +61,9 @@ int xenXMDomainUndefine(virDomainPtr domain); virConfPtr xenXMParseXMLToConfig(virConnectPtr conn, const char *xml); char *xenXMDomainFormatXML(virConnectPtr conn, virConfPtr conf); +static int xenXMDomainAttachDevice(virDomainPtr domain, const char *xml); +static int xenXMDomainDetachDevice(virDomainPtr domain, const char *xml); + #ifdef __cplusplus } #endif