virCPUDefPtr virCPUDefParseXML(const xmlNodePtr node, xmlXPathContextPtr ctxt, enum virCPUType mode) { virCPUDefPtr def; xmlNodePtr *nodes = NULL; int n; unsigned int i; char *cpuMode; if (!xmlStrEqual(node->name, BAD_CAST "cpu")) { virCPUReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("XML does not contain expected 'cpu' element")); return NULL; } if (VIR_ALLOC(def) < 0) { virReportOOMError(); return NULL; } if (mode == VIR_CPU_TYPE_AUTO) { if (virXPathBoolean("boolean(./arch)", ctxt)) { if (virXPathBoolean("boolean(./@match)", ctxt)) { virCPUReportError(VIR_ERR_XML_ERROR, "%s", _("'arch' element element cannot be used inside 'cpu'" " element with 'match' attribute'")); goto error; } def->type = VIR_CPU_TYPE_HOST; } else { def->type = VIR_CPU_TYPE_GUEST; } } else { def->type = mode; } if ((cpuMode = virXMLPropString(node, "mode"))) { if (def->type == VIR_CPU_TYPE_HOST) { VIR_FREE(cpuMode); virCPUReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("Attribute mode is only allowed for guest CPU")); goto error; } else { def->mode = virCPUModeTypeFromString(cpuMode); if (def->mode < 0) { virCPUReportError(VIR_ERR_INTERNAL_ERROR, _("Invalid mode attribute '%s'"), cpuMode); VIR_FREE(cpuMode); goto error; } VIR_FREE(cpuMode); } } else { if (def->type == VIR_CPU_TYPE_HOST) def->mode = -1; else def->mode = VIR_CPU_MODE_CUSTOM; } if (def->type == VIR_CPU_TYPE_GUEST) { char *match = virXMLPropString(node, "match"); if (!match) { if (virXPathBoolean("boolean(./model)", ctxt)) def->match = VIR_CPU_MATCH_EXACT; else def->match = -1; } else { def->match = virCPUMatchTypeFromString(match); VIR_FREE(match); if (def->match < 0) { virCPUReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid match attribute for CPU specification")); goto error; } } } if (def->type == VIR_CPU_TYPE_HOST) { def->arch = virXPathString("string(./arch[1])", ctxt); if (!def->arch) { virCPUReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Missing CPU architecture")); goto error; } } if (!(def->model = virXPathString("string(./model[1])", ctxt)) && def->type == VIR_CPU_TYPE_HOST) { virCPUReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Missing CPU model name")); goto error; } if (def->type == VIR_CPU_TYPE_GUEST && def->mode != VIR_CPU_MODE_HOST_PASSTHROUGH && virXPathBoolean("boolean(./model[1]/@fallback)", ctxt)) { const char *fallback; fallback = virXPathString("string(./model[1]/@fallback)", ctxt); if (fallback) { def->fallback = virCPUFallbackTypeFromString(fallback); VIR_FREE(fallback); if (def->fallback < 0) { virCPUReportError(VIR_ERR_XML_ERROR, "%s", _("Invalid fallback attribute")); goto error; } } } def->vendor = virXPathString("string(./vendor[1])", ctxt); if (def->vendor && !def->model) { virCPUReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("CPU vendor specified without CPU model")); goto error; } if (virXPathNode("./topology[1]", ctxt)) { int ret; unsigned long ul; ret = virXPathULong("string(./topology[1]/@sockets)", ctxt, &ul); if (ret < 0) { virCPUReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Missing 'sockets' attribute in CPU topology")); goto error; } def->sockets = (unsigned int) ul; ret = virXPathULong("string(./topology[1]/@cores)", ctxt, &ul); if (ret < 0) { virCPUReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Missing 'cores' attribute in CPU topology")); goto error; } def->cores = (unsigned int) ul; ret = virXPathULong("string(./topology[1]/@threads)", ctxt, &ul); if (ret < 0) { virCPUReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Missing 'threads' attribute in CPU topology")); goto error; } def->threads = (unsigned int) ul; if (!def->sockets || !def->cores || !def->threads) { virCPUReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid CPU topology")); goto error; } } n = virXPathNodeSet("./feature", ctxt, &nodes); if (n < 0) goto error; if (n > 0) { if (!def->model) { virCPUReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Non-empty feature list specified without CPU model")); goto error; } if (VIR_RESIZE_N(def->features, def->nfeatures_max, def->nfeatures, n) < 0) goto no_memory; def->nfeatures = n; } for (i = 0 ; i < n ; i++) { char *name; int policy; /* enum virDomainCPUFeaturePolicy */ unsigned int j; if (def->type == VIR_CPU_TYPE_GUEST) { char *strpolicy; strpolicy = virXMLPropString(nodes[i], "policy"); if (strpolicy == NULL) policy = VIR_CPU_FEATURE_REQUIRE; else policy = virCPUFeaturePolicyTypeFromString(strpolicy); VIR_FREE(strpolicy); if (policy < 0) { virCPUReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid CPU feature policy")); goto error; } } else { policy = -1; } if (!(name = virXMLPropString(nodes[i], "name")) || *name == 0) { VIR_FREE(name); virCPUReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid CPU feature name")); goto error; } for (j = 0 ; j < i ; j++) { if (STREQ(name, def->features[j].name)) { virCPUReportError(VIR_ERR_INTERNAL_ERROR, _("CPU feature `%s' specified more than once"), name); VIR_FREE(name); goto error; } } def->features[i].name = name; def->features[i].policy = policy; } if (virXPathNode("./numa[1]", ctxt)) { VIR_FREE(nodes); n = virXPathNodeSet("./numa[1]/cell", ctxt, &nodes); if (n <= 0) { virCPUReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("NUMA topology defined without NUMA cells")); goto error; } if (VIR_RESIZE_N(def->cells, def->ncells_max, def->ncells, n) < 0) goto no_memory; def->ncells = n; for (i = 0 ; i < n ; i++) { char *cpus, *memory; int cpumasklen = VIR_DOMAIN_CPUMASK_LEN; int ret, ncpus = 0; def->cells[i].cellid = i; cpus = virXMLPropString(nodes[i], "cpus"); if (!cpus) { virCPUReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Missing 'cpus' attribute in NUMA cell")); goto error; } def->cells[i].cpustr = cpus; if (VIR_ALLOC_N(def->cells[i].cpumask, cpumasklen) < 0) goto no_memory; ncpus = virDomainCpuSetParse(cpus, 0, def->cells[i].cpumask, cpumasklen); if (ncpus <= 0) goto error; def->cells_cpus += ncpus; memory = virXMLPropString(nodes[i], "memory"); if (!memory) { virCPUReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Missing 'memory' attribute in NUMA cell")); goto error; } ret = virStrToLong_ui(memory, NULL, 10, &def->cells[i].mem); if (ret == -1) { virCPUReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid 'memory' attribute in NUMA cell")); VIR_FREE(memory); goto error; } VIR_FREE(memory); } } cleanup: VIR_FREE(nodes); return def; no_memory: virReportOOMError(); error: virCPUDefFree(def); def = NULL; goto cleanup; }
static int virStorageBackendLogicalMakeVol(virStoragePoolObjPtr pool, char **const groups, void *data) { virStorageVolDefPtr vol = NULL; unsigned long long offset, size, length; /* See if we're only looking for a specific volume */ if (data != NULL) { vol = data; if (STRNEQ(vol->name, groups[0])) return 0; } /* Or filling in more data on an existing volume */ if (vol == NULL) vol = virStorageVolDefFindByName(pool, groups[0]); /* Or a completely new volume */ if (vol == NULL) { if (VIR_ALLOC(vol) < 0) { virReportOOMError(); return -1; } vol->type = VIR_STORAGE_VOL_BLOCK; if ((vol->name = strdup(groups[0])) == NULL) { virReportOOMError(); virStorageVolDefFree(vol); return -1; } if (VIR_REALLOC_N(pool->volumes.objs, pool->volumes.count + 1)) { virReportOOMError(); virStorageVolDefFree(vol); return -1; } pool->volumes.objs[pool->volumes.count++] = vol; } if (vol->target.path == NULL) { if (virAsprintf(&vol->target.path, "%s/%s", pool->def->target.path, vol->name) < 0) { virReportOOMError(); virStorageVolDefFree(vol); return -1; } } if (groups[1] && !STREQ(groups[1], "")) { if (virAsprintf(&vol->backingStore.path, "%s/%s", pool->def->target.path, groups[1]) < 0) { virReportOOMError(); virStorageVolDefFree(vol); return -1; } vol->backingStore.format = VIR_STORAGE_POOL_LOGICAL_LVM2; } if (vol->key == NULL && (vol->key = strdup(groups[2])) == NULL) { virReportOOMError(); return -1; } if (virStorageBackendUpdateVolInfo(vol, 1) < 0) return -1; /* Finally fill in extents information */ if (VIR_REALLOC_N(vol->source.extents, vol->source.nextent + 1) < 0) { virReportOOMError(); return -1; } if ((vol->source.extents[vol->source.nextent].path = strdup(groups[3])) == NULL) { virReportOOMError(); return -1; } if (virStrToLong_ull(groups[4], NULL, 10, &offset) < 0) { virStorageReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("malformed volume extent offset value")); return -1; } if (virStrToLong_ull(groups[5], NULL, 10, &length) < 0) { virStorageReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("malformed volume extent length value")); return -1; } if (virStrToLong_ull(groups[6], NULL, 10, &size) < 0) { virStorageReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("malformed volume extent size value")); return -1; } vol->source.extents[vol->source.nextent].start = offset * size; vol->source.extents[vol->source.nextent].end = (offset * size) + length; vol->source.nextent++; return 0; }
/* * Attempt to create a new LUN * * Returns: * * 0 => Success * -1 => Failure due to some sort of OOM or other fatal issue found when * attempting to get/update information about a found volume * -2 => Failure to find a stable path, not fatal, caller can try another */ static int virStorageBackendSCSINewLun(virStoragePoolObjPtr pool, uint32_t host ATTRIBUTE_UNUSED, uint32_t bus, uint32_t target, uint32_t lun, const char *dev) { virStorageVolDefPtr vol = NULL; char *devpath = NULL; int retval = -1; /* Check if the pool is using a stable target path. The call to * virStorageBackendStablePath will fail if the pool target path * isn't stable and just return the strdup'd 'devpath' anyway. * This would be indistinguishable to failing to find the stable * path to the device if the virDirRead loop to search the * target pool path for our devpath had failed. */ if (!virStorageBackendPoolPathIsStable(pool->def->target.path) && !(STREQ(pool->def->target.path, "/dev") || STREQ(pool->def->target.path, "/dev/"))) { virReportError(VIR_ERR_INVALID_ARG, _("unable to use target path '%s' for dev '%s'"), NULLSTR(pool->def->target.path), dev); goto cleanup; } if (VIR_ALLOC(vol) < 0) goto cleanup; vol->type = VIR_STORAGE_VOL_BLOCK; /* 'host' is dynamically allocated by the kernel, first come, * first served, per HBA. As such it isn't suitable for use * in the volume name. We only need uniqueness per-pool, so * just leave 'host' out */ if (virAsprintf(&(vol->name), "unit:%u:%u:%u", bus, target, lun) < 0) goto cleanup; if (virAsprintf(&devpath, "/dev/%s", dev) < 0) goto cleanup; VIR_DEBUG("Trying to create volume for '%s'", devpath); /* Now figure out the stable path * * XXX this method is O(N) because it scans the pool target * dir every time its run. Should figure out a more efficient * way of doing this... */ if ((vol->target.path = virStorageBackendStablePath(pool, devpath, true)) == NULL) goto cleanup; if (STREQ(devpath, vol->target.path) && !(STREQ(pool->def->target.path, "/dev") || STREQ(pool->def->target.path, "/dev/"))) { VIR_DEBUG("No stable path found for '%s' in '%s'", devpath, pool->def->target.path); retval = -2; goto cleanup; } /* Allow a volume read failure to ignore or skip this block file */ if ((retval = virStorageBackendUpdateVolInfo(vol, true, VIR_STORAGE_VOL_OPEN_DEFAULT, VIR_STORAGE_VOL_READ_NOERROR)) < 0) goto cleanup; if (!(vol->key = virStorageBackendSCSISerial(vol->target.path))) goto cleanup; pool->def->capacity += vol->target.capacity; pool->def->allocation += vol->target.allocation; if (VIR_APPEND_ELEMENT(pool->volumes.objs, pool->volumes.count, vol) < 0) goto cleanup; vol = NULL; retval = 0; cleanup: virStorageVolDefFree(vol); VIR_FREE(devpath); return retval; }
static int xenFormatXLUSB(virConfPtr conf, virDomainDefPtr def) { virConfValuePtr usbVal = NULL; int hasUSB = 0; size_t i; for (i = 0; i < def->nhostdevs; i++) { if (def->hostdevs[i]->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && def->hostdevs[i]->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) { hasUSB = 1; break; } } if (!hasUSB) return 0; if (VIR_ALLOC(usbVal) < 0) return -1; usbVal->type = VIR_CONF_LIST; usbVal->list = NULL; for (i = 0; i < def->nhostdevs; i++) { if (def->hostdevs[i]->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && def->hostdevs[i]->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) { virConfValuePtr val, tmp; char *buf; if (virAsprintf(&buf, "hostbus=%x,hostaddr=%x", def->hostdevs[i]->source.subsys.u.usb.bus, def->hostdevs[i]->source.subsys.u.usb.device) < 0) goto error; if (VIR_ALLOC(val) < 0) { VIR_FREE(buf); goto error; } val->type = VIR_CONF_STRING; val->str = buf; tmp = usbVal->list; while (tmp && tmp->next) tmp = tmp->next; if (tmp) tmp->next = val; else usbVal->list = val; } } if (usbVal->list != NULL) { int ret = virConfSetValue(conf, "usbdev", usbVal); usbVal = NULL; if (ret < 0) return -1; } VIR_FREE(usbVal); return 0; error: virConfFreeValue(usbVal); return -1; }
/* * For details on xl disk config syntax, see * docs/misc/xl-disk-configuration.txt in the Xen sources. The important * section of text is: * * More formally, the string is a series of comma-separated keyword/value * pairs, flags and positional parameters. Parameters which are not bare * keywords and which do not contain "=" symbols are assigned to the * so-far-unspecified positional parameters, in the order below. The * positional parameters may also be specified explicitly by name. * * Each parameter may be specified at most once, either as a positional * parameter or a named parameter. Default values apply if the parameter * is not specified, or if it is specified with an empty value (whether * positionally or explicitly). * * Whitespace may appear before each parameter and will be ignored. * * The order of the positional parameters mentioned in the quoted text is: * * target,format,vdev,access * * The following options must be specified by key=value: * * devtype=<devtype> * backendtype=<backend-type> * * The following options are currently not supported: * * backend=<domain-name> * script=<script> * direct-io-safe * */ static int xenParseXLDisk(virConfPtr conf, virDomainDefPtr def) { int ret = -1; virConfValuePtr list = virConfGetValue(conf, "disk"); XLU_Config *xluconf; libxl_device_disk *libxldisk; virDomainDiskDefPtr disk = NULL; if (VIR_ALLOC(libxldisk) < 0) return -1; if (!(xluconf = xlu_cfg_init(stderr, "command line"))) goto cleanup; if (list && list->type == VIR_CONF_LIST) { list = list->list; while (list) { const char *disk_spec = list->str; if (list->type != VIR_CONF_STRING || list->str == NULL) goto skipdisk; libxl_device_disk_init(libxldisk); if (xlu_disk_parse(xluconf, 1, &disk_spec, libxldisk)) goto fail; if (!(disk = virDomainDiskDefNew(NULL))) goto fail; if (xenParseXLDiskSrc(disk, libxldisk->pdev_path) < 0) goto fail; if (VIR_STRDUP(disk->dst, libxldisk->vdev) < 0) goto fail; disk->src->readonly = !libxldisk->readwrite; disk->removable = libxldisk->removable; if (libxldisk->is_cdrom) { if (virDomainDiskSetDriver(disk, "qemu") < 0) goto fail; virDomainDiskSetType(disk, VIR_STORAGE_TYPE_FILE); disk->device = VIR_DOMAIN_DISK_DEVICE_CDROM; if (!disk->src->path || STREQ(disk->src->path, "")) disk->src->format = VIR_STORAGE_FILE_NONE; else disk->src->format = VIR_STORAGE_FILE_RAW; } else { switch (libxldisk->format) { case LIBXL_DISK_FORMAT_QCOW: disk->src->format = VIR_STORAGE_FILE_QCOW; break; case LIBXL_DISK_FORMAT_QCOW2: disk->src->format = VIR_STORAGE_FILE_QCOW2; break; case LIBXL_DISK_FORMAT_VHD: disk->src->format = VIR_STORAGE_FILE_VHD; break; case LIBXL_DISK_FORMAT_RAW: case LIBXL_DISK_FORMAT_UNKNOWN: disk->src->format = VIR_STORAGE_FILE_RAW; break; case LIBXL_DISK_FORMAT_EMPTY: break; } switch (libxldisk->backend) { case LIBXL_DISK_BACKEND_QDISK: case LIBXL_DISK_BACKEND_UNKNOWN: if (virDomainDiskSetDriver(disk, "qemu") < 0) goto fail; if (virDomainDiskGetType(disk) == VIR_STORAGE_TYPE_NONE) virDomainDiskSetType(disk, VIR_STORAGE_TYPE_FILE); break; case LIBXL_DISK_BACKEND_TAP: if (virDomainDiskSetDriver(disk, "tap") < 0) goto fail; virDomainDiskSetType(disk, VIR_STORAGE_TYPE_FILE); break; case LIBXL_DISK_BACKEND_PHY: if (virDomainDiskSetDriver(disk, "phy") < 0) goto fail; virDomainDiskSetType(disk, VIR_STORAGE_TYPE_BLOCK); break; } } if (STRPREFIX(libxldisk->vdev, "xvd") || def->os.type != VIR_DOMAIN_OSTYPE_HVM) disk->bus = VIR_DOMAIN_DISK_BUS_XEN; else if (STRPREFIX(libxldisk->vdev, "sd")) disk->bus = VIR_DOMAIN_DISK_BUS_SCSI; else disk->bus = VIR_DOMAIN_DISK_BUS_IDE; if (VIR_APPEND_ELEMENT(def->disks, def->ndisks, disk) < 0) goto fail; libxl_device_disk_dispose(libxldisk); skipdisk: list = list->next; } } ret = 0; cleanup: virDomainDiskDefFree(disk); xlu_cfg_destroy(xluconf); VIR_FREE(libxldisk); return ret; fail: libxl_device_disk_dispose(libxldisk); goto cleanup; }
/* Functions */ virCapsPtr virLXCDriverCapsInit(virLXCDriverPtr driver) { virCapsPtr caps; virCapsGuestPtr guest; virArch altArch; char *lxc_path = NULL; if ((caps = virCapabilitiesNew(virArchFromHost(), false, false)) == NULL) goto error; /* Some machines have problematic NUMA toplogy causing * unexpected failures. We don't want to break the lxc * driver in this scenario, so log errors & carry on */ if (nodeCapsInitNUMA(caps) < 0) { virCapabilitiesFreeNUMAInfo(caps); VIR_WARN("Failed to query host NUMA topology, disabling NUMA capabilities"); } /* Only probe for power management capabilities in the driver, * not in the emulator */ if (driver && virNodeSuspendGetTargetMask(&caps->host.powerMgmt) < 0) VIR_WARN("Failed to get host power management capabilities"); if (virGetHostUUID(caps->host.host_uuid)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot get the host uuid")); goto error; } if (!(lxc_path = virFileFindResource("libvirt_lxc", abs_topbuilddir "/src", LIBEXECDIR))) goto error; if ((guest = virCapabilitiesAddGuest(caps, VIR_DOMAIN_OSTYPE_EXE, caps->host.arch, lxc_path, NULL, 0, NULL)) == NULL) goto error; if (virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_LXC, NULL, NULL, 0, NULL) == NULL) goto error; /* On 64-bit hosts, we can use personality() to request a 32bit process */ if ((altArch = lxcContainerGetAlt32bitArch(caps->host.arch)) != VIR_ARCH_NONE) { if ((guest = virCapabilitiesAddGuest(caps, VIR_DOMAIN_OSTYPE_EXE, altArch, lxc_path, NULL, 0, NULL)) == NULL) goto error; if (virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_LXC, NULL, NULL, 0, NULL) == NULL) goto error; } VIR_FREE(lxc_path); if (driver) { /* Security driver data */ const char *doi, *model, *label, *type; doi = virSecurityManagerGetDOI(driver->securityManager); model = virSecurityManagerGetModel(driver->securityManager); label = virSecurityManagerGetBaseLabel(driver->securityManager, VIR_DOMAIN_VIRT_LXC); type = virDomainVirtTypeToString(VIR_DOMAIN_VIRT_LXC); /* Allocate the primary security driver for LXC. */ if (VIR_ALLOC(caps->host.secModels) < 0) goto error; caps->host.nsecModels = 1; if (VIR_STRDUP(caps->host.secModels[0].model, model) < 0) goto error; if (VIR_STRDUP(caps->host.secModels[0].doi, doi) < 0) goto error; if (label && virCapabilitiesHostSecModelAddBaseLabel(&caps->host.secModels[0], type, label) < 0) goto error; VIR_DEBUG("Initialized caps for security driver \"%s\" with " "DOI \"%s\"", model, doi); } else { VIR_INFO("No driver, not initializing security driver"); } return caps; error: VIR_FREE(lxc_path); virObjectUnref(caps); return NULL; }
static int xenParseXLOS(virConfPtr conf, virDomainDefPtr def, virCapsPtr caps) { size_t i; if (def->os.type == VIR_DOMAIN_OSTYPE_HVM) { const char *bios; const char *boot; if (xenConfigGetString(conf, "bios", &bios, NULL) < 0) return -1; if (bios && STREQ(bios, "ovmf")) { if (VIR_ALLOC(def->os.loader) < 0) return -1; def->os.loader->type = VIR_DOMAIN_LOADER_TYPE_PFLASH; def->os.loader->readonly = VIR_TRISTATE_BOOL_YES; if (VIR_STRDUP(def->os.loader->path, LIBXL_FIRMWARE_DIR "/ovmf.bin") < 0) return -1; } else { for (i = 0; i < caps->nguests; i++) { if (caps->guests[i]->ostype == VIR_DOMAIN_OSTYPE_HVM && caps->guests[i]->arch.id == def->os.arch) { if (VIR_ALLOC(def->os.loader) < 0 || VIR_STRDUP(def->os.loader->path, caps->guests[i]->arch.defaultInfo.loader) < 0) return -1; } } } #ifdef LIBXL_HAVE_BUILDINFO_KERNEL if (xenConfigCopyStringOpt(conf, "kernel", &def->os.kernel) < 0) return -1; if (xenConfigCopyStringOpt(conf, "ramdisk", &def->os.initrd) < 0) return -1; if (xenParseCmdline(conf, &def->os.cmdline) < 0) return -1; #endif if (xenConfigGetString(conf, "boot", &boot, "c") < 0) return -1; for (i = 0; i < VIR_DOMAIN_BOOT_LAST && boot[i]; i++) { switch (boot[i]) { case 'a': def->os.bootDevs[i] = VIR_DOMAIN_BOOT_FLOPPY; break; case 'd': def->os.bootDevs[i] = VIR_DOMAIN_BOOT_CDROM; break; case 'n': def->os.bootDevs[i] = VIR_DOMAIN_BOOT_NET; break; case 'c': default: def->os.bootDevs[i] = VIR_DOMAIN_BOOT_DISK; break; } def->os.nBootDevs++; } } else { if (xenConfigCopyStringOpt(conf, "bootloader", &def->os.bootloader) < 0) return -1; if (xenConfigCopyStringOpt(conf, "bootargs", &def->os.bootloaderArgs) < 0) return -1; if (xenConfigCopyStringOpt(conf, "kernel", &def->os.kernel) < 0) return -1; if (xenConfigCopyStringOpt(conf, "ramdisk", &def->os.initrd) < 0) return -1; if (xenParseCmdline(conf, &def->os.cmdline) < 0) return -1; } return 0; }
virQEMUDriverConfigPtr virQEMUDriverConfigNew(bool privileged) { virQEMUDriverConfigPtr cfg; if (virQEMUConfigInitialize() < 0) return NULL; if (!(cfg = virObjectNew(virQEMUDriverConfigClass))) return NULL; cfg->uri = privileged ? "qemu:///system" : "qemu:///session"; if (privileged) { if (virGetUserID(QEMU_USER, &cfg->user) < 0) goto error; if (virGetGroupID(QEMU_GROUP, &cfg->group) < 0) goto error; } else { cfg->user = (uid_t)-1; cfg->group = (gid_t)-1; } cfg->dynamicOwnership = privileged; cfg->cgroupControllers = -1; /* -1 == auto-detect */ if (privileged) { if (virAsprintf(&cfg->logDir, "%s/log/libvirt/qemu", LOCALSTATEDIR) < 0) goto error; if (VIR_STRDUP(cfg->configBaseDir, SYSCONFDIR "/libvirt") < 0) goto error; if (virAsprintf(&cfg->stateDir, "%s/run/libvirt/qemu", LOCALSTATEDIR) < 0) goto error; if (virAsprintf(&cfg->cacheDir, "%s/cache/libvirt/qemu", LOCALSTATEDIR) < 0) goto error; if (virAsprintf(&cfg->libDir, "%s/lib/libvirt/qemu", LOCALSTATEDIR) < 0) goto error; if (virAsprintf(&cfg->saveDir, "%s/save", cfg->libDir) < 0) goto error; if (virAsprintf(&cfg->snapshotDir, "%s/snapshot", cfg->libDir) < 0) goto error; if (virAsprintf(&cfg->autoDumpPath, "%s/dump", cfg->libDir) < 0) goto error; if (virAsprintf(&cfg->channelTargetDir, "%s/channel/target", cfg->libDir) < 0) goto error; if (virAsprintf(&cfg->nvramDir, "%s/nvram", cfg->libDir) < 0) goto error; } else { char *rundir; char *cachedir; cachedir = virGetUserCacheDirectory(); if (!cachedir) goto error; if (virAsprintf(&cfg->logDir, "%s/qemu/log", cachedir) < 0) { VIR_FREE(cachedir); goto error; } if (virAsprintf(&cfg->cacheDir, "%s/qemu/cache", cachedir) < 0) { VIR_FREE(cachedir); goto error; } VIR_FREE(cachedir); rundir = virGetUserRuntimeDirectory(); if (!rundir) goto error; if (virAsprintf(&cfg->stateDir, "%s/qemu/run", rundir) < 0) { VIR_FREE(rundir); goto error; } VIR_FREE(rundir); if (!(cfg->configBaseDir = virGetUserConfigDirectory())) goto error; if (virAsprintf(&cfg->libDir, "%s/qemu/lib", cfg->configBaseDir) < 0) goto error; if (virAsprintf(&cfg->saveDir, "%s/qemu/save", cfg->configBaseDir) < 0) goto error; if (virAsprintf(&cfg->snapshotDir, "%s/qemu/snapshot", cfg->configBaseDir) < 0) goto error; if (virAsprintf(&cfg->autoDumpPath, "%s/qemu/dump", cfg->configBaseDir) < 0) goto error; if (virAsprintf(&cfg->channelTargetDir, "%s/qemu/channel/target", cfg->configBaseDir) < 0) goto error; if (virAsprintf(&cfg->nvramDir, "%s/qemu/nvram", cfg->configBaseDir) < 0) goto error; } if (virAsprintf(&cfg->configDir, "%s/qemu", cfg->configBaseDir) < 0) goto error; if (virAsprintf(&cfg->autostartDir, "%s/qemu/autostart", cfg->configBaseDir) < 0) goto error; if (VIR_STRDUP(cfg->vncListen, "127.0.0.1") < 0) goto error; if (VIR_STRDUP(cfg->vncTLSx509certdir, SYSCONFDIR "/pki/libvirt-vnc") < 0) goto error; if (VIR_STRDUP(cfg->spiceListen, "127.0.0.1") < 0) goto error; if (VIR_STRDUP(cfg->spiceTLSx509certdir, SYSCONFDIR "/pki/libvirt-spice") < 0) goto error; cfg->remotePortMin = QEMU_REMOTE_PORT_MIN; cfg->remotePortMax = QEMU_REMOTE_PORT_MAX; cfg->webSocketPortMin = QEMU_WEBSOCKET_PORT_MIN; cfg->webSocketPortMax = QEMU_WEBSOCKET_PORT_MAX; cfg->migrationPortMin = QEMU_MIGRATION_PORT_MIN; cfg->migrationPortMax = QEMU_MIGRATION_PORT_MAX; /* For privileged driver, try and find hugetlbfs mounts automatically. * Non-privileged driver requires admin to create a dir for the * user, chown it, and then let user configure it manually. */ if (privileged && virFileFindHugeTLBFS(&cfg->hugetlbfs, &cfg->nhugetlbfs) < 0) { /* This however is not implemented on all platforms. */ virErrorPtr err = virGetLastError(); if (err && err->code != VIR_ERR_NO_SUPPORT) goto error; } if (VIR_STRDUP(cfg->bridgeHelperName, QEMU_BRIDGE_HELPER) < 0) goto error; cfg->clearEmulatorCapabilities = true; cfg->securityDefaultConfined = true; cfg->securityRequireConfined = false; cfg->keepAliveInterval = 5; cfg->keepAliveCount = 5; cfg->seccompSandbox = -1; cfg->logTimestamp = true; cfg->stdioLogD = true; #ifdef DEFAULT_LOADER_NVRAM if (virFirmwareParseList(DEFAULT_LOADER_NVRAM, &cfg->firmwares, &cfg->nfirmwares) < 0) goto error; #else if (VIR_ALLOC_N(cfg->firmwares, 2) < 0) goto error; cfg->nfirmwares = 2; if (VIR_ALLOC(cfg->firmwares[0]) < 0 || VIR_ALLOC(cfg->firmwares[1]) < 0) goto error; if (VIR_STRDUP(cfg->firmwares[0]->name, VIR_QEMU_AAVMF_LOADER_PATH) < 0 || VIR_STRDUP(cfg->firmwares[0]->nvram, VIR_QEMU_AAVMF_NVRAM_PATH) < 0 || VIR_STRDUP(cfg->firmwares[1]->name, VIR_QEMU_OVMF_LOADER_PATH) < 0 || VIR_STRDUP(cfg->firmwares[1]->nvram, VIR_QEMU_OVMF_NVRAM_PATH) < 0) goto error; #endif return cfg; error: virObjectUnref(cfg); return NULL; }
int virQEMUDriverConfigLoadFile(virQEMUDriverConfigPtr cfg, const char *filename) { virConfPtr conf = NULL; virConfValuePtr p; int ret = -1; size_t i; char *stdioHandler = NULL; /* Just check the file is readable before opening it, otherwise * libvirt emits an error. */ if (access(filename, R_OK) == -1) { VIR_INFO("Could not read qemu config file %s", filename); return 0; } if (!(conf = virConfReadFile(filename, 0))) goto cleanup; #define CHECK_TYPE(name, typ) \ if (p && p->type != (typ)) { \ virReportError(VIR_ERR_INTERNAL_ERROR, \ "%s: %s: expected type " #typ, \ filename, (name)); \ goto cleanup; \ } #define CHECK_TYPE_ALT(name, type1, type2) \ if (p && (p->type != (type1) && p->type != (type2))) { \ virReportError(VIR_ERR_INTERNAL_ERROR, \ "%s: %s: expected type " #type1, \ filename, (name)); \ goto cleanup; \ } #define GET_VALUE_LONG(NAME, VAR) \ p = virConfGetValue(conf, NAME); \ CHECK_TYPE_ALT(NAME, VIR_CONF_LONG, VIR_CONF_ULONG); \ if (p) \ VAR = p->l; #define GET_VALUE_ULONG(NAME, VAR) \ p = virConfGetValue(conf, NAME); \ CHECK_TYPE(NAME, VIR_CONF_ULONG); \ if (p) \ VAR = p->l; #define GET_VALUE_BOOL(NAME, VAR) \ p = virConfGetValue(conf, NAME); \ CHECK_TYPE(NAME, VIR_CONF_ULONG); \ if (p) \ VAR = p->l != 0; #define GET_VALUE_STR(NAME, VAR) \ p = virConfGetValue(conf, NAME); \ CHECK_TYPE(NAME, VIR_CONF_STRING); \ if (p && p->str) { \ VIR_FREE(VAR); \ if (VIR_STRDUP(VAR, p->str) < 0) \ goto cleanup; \ } GET_VALUE_BOOL("vnc_auto_unix_socket", cfg->vncAutoUnixSocket); GET_VALUE_BOOL("vnc_tls", cfg->vncTLS); GET_VALUE_BOOL("vnc_tls_x509_verify", cfg->vncTLSx509verify); GET_VALUE_STR("vnc_tls_x509_cert_dir", cfg->vncTLSx509certdir); GET_VALUE_STR("vnc_listen", cfg->vncListen); GET_VALUE_STR("vnc_password", cfg->vncPassword); GET_VALUE_BOOL("vnc_sasl", cfg->vncSASL); GET_VALUE_STR("vnc_sasl_dir", cfg->vncSASLdir); GET_VALUE_BOOL("vnc_allow_host_audio", cfg->vncAllowHostAudio); GET_VALUE_BOOL("nographics_allow_host_audio", cfg->nogfxAllowHostAudio); p = virConfGetValue(conf, "security_driver"); if (p && p->type == VIR_CONF_LIST) { size_t len, j; virConfValuePtr pp; /* Calc length and check items */ for (len = 0, pp = p->list; pp; len++, pp = pp->next) { if (pp->type != VIR_CONF_STRING) { virReportError(VIR_ERR_CONF_SYNTAX, "%s", _("security_driver must be a list of strings")); goto cleanup; } } if (VIR_ALLOC_N(cfg->securityDriverNames, len + 1) < 0) goto cleanup; for (i = 0, pp = p->list; pp; i++, pp = pp->next) { for (j = 0; j < i; j++) { if (STREQ(pp->str, cfg->securityDriverNames[j])) { virReportError(VIR_ERR_CONF_SYNTAX, _("Duplicate security driver %s"), pp->str); goto cleanup; } } if (VIR_STRDUP(cfg->securityDriverNames[i], pp->str) < 0) goto cleanup; } cfg->securityDriverNames[len] = NULL; } else { CHECK_TYPE("security_driver", VIR_CONF_STRING); if (p && p->str) { if (VIR_ALLOC_N(cfg->securityDriverNames, 2) < 0) goto cleanup; if (VIR_STRDUP(cfg->securityDriverNames[0], p->str) < 0) goto cleanup; cfg->securityDriverNames[1] = NULL; } } GET_VALUE_BOOL("security_default_confined", cfg->securityDefaultConfined); GET_VALUE_BOOL("security_require_confined", cfg->securityRequireConfined); GET_VALUE_BOOL("spice_tls", cfg->spiceTLS); GET_VALUE_STR("spice_tls_x509_cert_dir", cfg->spiceTLSx509certdir); GET_VALUE_BOOL("spice_sasl", cfg->spiceSASL); GET_VALUE_STR("spice_sasl_dir", cfg->spiceSASLdir); GET_VALUE_STR("spice_listen", cfg->spiceListen); GET_VALUE_STR("spice_password", cfg->spicePassword); GET_VALUE_BOOL("spice_auto_unix_socket", cfg->spiceAutoUnixSocket); GET_VALUE_ULONG("remote_websocket_port_min", cfg->webSocketPortMin); if (cfg->webSocketPortMin < QEMU_WEBSOCKET_PORT_MIN) { /* if the port is too low, we can't get the display name * to tell to vnc (usually subtract 5700, e.g. localhost:1 * for port 5701) */ virReportError(VIR_ERR_INTERNAL_ERROR, _("%s: remote_websocket_port_min: port must be greater " "than or equal to %d"), filename, QEMU_WEBSOCKET_PORT_MIN); goto cleanup; } GET_VALUE_ULONG("remote_websocket_port_max", cfg->webSocketPortMax); if (cfg->webSocketPortMax > QEMU_WEBSOCKET_PORT_MAX || cfg->webSocketPortMax < cfg->webSocketPortMin) { virReportError(VIR_ERR_INTERNAL_ERROR, _("%s: remote_websocket_port_max: port must be between " "the minimal port and %d"), filename, QEMU_WEBSOCKET_PORT_MAX); goto cleanup; } if (cfg->webSocketPortMin > cfg->webSocketPortMax) { virReportError(VIR_ERR_INTERNAL_ERROR, _("%s: remote_websocket_port_min: min port must not be " "greater than max port"), filename); goto cleanup; } GET_VALUE_ULONG("remote_display_port_min", cfg->remotePortMin); if (cfg->remotePortMin < QEMU_REMOTE_PORT_MIN) { /* if the port is too low, we can't get the display name * to tell to vnc (usually subtract 5900, e.g. localhost:1 * for port 5901) */ virReportError(VIR_ERR_INTERNAL_ERROR, _("%s: remote_display_port_min: port must be greater " "than or equal to %d"), filename, QEMU_REMOTE_PORT_MIN); goto cleanup; } GET_VALUE_ULONG("remote_display_port_max", cfg->remotePortMax); if (cfg->remotePortMax > QEMU_REMOTE_PORT_MAX || cfg->remotePortMax < cfg->remotePortMin) { virReportError(VIR_ERR_INTERNAL_ERROR, _("%s: remote_display_port_max: port must be between " "the minimal port and %d"), filename, QEMU_REMOTE_PORT_MAX); goto cleanup; } if (cfg->remotePortMin > cfg->remotePortMax) { virReportError(VIR_ERR_INTERNAL_ERROR, _("%s: remote_display_port_min: min port must not be " "greater than max port"), filename); goto cleanup; } GET_VALUE_ULONG("migration_port_min", cfg->migrationPortMin); if (cfg->migrationPortMin <= 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("%s: migration_port_min: port must be greater than 0"), filename); goto cleanup; } GET_VALUE_ULONG("migration_port_max", cfg->migrationPortMax); if (cfg->migrationPortMax > 65535 || cfg->migrationPortMax < cfg->migrationPortMin) { virReportError(VIR_ERR_INTERNAL_ERROR, _("%s: migration_port_max: port must be between " "the minimal port %d and 65535"), filename, cfg->migrationPortMin); goto cleanup; } p = virConfGetValue(conf, "user"); CHECK_TYPE("user", VIR_CONF_STRING); if (p && p->str && virGetUserID(p->str, &cfg->user) < 0) goto cleanup; p = virConfGetValue(conf, "group"); CHECK_TYPE("group", VIR_CONF_STRING); if (p && p->str && virGetGroupID(p->str, &cfg->group) < 0) goto cleanup; GET_VALUE_BOOL("dynamic_ownership", cfg->dynamicOwnership); p = virConfGetValue(conf, "cgroup_controllers"); CHECK_TYPE("cgroup_controllers", VIR_CONF_LIST); if (p) { cfg->cgroupControllers = 0; virConfValuePtr pp; for (i = 0, pp = p->list; pp; ++i, pp = pp->next) { int ctl; if (pp->type != VIR_CONF_STRING) { virReportError(VIR_ERR_CONF_SYNTAX, "%s", _("cgroup_controllers must be a " "list of strings")); goto cleanup; } if ((ctl = virCgroupControllerTypeFromString(pp->str)) < 0) { virReportError(VIR_ERR_CONF_SYNTAX, _("Unknown cgroup controller '%s'"), pp->str); goto cleanup; } cfg->cgroupControllers |= (1 << ctl); } } p = virConfGetValue(conf, "cgroup_device_acl"); CHECK_TYPE("cgroup_device_acl", VIR_CONF_LIST); if (p) { int len = 0; virConfValuePtr pp; for (pp = p->list; pp; pp = pp->next) len++; if (VIR_ALLOC_N(cfg->cgroupDeviceACL, 1+len) < 0) goto cleanup; for (i = 0, pp = p->list; pp; ++i, pp = pp->next) { if (pp->type != VIR_CONF_STRING) { virReportError(VIR_ERR_CONF_SYNTAX, "%s", _("cgroup_device_acl must be a " "list of strings")); goto cleanup; } if (VIR_STRDUP(cfg->cgroupDeviceACL[i], pp->str) < 0) goto cleanup; } cfg->cgroupDeviceACL[i] = NULL; } GET_VALUE_STR("save_image_format", cfg->saveImageFormat); GET_VALUE_STR("dump_image_format", cfg->dumpImageFormat); GET_VALUE_STR("snapshot_image_format", cfg->snapshotImageFormat); GET_VALUE_STR("auto_dump_path", cfg->autoDumpPath); GET_VALUE_BOOL("auto_dump_bypass_cache", cfg->autoDumpBypassCache); GET_VALUE_BOOL("auto_start_bypass_cache", cfg->autoStartBypassCache); /* Some crazy backcompat. Back in the old days, this was just a pure * string. We must continue supporting it. These days however, this may be * an array of strings. */ p = virConfGetValue(conf, "hugetlbfs_mount"); if (p) { /* There already might be something autodetected. Avoid leaking it. */ while (cfg->nhugetlbfs) { cfg->nhugetlbfs--; VIR_FREE(cfg->hugetlbfs[cfg->nhugetlbfs].mnt_dir); } VIR_FREE(cfg->hugetlbfs); if (p->type == VIR_CONF_LIST) { size_t len = 0; virConfValuePtr pp = p->list; /* Calc length and check items */ while (pp) { if (pp->type != VIR_CONF_STRING) { virReportError(VIR_ERR_CONF_SYNTAX, "%s", _("hugetlbfs_mount must be a list of strings")); goto cleanup; } len++; pp = pp->next; } if (len && VIR_ALLOC_N(cfg->hugetlbfs, len) < 0) goto cleanup; cfg->nhugetlbfs = len; pp = p->list; len = 0; while (pp) { if (virQEMUDriverConfigHugeTLBFSInit(&cfg->hugetlbfs[len], pp->str, !len) < 0) goto cleanup; len++; pp = pp->next; } } else { CHECK_TYPE("hugetlbfs_mount", VIR_CONF_STRING); if (STRNEQ(p->str, "")) { if (VIR_ALLOC_N(cfg->hugetlbfs, 1) < 0) goto cleanup; cfg->nhugetlbfs = 1; if (virQEMUDriverConfigHugeTLBFSInit(&cfg->hugetlbfs[0], p->str, true) < 0) goto cleanup; } } } GET_VALUE_STR("bridge_helper", cfg->bridgeHelperName); GET_VALUE_BOOL("mac_filter", cfg->macFilter); GET_VALUE_BOOL("relaxed_acs_check", cfg->relaxedACS); GET_VALUE_BOOL("clear_emulator_capabilities", cfg->clearEmulatorCapabilities); GET_VALUE_BOOL("allow_disk_format_probing", cfg->allowDiskFormatProbing); GET_VALUE_BOOL("set_process_name", cfg->setProcessName); GET_VALUE_ULONG("max_processes", cfg->maxProcesses); GET_VALUE_ULONG("max_files", cfg->maxFiles); GET_VALUE_STR("lock_manager", cfg->lockManagerName); GET_VALUE_STR("stdio_handler", stdioHandler); if (stdioHandler) { if (STREQ(stdioHandler, "logd")) { cfg->stdioLogD = true; } else if (STREQ(stdioHandler, "file")) { cfg->stdioLogD = false; } else { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Unknown stdio handler %s"), stdioHandler); VIR_FREE(stdioHandler); goto cleanup; } VIR_FREE(stdioHandler); } GET_VALUE_ULONG("max_queued", cfg->maxQueuedJobs); GET_VALUE_LONG("keepalive_interval", cfg->keepAliveInterval); GET_VALUE_ULONG("keepalive_count", cfg->keepAliveCount); GET_VALUE_LONG("seccomp_sandbox", cfg->seccompSandbox); GET_VALUE_STR("migration_host", cfg->migrateHost); virStringStripIPv6Brackets(cfg->migrateHost); if (cfg->migrateHost && (STRPREFIX(cfg->migrateHost, "localhost") || virSocketAddrIsNumericLocalhost(cfg->migrateHost))) { virReportError(VIR_ERR_CONF_SYNTAX, _("migration_host must not be the address of" " the local machine: %s"), cfg->migrateHost); goto cleanup; } GET_VALUE_STR("migration_address", cfg->migrationAddress); virStringStripIPv6Brackets(cfg->migrationAddress); if (cfg->migrationAddress && (STRPREFIX(cfg->migrationAddress, "localhost") || virSocketAddrIsNumericLocalhost(cfg->migrationAddress))) { virReportError(VIR_ERR_CONF_SYNTAX, _("migration_address must not be the address of" " the local machine: %s"), cfg->migrationAddress); goto cleanup; } GET_VALUE_BOOL("log_timestamp", cfg->logTimestamp); if ((p = virConfGetValue(conf, "nvram"))) { size_t len; virConfValuePtr pp; CHECK_TYPE("nvram", VIR_CONF_LIST); virFirmwareFreeList(cfg->firmwares, cfg->nfirmwares); /* Calc length and check items */ for (len = 0, pp = p->list; pp; len++, pp = pp->next) { if (pp->type != VIR_CONF_STRING) { virReportError(VIR_ERR_CONF_SYNTAX, "%s", _("nvram must be a list of strings")); goto cleanup; } } if (len && VIR_ALLOC_N(cfg->firmwares, len) < 0) goto cleanup; cfg->nfirmwares = len; for (i = 0, pp = p->list; pp; i++, pp = pp->next) { if (VIR_ALLOC(cfg->firmwares[i]) < 0) goto cleanup; if (virFirmwareParse(pp->str, cfg->firmwares[i]) < 0) goto cleanup; } } ret = 0; cleanup: virConfFree(conf); return ret; }
/** * virObjectEventCallbackListAddID: * @conn: pointer to the connection * @cbList: the list * @key: the optional key of the object to filter on * @filter: optional last-ditch filter callback * @filter_opaque: opaque data to pass to @filter * @klass: the base event class * @eventID: the event ID * @callback: the callback to add * @opaque: opaque data to pass to @callback * @freecb: callback to free @opaque * @legacy: true if callback is tracked by function instead of callbackID * @callbackID: filled with callback ID * @serverFilter: true if server supports object filtering * * Internal function to add a callback from a virObjectEventCallbackListPtr */ static int virObjectEventCallbackListAddID(virConnectPtr conn, virObjectEventCallbackListPtr cbList, const char *key, virObjectEventCallbackFilter filter, void *filter_opaque, virClassPtr klass, int eventID, virConnectObjectEventGenericCallback callback, void *opaque, virFreeCallback freecb, bool legacy, int *callbackID, bool serverFilter) { virObjectEventCallbackPtr cb; int ret = -1; int remoteID = -1; VIR_DEBUG("conn=%p cblist=%p key=%p filter=%p filter_opaque=%p " "klass=%p eventID=%d callback=%p opaque=%p " "legacy=%d callbackID=%p serverFilter=%d", conn, cbList, key, filter, filter_opaque, klass, eventID, callback, opaque, legacy, callbackID, serverFilter); /* Check incoming */ if (!cbList) return -1; /* If there is no additional filtering, then check if we already * have this callback on our list. */ if (!filter && virObjectEventCallbackLookup(conn, cbList, key, klass, eventID, callback, legacy, serverFilter ? &remoteID : NULL) != -1) { virReportError(VIR_ERR_INVALID_ARG, "%s", _("event callback already tracked")); return -1; } /* Allocate new cb */ if (VIR_ALLOC(cb) < 0) goto cleanup; cb->conn = virObjectRef(conn); *callbackID = cb->callbackID = cbList->nextID++; cb->cb = callback; cb->klass = klass; cb->eventID = eventID; cb->opaque = opaque; cb->freecb = freecb; cb->remoteID = remoteID; if (key) { cb->key_filter = true; if (VIR_STRDUP(cb->key, key) < 0) goto cleanup; } cb->filter = filter; cb->filter_opaque = filter_opaque; cb->legacy = legacy; if (VIR_APPEND_ELEMENT(cbList->callbacks, cbList->count, cb) < 0) goto cleanup; /* When additional filtering is being done, every client callback * is matched to exactly one server callback. */ if (filter) { ret = 1; } else { ret = virObjectEventCallbackListCount(conn, cbList, klass, eventID, key, serverFilter); if (serverFilter && remoteID < 0) ret++; } cleanup: virObjectEventCallbackFree(cb); return ret; }
static virCPUDefPtr genericBaseline(virCPUDefPtr *cpus, unsigned int ncpus, const char **models, unsigned int nmodels, unsigned int flags) { virCPUDefPtr cpu = NULL; virCPUFeatureDefPtr features = NULL; unsigned int nfeatures; unsigned int count; size_t i, j; virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES | VIR_CONNECT_BASELINE_CPU_MIGRATABLE, NULL); if (!cpuModelIsAllowed(cpus[0]->model, models, nmodels)) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("CPU model %s is not supported by hypervisor"), cpus[0]->model); goto error; } if (VIR_ALLOC(cpu) < 0 || VIR_STRDUP(cpu->model, cpus[0]->model) < 0 || VIR_ALLOC_N(features, cpus[0]->nfeatures) < 0) goto error; cpu->arch = cpus[0]->arch; cpu->type = VIR_CPU_TYPE_HOST; count = nfeatures = cpus[0]->nfeatures; for (i = 0; i < nfeatures; i++) features[i].name = cpus[0]->features[i].name; for (i = 1; i < ncpus; i++) { virHashTablePtr hash; if (cpu->arch != cpus[i]->arch) { virReportError(VIR_ERR_INTERNAL_ERROR, _("CPUs have incompatible architectures: '%s' != '%s'"), virArchToString(cpu->arch), virArchToString(cpus[i]->arch)); goto error; } if (STRNEQ(cpu->model, cpus[i]->model)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("CPU models don't match: '%s' != '%s'"), cpu->model, cpus[i]->model); goto error; } if (!(hash = genericHashFeatures(cpus[i]))) goto error; for (j = 0; j < nfeatures; j++) { if (features[j].name && !virHashLookup(hash, features[j].name)) { features[j].name = NULL; count--; } } virHashFree(hash); } if (VIR_ALLOC_N(cpu->features, count) < 0) goto error; cpu->nfeatures = count; j = 0; for (i = 0; i < nfeatures; i++) { if (!features[i].name) continue; if (VIR_STRDUP(cpu->features[j++].name, features[i].name) < 0) goto error; } cleanup: VIR_FREE(features); return cpu; error: virCPUDefFree(cpu); cpu = NULL; goto cleanup; }
static int virStorageBackendSCSINewLun(virStoragePoolObjPtr pool, uint32_t host ATTRIBUTE_UNUSED, uint32_t bus, uint32_t target, uint32_t lun, const char *dev) { virStorageVolDefPtr vol; char *devpath = NULL; int retval = 0; if (VIR_ALLOC(vol) < 0) { retval = -1; goto out; } vol->type = VIR_STORAGE_VOL_BLOCK; /* 'host' is dynamically allocated by the kernel, first come, * first served, per HBA. As such it isn't suitable for use * in the volume name. We only need uniqueness per-pool, so * just leave 'host' out */ if (virAsprintf(&(vol->name), "unit:%u:%u:%u", bus, target, lun) < 0) { retval = -1; goto free_vol; } if (virAsprintf(&devpath, "/dev/%s", dev) < 0) { retval = -1; goto free_vol; } VIR_DEBUG("Trying to create volume for '%s'", devpath); /* Now figure out the stable path * * XXX this method is O(N) because it scans the pool target * dir every time its run. Should figure out a more efficient * way of doing this... */ if ((vol->target.path = virStorageBackendStablePath(pool, devpath, true)) == NULL) { retval = -1; goto free_vol; } if (STREQ(devpath, vol->target.path) && !(STREQ(pool->def->target.path, "/dev") || STREQ(pool->def->target.path, "/dev/"))) { VIR_DEBUG("No stable path found for '%s' in '%s'", devpath, pool->def->target.path); retval = -1; goto free_vol; } if (virStorageBackendUpdateVolInfo(vol, true, VIR_STORAGE_VOL_OPEN_DEFAULT) < 0) { retval = -1; goto free_vol; } if (!(vol->key = virStorageBackendSCSISerial(vol->target.path))) { retval = -1; goto free_vol; } pool->def->capacity += vol->target.capacity; pool->def->allocation += vol->target.allocation; if (VIR_APPEND_ELEMENT(pool->volumes.objs, pool->volumes.count, vol) < 0) { retval = -1; goto free_vol; } goto out; free_vol: virStorageVolDefFree(vol); out: VIR_FREE(devpath); return retval; }
static int virLockManagerLockDaemonNew(virLockManagerPtr lock, unsigned int type, size_t nparams, virLockManagerParamPtr params, unsigned int flags) { virLockManagerLockDaemonPrivatePtr priv; size_t i; virCheckFlags(VIR_LOCK_MANAGER_USES_STATE, -1); if (VIR_ALLOC(priv) < 0) { virReportOOMError(); return -1; } lock->privateData = priv; switch (type) { case VIR_LOCK_MANAGER_OBJECT_TYPE_DOMAIN: for (i = 0 ; i < nparams ; i++) { if (STREQ(params[i].key, "uuid")) { memcpy(priv->uuid, params[i].value.uuid, VIR_UUID_BUFLEN); } else if (STREQ(params[i].key, "name")) { if (!(priv->name = strdup(params[i].value.str))) { virReportOOMError(); return -1; } } else if (STREQ(params[i].key, "id")) { priv->id = params[i].value.i; } else if (STREQ(params[i].key, "pid")) { priv->pid = params[i].value.i; } else if (STREQ(params[i].key, "uri")) { /* ignored */ } else { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unexpected parameter %s for object"), params[i].key); } } if (priv->id == 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Missing ID parameter for domain object")); return -1; } if (priv->pid == 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Missing PID parameter for domain object")); return -1; } if (!priv->name) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Missing name parameter for domain object")); return -1; } if (!virUUIDIsValid(priv->uuid)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Missing UUID parameter for domain object")); return -1; } break; default: virReportError(VIR_ERR_INTERNAL_ERROR, _("Unknown lock manager object type %d"), type); return -1; } return 0; }
static virCapsPtr parallelsBuildCapabilities(void) { virCapsPtr caps = NULL; virCPUDefPtr cpu = NULL; virCPUDataPtr data = NULL; virCapsGuestPtr guest; virNodeInfo nodeinfo; if ((caps = virCapabilitiesNew(virArchFromHost(), false, false)) == NULL) return NULL; if (nodeCapsInitNUMA(caps) < 0) goto error; if ((guest = virCapabilitiesAddGuest(caps, "hvm", VIR_ARCH_X86_64, "parallels", NULL, 0, NULL)) == NULL) goto error; if ((guest = virCapabilitiesAddGuest(caps, "hvm", VIR_ARCH_I686, "parallels", NULL, 0, NULL)) == NULL) goto error; if (virCapabilitiesAddGuestDomain(guest, "parallels", NULL, NULL, 0, NULL) == NULL) goto error; if ((guest = virCapabilitiesAddGuest(caps, "exe", VIR_ARCH_X86_64, "parallels", NULL, 0, NULL)) == NULL) goto error; if (virCapabilitiesAddGuestDomain(guest, "parallels", NULL, NULL, 0, NULL) == NULL) goto error; if (nodeGetInfo(&nodeinfo)) goto error; if (VIR_ALLOC(cpu) < 0) goto error; cpu->arch = caps->host.arch; cpu->type = VIR_CPU_TYPE_HOST; cpu->sockets = nodeinfo.sockets; cpu->cores = nodeinfo.cores; cpu->threads = nodeinfo.threads; caps->host.cpu = cpu; if (!(data = cpuNodeData(cpu->arch)) || cpuDecode(cpu, data, NULL, 0, NULL) < 0) { goto cleanup; } cleanup: cpuDataFree(data); return caps; error: virObjectUnref(caps); goto cleanup; }
/** * virDomainEventCallbackListAddID: * @conn: pointer to the connection * @cbList: the list * @eventID: the event ID * @callback: the callback to add * @opaque: opaque data tio pass to callback * @callbackID: filled with callback ID * * Internal function to add a callback from a virDomainEventCallbackListPtr */ static int virDomainEventCallbackListAddID(virConnectPtr conn, virDomainEventCallbackListPtr cbList, virDomainPtr dom, int eventID, virConnectDomainEventGenericCallback callback, void *opaque, virFreeCallback freecb, int *callbackID) { virDomainEventCallbackPtr event; int i; int ret = 0; /* Check incoming */ if ( !cbList ) { return -1; } /* check if we already have this callback on our list */ for (i = 0 ; i < cbList->count ; i++) { if (cbList->callbacks[i]->cb == VIR_DOMAIN_EVENT_CALLBACK(callback) && cbList->callbacks[i]->eventID == eventID && cbList->callbacks[i]->conn == conn) { eventReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("event callback already tracked")); return -1; } } /* Allocate new event */ if (VIR_ALLOC(event) < 0) goto no_memory; event->conn = conn; event->cb = callback; event->eventID = eventID; event->opaque = opaque; event->freecb = freecb; if (dom) { if (VIR_ALLOC(event->dom) < 0) goto no_memory; if (!(event->dom->name = strdup(dom->name))) goto no_memory; memcpy(event->dom->uuid, dom->uuid, VIR_UUID_BUFLEN); event->dom->id = dom->id; } /* Make space on list */ if (VIR_REALLOC_N(cbList->callbacks, cbList->count + 1) < 0) goto no_memory; event->conn->refs++; cbList->callbacks[cbList->count] = event; cbList->count++; event->callbackID = cbList->nextID++; for (i = 0 ; i < cbList->count ; i++) { if (cbList->callbacks[i]->eventID == eventID && cbList->callbacks[i]->conn == conn && !cbList->callbacks[i]->deleted) ret++; } if (callbackID) *callbackID = event->callbackID; return ret; no_memory: virReportOOMError(); if (event) { if (event->dom) VIR_FREE(event->dom->name); VIR_FREE(event->dom); } VIR_FREE(event); return -1; }
/* 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; }
virCapsPtr vmwareCapsInit(void) { virCapsPtr caps = NULL; virCapsGuestPtr guest = NULL; virCPUDefPtr cpu = NULL; virCPUDataPtr data = NULL; if ((caps = virCapabilitiesNew(virArchFromHost(), 0, 0)) == NULL) goto error; if (nodeCapsInitNUMA(caps) < 0) goto error; /* i686 guests are always supported */ if ((guest = virCapabilitiesAddGuest(caps, "hvm", VIR_ARCH_I686, NULL, NULL, 0, NULL)) == NULL) goto error; if (virCapabilitiesAddGuestDomain(guest, "vmware", NULL, NULL, 0, NULL) == NULL) goto error; if (VIR_ALLOC(cpu) < 0) goto error; cpu->arch = caps->host.arch; cpu->type = VIR_CPU_TYPE_HOST; if (!(data = cpuNodeData(cpu->arch)) || cpuDecode(cpu, data, NULL, 0, NULL) < 0) { goto error; } /* x86_64 guests are supported if * - Host arch is x86_64 * Or * - Host CPU is x86_64 with virtualization extensions */ if (caps->host.arch == VIR_ARCH_X86_64 || (cpuHasFeature(data, "lm") && (cpuHasFeature(data, "vmx") || cpuHasFeature(data, "svm")))) { if ((guest = virCapabilitiesAddGuest(caps, "hvm", VIR_ARCH_X86_64, NULL, NULL, 0, NULL)) == NULL) goto error; if (virCapabilitiesAddGuestDomain(guest, "vmware", NULL, NULL, 0, NULL) == NULL) goto error; } cleanup: virCPUDefFree(cpu); cpuDataFree(data); return caps; error: virObjectUnref(caps); goto cleanup; }
/** * xenInotifyOpen: * @conn: pointer to the connection block * @name: URL for the target, NULL for local * @flags: combination of virDrvOpenFlag(s) * * Connects and starts listening for inotify events * * Returns 0 or -1 in case of error. */ int xenInotifyOpen(virConnectPtr conn, virConnectAuthPtr auth ATTRIBUTE_UNUSED, unsigned int flags) { DIR *dh; struct dirent *ent; char *path; xenUnifiedPrivatePtr priv = conn->privateData; virCheckFlags(VIR_CONNECT_RO, -1); if (priv->configDir) { priv->useXenConfigCache = 1; } else { /* /var/lib/xend/domains/<uuid>/config.sxp */ priv->configDir = XEND_DOMAINS_DIR; priv->useXenConfigCache = 0; if (VIR_ALLOC(priv->configInfoList) < 0) return -1; /* populate initial list */ if (!(dh = opendir(priv->configDir))) { virReportSystemError(errno, _("cannot open directory: %s"), priv->configDir); return -1; } while ((ent = readdir(dh))) { if (STRPREFIX(ent->d_name, ".")) continue; /* Build the full file path */ if (!(path = virFileBuildPath(priv->configDir, ent->d_name, NULL))) { closedir(dh); return -1; } if (xenInotifyAddDomainConfigInfo(conn, path) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Error adding file to config list")); closedir(dh); VIR_FREE(path); return -1; } VIR_FREE(path); } closedir(dh); } if ((priv->inotifyFD = inotify_init()) < 0) { virReportSystemError(errno, "%s", _("initializing inotify")); return -1; } VIR_DEBUG("Adding a watch on %s", priv->configDir); if (inotify_add_watch(priv->inotifyFD, priv->configDir, IN_CREATE | IN_CLOSE_WRITE | IN_DELETE | IN_MOVED_TO | IN_MOVED_FROM) < 0) { virReportSystemError(errno, _("adding watch on %s"), priv->configDir); return -1; } VIR_DEBUG("Building initial config cache"); if (priv->useXenConfigCache && xenXMConfigCacheRefresh(conn) < 0) { VIR_DEBUG("Failed to enable XM config cache %s", conn->err.message); return -1; } VIR_DEBUG("Registering with event loop"); /* Add the handle for monitoring */ if ((priv->inotifyWatch = virEventAddHandle(priv->inotifyFD, VIR_EVENT_HANDLE_READABLE, xenInotifyEvent, conn, NULL)) < 0) { VIR_DEBUG("Failed to add inotify handle, disabling events"); } return 0; }
/** * virNetlinkEventServiceStart: * * start a monitor to receive netlink messages for libvirtd. * This registers a netlink socket with the event interface. * * @protocol: netlink protocol * @groups: broadcast groups to join in * Returns -1 if the monitor cannot be registered, 0 upon success */ int virNetlinkEventServiceStart(unsigned int protocol, unsigned int groups) { virNetlinkEventSrvPrivatePtr srv; int fd; int ret = -1; if (protocol >= MAX_LINKS) { virReportSystemError(EINVAL, _("invalid protocol argument: %d"), protocol); return -EINVAL; } if (server[protocol]) return 0; VIR_INFO("starting netlink event service with protocol %d", protocol); if (VIR_ALLOC(srv) < 0) return -1; if (virMutexInit(&srv->lock) < 0) { VIR_FREE(srv); return -1; } virNetlinkEventServerLock(srv); /* Allocate a new socket and get fd */ if (!(srv->netlinknh = virNetlinkCreateSocket(protocol))) goto error_locked; fd = nl_socket_get_fd(srv->netlinknh); if (fd < 0) { virReportSystemError(errno, "%s", _("cannot get netlink socket fd")); goto error_server; } if (groups && nl_socket_add_membership(srv->netlinknh, groups) < 0) { virReportSystemError(errno, "%s", _("cannot add netlink membership")); goto error_server; } if (nl_socket_set_nonblocking(srv->netlinknh)) { virReportSystemError(errno, "%s", _("cannot set netlink socket nonblocking")); goto error_server; } if ((srv->eventwatch = virEventAddHandle(fd, VIR_EVENT_HANDLE_READABLE, virNetlinkEventCallback, srv, NULL)) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Failed to add netlink event handle watch")); goto error_server; } srv->netlinkfd = fd; VIR_DEBUG("netlink event listener on fd: %i running", fd); ret = 0; server[protocol] = srv; error_server: if (ret < 0) { nl_close(srv->netlinknh); virNetlinkFree(srv->netlinknh); } error_locked: virNetlinkEventServerUnlock(srv); if (ret < 0) { virMutexDestroy(&srv->lock); VIR_FREE(srv); } return ret; }
/** * virLXCProcessStart: * @conn: pointer to connection * @driver: pointer to driver structure * @vm: pointer to virtual machine structure * @autoDestroy: mark the domain for auto destruction * @reason: reason for switching vm to running state * * Starts a vm * * Returns 0 on success or -1 in case of error */ int virLXCProcessStart(virConnectPtr conn, virLXCDriverPtr driver, virDomainObjPtr vm, unsigned int nfiles, int *files, bool autoDestroy, virDomainRunningReason reason) { int rc = -1, r; size_t nttyFDs = 0; int *ttyFDs = NULL; size_t i; char *logfile = NULL; int logfd = -1; size_t nveths = 0; char **veths = NULL; int handshakefds[2] = { -1, -1 }; off_t pos = -1; char ebuf[1024]; char *timestamp; virCommandPtr cmd = NULL; virLXCDomainObjPrivatePtr priv = vm->privateData; virCapsPtr caps = NULL; virErrorPtr err = NULL; virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver); virCgroupPtr selfcgroup; int status; if (virCgroupNewSelf(&selfcgroup) < 0) return -1; if (!virCgroupHasController(selfcgroup, VIR_CGROUP_CONTROLLER_CPUACCT)) { virCgroupFree(&selfcgroup); virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unable to find 'cpuacct' cgroups controller mount")); return -1; } if (!virCgroupHasController(selfcgroup, VIR_CGROUP_CONTROLLER_DEVICES)) { virCgroupFree(&selfcgroup); virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unable to find 'devices' cgroups controller mount")); return -1; } if (!virCgroupHasController(selfcgroup, VIR_CGROUP_CONTROLLER_MEMORY)) { virCgroupFree(&selfcgroup); virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unable to find 'memory' cgroups controller mount")); return -1; } virCgroupFree(&selfcgroup); if (virFileMakePath(cfg->logDir) < 0) { virReportSystemError(errno, _("Cannot create log directory '%s'"), cfg->logDir); return -1; } if (!vm->def->resource) { virDomainResourceDefPtr res; if (VIR_ALLOC(res) < 0) goto cleanup; if (VIR_STRDUP(res->partition, "/machine") < 0) { VIR_FREE(res); goto cleanup; } vm->def->resource = res; } if (virAsprintf(&logfile, "%s/%s.log", cfg->logDir, vm->def->name) < 0) return -1; if (!(caps = virLXCDriverGetCapabilities(driver, false))) goto cleanup; /* Do this up front, so any part of the startup process can add * runtime state to vm->def that won't be persisted. This let's us * report implicit runtime defaults in the XML, like vnc listen/socket */ VIR_DEBUG("Setting current domain def as transient"); if (virDomainObjSetDefTransient(caps, driver->xmlopt, vm, true) < 0) goto cleanup; /* Run an early hook to set-up missing devices */ if (virHookPresent(VIR_HOOK_DRIVER_LXC)) { char *xml = virDomainDefFormat(vm->def, 0); int hookret; hookret = virHookCall(VIR_HOOK_DRIVER_LXC, vm->def->name, VIR_HOOK_LXC_OP_PREPARE, VIR_HOOK_SUBOP_BEGIN, NULL, xml, NULL); VIR_FREE(xml); /* * If the script raised an error abort the launch */ if (hookret < 0) goto cleanup; } if (virLXCProcessEnsureRootFS(vm) < 0) goto cleanup; /* Must be run before security labelling */ VIR_DEBUG("Preparing host devices"); if (virLXCPrepareHostDevices(driver, vm->def) < 0) goto cleanup; /* Here we open all the PTYs we need on the host OS side. * The LXC controller will open the guest OS side PTYs * and forward I/O between them. */ nttyFDs = vm->def->nconsoles; if (VIR_ALLOC_N(ttyFDs, nttyFDs) < 0) goto cleanup; for (i = 0; i < vm->def->nconsoles; i++) ttyFDs[i] = -1; /* If you are using a SecurityDriver with dynamic labelling, then generate a security label for isolation */ VIR_DEBUG("Generating domain security label (if required)"); if (vm->def->nseclabels && vm->def->seclabels[0]->type == VIR_DOMAIN_SECLABEL_DEFAULT) vm->def->seclabels[0]->type = VIR_DOMAIN_SECLABEL_NONE; if (virSecurityManagerGenLabel(driver->securityManager, vm->def) < 0) { virDomainAuditSecurityLabel(vm, false); goto cleanup; } virDomainAuditSecurityLabel(vm, true); VIR_DEBUG("Setting domain security labels"); if (virSecurityManagerSetAllLabel(driver->securityManager, vm->def, NULL) < 0) goto cleanup; for (i = 0; i < vm->def->nconsoles; i++) { char *ttyPath; if (vm->def->consoles[i]->source.type != VIR_DOMAIN_CHR_TYPE_PTY) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("Only PTY console types are supported")); goto cleanup; } if (virFileOpenTty(&ttyFDs[i], &ttyPath, 1) < 0) { virReportSystemError(errno, "%s", _("Failed to allocate tty")); goto cleanup; } VIR_FREE(vm->def->consoles[i]->source.data.file.path); vm->def->consoles[i]->source.data.file.path = ttyPath; VIR_FREE(vm->def->consoles[i]->info.alias); if (virAsprintf(&vm->def->consoles[i]->info.alias, "console%zu", i) < 0) goto cleanup; } if (virLXCProcessSetupInterfaces(conn, vm->def, &nveths, &veths) < 0) goto cleanup; /* Save the configuration for the controller */ if (virDomainSaveConfig(cfg->stateDir, vm->def) < 0) goto cleanup; if ((logfd = open(logfile, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR|S_IWUSR)) < 0) { virReportSystemError(errno, _("Failed to open '%s'"), logfile); goto cleanup; } if (pipe(handshakefds) < 0) { virReportSystemError(errno, "%s", _("Unable to create pipe")); goto cleanup; } if (!(cmd = virLXCProcessBuildControllerCmd(driver, vm, nveths, veths, ttyFDs, nttyFDs, files, nfiles, handshakefds[1]))) goto cleanup; virCommandSetOutputFD(cmd, &logfd); virCommandSetErrorFD(cmd, &logfd); /* now that we know it is about to start call the hook if present */ if (virHookPresent(VIR_HOOK_DRIVER_LXC)) { char *xml = virDomainDefFormat(vm->def, 0); int hookret; hookret = virHookCall(VIR_HOOK_DRIVER_LXC, vm->def->name, VIR_HOOK_LXC_OP_START, VIR_HOOK_SUBOP_BEGIN, NULL, xml, NULL); VIR_FREE(xml); /* * If the script raised an error abort the launch */ if (hookret < 0) goto cleanup; } /* Log timestamp */ if ((timestamp = virTimeStringNow()) == NULL) goto cleanup; if (safewrite(logfd, timestamp, strlen(timestamp)) < 0 || safewrite(logfd, START_POSTFIX, strlen(START_POSTFIX)) < 0) { VIR_WARN("Unable to write timestamp to logfile: %s", virStrerror(errno, ebuf, sizeof(ebuf))); } VIR_FREE(timestamp); /* Log generated command line */ virCommandWriteArgLog(cmd, logfd); if ((pos = lseek(logfd, 0, SEEK_END)) < 0) VIR_WARN("Unable to seek to end of logfile: %s", virStrerror(errno, ebuf, sizeof(ebuf))); virCommandRawStatus(cmd); if (virCommandRun(cmd, &status) < 0) goto cleanup; if (status != 0) { if (virLXCProcessReadLogOutput(vm, logfile, pos, ebuf, sizeof(ebuf)) <= 0) { if (WIFEXITED(status)) snprintf(ebuf, sizeof(ebuf), _("unexpected exit status %d"), WEXITSTATUS(status)); else snprintf(ebuf, sizeof(ebuf), "%s", _("terminated abnormally")); } virReportError(VIR_ERR_INTERNAL_ERROR, _("guest failed to start: %s"), ebuf); goto cleanup; } if (VIR_CLOSE(handshakefds[1]) < 0) { virReportSystemError(errno, "%s", _("could not close handshake fd")); goto cleanup; } /* Connect to the controller as a client *first* because * this will block until the child has written their * pid file out to disk & created their cgroup */ if (!(priv->monitor = virLXCProcessConnectMonitor(driver, vm))) { /* Intentionally overwrite the real monitor error message, * since a better one is almost always found in the logs */ if (virLXCProcessReadLogOutput(vm, logfile, pos, ebuf, sizeof(ebuf)) > 0) { virResetLastError(); virReportError(VIR_ERR_INTERNAL_ERROR, _("guest failed to start: %s"), ebuf); } goto cleanup; } /* And get its pid */ if ((r = virPidFileRead(cfg->stateDir, vm->def->name, &vm->pid)) < 0) { if (virLXCProcessReadLogOutput(vm, logfile, pos, ebuf, sizeof(ebuf)) > 0) virReportError(VIR_ERR_INTERNAL_ERROR, _("guest failed to start: %s"), ebuf); else virReportSystemError(-r, _("Failed to read pid file %s/%s.pid"), cfg->stateDir, vm->def->name); goto cleanup; } if (virCgroupNewDetectMachine(vm->def->name, "lxc", vm->pid, vm->def->resource ? vm->def->resource->partition : NULL, -1, &priv->cgroup) < 0) goto error; if (!priv->cgroup) { virReportError(VIR_ERR_INTERNAL_ERROR, _("No valid cgroup for machine %s"), vm->def->name); goto error; } priv->stopReason = VIR_DOMAIN_EVENT_STOPPED_FAILED; priv->wantReboot = false; vm->def->id = vm->pid; virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, reason); priv->doneStopEvent = false; if (virAtomicIntInc(&driver->nactive) == 1 && driver->inhibitCallback) driver->inhibitCallback(true, driver->inhibitOpaque); if (lxcContainerWaitForContinue(handshakefds[0]) < 0) { char out[1024]; if (!(virLXCProcessReadLogOutput(vm, logfile, pos, out, 1024) < 0)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("guest failed to start: %s"), out); } goto error; } if (autoDestroy && virCloseCallbacksSet(driver->closeCallbacks, vm, conn, lxcProcessAutoDestroy) < 0) goto error; if (virDomainObjSetDefTransient(caps, driver->xmlopt, vm, false) < 0) goto error; /* Write domain status to disk. * * XXX: Earlier we wrote the plain "live" domain XML to this * location for the benefit of libvirt_lxc. We're now overwriting * it with the live status XML instead. This is a (currently * harmless) inconsistency we should fix one day */ if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0) goto error; /* finally we can call the 'started' hook script if any */ if (virHookPresent(VIR_HOOK_DRIVER_LXC)) { char *xml = virDomainDefFormat(vm->def, 0); int hookret; hookret = virHookCall(VIR_HOOK_DRIVER_LXC, vm->def->name, VIR_HOOK_LXC_OP_STARTED, VIR_HOOK_SUBOP_BEGIN, NULL, xml, NULL); VIR_FREE(xml); /* * If the script raised an error abort the launch */ if (hookret < 0) goto error; } rc = 0; cleanup: if (rc != 0 && !err) err = virSaveLastError(); virCommandFree(cmd); if (VIR_CLOSE(logfd) < 0) { virReportSystemError(errno, "%s", _("could not close logfile")); rc = -1; } for (i = 0; i < nveths; i++) { if (rc != 0 && veths[i]) ignore_value(virNetDevVethDelete(veths[i])); VIR_FREE(veths[i]); } if (rc != 0) { if (vm->newDef) { virDomainDefFree(vm->newDef); vm->newDef = NULL; } if (priv->monitor) { virObjectUnref(priv->monitor); priv->monitor = NULL; } virDomainConfVMNWFilterTeardown(vm); virSecurityManagerRestoreAllLabel(driver->securityManager, vm->def, false); virSecurityManagerReleaseLabel(driver->securityManager, vm->def); /* Clear out dynamically assigned labels */ if (vm->def->nseclabels && vm->def->seclabels[0]->type == VIR_DOMAIN_SECLABEL_DYNAMIC) { VIR_FREE(vm->def->seclabels[0]->model); VIR_FREE(vm->def->seclabels[0]->label); VIR_FREE(vm->def->seclabels[0]->imagelabel); } } for (i = 0; i < nttyFDs; i++) VIR_FORCE_CLOSE(ttyFDs[i]); VIR_FREE(ttyFDs); VIR_FORCE_CLOSE(handshakefds[0]); VIR_FORCE_CLOSE(handshakefds[1]); VIR_FREE(logfile); virObjectUnref(cfg); virObjectUnref(caps); if (err) { virSetError(err); virFreeError(err); } return rc; error: err = virSaveLastError(); virLXCProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED); goto cleanup; }
static int xenFormatXLInputDevs(virConfPtr conf, virDomainDefPtr def) { size_t i; const char *devtype; virConfValuePtr usbdevices = NULL, lastdev; if (def->os.type == VIR_DOMAIN_OSTYPE_HVM) { if (VIR_ALLOC(usbdevices) < 0) goto error; usbdevices->type = VIR_CONF_LIST; usbdevices->list = NULL; lastdev = NULL; for (i = 0; i < def->ninputs; i++) { if (def->inputs[i]->bus == VIR_DOMAIN_INPUT_BUS_USB) { if (xenConfigSetInt(conf, "usb", 1) < 0) goto error; switch (def->inputs[i]->type) { case VIR_DOMAIN_INPUT_TYPE_MOUSE: devtype = "mouse"; break; case VIR_DOMAIN_INPUT_TYPE_TABLET: devtype = "tablet"; break; case VIR_DOMAIN_INPUT_TYPE_KBD: devtype = "keyboard"; break; default: continue; } if (lastdev == NULL) { if (VIR_ALLOC(lastdev) < 0) goto error; usbdevices->list = lastdev; } else { if (VIR_ALLOC(lastdev->next) < 0) goto error; lastdev = lastdev->next; } lastdev->type = VIR_CONF_STRING; if (VIR_STRDUP(lastdev->str, devtype) < 0) goto error; } } if (usbdevices->list != NULL) { if (usbdevices->list->next == NULL) { /* for compatibility with Xen <= 4.2, use old syntax when * only one device present */ if (xenConfigSetString(conf, "usbdevice", usbdevices->list->str) < 0) goto error; virConfFreeValue(usbdevices); } else { virConfSetValue(conf, "usbdevice", usbdevices); } } else { VIR_FREE(usbdevices); } } return 0; error: virConfFreeValue(usbdevices); return -1; }
static virDrvOpenStatus hypervConnectOpen(virConnectPtr conn, virConnectAuthPtr auth, unsigned int flags) { virDrvOpenStatus result = VIR_DRV_OPEN_ERROR; char *plus; hypervPrivate *priv = NULL; char *username = NULL; char *password = NULL; virBuffer query = VIR_BUFFER_INITIALIZER; Msvm_ComputerSystem *computerSystem = NULL; virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR); /* Decline if the URI is NULL or the scheme is NULL */ if (conn->uri == NULL || conn->uri->scheme == NULL) { return VIR_DRV_OPEN_DECLINED; } /* Decline if the scheme is not hyperv */ plus = strchr(conn->uri->scheme, '+'); if (plus == NULL) { if (STRCASENEQ(conn->uri->scheme, "hyperv")) { return VIR_DRV_OPEN_DECLINED; } } else { if (plus - conn->uri->scheme != 6 || STRCASENEQLEN(conn->uri->scheme, "hyperv", 6)) { return VIR_DRV_OPEN_DECLINED; } virReportError(VIR_ERR_INVALID_ARG, _("Transport '%s' in URI scheme is not supported, try again " "without the transport part"), plus + 1); return VIR_DRV_OPEN_ERROR; } /* Require server part */ if (conn->uri->server == NULL) { virReportError(VIR_ERR_INVALID_ARG, "%s", _("URI is missing the server part")); return VIR_DRV_OPEN_ERROR; } /* Require auth */ if (auth == NULL || auth->cb == NULL) { virReportError(VIR_ERR_INVALID_ARG, "%s", _("Missing or invalid auth pointer")); return VIR_DRV_OPEN_ERROR; } /* Allocate per-connection private data */ if (VIR_ALLOC(priv) < 0) goto cleanup; if (hypervParseUri(&priv->parsedUri, conn->uri) < 0) { goto cleanup; } /* Set the port dependent on the transport protocol if no port is * specified. This allows us to rely on the port parameter being * correctly set when building URIs later on, without the need to * distinguish between the situations port == 0 and port != 0 */ if (conn->uri->port == 0) { if (STRCASEEQ(priv->parsedUri->transport, "https")) { conn->uri->port = 5986; } else { conn->uri->port = 5985; } } /* Request credentials */ if (conn->uri->user != NULL) { if (VIR_STRDUP(username, conn->uri->user) < 0) goto cleanup; } else { username = virAuthGetUsername(conn, auth, "hyperv", "administrator", conn->uri->server); if (username == NULL) { virReportError(VIR_ERR_AUTH_FAILED, "%s", _("Username request failed")); goto cleanup; } } password = virAuthGetPassword(conn, auth, "hyperv", username, conn->uri->server); if (password == NULL) { virReportError(VIR_ERR_AUTH_FAILED, "%s", _("Password request failed")); goto cleanup; } /* Initialize the openwsman connection */ priv->client = wsmc_create(conn->uri->server, conn->uri->port, "/wsman", priv->parsedUri->transport, username, password); if (priv->client == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not create openwsman client")); goto cleanup; } if (wsmc_transport_init(priv->client, NULL) != 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not initialize openwsman transport")); goto cleanup; } /* FIXME: Currently only basic authentication is supported */ wsman_transport_set_auth_method(priv->client, "basic"); /* Check if the connection can be established and if the server has the * Hyper-V role installed. If the call to hypervGetMsvmComputerSystemList * succeeds than the connection has been established. If the returned list * is empty than the server isn't a Hyper-V server. */ virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_SELECT); virBufferAddLit(&query, "where "); virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_PHYSICAL); if (hypervGetMsvmComputerSystemList(priv, &query, &computerSystem) < 0) { goto cleanup; } if (computerSystem == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, _("%s is not a Hyper-V server"), conn->uri->server); goto cleanup; } conn->privateData = priv; priv = NULL; result = VIR_DRV_OPEN_SUCCESS; cleanup: hypervFreePrivate(&priv); VIR_FREE(username); VIR_FREE(password); hypervFreeObject(priv, (hypervObject *)computerSystem); return result; }
static int xenParseXLSpice(virConfPtr conf, virDomainDefPtr def) { virDomainGraphicsDefPtr graphics = NULL; unsigned long port; char *listenAddr = NULL; int val; if (def->os.type == VIR_DOMAIN_OSTYPE_HVM) { if (xenConfigGetBool(conf, "spice", &val, 0) < 0) return -1; if (val) { if (VIR_ALLOC(graphics) < 0) return -1; graphics->type = VIR_DOMAIN_GRAPHICS_TYPE_SPICE; if (xenConfigCopyStringOpt(conf, "spicehost", &listenAddr) < 0) goto cleanup; if (virDomainGraphicsListenAppendAddress(graphics, listenAddr) < 0) goto cleanup; VIR_FREE(listenAddr); if (xenConfigGetULong(conf, "spicetls_port", &port, 0) < 0) goto cleanup; graphics->data.spice.tlsPort = (int)port; if (xenConfigGetULong(conf, "spiceport", &port, 0) < 0) goto cleanup; graphics->data.spice.port = (int)port; if (!graphics->data.spice.tlsPort && !graphics->data.spice.port) graphics->data.spice.autoport = 1; if (xenConfigGetBool(conf, "spicedisable_ticketing", &val, 0) < 0) goto cleanup; if (!val) { if (xenConfigCopyString(conf, "spicepasswd", &graphics->data.spice.auth.passwd) < 0) goto cleanup; } if (xenConfigGetBool(conf, "spiceagent_mouse", &val, 0) < 0) goto cleanup; if (val) { graphics->data.spice.mousemode = VIR_DOMAIN_GRAPHICS_SPICE_MOUSE_MODE_CLIENT; } else { graphics->data.spice.mousemode = VIR_DOMAIN_GRAPHICS_SPICE_MOUSE_MODE_SERVER; } if (xenConfigGetBool(conf, "spice_clipboard_sharing", &val, 0) < 0) goto cleanup; if (val) graphics->data.spice.copypaste = VIR_TRISTATE_BOOL_YES; else graphics->data.spice.copypaste = VIR_TRISTATE_BOOL_NO; if (VIR_ALLOC_N(def->graphics, 1) < 0) goto cleanup; def->graphics[0] = graphics; def->ngraphics = 1; } } return 0; cleanup: VIR_FREE(listenAddr); virDomainGraphicsDefFree(graphics); return -1; }
static char * hypervDomainGetXMLDesc(virDomainPtr domain, unsigned int flags) { char *xml = NULL; hypervPrivate *priv = domain->conn->privateData; virDomainDefPtr def = NULL; char uuid_string[VIR_UUID_STRING_BUFLEN]; virBuffer query = VIR_BUFFER_INITIALIZER; Msvm_ComputerSystem *computerSystem = NULL; Msvm_VirtualSystemSettingData *virtualSystemSettingData = NULL; Msvm_ProcessorSettingData *processorSettingData = NULL; Msvm_MemorySettingData *memorySettingData = NULL; /* Flags checked by virDomainDefFormat */ if (VIR_ALLOC(def) < 0) goto cleanup; virUUIDFormat(domain->uuid, uuid_string); /* Get Msvm_ComputerSystem */ if (hypervMsvmComputerSystemFromDomain(domain, &computerSystem) < 0) { goto cleanup; } /* Get Msvm_VirtualSystemSettingData */ virBufferAsprintf(&query, "associators of " "{Msvm_ComputerSystem.CreationClassName=\"Msvm_ComputerSystem\"," "Name=\"%s\"} " "where AssocClass = Msvm_SettingsDefineState " "ResultClass = Msvm_VirtualSystemSettingData", uuid_string); if (hypervGetMsvmVirtualSystemSettingDataList(priv, &query, &virtualSystemSettingData) < 0) { goto cleanup; } if (virtualSystemSettingData == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not lookup %s for domain %s"), "Msvm_VirtualSystemSettingData", computerSystem->data->ElementName); goto cleanup; } /* Get Msvm_ProcessorSettingData */ virBufferAsprintf(&query, "associators of " "{Msvm_VirtualSystemSettingData.InstanceID=\"%s\"} " "where AssocClass = Msvm_VirtualSystemSettingDataComponent " "ResultClass = Msvm_ProcessorSettingData", virtualSystemSettingData->data->InstanceID); if (hypervGetMsvmProcessorSettingDataList(priv, &query, &processorSettingData) < 0) { goto cleanup; } if (processorSettingData == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not lookup %s for domain %s"), "Msvm_ProcessorSettingData", computerSystem->data->ElementName); goto cleanup; } /* Get Msvm_MemorySettingData */ virBufferAsprintf(&query, "associators of " "{Msvm_VirtualSystemSettingData.InstanceID=\"%s\"} " "where AssocClass = Msvm_VirtualSystemSettingDataComponent " "ResultClass = Msvm_MemorySettingData", virtualSystemSettingData->data->InstanceID); if (hypervGetMsvmMemorySettingDataList(priv, &query, &memorySettingData) < 0) { goto cleanup; } if (memorySettingData == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not lookup %s for domain %s"), "Msvm_MemorySettingData", computerSystem->data->ElementName); goto cleanup; } /* Fill struct */ def->virtType = VIR_DOMAIN_VIRT_HYPERV; if (hypervIsMsvmComputerSystemActive(computerSystem, NULL)) { def->id = computerSystem->data->ProcessID; } else { def->id = -1; } if (virUUIDParse(computerSystem->data->Name, def->uuid) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not parse UUID from string '%s'"), computerSystem->data->Name); return NULL; } if (VIR_STRDUP(def->name, computerSystem->data->ElementName) < 0) goto cleanup; def->mem.max_balloon = memorySettingData->data->Limit * 1024; /* megabyte to kilobyte */ def->mem.cur_balloon = memorySettingData->data->VirtualQuantity * 1024; /* megabyte to kilobyte */ def->vcpus = processorSettingData->data->VirtualQuantity; def->maxvcpus = processorSettingData->data->VirtualQuantity; if (VIR_STRDUP(def->os.type, "hvm") < 0) goto cleanup; /* FIXME: devices section is totally missing */ xml = virDomainDefFormat(def, flags); cleanup: virDomainDefFree(def); hypervFreeObject(priv, (hypervObject *)computerSystem); hypervFreeObject(priv, (hypervObject *)virtualSystemSettingData); hypervFreeObject(priv, (hypervObject *)processorSettingData); hypervFreeObject(priv, (hypervObject *)memorySettingData); return xml; }
static int xenFormatXLDisk(virConfValuePtr list, virDomainDiskDefPtr disk) { virBuffer buf = VIR_BUFFER_INITIALIZER; virConfValuePtr val, tmp; int format = virDomainDiskGetFormat(disk); const char *driver = virDomainDiskGetDriver(disk); char *target = NULL; /* format */ virBufferAddLit(&buf, "format="); switch (format) { case VIR_STORAGE_FILE_RAW: virBufferAddLit(&buf, "raw,"); break; case VIR_STORAGE_FILE_VHD: virBufferAddLit(&buf, "xvhd,"); break; case VIR_STORAGE_FILE_QCOW: virBufferAddLit(&buf, "qcow,"); break; case VIR_STORAGE_FILE_QCOW2: virBufferAddLit(&buf, "qcow2,"); break; /* set default */ default: virBufferAddLit(&buf, "raw,"); } /* device */ virBufferAsprintf(&buf, "vdev=%s,", disk->dst); /* access */ virBufferAddLit(&buf, "access="); if (disk->src->readonly) virBufferAddLit(&buf, "ro,"); else if (disk->src->shared) virBufferAddLit(&buf, "!,"); else virBufferAddLit(&buf, "rw,"); if (disk->transient) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("transient disks not supported yet")); goto cleanup; } /* backendtype */ if (driver) { virBufferAddLit(&buf, "backendtype="); if (STREQ(driver, "qemu") || STREQ(driver, "file")) virBufferAddLit(&buf, "qdisk,"); else if (STREQ(driver, "tap")) virBufferAddLit(&buf, "tap,"); else if (STREQ(driver, "phy")) virBufferAddLit(&buf, "phy,"); } /* devtype */ if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) virBufferAddLit(&buf, "devtype=cdrom,"); /* * target * From $xensrc/docs/misc/xl-disk-configuration.txt: * When this parameter is specified by name, ie with the "target=" * syntax in the configuration file, it consumes the whole rest of the * <diskspec> including trailing whitespaces. Therefore in that case * it must come last. */ if (xenFormatXLDiskSrc(disk->src, &target) < 0) goto cleanup; virBufferAsprintf(&buf, "target=%s", target); if (virBufferCheckError(&buf) < 0) goto cleanup; if (VIR_ALLOC(val) < 0) goto cleanup; val->type = VIR_CONF_STRING; val->str = virBufferContentAndReset(&buf); tmp = list->list; while (tmp && tmp->next) tmp = tmp->next; if (tmp) tmp->next = val; else list->list = val; return 0; cleanup: VIR_FREE(target); virBufferFreeAndReset(&buf); return -1; }
/** * virNetDevIPAddrAdd: * @ifname: the interface name * @addr: the IP address (IPv4 or IPv6) * @peer: The IP address of peer (IPv4 or IPv6) * @prefix: number of 1 bits in the netmask * * Add an IP address to an interface. This function *does not* remove * any previously added IP addresses - that must be done separately with * virNetDevIPAddrClear. * * Returns 0 in case of success or -1 in case of error. */ int virNetDevIPAddrAdd(const char *ifname, virSocketAddr *addr, virSocketAddr *peer, unsigned int prefix) { virSocketAddr *broadcast = NULL; int ret = -1; struct nl_msg *nlmsg = NULL; struct nlmsghdr *resp = NULL; unsigned int recvbuflen; char *ipStr = NULL; char *peerStr = NULL; char *bcastStr = NULL; ipStr = virSocketAddrFormat(addr); if (peer && VIR_SOCKET_ADDR_VALID(peer)) peerStr = virSocketAddrFormat(peer); /* The caller needs to provide a correct address */ if (VIR_SOCKET_ADDR_FAMILY(addr) == AF_INET && !(peer && VIR_SOCKET_ADDR_VALID(peer))) { /* compute a broadcast address if this is IPv4 */ if (VIR_ALLOC(broadcast) < 0) goto cleanup; if (virSocketAddrBroadcastByPrefix(addr, prefix, broadcast) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Failed to determine broadcast address for '%s/%d'"), ipStr, prefix); goto cleanup; } bcastStr = virSocketAddrFormat(broadcast); } VIR_DEBUG("Adding IP address %s/%d%s%s%s%s to %s", NULLSTR(ipStr), prefix, peerStr ? " peer " : "", peerStr ? peerStr : "", bcastStr ? " bcast " : "", bcastStr ? bcastStr : "", ifname); if (!(nlmsg = virNetDevCreateNetlinkAddressMessage(RTM_NEWADDR, ifname, addr, prefix, broadcast, peer))) goto cleanup; if (virNetlinkCommand(nlmsg, &resp, &recvbuflen, 0, 0, NETLINK_ROUTE, 0) < 0) goto cleanup; if (virNetlinkGetErrorCode(resp, recvbuflen) < 0) { virReportError(VIR_ERR_SYSTEM_ERROR, _("Failed to add IP address %s/%d%s%s%s%s to %s"), ipStr, prefix, peerStr ? " peer " : "", peerStr ? peerStr : "", bcastStr ? " bcast " : "", bcastStr ? bcastStr : "", ifname); goto cleanup; } ret = 0; cleanup: VIR_FREE(ipStr); VIR_FREE(peerStr); VIR_FREE(bcastStr); nlmsg_free(nlmsg); VIR_FREE(resp); VIR_FREE(broadcast); return ret; }
/** * virNetlinkEventServiceStart: * * start a monitor to receive netlink messages for libvirtd. * This registers a netlink socket with the event interface. * * Returns -1 if the monitor cannot be registered, 0 upon success */ int virNetlinkEventServiceStart(void) { virNetlinkEventSrvPrivatePtr srv; int fd; int ret = -1; if (server) return 0; VIR_INFO("starting netlink event service"); if (VIR_ALLOC(srv) < 0) { virReportOOMError(); return -1; } if (virMutexInit(&srv->lock) < 0) { VIR_FREE(srv); return -1; } virNetlinkEventServerLock(srv); /* Allocate a new socket and get fd */ srv->netlinknh = virNetlinkAlloc(); if (!srv->netlinknh) { virReportSystemError(errno, "%s", _("cannot allocate nlhandle for virNetlinkEvent server")); goto error_locked; } if (nl_connect(srv->netlinknh, NETLINK_ROUTE) < 0) { virReportSystemError(errno, "%s", _("cannot connect to netlink socket")); goto error_server; } fd = nl_socket_get_fd(srv->netlinknh); if (fd < 0) { virReportSystemError(errno, "%s", _("cannot get netlink socket fd")); goto error_server; } if (nl_socket_set_nonblocking(srv->netlinknh)) { virReportSystemError(errno, "%s", _("cannot set netlink socket nonblocking")); goto error_server; } if ((srv->eventwatch = virEventAddHandle(fd, VIR_EVENT_HANDLE_READABLE, virNetlinkEventCallback, srv, NULL)) < 0) { netlinkError(VIR_ERR_INTERNAL_ERROR, "%s", _("Failed to add netlink event handle watch")); goto error_server; } srv->netlinkfd = fd; VIR_DEBUG("netlink event listener on fd: %i running", fd); ret = 0; server = srv; error_server: if (ret < 0) { nl_close(srv->netlinknh); virNetlinkFree(srv->netlinknh); } error_locked: virNetlinkEventServerUnlock(srv); if (ret < 0) { virMutexDestroy(&srv->lock); VIR_FREE(srv); } return ret; }
virStorageBackendProbeTarget(virStorageVolTargetPtr target, char **backingStore, int *backingStoreFormat, unsigned long long *allocation, unsigned long long *capacity, virStorageEncryptionPtr *encryption) { int fd = -1; int ret = -1; virStorageFileMetadata *meta; if (VIR_ALLOC(meta) < 0) { virReportOOMError(); return ret; } *backingStore = NULL; *backingStoreFormat = VIR_STORAGE_FILE_AUTO; if (encryption) *encryption = NULL; if ((ret = virStorageBackendVolOpenCheckMode(target->path, VIR_STORAGE_VOL_FS_REFRESH_FLAGS)) < 0) goto error; /* Take care to propagate ret, it is not always -1 */ fd = ret; if ((ret = virStorageBackendUpdateVolTargetInfoFD(target, fd, allocation, capacity)) < 0) { goto error; } if ((target->format = virStorageFileProbeFormatFromFD(target->path, fd)) < 0) { ret = -1; goto error; } if (virStorageFileGetMetadataFromFD(target->path, fd, target->format, meta) < 0) { ret = -1; goto error; } VIR_FORCE_CLOSE(fd); if (meta->backingStore) { *backingStore = meta->backingStore; meta->backingStore = NULL; if (meta->backingStoreFormat == VIR_STORAGE_FILE_AUTO) { if ((ret = virStorageFileProbeFormat(*backingStore)) < 0) { /* If the backing file is currently unavailable, only log an error, * but continue. Returning -1 here would disable the whole storage * pool, making it unavailable for even maintenance. */ virStorageReportError(VIR_ERR_INTERNAL_ERROR, _("cannot probe backing volume format: %s"), *backingStore); ret = -3; } else { *backingStoreFormat = ret; ret = 0; } } else { *backingStoreFormat = meta->backingStoreFormat; ret = 0; } } else { ret = 0; } if (capacity && meta->capacity) *capacity = meta->capacity; if (encryption != NULL && meta->encrypted) { if (VIR_ALLOC(*encryption) < 0) { virReportOOMError(); goto cleanup; } switch (target->format) { case VIR_STORAGE_FILE_QCOW: case VIR_STORAGE_FILE_QCOW2: (*encryption)->format = VIR_STORAGE_ENCRYPTION_FORMAT_QCOW; break; default: break; } /* XXX ideally we'd fill in secret UUID here * but we cannot guarantee 'conn' is non-NULL * at this point in time :-( So we only fill * in secrets when someone first queries a vol */ } virStorageFileFreeMetadata(meta); return ret; error: VIR_FORCE_CLOSE(fd); cleanup: virStorageFileFreeMetadata(meta); return ret; }
static int virStorageBackendRBDRefreshPool(virConnectPtr conn ATTRIBUTE_UNUSED, virStoragePoolObjPtr pool) { size_t max_size = 1024; int ret = -1; int len = -1; int i; char *name, *names = NULL; virStorageBackendRBDStatePtr ptr; ptr.cluster = NULL; ptr.ioctx = NULL; if (virStorageBackendRBDOpenRADOSConn(&ptr, conn, pool) < 0) { goto cleanup; } if (rados_ioctx_create(ptr.cluster, pool->def->source.name, &ptr.ioctx) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("failed to create the RBD IoCTX. Does the pool '%s' exist?"), pool->def->source.name); goto cleanup; } struct rados_cluster_stat_t stat; if (rados_cluster_stat(ptr.cluster, &stat) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("failed to stat the RADOS cluster")); goto cleanup; } struct rados_pool_stat_t poolstat; if (rados_ioctx_pool_stat(ptr.ioctx, &poolstat) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("failed to stat the RADOS pool '%s'"), pool->def->source.name); goto cleanup; } pool->def->capacity = stat.kb * 1024; pool->def->available = stat.kb_avail * 1024; pool->def->allocation = poolstat.num_bytes; VIR_DEBUG("Utilization of RBD pool %s: (kb: %llu kb_avail: %llu num_bytes: %llu)", pool->def->source.name, (unsigned long long)stat.kb, (unsigned long long)stat.kb_avail, (unsigned long long)poolstat.num_bytes); while (true) { if (VIR_ALLOC_N(names, max_size) < 0) goto out_of_memory; len = rbd_list(ptr.ioctx, names, &max_size); if (len >= 0) break; if (len != -ERANGE) { VIR_WARN("%s", _("A problem occurred while listing RBD images")); goto cleanup; } VIR_FREE(names); } for (i = 0, name = names; name < names + max_size; i++) { virStorageVolDefPtr vol; if (VIR_REALLOC_N(pool->volumes.objs, pool->volumes.count + 1) < 0) { virStoragePoolObjClearVols(pool); goto out_of_memory; } if (STREQ(name, "")) break; if (VIR_ALLOC(vol) < 0) goto out_of_memory; vol->name = strdup(name); if (vol->name == NULL) { VIR_FREE(vol); goto out_of_memory; } name += strlen(name) + 1; if (volStorageBackendRBDRefreshVolInfo(vol, pool, ptr) < 0) { virStorageVolDefFree(vol); goto cleanup; } pool->volumes.objs[pool->volumes.count++] = vol; } VIR_DEBUG("Found %d images in RBD pool %s", pool->volumes.count, pool->def->source.name); ret = 0; cleanup: VIR_FREE(names); virStorageBackendRBDCloseRADOSConn(ptr); return ret; out_of_memory: virReportOOMError(); goto cleanup; }
struct daemonConfig* daemonConfigNew(bool privileged ATTRIBUTE_UNUSED) { struct daemonConfig *data; char *localhost; int ret; if (VIR_ALLOC(data) < 0) { virReportOOMError(); return NULL; } data->listen_tls = 1; data->listen_tcp = 0; if (!(data->tls_port = strdup(LIBVIRTD_TLS_PORT))) goto no_memory; if (!(data->tcp_port = strdup(LIBVIRTD_TCP_PORT))) goto no_memory; /* Only default to PolicyKit if running as root */ #if WITH_POLKIT if (privileged) { data->auth_unix_rw = REMOTE_AUTH_POLKIT; data->auth_unix_ro = REMOTE_AUTH_POLKIT; } else { #endif data->auth_unix_rw = REMOTE_AUTH_NONE; data->auth_unix_ro = REMOTE_AUTH_NONE; #if WITH_POLKIT } #endif if (data->auth_unix_rw == REMOTE_AUTH_POLKIT) data->unix_sock_rw_perms = strdup("0777"); /* Allow world */ else data->unix_sock_rw_perms = strdup("0700"); /* Allow user only */ data->unix_sock_ro_perms = strdup("0777"); /* Always allow world */ if (!data->unix_sock_ro_perms || !data->unix_sock_rw_perms) goto no_memory; #if WITH_SASL data->auth_tcp = REMOTE_AUTH_SASL; #else data->auth_tcp = REMOTE_AUTH_NONE; #endif data->auth_tls = REMOTE_AUTH_NONE; data->mdns_adv = 0; data->min_workers = 5; data->max_workers = 20; data->max_clients = 20; data->prio_workers = 5; data->max_requests = 20; data->max_client_requests = 5; data->log_buffer_size = 64; data->audit_level = 1; data->audit_logging = 0; data->keepalive_interval = 5; data->keepalive_count = 5; data->keepalive_required = 0; localhost = virGetHostname(NULL); if (localhost == NULL) { /* we couldn't resolve the hostname; assume that we are * running in disconnected operation, and report a less * useful Avahi string */ ret = virAsprintf(&data->mdns_name, "Virtualization Host"); } else { char *tmp; /* Extract the host part of the potentially FQDN */ if ((tmp = strchr(localhost, '.'))) *tmp = '\0'; ret = virAsprintf(&data->mdns_name, "Virtualization Host %s", localhost); } VIR_FREE(localhost); if (ret < 0) goto no_memory; return data; no_memory: virReportOOMError(); daemonConfigFree(data); return NULL; }