static int testInfoSet(struct testInfo *info, const char *name, int when) { if (!(info->qemuCaps = virQEMUCapsNew())) goto error; virQEMUCapsSetList(info->qemuCaps, QEMU_CAPS_DEVICE, QEMU_CAPS_LAST); if (qemuTestCapsCacheInsert(driver.qemuCapsCache, name, info->qemuCaps) < 0) goto error; if (virAsprintf(&info->inName, "%s/qemuxml2argvdata/qemuxml2argv-%s.xml", abs_srcdir, name) < 0) goto error; if (when & WHEN_INACTIVE) { if (virAsprintf(&info->outInactiveName, "%s/qemuxml2xmloutdata/qemuxml2xmlout-%s-inactive.xml", abs_srcdir, name) < 0) goto error; if (!virFileExists(info->outInactiveName)) { VIR_FREE(info->outInactiveName); if (virAsprintf(&info->outInactiveName, "%s/qemuxml2xmloutdata/qemuxml2xmlout-%s.xml", abs_srcdir, name) < 0) goto error; } } if (when & WHEN_ACTIVE) { if (virAsprintf(&info->outActiveName, "%s/qemuxml2xmloutdata/qemuxml2xmlout-%s-active.xml", abs_srcdir, name) < 0) goto error; if (!virFileExists(info->outActiveName)) { VIR_FREE(info->outActiveName); if (virAsprintf(&info->outActiveName, "%s/qemuxml2xmloutdata/qemuxml2xmlout-%s.xml", abs_srcdir, name) < 0) goto error; } } return 0; error: testInfoFree(info); return -1; }
static int virNodeParseNode(const char *sysfs_dir) { char *file = NULL; char *possible = NULL; char *tmp; int ret = -1; if (virAsprintf(&file, "%s/node/possible", sysfs_dir) < 0) { virReportOOMError(); goto cleanup; } /* Assume that a missing node/possible file implies no NUMA * support, and hence all cpus belong to the same node. */ if (!virFileExists(file)) { ret = 1; goto cleanup; } if (virFileReadAll(file, 1024, &possible) < 0) goto cleanup; if (virStrToLong_i(possible, &tmp, 10, &ret) < 0 || (*tmp == '-' && virStrToLong_i(tmp+1, &tmp, 10, &ret) < 0) || *tmp != '\n') { nodeReportError(VIR_ERR_INTERNAL_ERROR, _("failed to parse possible nodes '%s'"), possible); goto cleanup; } ret++; cleanup: VIR_FREE(file); VIR_FREE(possible); return ret; }
static unsigned long virHostCPUCountThreadSiblings(const char *dir, unsigned int cpu) { unsigned long ret = 0; char *path; char *str = NULL; size_t i; if (virAsprintf(&path, "%s/cpu%u/topology/thread_siblings", dir, cpu) < 0) return 0; if (!virFileExists(path)) { /* If file doesn't exist, then pretend our only * sibling is ourself */ ret = 1; goto cleanup; } if (virFileReadAll(path, SYSFS_THREAD_SIBLINGS_LIST_LENGTH_MAX, &str) < 0) goto cleanup; for (i = 0; str[i] != '\0'; i++) { if (c_isxdigit(str[i])) ret += count_one_bits(virHexToBin(str[i])); } cleanup: VIR_FREE(str); VIR_FREE(path); return ret; }
int virConfLoadConfig(virConfPtr *conf, const char *name) { char *path = NULL; int ret = -1; *conf = NULL; if (!(path = virConfLoadConfigPath(name))) goto cleanup; if (!virFileExists(path)) { ret = 0; goto cleanup; } VIR_DEBUG("Loading config file '%s'", path); if (!(*conf = virConfReadFile(path, 0))) goto cleanup; ret = 0; cleanup: VIR_FREE(path); return ret; }
/* * Poor man's mocked NUMA guesser. We basically check if * /sys/devices/system/node (where /sys/devices/system can already be mocked or * changed in the tests) exists and cache the result. */ bool virNumaIsAvailable(void) { if (numa_avail < 0) { char *sysfs_node_path = NULL; if (virAsprintfQuiet(&sysfs_node_path, "%s/node", SYSFS_SYSTEM_PATH) < 0) return false; numa_avail = virFileExists(sysfs_node_path); VIR_FREE(sysfs_node_path); } /* * Quite a few more things need to be mocked if NUMA is not available and * you are using this file. Do not remove the abort() call below unless you * make sure all under virCapabilitiesInitNUMAFake() is mocked (and whatever * might have changed since this comment was added. You are welcome. */ if (!numa_avail) abort(); return numa_avail; }
int libxlDomainGetEmulatorType(const virDomainDef *def) { int ret = LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN; virCommandPtr cmd = NULL; char *output = NULL; if (def->os.type == VIR_DOMAIN_OSTYPE_HVM) { if (def->emulator) { if (!virFileExists(def->emulator)) goto cleanup; cmd = virCommandNew(def->emulator); virCommandAddArgList(cmd, "-help", NULL); virCommandSetOutputBuffer(cmd, &output); if (virCommandRun(cmd, NULL) < 0) goto cleanup; if (strstr(output, LIBXL_QEMU_DM_STR)) ret = LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN_TRADITIONAL; } } cleanup: VIR_FREE(output); virCommandFree(cmd); return ret; }
int vmwareMoveFile(char *srcFile, char *dstFile) { const char *cmdmv[] = { "mv", PROGRAM_SENTINAL, PROGRAM_SENTINAL, NULL }; if (!virFileExists(srcFile)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("file %s does not exist"), srcFile); return -1; } if (STREQ(srcFile, dstFile)) return 0; vmwareSetSentinal(cmdmv, srcFile); vmwareSetSentinal(cmdmv, dstFile); if (virRun(cmdmv, NULL) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("failed to move file to %s "), dstFile); return -1; } return 0; }
/** * virHookCheck: * @driver: the driver name "daemon", "qemu", "lxc"... * * Check is there is an installed hook for the given driver, if this * is the case register it. Then subsequent calls to virHookCall * will call the hook if found. * * Returns 1 if found, 0 if not found, and -1 in case of error */ static int virHookCheck(int no, const char *driver) { char *path; int ret; if (driver == NULL) { virHookReportError(VIR_ERR_INTERNAL_ERROR, _("Invalid hook name for #%d"), no); return -1; } ret = virBuildPath(&path, LIBVIRT_HOOK_DIR, driver); if ((ret < 0) || (path == NULL)) { virHookReportError(VIR_ERR_INTERNAL_ERROR, _("Failed to build path for %s hook"), driver); return -1; } if (!virFileExists(path)) { ret = 0; VIR_DEBUG("No hook script %s", path); } else if (!virFileIsExecutable(path)) { ret = 0; VIR_WARN("Non-executable hook script %s", path); } else { ret = 1; VIR_DEBUG("Found hook script %s", path); } VIR_FREE(path); return ret; }
static int parallelsFindVmVolumes(virStoragePoolObjPtr pool, virDomainObjPtr dom) { parallelsDomObjPtr pdom = dom->privateData; DIR *dir; struct dirent *ent; char *diskPath = NULL, *diskDescPath = NULL; struct stat sb; int ret = -1; int direrr; if (!(dir = opendir(pdom->home))) { virReportSystemError(errno, _("cannot open path '%s'"), pdom->home); goto cleanup; } while ((direrr = virDirRead(dir, &ent, pdom->home)) > 0) { VIR_FREE(diskPath); VIR_FREE(diskDescPath); if (!(diskPath = virFileBuildPath(pdom->home, ent->d_name, NULL))) goto cleanup; if (lstat(diskPath, &sb) < 0) { virReportSystemError(errno, _("cannot stat path '%s'"), ent->d_name); goto cleanup; } if (!S_ISDIR(sb.st_mode)) continue; if (!(diskDescPath = virFileBuildPath(diskPath, "DiskDescriptor", ".xml"))) goto cleanup; if (!virFileExists(diskDescPath)) continue; /* here we know, that ent->d_name is a disk image directory */ if (parallelsAddDiskVolume(pool, dom, ent->d_name, diskPath, diskDescPath)) goto cleanup; } if (direrr < 0) goto cleanup; ret = 0; cleanup: VIR_FREE(diskPath); VIR_FREE(diskDescPath); closedir(dir); return ret; }
static int virStorageBackendMpathCheckPool(virConnectPtr conn ATTRIBUTE_UNUSED, virStoragePoolObjPtr pool ATTRIBUTE_UNUSED, bool *isActive) { *isActive = virFileExists("/dev/mpath"); return 0; }
int qemuTeardownImageCgroup(virDomainObjPtr vm, virStorageSourcePtr src) { qemuDomainObjPrivatePtr priv = vm->privateData; int perms = VIR_CGROUP_DEVICE_RWM; size_t i; int ret; if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) return 0; if (!src->path || !virStorageSourceIsLocalStorage(src)) { VIR_DEBUG("Not updating cgroups for disk path '%s', type: %s", NULLSTR(src->path), virStorageTypeToString(src->type)); return 0; } if (virFileExists(DEVICE_MAPPER_CONTROL_PATH)) { for (i = 0; i < vm->def->ndisks; i++) { virStorageSourcePtr diskSrc = vm->def->disks[i]->src; if (src == diskSrc) continue; if (virStoragePRDefIsManaged(diskSrc->pr)) break; } if (i == vm->def->ndisks) { VIR_DEBUG("Disabling device mapper control"); ret = virCgroupDenyDevicePath(priv->cgroup, DEVICE_MAPPER_CONTROL_PATH, perms, true); virDomainAuditCgroupPath(vm, priv->cgroup, "deny", DEVICE_MAPPER_CONTROL_PATH, virCgroupGetDevicePermsString(perms), ret); if (ret < 0) return ret; } } VIR_DEBUG("Deny path %s", src->path); ret = virCgroupDenyDevicePath(priv->cgroup, src->path, perms, true); virDomainAuditCgroupPath(vm, priv->cgroup, "deny", src->path, virCgroupGetDevicePermsString(perms), ret); /* If you're looking for a counter part to * qemuSetupImagePathCgroup you're at the right place. * However, we can't just blindly deny all the device mapper * targets of src->path because they might still be used by * another disk in domain. Just like we are not removing * disks from namespace. */ return ret; }
static int testCompareXMLToArgvFiles(const char *xml, const char *cmdline, const char *ldcmdline, const char *dmcmdline) { char *actualargv = NULL, *actualld = NULL, *actualdm = NULL; virDomainDefPtr vmdef = NULL; virCommandPtr cmd = NULL, ldcmd = NULL; virConnectPtr conn; int ret = -1; if (!(conn = virGetConnect())) goto out; if (!(vmdef = virDomainDefParseFile(xml, driver.caps, driver.xmlopt, VIR_DOMAIN_DEF_PARSE_INACTIVE))) goto out; conn->privateData = &driver; if (!(cmd = virBhyveProcessBuildBhyveCmd(conn, vmdef, false))) goto out; if (!(actualargv = virCommandToString(cmd))) goto out; if (!(ldcmd = virBhyveProcessBuildLoadCmd(conn, vmdef, "<device.map>", &actualdm))) goto out; if (actualdm != NULL) virTrimSpaces(actualdm, NULL); if (!(actualld = virCommandToString(ldcmd))) goto out; if (virtTestCompareToFile(actualargv, cmdline) < 0) goto out; if (virtTestCompareToFile(actualld, ldcmdline) < 0) goto out; if (virFileExists(dmcmdline) || actualdm) { if (virtTestCompareToFile(actualdm, dmcmdline) < 0) goto out; } ret = 0; out: VIR_FREE(actualargv); VIR_FREE(actualld); VIR_FREE(actualdm); virCommandFree(cmd); virCommandFree(ldcmd); virDomainDefFree(vmdef); return ret; }
bool virFCIsCapableRport(const char *rport) { VIR_AUTOFREE(char *) path = NULL; if (virBuildPath(&path, SYSFS_FC_RPORT_PATH, rport) < 0) return false; return virFileExists(path); }
static int virNetDevVethExists(int devNum) { int ret; char *path = NULL; if (virAsprintf(&path, "/sys/class/net/vnet%d/", devNum) < 0) return -1; ret = virFileExists(path) ? 1 : 0; VIR_DEBUG("Checked dev vnet%d usage: %d", devNum, ret); VIR_FREE(path); return ret; }
static int get_sriov_function(const char *device_link, struct pci_config_address **bdf) { char *config_address = NULL; char *device_path = NULL; char errbuf[64]; int ret = SRIOV_ERROR; VIR_DEBUG("Attempting to resolve device path from device link '%s'", device_link); if (!virFileExists(device_link)) { VIR_DEBUG("SR IOV function link '%s' does not exist", device_link); /* Not an SR IOV device, not an error, either. */ ret = SRIOV_NOT_FOUND; goto out; } device_path = canonicalize_file_name (device_link); if (device_path == NULL) { memset(errbuf, '\0', sizeof(errbuf)); VIR_ERROR(_("Failed to resolve device link '%s': '%s'"), device_link, virStrerror(errno, errbuf, sizeof(errbuf))); goto out; } VIR_DEBUG("SR IOV device path is '%s'", device_path); config_address = basename(device_path); if (VIR_ALLOC(*bdf) != 0) { VIR_ERROR0(_("Failed to allocate memory for PCI device name")); goto out; } if (parse_pci_config_address(config_address, *bdf) != 0) { VIR_ERROR(_("Failed to parse PCI config address '%s'"), config_address); goto out; } VIR_DEBUG("SR IOV function %.4x:%.2x:%.2x.%.1x", (*bdf)->domain, (*bdf)->bus, (*bdf)->slot, (*bdf)->function); ret = SRIOV_FOUND; out: VIR_FREE(device_path); return ret; }
/* * Make necessary checks for the need to check and for the current setting * of the 'unpriv_sgio' value for the device_path passed. * * Returns: * 0 - Success * -1 - Some failure which would already have been messaged * -2 - Mismatch with the "shared" sgio setting - needs to be messaged * by caller since it has context of which type of disk resource is * being used and in the future the hostdev information. */ static int qemuCheckUnprivSGIO(virHashTablePtr sharedDevices, const char *device_path, int sgio) { char *sysfs_path = NULL; char *key = NULL; int val; int ret = -1; if (!(sysfs_path = virGetUnprivSGIOSysfsPath(device_path, NULL))) goto cleanup; /* It can't be conflict if unpriv_sgio is not supported by kernel. */ if (!virFileExists(sysfs_path)) { ret = 0; goto cleanup; } if (!(key = qemuGetSharedDeviceKey(device_path))) goto cleanup; /* It can't be conflict if no other domain is sharing it. */ if (!(virHashLookup(sharedDevices, key))) { ret = 0; goto cleanup; } if (virGetDeviceUnprivSGIO(device_path, NULL, &val) < 0) goto cleanup; /* Error message on failure needs to be handled in caller * since there is more specific knowledge of device */ if (!((val == 0 && (sgio == VIR_DOMAIN_DEVICE_SGIO_FILTERED || sgio == VIR_DOMAIN_DEVICE_SGIO_DEFAULT)) || (val == 1 && sgio == VIR_DOMAIN_DEVICE_SGIO_UNFILTERED))) { ret = -2; goto cleanup; } ret = 0; cleanup: VIR_FREE(sysfs_path); VIR_FREE(key); return ret; }
static int genericFileDelete(char *path) { if (!virFileExists(path)) return 0; if (unlink(path) < 0) { virReportSystemError(errno, _("cannot remove config file '%s'"), path); return -1; } return 0; }
static int virNetTLSContextCheckCertFile(const char *type, const char *file, bool allowMissing) { if (!virFileExists(file)) { if (allowMissing) return 1; virReportSystemError(errno, _("Cannot read %s '%s'"), type, file); return -1; } return 0; }
bool virFCIsCapableRport(const char *rport) { bool ret = false; char *path = NULL; if (virBuildPath(&path, SYSFS_FC_RPORT_PATH, rport) < 0) return false; ret = virFileExists(path); VIR_FREE(path); return ret; }
static int hostsfileDelete(dnsmasqHostsfile *hostsfile) { if (!virFileExists(hostsfile->path)) return 0; if (unlink(hostsfile->path) < 0) { virReportSystemError(errno, _("cannot remove config file '%s'"), hostsfile->path); return -1; } return 0; }
static int SELinuxSecurityDriverProbe(const char *virtDriver) { if (!is_selinux_enabled()) return SECURITY_DRIVER_DISABLE; if (virtDriver && STREQ(virtDriver, "LXC")) { #if HAVE_SELINUX_LXC_CONTEXTS_PATH if (!virFileExists(selinux_lxc_contexts_path())) #endif return SECURITY_DRIVER_DISABLE; } return SECURITY_DRIVER_ENABLE; }
/* * Bridge parameters can be set via sysfs on newish kernels, * or by ioctl on older kernels. Perhaps we could just use * ioctl for every kernel, but its not clear what the long * term lifespan of the ioctl interface is... */ static int virNetDevBridgeSet(const char *brname, const char *paramname, /* sysfs param name */ unsigned long value, /* new value */ int fd, /* control socket */ struct ifreq *ifr) /* pre-filled bridge name */ { char *path = NULL; int ret = -1; if (virAsprintf(&path, "%s/%s/bridge/%s", SYSFS_NET_DIR, brname, paramname) < 0) { virReportOOMError(); return -1; } if (virFileExists(path)) { char valuestr[INT_BUFSIZE_BOUND(value)]; snprintf(valuestr, sizeof(valuestr), "%lu", value); if (virFileWriteStr(path, valuestr, 0) < 0) { virReportSystemError(errno, _("Unable to set bridge %s %s"), brname, paramname); goto cleanup; } } else { unsigned long paramid; if (STREQ(paramname, "stp_state")) { paramid = BRCTL_SET_BRIDGE_STP_STATE; } else if (STREQ(paramname, "forward_delay")) { paramid = BRCTL_SET_BRIDGE_FORWARD_DELAY; } else { virReportSystemError(EINVAL, _("Unable to set bridge %s %s"), brname, paramname); goto cleanup; } unsigned long args[] = { paramid, value, 0, 0 }; ifr->ifr_data = (char*)&args; if (ioctl(fd, SIOCDEVPRIVATE, ifr) < 0) { virReportSystemError(errno, _("Unable to set bridge %s %s"), brname, paramname); goto cleanup; } } ret = 0; cleanup: VIR_FREE(path); return ret; }
static int qemuSetupImageCgroupInternal(virDomainObjPtr vm, virStorageSourcePtr src, bool forceReadonly) { if (!src->path || !virStorageSourceIsLocalStorage(src)) { VIR_DEBUG("Not updating cgroups for disk path '%s', type: %s", NULLSTR(src->path), virStorageTypeToString(src->type)); return 0; } if (virStoragePRDefIsManaged(src->pr) && virFileExists(DEVICE_MAPPER_CONTROL_PATH) && qemuSetupImagePathCgroup(vm, DEVICE_MAPPER_CONTROL_PATH, false) < 0) return -1; return qemuSetupImagePathCgroup(vm, src->path, src->readonly || forceReadonly); }
static char * openvzLocateConfDir(void) { const char *conf_dir_list[] = {"/etc/vz/conf", "/usr/local/etc/conf", NULL}; size_t i = 0; char *ret = NULL; while (conf_dir_list[i]) { if (virFileExists(conf_dir_list[i])) { ignore_value(VIR_STRDUP(ret, conf_dir_list[i])); goto cleanup; } i++; } cleanup: return ret; }
static int virNumaGetHugePageInfoPath(char **path, int node, unsigned int page_size, const char *suffix) { int ret; if (node == -1) { /* We are aiming at overall system info */ ret = virAsprintf(path, HUGEPAGES_SYSTEM_PREFIX HUGEPAGES_PREFIX "%ukB/%s", page_size, suffix ? suffix : ""); } else { /* We are aiming on specific NUMA node */ ret = virAsprintf(path, HUGEPAGES_NUMA_PREFIX "node%d/hugepages/" HUGEPAGES_PREFIX "%ukB/%s", node, page_size, suffix ? suffix : ""); } if (ret >= 0 && !virFileExists(*path)) { ret = -1; if (node != -1) { if (!virNumaNodeIsAvailable(node)) { virReportError(VIR_ERR_OPERATION_FAILED, _("NUMA node %d is not available"), node); } else { virReportError(VIR_ERR_OPERATION_FAILED, _("page size %u is not available on node %d"), page_size, node); } } else { virReportError(VIR_ERR_OPERATION_FAILED, _("page size %u is not available"), page_size); } } return ret; }
/** * virNetDevVethGetFreeName: * @veth: pointer to store returned name for veth device * @startDev: device number to start at (x in vethx) * * Looks in /sys/class/net/ to find the first available veth device * name. * * Returns non-negative device number on success or -1 in case of error */ static int virNetDevVethGetFreeName(char **veth, int startDev) { int devNum = startDev-1; char *path = NULL; VIR_DEBUG("Find free from veth%d", startDev); do { VIR_FREE(path); ++devNum; if (virAsprintf(&path, "/sys/class/net/veth%d/", devNum) < 0) return -1; VIR_DEBUG("Probe %s", path); } while (virFileExists(path)); VIR_FREE(path); if (virAsprintf(veth, "veth%d", devNum) < 0) return -1; return devNum; }
/* * profile_status_file returns '-1' on error, '0' if file on disk is in * complain mode and '1' if file on disk is in enforcing mode */ static int profile_status_file(const char *str) { char *profile = NULL; char *content = NULL; char *tmp = NULL; int rc = -1; int len; if (virAsprintf(&profile, "%s/%s", APPARMOR_DIR "/libvirt", str) == -1) { virReportOOMError(); return rc; } if (!virFileExists(profile)) goto failed; if ((len = virFileReadAll(profile, MAX_FILE_LEN, &content)) < 0) { virReportSystemError(errno, _("Failed to read \'%s\'"), profile); goto failed; } /* create string that is ' <str> flags=(complain)\0' */ if (virAsprintf(&tmp, " %s flags=(complain)", str) == -1) { virReportOOMError(); goto failed; } if (strstr(content, tmp) != NULL) rc = 0; else rc = 1; failed: VIR_FREE(tmp); VIR_FREE(profile); VIR_FREE(content); return rc; }
/* * qemuTPMCreateEmulatorStorage * * @storagepath: directory for swtpm's persistent state * @created: a pointer to a bool that will be set to true if the * storage was created because it did not exist yet * @swtpm_user: The uid that needs to be able to access the directory * @swtpm_group: The gid that needs to be able to access the directory * * Unless the storage path for the swtpm for the given VM * already exists, create it and make it accessible for the given userid. * Adapt ownership of the directory and all swtpm's state files there. */ static int qemuTPMCreateEmulatorStorage(const char *storagepath, bool *created, uid_t swtpm_user, gid_t swtpm_group) { int ret = -1; char *swtpmStorageDir = qemuTPMGetTPMStorageDir(storagepath); if (!swtpmStorageDir) return -1; if (qemuTPMEmulatorInitStorage(swtpmStorageDir) < 0) goto cleanup; *created = false; if (!virFileExists(storagepath)) *created = true; if (virDirCreate(storagepath, 0700, swtpm_user, swtpm_group, VIR_DIR_CREATE_ALLOW_EXIST) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not create directory %s as %u:%d"), storagepath, swtpm_user, swtpm_group); goto cleanup; } if (virFileChownFiles(storagepath, swtpm_user, swtpm_group) < 0) goto cleanup; ret = 0; cleanup: VIR_FREE(swtpmStorageDir); return ret; }
/* * qemuTPMEmulatorStop * @swtpmStateDir: A directory where the socket is located * @shortName: short and unique name of the domain * * Gracefully stop the swptm */ static void qemuTPMEmulatorStop(const char *swtpmStateDir, const char *shortName) { virCommandPtr cmd; char *pathname; char *errbuf = NULL; if (qemuTPMEmulatorInit() < 0) return; if (!(pathname = qemuTPMCreateEmulatorSocket(swtpmStateDir, shortName))) return; if (!virFileExists(pathname)) goto cleanup; cmd = virCommandNew(swtpm_ioctl); if (!cmd) goto cleanup; virCommandAddArgList(cmd, "--unix", pathname, "-s", NULL); virCommandSetErrorBuffer(cmd, &errbuf); ignore_value(virCommandRun(cmd, NULL)); virCommandFree(cmd); /* clean up the socket */ unlink(pathname); cleanup: VIR_FREE(pathname); VIR_FREE(errbuf); }
static bool qemuHostdevHostSupportsPassthroughVFIO(void) { DIR *iommuDir = NULL; struct dirent *iommuGroup = NULL; bool ret = false; /* condition 1 - /sys/kernel/iommu_groups/ contains entries */ if (!(iommuDir = opendir("/sys/kernel/iommu_groups/"))) goto cleanup; while ((iommuGroup = readdir(iommuDir))) { /* skip ./ ../ */ if (STRPREFIX(iommuGroup->d_name, ".")) continue; /* assume we found a group */ break; } if (!iommuGroup) goto cleanup; /* okay, iommu is on and recognizes groups */ /* condition 2 - /dev/vfio/vfio exists */ if (!virFileExists("/dev/vfio/vfio")) goto cleanup; ret = true; cleanup: if (iommuDir) closedir(iommuDir); return ret; }