static lxcFstabPtr lxcParseFstabLine(char *fstabLine) { lxcFstabPtr fstab = NULL; char **parts; if (!fstabLine || VIR_ALLOC(fstab) < 0) return NULL; if (!(parts = lxcStringSplit(fstabLine))) goto error; if (!parts[0] || !parts[1] || !parts[2] || !parts[3]) goto error; if (VIR_STRDUP(fstab->src, parts[0]) < 0 || VIR_STRDUP(fstab->dst, parts[1]) < 0 || VIR_STRDUP(fstab->type, parts[2]) < 0 || VIR_STRDUP(fstab->options, parts[3]) < 0) goto error; virStringFreeList(parts); return fstab; error: lxcFstabFree(fstab); virStringFreeList(parts); return NULL; }
virDomainDefPtr bhyveParseCommandLineString(const char* nativeConfig, unsigned caps, virDomainXMLOptionPtr xmlopt) { virDomainDefPtr def = NULL; int bhyve_argc = 0; char **bhyve_argv = NULL; int loader_argc = 0; char **loader_argv = NULL; if (!(def = virDomainDefNew())) goto cleanup; /* Initialize defaults. */ def->virtType = VIR_DOMAIN_VIRT_BHYVE; if (virUUIDGenerate(def->uuid) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Failed to generate uuid")); virDomainDefFree(def); def = NULL; goto cleanup; } def->id = -1; def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME; if (bhyveCommandLineToArgv(nativeConfig, &loader_argc, &loader_argv, &bhyve_argc, &bhyve_argv)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Failed to convert the command string to argv-lists")); goto error; } if (bhyveParseBhyveCommandLine(def, xmlopt, caps, bhyve_argc, bhyve_argv)) goto error; if (loader_argv && STREQ(loader_argv[0], "/usr/sbin/bhyveload")) { if (bhyveParseBhyveLoadCommandLine(def, loader_argc, loader_argv)) goto error; } else if (loader_argv) { if (bhyveParseCustomLoaderCommandLine(def, loader_argc, loader_argv)) goto error; } cleanup: virStringFreeList(loader_argv); virStringFreeList(bhyve_argv); return def; error: virDomainDefFree(def); def = NULL; goto cleanup; }
static void virQEMUDriverConfigDispose(void *obj) { virQEMUDriverConfigPtr cfg = obj; virStringFreeList(cfg->cgroupDeviceACL); VIR_FREE(cfg->configBaseDir); VIR_FREE(cfg->configDir); VIR_FREE(cfg->autostartDir); VIR_FREE(cfg->logDir); VIR_FREE(cfg->stateDir); VIR_FREE(cfg->libDir); VIR_FREE(cfg->cacheDir); VIR_FREE(cfg->saveDir); VIR_FREE(cfg->snapshotDir); VIR_FREE(cfg->channelTargetDir); VIR_FREE(cfg->nvramDir); VIR_FREE(cfg->vncTLSx509certdir); VIR_FREE(cfg->vncListen); VIR_FREE(cfg->vncPassword); VIR_FREE(cfg->vncSASLdir); VIR_FREE(cfg->spiceTLSx509certdir); VIR_FREE(cfg->spiceListen); VIR_FREE(cfg->spicePassword); VIR_FREE(cfg->spiceSASLdir); while (cfg->nhugetlbfs) { cfg->nhugetlbfs--; VIR_FREE(cfg->hugetlbfs[cfg->nhugetlbfs].mnt_dir); } VIR_FREE(cfg->hugetlbfs); VIR_FREE(cfg->bridgeHelperName); VIR_FREE(cfg->saveImageFormat); VIR_FREE(cfg->dumpImageFormat); VIR_FREE(cfg->autoDumpPath); virStringFreeList(cfg->securityDriverNames); VIR_FREE(cfg->lockManagerName); while (cfg->nloader) { VIR_FREE(cfg->loader[cfg->nloader - 1]); VIR_FREE(cfg->nvram[cfg->nloader - 1]); cfg->nloader--; } VIR_FREE(cfg->loader); VIR_FREE(cfg->nvram); }
static int virQEMUDriverConfigNVRAMParse(const char *str, char **loader, char **nvram) { int ret = -1; char **token; if (!(token = virStringSplit(str, ":", 0))) goto cleanup; if (token[0]) { virSkipSpaces((const char **) &token[0]); if (token[1]) virSkipSpaces((const char **) &token[1]); } /* Exactly two tokens are expected */ if (!token[0] || !token[1] || token[2] || STREQ(token[0], "") || STREQ(token[1], "")) { virReportError(VIR_ERR_CONF_SYNTAX, _("Invalid nvram format: '%s'"), str); goto cleanup; } if (VIR_STRDUP(*loader, token[0]) < 0 || VIR_STRDUP(*nvram, token[1]) < 0) goto cleanup; ret = 0; cleanup: virStringFreeList(token); return ret; }
static char * testFilterXML(char *xml) { virBuffer buf = VIR_BUFFER_INITIALIZER; char **xmlLines = NULL; char **xmlLine; char *ret = NULL; if (!(xmlLines = virStringSplit(xml, "\n", 0))) { VIR_FREE(xml); goto cleanup; } VIR_FREE(xml); for (xmlLine = xmlLines; *xmlLine; xmlLine++) { if (regexec(testSnapshotXMLVariableLineRegex, *xmlLine, 0, NULL, 0) == 0) continue; virBufferStrcat(&buf, *xmlLine, "\n", NULL); } if (virBufferCheckError(&buf) < 0) goto cleanup; ret = virBufferContentAndReset(&buf); cleanup: virBufferFreeAndReset(&buf); virStringFreeList(xmlLines); return ret; }
static int virStorageBackendSheepdogRefreshAllVol(virConnectPtr conn ATTRIBUTE_UNUSED, virStoragePoolObjPtr pool) { int ret = -1; char *output = NULL; char **lines = NULL; char **cells = NULL; size_t i; virCommandPtr cmd = virCommandNewArgList(COLLIE, "vdi", "list", "-r", NULL); virStorageBackendSheepdogAddHostArg(cmd, pool); virCommandSetOutputBuffer(cmd, &output); if (virCommandRun(cmd, NULL) < 0) goto cleanup; lines = virStringSplit(output, "\n", 0); if (lines == NULL) goto cleanup; for (i = 0; lines[i]; i++) { const char *line = lines[i]; if (line == NULL) break; cells = virStringSplit(line, " ", 0); if (cells != NULL && virStringListLength(cells) > 2) { if (virStorageBackendSheepdogAddVolume(conn, pool, cells[1]) < 0) goto cleanup; } virStringFreeList(cells); cells = NULL; } ret = 0; cleanup: virCommandFree(cmd); virStringFreeList(lines); virStringFreeList(cells); VIR_FREE(output); return ret; }
static void virQEMUDriverConfigDispose(void *obj) { virQEMUDriverConfigPtr cfg = obj; virStringFreeList(cfg->cgroupDeviceACL); VIR_FREE(cfg->configBaseDir); VIR_FREE(cfg->configDir); VIR_FREE(cfg->autostartDir); VIR_FREE(cfg->logDir); VIR_FREE(cfg->stateDir); VIR_FREE(cfg->libDir); VIR_FREE(cfg->cacheDir); VIR_FREE(cfg->saveDir); VIR_FREE(cfg->snapshotDir); VIR_FREE(cfg->vncTLSx509certdir); VIR_FREE(cfg->vncListen); VIR_FREE(cfg->vncPassword); VIR_FREE(cfg->vncSASLdir); VIR_FREE(cfg->spiceTLSx509certdir); VIR_FREE(cfg->spiceListen); VIR_FREE(cfg->spicePassword); VIR_FREE(cfg->spiceSASLdir); VIR_FREE(cfg->hugetlbfsMount); VIR_FREE(cfg->hugepagePath); VIR_FREE(cfg->bridgeHelperName); VIR_FREE(cfg->saveImageFormat); VIR_FREE(cfg->dumpImageFormat); VIR_FREE(cfg->autoDumpPath); virStringFreeList(cfg->securityDriverNames); VIR_FREE(cfg->lockManagerName); }
static int testQemuMonitorJSONGetTPMModels(const void *data) { const virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data; qemuMonitorTestPtr test = qemuMonitorTestNew(true, xmlopt); int ret = -1; char **tpmmodels = NULL; int ntpmmodels = 0; if (!test) return -1; if (qemuMonitorTestAddItem(test, "query-tpm-models", "{ " " \"return\": [ " " \"passthrough\"" " ]" "}") < 0) goto cleanup; if ((ntpmmodels = qemuMonitorGetTPMModels(qemuMonitorTestGetMonitor(test), &tpmmodels)) < 0) goto cleanup; if (ntpmmodels != 1) { virReportError(VIR_ERR_INTERNAL_ERROR, "ntpmmodels %d is not 1", ntpmmodels); goto cleanup; } #define CHECK(i, wantname) \ do { \ if (STRNEQ(tpmmodels[i], (wantname))) { \ virReportError(VIR_ERR_INTERNAL_ERROR, \ "name %s is not %s", \ tpmmodels[i], (wantname)); \ goto cleanup; \ } \ } while (0) CHECK(0, "passthrough"); #undef CHECK ret = 0; cleanup: qemuMonitorTestFree(test); virStringFreeList(tpmmodels); return ret; }
static int testSplit(const void *args) { const struct testSplitData *data = args; char **got; size_t ntokens; size_t exptokens = 0; char **tmp1; const char **tmp2; int ret = -1; if (!(got = virStringSplitCount(data->string, data->delim, data->max_tokens, &ntokens))) { VIR_DEBUG("Got no tokens at all"); return -1; } tmp1 = got; tmp2 = data->tokens; while (*tmp1 && *tmp2) { if (STRNEQ(*tmp1, *tmp2)) { virFilePrintf(stderr, "Mismatch '%s' vs '%s'\n", *tmp1, *tmp2); goto cleanup; } tmp1++; tmp2++; exptokens++; } if (*tmp1) { virFilePrintf(stderr, "Too many pieces returned\n"); goto cleanup; } if (*tmp2) { virFilePrintf(stderr, "Too few pieces returned\n"); goto cleanup; } if (ntokens != exptokens) { virFilePrintf(stderr, "Returned token count (%zu) doesn't match " "expected count (%zu)", ntokens, exptokens); goto cleanup; } ret = 0; cleanup: virStringFreeList(got); return ret; }
static int virStorageBackendZFSFindVols(virStoragePoolObjPtr pool, virStorageVolDefPtr vol) { virCommandPtr cmd = NULL; char *volumes_list = NULL; char **lines = NULL; size_t i; /** * $ zfs list -Hp -t volume -o name,volsize -r test * test/vol1 5368709120 * test/vol3 1073741824 * test/vol4 1572864000 * $ * * Arguments description: * -t volume -- we want to see only volumes * -o name,volsize -- limit output to name and volume size * -r -- we want to see all the childer of our pool */ cmd = virCommandNewArgList(ZFS, "list", "-Hp", "-t", "volume", "-r", "-o", "name,volsize", pool->def->source.name, NULL); virCommandSetOutputBuffer(cmd, &volumes_list); if (virCommandRun(cmd, NULL) < 0) goto cleanup; if (!(lines = virStringSplit(volumes_list, "\n", 0))) goto cleanup; for (i = 0; lines[i]; i++) { if (STREQ(lines[i], "")) continue; if (virStorageBackendZFSParseVol(pool, vol, lines[i]) < 0) continue; } cleanup: virCommandFree(cmd); virStringFreeList(lines); VIR_FREE(volumes_list); return 0; }
static bool cmdNodeDeviceDestroy(vshControl *ctl, const vshCmd *cmd) { virNodeDevicePtr dev = NULL; bool ret = false; const char *device_value = NULL; char **arr = NULL; int narr; if (vshCommandOptStringReq(ctl, cmd, "device", &device_value) < 0) return false; if (strchr(device_value, ',')) { narr = vshStringToArray(device_value, &arr); if (narr != 2) { vshError(ctl, _("Malformed device value '%s'"), device_value); goto cleanup; } if (!virValidateWWN(arr[0]) || !virValidateWWN(arr[1])) goto cleanup; dev = virNodeDeviceLookupSCSIHostByWWN(ctl->conn, arr[0], arr[1], 0); } else { dev = virNodeDeviceLookupByName(ctl->conn, device_value); } if (!dev) { vshError(ctl, "%s '%s'", _("Could not find matching device"), device_value); goto cleanup; } if (virNodeDeviceDestroy(dev) == 0) { vshPrint(ctl, _("Destroyed node device '%s'\n"), device_value); } else { vshError(ctl, _("Failed to destroy node device '%s'"), device_value); goto cleanup; } ret = true; cleanup: virStringFreeList(arr); if (dev) virNodeDeviceFree(dev); return ret; }
static void lxcSetCapDrop(virDomainDefPtr def, virConfPtr properties) { virConfValuePtr value; char **toDrop = NULL; const char *capString; size_t i; if ((value = virConfGetValue(properties, "lxc.cap.drop")) && value->str) toDrop = virStringSplit(value->str, " ", 0); for (i = 0; i < VIR_DOMAIN_CAPS_FEATURE_LAST; i++) { capString = virDomainCapsFeatureTypeToString(i); if (toDrop != NULL && virStringArrayHasString(toDrop, capString)) def->caps_features[i] = VIR_TRISTATE_SWITCH_OFF; } def->features[VIR_DOMAIN_FEATURE_CAPABILITIES] = VIR_DOMAIN_CAPABILITIES_POLICY_ALLOW; virStringFreeList(toDrop); }
static int ATTRIBUTE_UNUSED virQEMUDriverConfigLoaderNVRAMParse(virQEMUDriverConfigPtr cfg, const char *list) { int ret = -1; char **token; size_t i, j; if (!(token = virStringSplit(list, ":", 0))) goto cleanup; for (i = 0; token[i]; i += 2) { if (!token[i] || !token[i + 1] || STREQ(token[i], "") || STREQ(token[i + 1], "")) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Invalid --with-loader-nvram list: %s"), list); goto cleanup; } } if (i) { if (VIR_ALLOC_N(cfg->loader, i / 2) < 0 || VIR_ALLOC_N(cfg->nvram, i / 2) < 0) goto cleanup; cfg->nloader = i / 2; for (j = 0; j < i / 2; j++) { if (VIR_STRDUP(cfg->loader[j], token[2 * j]) < 0 || VIR_STRDUP(cfg->nvram[j], token[2 * j + 1]) < 0) goto cleanup; } } ret = 0; cleanup: virStringFreeList(token); return ret; }
static int testSplit(const void *args) { const struct testSplitData *data = args; char **got; char **tmp1; const char **tmp2; int ret = -1; if (!(got = virStringSplit(data->string, data->delim, data->max_tokens))) { VIR_DEBUG("Got no tokens at all"); return -1; } tmp1 = got; tmp2 = data->tokens; while (*tmp1 && *tmp2) { if (STRNEQ(*tmp1, *tmp2)) { fprintf(stderr, "Mismatch '%s' vs '%s'\n", *tmp1, *tmp2); goto cleanup; } tmp1++; tmp2++; } if (*tmp1) { fprintf(stderr, "Too many pieces returned\n"); goto cleanup; } if (*tmp2) { fprintf(stderr, "Too few pieces returned\n"); goto cleanup; } ret = 0; cleanup: virStringFreeList(got); return ret; }
static int lxcBlkioDeviceWalkCallback(const char *name, virConfValuePtr value, void *data) { char **parts = NULL; virBlkioDevicePtr device = NULL; virDomainDefPtr def = data; size_t i = 0; char *path = NULL; int ret = -1; if (!STRPREFIX(name, "lxc.cgroup.blkio.") || STREQ(name, "lxc.cgroup.blkio.weight")|| !value->str) return 0; if (!(parts = lxcStringSplit(value->str))) return -1; if (!parts[0] || !parts[1]) { virReportError(VIR_ERR_INTERNAL_ERROR, _("invalid %s value: '%s'"), name, value->str); goto cleanup; } if (virAsprintf(&path, "/dev/block/%s", parts[0]) < 0) goto cleanup; /* Do we already have a device definition for this path? * Get that device or create a new one */ for (i = 0; !device && i < def->blkio.ndevices; i++) { if (STREQ(def->blkio.devices[i].path, path)) device = &def->blkio.devices[i]; } if (!device) { if (VIR_EXPAND_N(def->blkio.devices, def->blkio.ndevices, 1) < 0) goto cleanup; device = &def->blkio.devices[def->blkio.ndevices - 1]; device->path = path; path = NULL; } /* Set the value */ if (STREQ(name, "lxc.cgroup.blkio.device_weight")) { if (virStrToLong_ui(parts[1], NULL, 10, &device->weight) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("failed to parse device weight: '%s'"), parts[1]); goto cleanup; } } else if (STREQ(name, "lxc.cgroup.blkio.throttle.read_bps_device")) { if (virStrToLong_ull(parts[1], NULL, 10, &device->rbps) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("failed to parse read_bps_device: '%s'"), parts[1]); goto cleanup; } } else if (STREQ(name, "lxc.cgroup.blkio.throttle.write_bps_device")) { if (virStrToLong_ull(parts[1], NULL, 10, &device->wbps) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("failed to parse write_bps_device: '%s'"), parts[1]); goto cleanup; } } else if (STREQ(name, "lxc.cgroup.blkio.throttle.read_iops_device")) { if (virStrToLong_ui(parts[1], NULL, 10, &device->riops) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("failed to parse read_iops_device: '%s'"), parts[1]); goto cleanup; } } else if (STREQ(name, "lxc.cgroup.blkio.throttle.write_iops_device")) { if (virStrToLong_ui(parts[1], NULL, 10, &device->wiops) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("failed to parse write_iops_device: '%s'"), parts[1]); goto cleanup; } } else { VIR_WARN("Unhandled blkio tune config: %s", name); } ret = 0; cleanup: virStringFreeList(parts); VIR_FREE(path); return ret; }
static int lxcNetworkWalkCallback(const char *name, virConfValuePtr value, void *data) { lxcNetworkParseData *parseData = data; int status; if (STREQ(name, "lxc.network.type")) { /* Store the previous NIC */ status = lxcAddNetworkDefinition(parseData); if (status < 0) return -1; else if (status > 0) parseData->networks++; else if (parseData->type != NULL && STREQ(parseData->type, "none")) parseData->privnet = false; /* Start a new network interface config */ parseData->type = NULL; parseData->link = NULL; parseData->mac = NULL; parseData->flag = NULL; parseData->macvlanmode = NULL; parseData->vlanid = NULL; parseData->name = NULL; parseData->ips = NULL; parseData->nips = 0; /* Keep the new value */ parseData->type = value->str; } else if (STREQ(name, "lxc.network.link")) parseData->link = value->str; else if (STREQ(name, "lxc.network.hwaddr")) parseData->mac = value->str; else if (STREQ(name, "lxc.network.flags")) parseData->flag = value->str; else if (STREQ(name, "lxc.network.macvlan.mode")) parseData->macvlanmode = value->str; else if (STREQ(name, "lxc.network.vlan.id")) parseData->vlanid = value->str; else if (STREQ(name, "lxc.network.name")) parseData->name = value->str; else if (STREQ(name, "lxc.network.ipv4") || STREQ(name, "lxc.network.ipv6")) { int family = AF_INET; char **ipparts = NULL; virDomainNetIpDefPtr ip = NULL; if (VIR_ALLOC(ip) < 0) return -1; if (STREQ(name, "lxc.network.ipv6")) family = AF_INET6; ipparts = virStringSplit(value->str, "/", 2); if (virStringListLength((const char * const *)ipparts) != 2 || virSocketAddrParse(&ip->address, ipparts[0], family) < 0 || virStrToLong_ui(ipparts[1], NULL, 10, &ip->prefix) < 0) { virReportError(VIR_ERR_INVALID_ARG, _("Invalid CIDR address: '%s'"), value->str); virStringFreeList(ipparts); VIR_FREE(ip); return -1; } virStringFreeList(ipparts); if (VIR_APPEND_ELEMENT(parseData->ips, parseData->nips, ip) < 0) { VIR_FREE(ip); return -1; } } else if (STREQ(name, "lxc.network.ipv4.gateway")) { parseData->gateway_ipv4 = value->str; } else if (STREQ(name, "lxc.network.ipv6.gateway")) { parseData->gateway_ipv6 = value->str; } else if (STRPREFIX(name, "lxc.network")) { VIR_WARN("Unhandled network property: %s = %s", name, value->str); } return 0; }
static int lxcAddFstabLine(virDomainDefPtr def, lxcFstabPtr fstab) { const char *src = NULL; char *dst = NULL; char **options = virStringSplit(fstab->options, ",", 0); bool readonly; int type = VIR_DOMAIN_FS_TYPE_MOUNT; unsigned long long usage = 0; int ret = -1; if (!options) return -1; if (fstab->dst[0] != '/') { if (virAsprintf(&dst, "/%s", fstab->dst) < 0) goto cleanup; } else { if (VIR_STRDUP(dst, fstab->dst) < 0) goto cleanup; } /* Check that we don't add basic mounts */ if (lxcIsBasicMountLocation(dst)) { ret = 0; goto cleanup; } if (STREQ(fstab->type, "tmpfs")) { char *sizeStr = NULL; size_t i; type = VIR_DOMAIN_FS_TYPE_RAM; for (i = 0; options[i]; i++) { if ((sizeStr = STRSKIP(options[i], "size="))) { if (lxcConvertSize(sizeStr, &usage) < 0) goto cleanup; break; } } if (!sizeStr) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("missing tmpfs size, set the size option")); goto cleanup; } } else { src = fstab->src; } /* Is it a block device that needs special favor? */ if (STRPREFIX(fstab->src, "/dev/")) type = VIR_DOMAIN_FS_TYPE_BLOCK; /* Do we have ro in options? */ readonly = virStringArrayHasString(options, "ro"); if (lxcAddFSDef(def, type, src, dst, readonly, usage) < 0) goto cleanup; ret = 1; cleanup: VIR_FREE(dst); virStringFreeList(options); return ret; }
/* * Try to extract loader and bhyve argv lists from a command line string. */ static int bhyveCommandLineToArgv(const char *nativeConfig, int *loader_argc, char ***loader_argv, int *bhyve_argc, char ***bhyve_argv) { const char *curr = NULL; char *nativeConfig_unescaped = NULL; const char *start; const char *next; char *line; char **lines = NULL; size_t i; size_t line_count = 0; size_t lines_alloc = 0; char **_bhyve_argv = NULL; char **_loader_argv = NULL; nativeConfig_unescaped = bhyveParseCommandLineUnescape(nativeConfig); if (nativeConfig_unescaped == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Failed to unescape command line string")); goto error; } curr = nativeConfig_unescaped; /* Iterate over string, splitting on sequences of '\n' */ while (curr && *curr != '\0') { start = curr; next = strchr(curr, '\n'); if (VIR_STRNDUP(line, curr, next ? next - curr : -1) < 0) goto error; if (VIR_RESIZE_N(lines, lines_alloc, line_count, 2) < 0) { VIR_FREE(line); goto error; } if (*line) lines[line_count++] = line; lines[line_count] = NULL; while (next && (*next == '\n' || *next == '\r' || STRPREFIX(next, "\r\n"))) next++; curr = next; } for (i = 0; i < line_count; i++) { curr = lines[i]; size_t j; char **arglist = NULL; size_t args_count = 0; size_t args_alloc = 0; /* iterate over each line, splitting on sequences of ' '. This code is * adapted from qemu/qemu_parse_command.c. */ while (curr && *curr != '\0') { char *arg; start = curr; if (*start == '\'') { if (start == curr) curr++; next = strchr(start + 1, '\''); } else if (*start == '"') { if (start == curr) curr++; next = strchr(start + 1, '"'); } else { next = strchr(start, ' '); } if (VIR_STRNDUP(arg, curr, next ? next - curr : -1) < 0) goto error; if (next && (*next == '\'' || *next == '"')) next++; if (VIR_RESIZE_N(arglist, args_alloc, args_count, 2) < 0) { VIR_FREE(arg); goto error; } arglist[args_count++] = arg; arglist[args_count] = NULL; while (next && c_isspace(*next)) next++; curr = next; } VIR_FREE(nativeConfig_unescaped); /* To prevent a memory leak here, only set the argument lists when * the first matching command is found. This shouldn't really be a * problem, since usually no multiple loaders or bhyverun commands * are specified (this wouldn't really be valid anyways). * Otherwise, later argument lists may be assigned to _argv without * freeing the earlier ones. */ if (!_bhyve_argv && STREQ(arglist[0], "/usr/sbin/bhyve")) { if ((VIR_REALLOC_N(_bhyve_argv, args_count + 1) < 0) || (!bhyve_argc)) goto error; for (j = 0; j < args_count; j++) _bhyve_argv[j] = arglist[j]; _bhyve_argv[j] = NULL; *bhyve_argc = args_count-1; VIR_FREE(arglist); } else if (!_loader_argv) { if ((VIR_REALLOC_N(_loader_argv, args_count + 1) < 0) || (!loader_argc)) goto error; for (j = 0; j < args_count; j++) _loader_argv[j] = arglist[j]; _loader_argv[j] = NULL; *loader_argc = args_count-1; VIR_FREE(arglist); } else { /* To prevent a use-after-free here, only free the argument list * when it is definitely not going to be used */ virStringFreeList(arglist); } } *loader_argv = _loader_argv; if (!(*bhyve_argv = _bhyve_argv)) goto error; virStringFreeList(lines); return 0; error: VIR_FREE(_loader_argv); VIR_FREE(_bhyve_argv); virStringFreeList(lines); return -1; }
static int virStorageBackendZFSParseVol(virStoragePoolObjPtr pool, virStorageVolDefPtr vol, const char *volume_string) { int ret = -1; char **tokens; size_t count; char **name_tokens = NULL; char *vol_name; bool is_new_vol = false; virStorageVolDefPtr volume = NULL; if (!(tokens = virStringSplitCount(volume_string, "\t", 0, &count))) return -1; if (count != 2) goto cleanup; if (!(name_tokens = virStringSplit(tokens[0], "/", 2))) goto cleanup; vol_name = name_tokens[1]; if (vol == NULL) volume = virStorageVolDefFindByName(pool, vol_name); else volume = vol; if (volume == NULL) { if (VIR_ALLOC(volume) < 0) goto cleanup; is_new_vol = true; volume->type = VIR_STORAGE_VOL_BLOCK; if (VIR_STRDUP(volume->name, vol_name) < 0) goto cleanup; } if (!volume->key && VIR_STRDUP(volume->key, tokens[0]) < 0) goto cleanup; if (volume->target.path == NULL) { if (virAsprintf(&volume->target.path, "%s/%s", pool->def->target.path, volume->name) < 0) goto cleanup; } if (virStrToLong_ull(tokens[1], NULL, 10, &volume->target.capacity) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("malformed volsize reported")); goto cleanup; } if (is_new_vol && VIR_APPEND_ELEMENT(pool->volumes.objs, pool->volumes.count, volume) < 0) goto cleanup; ret = 0; cleanup: virStringFreeList(tokens); virStringFreeList(name_tokens); if (is_new_vol) virStorageVolDefFree(volume); return ret; }
static int virStorageBackendZFSRefreshPool(virConnectPtr conn ATTRIBUTE_UNUSED, virStoragePoolObjPtr pool ATTRIBUTE_UNUSED) { virCommandPtr cmd = NULL; char *zpool_props = NULL; char **lines = NULL; char **tokens = NULL; size_t i; /** * $ zpool get -Hp health,size,free,allocated test * test health ONLINE - * test size 199715979264 - * test free 198899976704 - * test allocated 816002560 - * $ * * Here we just provide a list of properties we want to see */ cmd = virCommandNewArgList(ZPOOL, "get", "-Hp", "health,size,free,allocated", pool->def->source.name, NULL); virCommandSetOutputBuffer(cmd, &zpool_props); if (virCommandRun(cmd, NULL) < 0) goto cleanup; if (!(lines = virStringSplit(zpool_props, "\n", 0))) goto cleanup; for (i = 0; lines[i]; i++) { size_t count; char *prop_name; if (STREQ(lines[i], "")) continue; virStringFreeList(tokens); if (!(tokens = virStringSplitCount(lines[i], "\t", 0, &count))) goto cleanup; if (count != 4) continue; prop_name = tokens[1]; if (STREQ(prop_name, "free") || STREQ(prop_name, "size") || STREQ(prop_name, "allocated")) { unsigned long long value; if (virStrToLong_ull(tokens[2], NULL, 10, &value) < 0) goto cleanup; if (STREQ(prop_name, "free")) pool->def->available = value; else if (STREQ(prop_name, "size")) pool->def->capacity = value; else if (STREQ(prop_name, "allocated")) pool->def->allocation = value; } } /* Obtain a list of volumes */ if (virStorageBackendZFSFindVols(pool, NULL) < 0) goto cleanup; cleanup: virCommandFree(cmd); virStringFreeList(lines); virStringFreeList(tokens); VIR_FREE(zpool_props); return 0; }
static int testQemuMonitorJSONGetCommandLineOptionParameters(const void *data) { const virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data; qemuMonitorTestPtr test = qemuMonitorTestNew(true, xmlopt); int ret = -1; char **params = NULL; int nparams = 0; if (!test) return -1; if (qemuMonitorTestAddItem(test, "query-command-line-options", "{ " " \"return\": [ " " {\"parameters\": [], \"option\": \"acpi\" }," " {\"parameters\": [" " {\"name\": \"romfile\", " " \"type\": \"string\"}, " " {\"name\": \"bootindex\", " " \"type\": \"number\"}], " " \"option\": \"option-rom\"}" " ]" "}") < 0) goto cleanup; /* present with params */ if ((nparams = qemuMonitorGetCommandLineOptionParameters(qemuMonitorTestGetMonitor(test), "option-rom", ¶ms)) < 0) goto cleanup; if (nparams != 2) { virReportError(VIR_ERR_INTERNAL_ERROR, "nparams was %d, expected 2", nparams); goto cleanup; } #define CHECK(i, wantname) \ do { \ if (STRNEQ(params[i], (wantname))) { \ virReportError(VIR_ERR_INTERNAL_ERROR, \ "name was %s, expected %s", \ params[i], (wantname)); \ goto cleanup; \ } \ } while (0) CHECK(0, "romfile"); CHECK(1, "bootindex"); #undef CHECK virStringFreeList(params); params = NULL; /* present but empty */ if ((nparams = qemuMonitorGetCommandLineOptionParameters(qemuMonitorTestGetMonitor(test), "acpi", ¶ms)) < 0) goto cleanup; if (nparams != 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "nparams was %d, expected 0", nparams); goto cleanup; } if (params && params[0]) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", "unexpected array contents"); goto cleanup; } virStringFreeList(params); params = NULL; /* no such option */ if ((nparams = qemuMonitorGetCommandLineOptionParameters(qemuMonitorTestGetMonitor(test), "foobar", ¶ms)) < 0) goto cleanup; if (nparams != 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "nparams was %d, expected 0", nparams); goto cleanup; } if (params && params[0]) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", "unexpected array contents"); goto cleanup; } ret = 0; cleanup: qemuMonitorTestFree(test); virStringFreeList(params); return ret; }
/** * virStringSearch: * @str: string to search * @regexp: POSIX Extended regular expression pattern used for matching * @max_matches: maximum number of substrings to return * @result: pointer to an array to be filled with NULL terminated list of matches * * Performs a POSIX extended regex search against a string and return all matching substrings. * The @result value should be freed with virStringFreeList() when no longer * required. * * @code * char *source = "6853a496-1c10-472e-867a-8244937bd6f0 * 773ab075-4cd7-4fc2-8b6e-21c84e9cb391 * bbb3c75c-d60f-43b0-b802-fd56b84a4222 * 60c04aa1-0375-4654-8d9f-e149d9885273 * 4548d465-9891-4c34-a184-3b1c34a26aa8"; * char **matches = NULL; * virStringSearch(source, * "([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})", * 3, * &matches); * * // matches[0] == "6853a496-1c10-472e-867a-8244937bd6f0"; * // matches[1] == "773ab075-4cd7-4fc2-8b6e-21c84e9cb391"; * // matches[2] == "bbb3c75c-d60f-43b0-b802-fd56b84a4222" * // matches[3] == NULL; * * virStringFreeList(matches); * @endcode * * Returns: -1 on error, or number of matches */ ssize_t virStringSearch(const char *str, const char *regexp, size_t max_matches, char ***matches) { regex_t re; regmatch_t rem; size_t nmatches = 0; ssize_t ret = -1; int rv = -1; *matches = NULL; VIR_DEBUG("search '%s' for '%s'", str, regexp); if ((rv = regcomp(&re, regexp, REG_EXTENDED)) != 0) { char error[100]; regerror(rv, &re, error, sizeof(error)); virReportError(VIR_ERR_INTERNAL_ERROR, _("Error while compiling regular expression '%s': %s"), regexp, error); return -1; } if (re.re_nsub != 1) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Regular expression '%s' must have exactly 1 match group, not %zu"), regexp, re.re_nsub); goto cleanup; } /* '*matches' must always be NULL terminated in every iteration * of the loop, so start by allocating 1 element */ if (VIR_EXPAND_N(*matches, nmatches, 1) < 0) goto cleanup; while ((nmatches - 1) < max_matches) { char *match; if (regexec(&re, str, 1, &rem, 0) != 0) break; if (VIR_EXPAND_N(*matches, nmatches, 1) < 0) goto cleanup; if (VIR_STRNDUP(match, str + rem.rm_so, rem.rm_eo - rem.rm_so) < 0) goto cleanup; VIR_DEBUG("Got '%s'", match); (*matches)[nmatches-2] = match; str = str + rem.rm_eo; } ret = nmatches - 1; /* don't count the trailing null */ cleanup: regfree(&re); if (ret < 0) { virStringFreeList(*matches); *matches = NULL; } return ret; }
int main(int argc, char **argv) { virConfPtr conf = NULL; const char *login_shell_path = conf_file; pid_t cpid = -1; int ret = EXIT_CANCELED; int status; uid_t uid = getuid(); gid_t gid = getgid(); char *name = NULL; char **shargv = NULL; virSecurityModelPtr secmodel = NULL; virSecurityLabelPtr seclabel = NULL; virDomainPtr dom = NULL; virConnectPtr conn = NULL; char *homedir = NULL; int arg; int longindex = -1; int ngroups; gid_t *groups = NULL; ssize_t nfdlist = 0; int *fdlist = NULL; int openmax; size_t i; struct option opt[] = { {"help", no_argument, NULL, 'h'}, {"version", optional_argument, NULL, 'V'}, {NULL, 0, NULL, 0} }; if (virInitialize() < 0) { fprintf(stderr, _("Failed to initialize libvirt error handling")); return EXIT_CANCELED; } setenv("PATH", "/bin:/usr/bin", 1); virSetErrorFunc(NULL, NULL); virSetErrorLogPriorityFunc(NULL); progname = argv[0]; if (!setlocale(LC_ALL, "")) { perror("setlocale"); /* failure to setup locale is not fatal */ } if (!bindtextdomain(PACKAGE, LOCALEDIR)) { perror("bindtextdomain"); return ret; } if (!textdomain(PACKAGE)) { perror("textdomain"); return ret; } while ((arg = getopt_long(argc, argv, "hV", opt, &longindex)) != -1) { switch (arg) { case 'h': usage(); exit(EXIT_SUCCESS); case 'V': show_version(); exit(EXIT_SUCCESS); case '?': default: usage(); exit(EXIT_CANCELED); } } if (argc > optind) { virReportSystemError(EINVAL, _("%s takes no options"), progname); goto cleanup; } if (uid == 0) { virReportSystemError(EPERM, _("%s must be run by non root users"), progname); goto cleanup; } name = virGetUserName(uid); if (!name) goto cleanup; homedir = virGetUserDirectoryByUID(uid); if (!homedir) goto cleanup; if (!(conf = virConfReadFile(login_shell_path, 0))) goto cleanup; if ((ngroups = virGetGroupList(uid, gid, &groups)) < 0) goto cleanup; if (virLoginShellAllowedUser(conf, name, groups) < 0) goto cleanup; if (!(shargv = virLoginShellGetShellArgv(conf))) goto cleanup; conn = virConnectOpen("lxc:///"); if (!conn) goto cleanup; dom = virDomainLookupByName(conn, name); if (!dom) goto cleanup; if (!virDomainIsActive(dom) && virDomainCreate(dom)) { virErrorPtr last_error; last_error = virGetLastError(); if (last_error->code != VIR_ERR_OPERATION_INVALID) { virReportSystemError(last_error->code, _("Can't create %s container: %s"), name, last_error->message); goto cleanup; } } openmax = sysconf(_SC_OPEN_MAX); if (openmax < 0) { virReportSystemError(errno, "%s", _("sysconf(_SC_OPEN_MAX) failed")); goto cleanup; } if ((nfdlist = virDomainLxcOpenNamespace(dom, &fdlist, 0)) < 0) goto cleanup; if (VIR_ALLOC(secmodel) < 0) goto cleanup; if (VIR_ALLOC(seclabel) < 0) goto cleanup; if (virNodeGetSecurityModel(conn, secmodel) < 0) goto cleanup; if (virDomainGetSecurityLabel(dom, seclabel) < 0) goto cleanup; if (virSetUIDGID(0, 0, NULL, 0) < 0) goto cleanup; if (virDomainLxcEnterSecurityLabel(secmodel, seclabel, NULL, 0) < 0) goto cleanup; if (nfdlist > 0 && virDomainLxcEnterNamespace(dom, nfdlist, fdlist, NULL, NULL, 0) < 0) goto cleanup; if (virSetUIDGID(uid, gid, groups, ngroups) < 0) goto cleanup; if (chdir(homedir) < 0) { virReportSystemError(errno, _("Unable to chdir(%s)"), homedir); goto cleanup; } /* A fork is required to create new process in correct pid namespace. */ if ((cpid = virFork()) < 0) goto cleanup; if (cpid == 0) { int tmpfd; for (i = 3; i < openmax; i++) { tmpfd = i; VIR_MASS_CLOSE(tmpfd); } if (execv(shargv[0], (char *const*) shargv) < 0) { virReportSystemError(errno, _("Unable to exec shell %s"), shargv[0]); virDispatchError(NULL); return errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE; } } /* At this point, the parent is now waiting for the child to exit, * but as that may take a long time, we release resources now. */ cleanup: if (nfdlist > 0) for (i = 0; i < nfdlist; i++) VIR_FORCE_CLOSE(fdlist[i]); VIR_FREE(fdlist); virConfFree(conf); if (dom) virDomainFree(dom); if (conn) virConnectClose(conn); virStringFreeList(shargv); VIR_FREE(name); VIR_FREE(homedir); VIR_FREE(seclabel); VIR_FREE(secmodel); VIR_FREE(groups); if (virProcessWait(cpid, &status, true) == 0) virProcessExitWithStatus(status); if (virGetLastError()) virDispatchError(NULL); return ret; }