static void virDomainSnapshotDiskDefFormat(virBufferPtr buf, virDomainSnapshotDiskDefPtr disk) { int type = disk->src->type; if (!disk->name) return; virBufferEscapeString(buf, "<disk name='%s'", disk->name); if (disk->snapshot > 0) virBufferAsprintf(buf, " snapshot='%s'", virDomainSnapshotLocationTypeToString(disk->snapshot)); if (!disk->src->path && disk->src->format == 0) { virBufferAddLit(buf, "/>\n"); return; } virBufferAsprintf(buf, " type='%s'>\n", virStorageTypeToString(type)); virBufferAdjustIndent(buf, 2); if (disk->src->format > 0) virBufferEscapeString(buf, "<driver type='%s'/>\n", virStorageFileFormatTypeToString(disk->src->format)); virDomainDiskSourceFormat(buf, disk->src, 0, 0); virBufferAdjustIndent(buf, -2); virBufferAddLit(buf, "</disk>\n"); }
static void virDomainSnapshotDiskDefFormat(virBufferPtr buf, virDomainSnapshotDiskDefPtr disk) { int type = disk->type; if (!disk->name) return; virBufferEscapeString(buf, " <disk name='%s'", disk->name); if (disk->snapshot > 0) virBufferAsprintf(buf, " snapshot='%s'", virDomainSnapshotLocationTypeToString(disk->snapshot)); if (type < 0) type = VIR_DOMAIN_DISK_TYPE_FILE; if (!disk->file && disk->format == 0) { virBufferAddLit(buf, "/>\n"); return; } virBufferAddLit(buf, ">\n"); if (disk->format > 0) virBufferEscapeString(buf, " <driver type='%s'/>\n", virStorageFileFormatTypeToString(disk->format)); virDomainDiskSourceDefFormatInternal(buf, type, disk->file, 0, 0, 0, NULL, 0, NULL, NULL, 0); virBufferAddLit(buf, " </disk>\n"); }
char *virDomainSnapshotDefFormat(const char *domain_uuid, virDomainSnapshotDefPtr def, unsigned int flags, int internal) { virBuffer buf = VIR_BUFFER_INITIALIZER; int i; virCheckFlags(VIR_DOMAIN_XML_SECURE | VIR_DOMAIN_XML_UPDATE_CPU, NULL); flags |= VIR_DOMAIN_XML_INACTIVE; virBufferAddLit(&buf, "<domainsnapshot>\n"); virBufferEscapeString(&buf, " <name>%s</name>\n", def->name); if (def->description) virBufferEscapeString(&buf, " <description>%s</description>\n", def->description); virBufferAsprintf(&buf, " <state>%s</state>\n", virDomainSnapshotStateTypeToString(def->state)); if (def->parent) { virBufferAddLit(&buf, " <parent>\n"); virBufferEscapeString(&buf, " <name>%s</name>\n", def->parent); virBufferAddLit(&buf, " </parent>\n"); } virBufferAsprintf(&buf, " <creationTime>%lld</creationTime>\n", def->creationTime); if (def->memory) { virBufferAsprintf(&buf, " <memory snapshot='%s'", virDomainSnapshotLocationTypeToString(def->memory)); virBufferEscapeString(&buf, " file='%s'", def->file); virBufferAddLit(&buf, "/>\n"); } if (def->ndisks) { virBufferAddLit(&buf, " <disks>\n"); for (i = 0; i < def->ndisks; i++) { virDomainSnapshotDiskDefPtr disk = &def->disks[i]; if (!disk->name) continue; virBufferEscapeString(&buf, " <disk name='%s'", disk->name); if (disk->snapshot) virBufferAsprintf(&buf, " snapshot='%s'", virDomainSnapshotLocationTypeToString(disk->snapshot)); if (disk->file || disk->format > 0) { virBufferAddLit(&buf, ">\n"); if (disk->format > 0) virBufferEscapeString(&buf, " <driver type='%s'/>\n", virStorageFileFormatTypeToString( disk->format)); if (disk->file) virBufferEscapeString(&buf, " <source file='%s'/>\n", disk->file); virBufferAddLit(&buf, " </disk>\n"); } else { virBufferAddLit(&buf, "/>\n"); } } virBufferAddLit(&buf, " </disks>\n"); } if (def->dom) { virBufferAdjustIndent(&buf, 2); if (virDomainDefFormatInternal(def->dom, flags, &buf) < 0) { virBufferFreeAndReset(&buf); return NULL; } virBufferAdjustIndent(&buf, -2); } else if (domain_uuid) { virBufferAddLit(&buf, " <domain>\n"); virBufferAsprintf(&buf, " <uuid>%s</uuid>\n", domain_uuid); virBufferAddLit(&buf, " </domain>\n"); } if (internal) virBufferAsprintf(&buf, " <active>%d</active>\n", def->current); virBufferAddLit(&buf, "</domainsnapshot>\n"); if (virBufferError(&buf)) { virBufferFreeAndReset(&buf); virReportOOMError(); return NULL; } return virBufferContentAndReset(&buf); }
/* Align def->disks to def->domain. Sort the list of def->disks, * filling in any missing disks or snapshot state defaults given by * the domain, with a fallback to a passed in default. Convert paths * to disk targets for uniformity. Issue an error and return -1 if * any def->disks[n]->name appears more than once or does not map to * dom->disks. If require_match, also ensure that there is no * conflicting requests for both internal and external snapshots. */ int virDomainSnapshotAlignDisks(virDomainSnapshotDefPtr def, int default_snapshot, bool require_match) { int ret = -1; virBitmapPtr map = NULL; int i; int ndisks; bool inuse; if (!def->dom) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("missing domain in snapshot")); goto cleanup; } if (def->ndisks > def->dom->ndisks) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("too many disk snapshot requests for domain")); goto cleanup; } /* Unlikely to have a guest without disks but technically possible. */ if (!def->dom->ndisks) { ret = 0; goto cleanup; } if (!(map = virBitmapNew(def->dom->ndisks))) { virReportOOMError(); goto cleanup; } /* Double check requested disks. */ for (i = 0; i < def->ndisks; i++) { virDomainSnapshotDiskDefPtr disk = &def->disks[i]; int idx = virDomainDiskIndexByName(def->dom, disk->name, false); int disk_snapshot; if (idx < 0) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("no disk named '%s'"), disk->name); goto cleanup; } if (virBitmapGetBit(map, idx, &inuse) < 0 || inuse) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("disk '%s' specified twice"), disk->name); goto cleanup; } ignore_value(virBitmapSetBit(map, idx)); disk->index = idx; disk_snapshot = def->dom->disks[idx]->snapshot; if (!disk->snapshot) { if (disk_snapshot && (!require_match || disk_snapshot == VIR_DOMAIN_SNAPSHOT_LOCATION_NONE)) disk->snapshot = disk_snapshot; else disk->snapshot = default_snapshot; } else if (require_match && disk->snapshot != default_snapshot && !(disk->snapshot == VIR_DOMAIN_SNAPSHOT_LOCATION_NONE && disk_snapshot == VIR_DOMAIN_SNAPSHOT_LOCATION_NONE)) { const char *tmp; tmp = virDomainSnapshotLocationTypeToString(default_snapshot); virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("disk '%s' must use snapshot mode '%s'"), disk->name, tmp); goto cleanup; } if (disk->file && disk->snapshot != VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("file '%s' for disk '%s' requires " "use of external snapshot mode"), disk->file, disk->name); goto cleanup; } if (STRNEQ(disk->name, def->dom->disks[idx]->dst)) { VIR_FREE(disk->name); if (!(disk->name = strdup(def->dom->disks[idx]->dst))) { virReportOOMError(); goto cleanup; } } } /* Provide defaults for all remaining disks. */ ndisks = def->ndisks; if (VIR_EXPAND_N(def->disks, def->ndisks, def->dom->ndisks - def->ndisks) < 0) { virReportOOMError(); goto cleanup; } for (i = 0; i < def->dom->ndisks; i++) { virDomainSnapshotDiskDefPtr disk; ignore_value(virBitmapGetBit(map, i, &inuse)); if (inuse) continue; disk = &def->disks[ndisks++]; if (!(disk->name = strdup(def->dom->disks[i]->dst))) { virReportOOMError(); goto cleanup; } disk->index = i; disk->snapshot = def->dom->disks[i]->snapshot; if (!disk->snapshot) disk->snapshot = default_snapshot; } qsort(&def->disks[0], def->ndisks, sizeof(def->disks[0]), disksorter); /* Generate any default external file names, but only if the * backing file is a regular file. */ for (i = 0; i < def->ndisks; i++) { virDomainSnapshotDiskDefPtr disk = &def->disks[i]; if (disk->snapshot == VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL && !disk->file) { const char *original = def->dom->disks[i]->src; const char *tmp; struct stat sb; if (!original) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("cannot generate external snapshot name " "for disk '%s' without source"), disk->name); goto cleanup; } if (stat(original, &sb) < 0 || !S_ISREG(sb.st_mode)) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("source for disk '%s' is not a regular " "file; refusing to generate external " "snapshot name"), disk->name); goto cleanup; } tmp = strrchr(original, '.'); if (!tmp || strchr(tmp, '/')) { ignore_value(virAsprintf(&disk->file, "%s.%s", original, def->name)); } else { if ((tmp - original) > INT_MAX) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("integer overflow")); goto cleanup; } ignore_value(virAsprintf(&disk->file, "%.*s.%s", (int) (tmp - original), original, def->name)); } if (!disk->file) { virReportOOMError(); goto cleanup; } } } ret = 0; cleanup: virBitmapFree(map); return ret; }
char *virDomainSnapshotDefFormat(const char *domain_uuid, virDomainSnapshotDefPtr def, unsigned int flags, int internal) { virBuffer buf = VIR_BUFFER_INITIALIZER; size_t i; virCheckFlags(VIR_DOMAIN_DEF_FORMAT_SECURE | VIR_DOMAIN_DEF_FORMAT_UPDATE_CPU, NULL); flags |= VIR_DOMAIN_DEF_FORMAT_INACTIVE; virBufferAddLit(&buf, "<domainsnapshot>\n"); virBufferAdjustIndent(&buf, 2); virBufferEscapeString(&buf, "<name>%s</name>\n", def->name); if (def->description) virBufferEscapeString(&buf, "<description>%s</description>\n", def->description); virBufferAsprintf(&buf, "<state>%s</state>\n", virDomainSnapshotStateTypeToString(def->state)); if (def->parent) { virBufferAddLit(&buf, "<parent>\n"); virBufferAdjustIndent(&buf, 2); virBufferEscapeString(&buf, "<name>%s</name>\n", def->parent); virBufferAdjustIndent(&buf, -2); virBufferAddLit(&buf, "</parent>\n"); } virBufferAsprintf(&buf, "<creationTime>%lld</creationTime>\n", def->creationTime); if (def->memory) { virBufferAsprintf(&buf, "<memory snapshot='%s'", virDomainSnapshotLocationTypeToString(def->memory)); virBufferEscapeString(&buf, " file='%s'", def->file); virBufferAddLit(&buf, "/>\n"); } if (def->ndisks) { virBufferAddLit(&buf, "<disks>\n"); virBufferAdjustIndent(&buf, 2); for (i = 0; i < def->ndisks; i++) virDomainSnapshotDiskDefFormat(&buf, &def->disks[i]); virBufferAdjustIndent(&buf, -2); virBufferAddLit(&buf, "</disks>\n"); } if (def->dom) { if (virDomainDefFormatInternal(def->dom, flags, &buf) < 0) { virBufferFreeAndReset(&buf); return NULL; } } else if (domain_uuid) { virBufferAddLit(&buf, "<domain>\n"); virBufferAdjustIndent(&buf, 2); virBufferAsprintf(&buf, "<uuid>%s</uuid>\n", domain_uuid); virBufferAdjustIndent(&buf, -2); virBufferAddLit(&buf, "</domain>\n"); } if (internal) virBufferAsprintf(&buf, "<active>%d</active>\n", def->current); virBufferAdjustIndent(&buf, -2); virBufferAddLit(&buf, "</domainsnapshot>\n"); if (virBufferCheckError(&buf) < 0) return NULL; return virBufferContentAndReset(&buf); }