static int virDomainSnapshotDiskDefParseXML(xmlNodePtr node, virDomainSnapshotDiskDefPtr def) { int ret = -1; char *snapshot = NULL; xmlNodePtr cur; def->name = virXMLPropString(node, "name"); if (!def->name) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("missing name from disk snapshot element")); goto cleanup; } snapshot = virXMLPropString(node, "snapshot"); if (snapshot) { def->snapshot = virDomainSnapshotLocationTypeFromString(snapshot); if (def->snapshot <= 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("unknown disk snapshot setting '%s'"), snapshot); goto cleanup; } } cur = node->children; while (cur) { if (cur->type == XML_ELEMENT_NODE) { if (!def->file && xmlStrEqual(cur->name, BAD_CAST "source")) { def->file = virXMLPropString(cur, "file"); } else if (!def->format && xmlStrEqual(cur->name, BAD_CAST "driver")) { char *driver = virXMLPropString(cur, "type"); def->format = virStorageFileFormatTypeFromString(driver); if (def->format <= 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("unknown disk snapshot driver '%s'"), driver); VIR_FREE(driver); goto cleanup; } VIR_FREE(driver); } } cur = cur->next; } if (!def->snapshot && (def->file || def->format)) def->snapshot = VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL; ret = 0; cleanup: VIR_FREE(snapshot); if (ret < 0) virDomainSnapshotDiskDefClear(def); return ret; }
/* flags is bitwise-or of virDomainSnapshotParseFlags. * If flags does not include VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE, then * caps and expectedVirtTypes are ignored. */ virDomainSnapshotDefPtr virDomainSnapshotDefParseString(const char *xmlStr, virCapsPtr caps, unsigned int expectedVirtTypes, unsigned int flags) { xmlXPathContextPtr ctxt = NULL; xmlDocPtr xml = NULL; virDomainSnapshotDefPtr def = NULL; virDomainSnapshotDefPtr ret = NULL; xmlNodePtr *nodes = NULL; int i; char *creation = NULL, *state = NULL; struct timeval tv; int active; char *tmp; int keepBlanksDefault = xmlKeepBlanksDefault(0); char *memorySnapshot = NULL; char *memoryFile = NULL; bool offline = !!(flags & VIR_DOMAIN_SNAPSHOT_PARSE_OFFLINE); xml = virXMLParseCtxt(NULL, xmlStr, _("(domain_snapshot)"), &ctxt); if (!xml) { xmlKeepBlanksDefault(keepBlanksDefault); return NULL; } xmlKeepBlanksDefault(keepBlanksDefault); if (VIR_ALLOC(def) < 0) { virReportOOMError(); goto cleanup; } if (!xmlStrEqual(ctxt->node->name, BAD_CAST "domainsnapshot")) { virReportError(VIR_ERR_XML_ERROR, "%s", _("domainsnapshot")); goto cleanup; } gettimeofday(&tv, NULL); def->name = virXPathString("string(./name)", ctxt); if (def->name == NULL) { if (flags & VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE) { virReportError(VIR_ERR_XML_ERROR, "%s", _("a redefined snapshot must have a name")); goto cleanup; } if (virAsprintf(&def->name, "%lld", (long long)tv.tv_sec) < 0) { virReportOOMError(); goto cleanup; } } def->description = virXPathString("string(./description)", ctxt); if (flags & VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE) { if (virXPathLongLong("string(./creationTime)", ctxt, &def->creationTime) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("missing creationTime from existing snapshot")); goto cleanup; } def->parent = virXPathString("string(./parent/name)", ctxt); state = virXPathString("string(./state)", ctxt); if (state == NULL) { /* there was no state in an existing snapshot; this * should never happen */ virReportError(VIR_ERR_XML_ERROR, "%s", _("missing state from existing snapshot")); goto cleanup; } def->state = virDomainSnapshotStateTypeFromString(state); if (def->state < 0) { virReportError(VIR_ERR_XML_ERROR, _("Invalid state '%s' in domain snapshot XML"), state); goto cleanup; } offline = (def->state == VIR_DOMAIN_SHUTOFF || def->state == VIR_DOMAIN_DISK_SNAPSHOT); /* Older snapshots were created with just <domain>/<uuid>, and * lack domain/@type. In that case, leave dom NULL, and * clients will have to decide between best effort * initialization or outright failure. */ if ((tmp = virXPathString("string(./domain/@type)", ctxt))) { xmlNodePtr domainNode = virXPathNode("./domain", ctxt); VIR_FREE(tmp); if (!domainNode) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("missing domain in snapshot")); goto cleanup; } def->dom = virDomainDefParseNode(caps, xml, domainNode, expectedVirtTypes, (VIR_DOMAIN_XML_INACTIVE | VIR_DOMAIN_XML_SECURE)); if (!def->dom) goto cleanup; } else { VIR_WARN("parsing older snapshot that lacks domain"); } } else { def->creationTime = tv.tv_sec; } memorySnapshot = virXPathString("string(./memory/@snapshot)", ctxt); memoryFile = virXPathString("string(./memory/@file)", ctxt); if (memorySnapshot) { def->memory = virDomainSnapshotLocationTypeFromString(memorySnapshot); if (def->memory <= 0) { virReportError(VIR_ERR_XML_ERROR, _("unknown memory snapshot setting '%s'"), memorySnapshot); goto cleanup; } if (memoryFile && def->memory != VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL) { virReportError(VIR_ERR_XML_ERROR, _("memory filename '%s' requires external snapshot"), memoryFile); goto cleanup; } if (!memoryFile && def->memory == VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL) { virReportError(VIR_ERR_XML_ERROR, "%s", _("external memory snapshots require a filename")); goto cleanup; } } else if (memoryFile) { def->memory = VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL; } else if (flags & VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE) { def->memory = (offline ? VIR_DOMAIN_SNAPSHOT_LOCATION_NONE : VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL); } if (offline && def->memory && def->memory != VIR_DOMAIN_SNAPSHOT_LOCATION_NONE) { virReportError(VIR_ERR_XML_ERROR, "%s", _("memory state cannot be saved with offline or " "disk-only snapshot")); goto cleanup; } def->file = memoryFile; memoryFile = NULL; if ((i = virXPathNodeSet("./disks/*", ctxt, &nodes)) < 0) goto cleanup; if (flags & VIR_DOMAIN_SNAPSHOT_PARSE_DISKS) { def->ndisks = i; if (def->ndisks && VIR_ALLOC_N(def->disks, def->ndisks) < 0) { virReportOOMError(); goto cleanup; } for (i = 0; i < def->ndisks; i++) { if (virDomainSnapshotDiskDefParseXML(nodes[i], &def->disks[i]) < 0) goto cleanup; } VIR_FREE(nodes); } else if (i) { virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", _("unable to handle disk requests in snapshot")); goto cleanup; } if (flags & VIR_DOMAIN_SNAPSHOT_PARSE_INTERNAL) { if (virXPathInt("string(./active)", ctxt, &active) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not find 'active' element")); goto cleanup; } def->current = active != 0; } ret = def; cleanup: VIR_FREE(creation); VIR_FREE(state); VIR_FREE(nodes); VIR_FREE(memorySnapshot); VIR_FREE(memoryFile); xmlXPathFreeContext(ctxt); if (ret == NULL) virDomainSnapshotDefFree(def); xmlFreeDoc(xml); return ret; }
static int virDomainSnapshotDiskDefParseXML(xmlNodePtr node, xmlXPathContextPtr ctxt, virDomainSnapshotDiskDefPtr def) { int ret = -1; char *snapshot = NULL; char *type = NULL; xmlNodePtr cur; if (VIR_ALLOC(def->src) < 0) goto cleanup; def->name = virXMLPropString(node, "name"); if (!def->name) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("missing name from disk snapshot element")); goto cleanup; } snapshot = virXMLPropString(node, "snapshot"); if (snapshot) { def->snapshot = virDomainSnapshotLocationTypeFromString(snapshot); if (def->snapshot <= 0) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("unknown disk snapshot setting '%s'"), snapshot); goto cleanup; } } if ((type = virXMLPropString(node, "type"))) { if ((def->src->type = virStorageTypeFromString(type)) <= 0 || def->src->type == VIR_STORAGE_TYPE_VOLUME || def->src->type == VIR_STORAGE_TYPE_DIR) { virReportError(VIR_ERR_XML_ERROR, _("unknown disk snapshot type '%s'"), type); goto cleanup; } } else { def->src->type = VIR_STORAGE_TYPE_FILE; } for (cur = node->children; cur; cur = cur->next) { if (cur->type != XML_ELEMENT_NODE) continue; if (!def->src->path && xmlStrEqual(cur->name, BAD_CAST "source")) { if (virDomainDiskSourceParse(cur, ctxt, def->src) < 0) goto cleanup; } else if (!def->src->format && xmlStrEqual(cur->name, BAD_CAST "driver")) { char *driver = virXMLPropString(cur, "type"); if (driver) { def->src->format = virStorageFileFormatTypeFromString(driver); if (def->src->format < VIR_STORAGE_FILE_BACKING) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, def->src->format <= 0 ? _("unknown disk snapshot driver '%s'") : _("disk format '%s' lacks backing file " "support"), driver); VIR_FREE(driver); goto cleanup; } VIR_FREE(driver); } } } /* validate that the passed path is absolute */ if (virStorageSourceIsLocalStorage(def->src) && def->src->path && def->src->path[0] != '/') { virReportError(VIR_ERR_XML_ERROR, _("disk snapshot image path '%s' must be absolute"), def->src->path); goto cleanup; } if (!def->snapshot && (def->src->path || def->src->format)) def->snapshot = VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL; ret = 0; cleanup: VIR_FREE(snapshot); VIR_FREE(type); if (ret < 0) virDomainSnapshotDiskDefClear(def); return ret; }