static int virLockManagerSanlockRegisterKillscript(int sock, const char *vmuri, const char *uuidstr, virDomainLockFailureAction action) { virBuffer buf = VIR_BUFFER_INITIALIZER; char *path; char *args = NULL; int ret = -1; int rv; if (action > VIR_DOMAIN_LOCK_FAILURE_IGNORE) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Failure action %s is not supported by sanlock"), virDomainLockFailureTypeToString(action)); goto cleanup; } virBufferEscape(&buf, '\\', "\\ ", "%s", vmuri); virBufferAddLit(&buf, " "); virBufferEscape(&buf, '\\', "\\ ", "%s", uuidstr); virBufferAddLit(&buf, " "); virBufferEscape(&buf, '\\', "\\ ", "%s", virDomainLockFailureTypeToString(action)); if (virBufferError(&buf)) { virBufferFreeAndReset(&buf); virReportOOMError(); goto cleanup; } /* Unfortunately, sanlock_killpath() does not use const for either * path or args even though it will just copy them into its own * buffers. */ path = (char *) VIR_LOCK_MANAGER_SANLOCK_KILLPATH; args = virBufferContentAndReset(&buf); VIR_DEBUG("Register sanlock killpath: %s %s", path, args); /* sanlock_killpath() would just crop the strings */ if (strlen(path) >= SANLK_HELPER_PATH_LEN) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Sanlock helper path is longer than %d: '%s'"), SANLK_HELPER_PATH_LEN - 1, path); goto cleanup; } if (strlen(args) >= SANLK_HELPER_ARGS_LEN) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Sanlock helper arguments are longer than %d:" " '%s'"), SANLK_HELPER_ARGS_LEN - 1, args); goto cleanup; } if ((rv = sanlock_killpath(sock, 0, path, args)) < 0) { if (rv <= -200) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Failed to register lock failure action:" " error %d"), rv); } else { virReportSystemError(-rv, "%s", _("Failed to register lock failure" " action")); } goto cleanup; } ret = 0; cleanup: VIR_FREE(args); return ret; }
static int SELinuxGenSecurityLabel(virSecurityManagerPtr mgr, virDomainDefPtr def) { int rc = -1; char *mcs = NULL; char *scontext = NULL; int c1 = 0; int c2 = 0; context_t ctx = NULL; const char *range; virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr); VIR_DEBUG("SELinuxGenSecurityLabel %s", virSecurityManagerGetDriver(mgr)); if ((def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC) && !def->seclabel.baselabel && def->seclabel.model) { virSecurityReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("security model already defined for VM")); return rc; } if (def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC && def->seclabel.label) { virSecurityReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("security label already defined for VM")); return rc; } if (def->seclabel.imagelabel) { virSecurityReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("security image label already defined for VM")); return rc; } if (def->seclabel.model && STRNEQ(def->seclabel.model, SECURITY_SELINUX_NAME)) { virSecurityReportError(VIR_ERR_INTERNAL_ERROR, _("security label model %s is not supported with selinux"), def->seclabel.model); return rc; } VIR_DEBUG("SELinuxGenSecurityLabel %d", def->seclabel.type); switch (def->seclabel.type) { case VIR_DOMAIN_SECLABEL_STATIC: if (!(ctx = context_new(def->seclabel.label)) ) { virReportSystemError(errno, _("unable to allocate socket security context '%s'"), def->seclabel.label); return rc; } range = context_range_get(ctx); if (!range || !(mcs = strdup(range))) { virReportOOMError(); goto cleanup; } break; case VIR_DOMAIN_SECLABEL_DYNAMIC: do { c1 = virRandomBits(10); c2 = virRandomBits(10); if ( c1 == c2 ) { if (virAsprintf(&mcs, "s0:c%d", c1) < 0) { virReportOOMError(); goto cleanup; } } else { if (c1 > c2) { c1 ^= c2; c2 ^= c1; c1 ^= c2; } if (virAsprintf(&mcs, "s0:c%d,c%d", c1, c2) < 0) { virReportOOMError(); goto cleanup; } } } while (mcsAdd(mcs) == -1); def->seclabel.label = SELinuxGenNewContext(def->seclabel.baselabel ? def->seclabel.baselabel : data->domain_context, mcs); if (! def->seclabel.label) { virSecurityReportError(VIR_ERR_INTERNAL_ERROR, _("cannot generate selinux context for %s"), mcs); goto cleanup; } break; case VIR_DOMAIN_SECLABEL_NONE: /* no op */ break; default: virSecurityReportError(VIR_ERR_INTERNAL_ERROR, _("unexpected security label type '%s'"), virDomainSeclabelTypeToString(def->seclabel.type)); goto cleanup; } if (!def->seclabel.norelabel) { def->seclabel.imagelabel = SELinuxGenNewContext(data->file_context, mcs); if (!def->seclabel.imagelabel) { virSecurityReportError(VIR_ERR_INTERNAL_ERROR, _("cannot generate selinux context for %s"), mcs); goto cleanup; } } if (!def->seclabel.model && !(def->seclabel.model = strdup(SECURITY_SELINUX_NAME))) { virReportOOMError(); goto cleanup; } rc = 0; cleanup: if (rc != 0) { if (def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC) VIR_FREE(def->seclabel.label); VIR_FREE(def->seclabel.imagelabel); if (def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC && !def->seclabel.baselabel) VIR_FREE(def->seclabel.model); } if (ctx) context_free(ctx); VIR_FREE(scontext); VIR_FREE(mcs); VIR_DEBUG("model=%s label=%s imagelabel=%s baselabel=%s", NULLSTR(def->seclabel.model), NULLSTR(def->seclabel.label), NULLSTR(def->seclabel.imagelabel), NULLSTR(def->seclabel.baselabel)); return rc; }
virNodeParseNode(const char *node, int *sockets, int *cores, int *threads, int *offline) { int ret = -1; int processors = 0; DIR *cpudir = NULL; struct dirent *cpudirent = NULL; int sock_max = 0; cpu_set_t sock_map; int sock; cpu_set_t *core_maps = NULL; int core; size_t i; int siblings; unsigned int cpu; int online; *threads = 0; *cores = 0; *sockets = 0; if (!(cpudir = opendir(node))) { virReportSystemError(errno, _("cannot opendir %s"), node); goto cleanup; } /* enumerate sockets in the node */ CPU_ZERO(&sock_map); errno = 0; while ((cpudirent = readdir(cpudir))) { if (sscanf(cpudirent->d_name, "cpu%u", &cpu) != 1) continue; if ((online = virNodeGetCpuValue(node, cpu, "online", 1)) < 0) goto cleanup; if (!online) continue; /* Parse socket */ if ((sock = virNodeParseSocket(node, cpu)) < 0) goto cleanup; CPU_SET(sock, &sock_map); if (sock > sock_max) sock_max = sock; errno = 0; } if (errno) { virReportSystemError(errno, _("problem reading %s"), node); goto cleanup; } sock_max++; /* allocate cpu maps for each socket */ if (VIR_ALLOC_N(core_maps, sock_max) < 0) goto cleanup; for (i = 0; i < sock_max; i++) CPU_ZERO(&core_maps[i]); /* iterate over all CPU's in the node */ rewinddir(cpudir); errno = 0; while ((cpudirent = readdir(cpudir))) { if (sscanf(cpudirent->d_name, "cpu%u", &cpu) != 1) continue; if ((online = virNodeGetCpuValue(node, cpu, "online", 1)) < 0) goto cleanup; if (!online) { (*offline)++; continue; } processors++; /* Parse socket */ if ((sock = virNodeParseSocket(node, cpu)) < 0) goto cleanup; if (!CPU_ISSET(sock, &sock_map)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("CPU socket topology has changed")); goto cleanup; } /* Parse core */ # if defined(__s390__) || \ defined(__s390x__) /* logical cpu is equivalent to a core on s390 */ core = cpu; # else core = virNodeGetCpuValue(node, cpu, "topology/core_id", 0); # endif CPU_SET(core, &core_maps[sock]); if (!(siblings = virNodeCountThreadSiblings(node, cpu))) goto cleanup; if (siblings > *threads) *threads = siblings; errno = 0; } if (errno) { virReportSystemError(errno, _("problem reading %s"), node); goto cleanup; } /* finalize the returned data */ *sockets = CPU_COUNT(&sock_map); for (i = 0; i < sock_max; i++) { if (!CPU_ISSET(i, &sock_map)) continue; core = CPU_COUNT(&core_maps[i]); if (core > *cores) *cores = core; } ret = processors; cleanup: /* don't shadow a more serious error */ if (cpudir && closedir(cpudir) < 0 && ret >= 0) { virReportSystemError(errno, _("problem closing %s"), node); ret = -1; } VIR_FREE(core_maps); return ret; }
/* * Try to kill the process and verify it has exited * * Returns 0 if it was killed gracefully, 1 if it * was killed forcibly, -1 if it is still alive, * or another error occurred. * * Callers can proide an extra delay in seconds to * wait longer than the default. */ int virProcessKillPainfullyDelay(pid_t pid, bool force, unsigned int extradelay) { size_t i; int ret = -1; /* This is in 1/5th seconds since polling is on a 0.2s interval */ unsigned int polldelay = (force ? 200 : 75) + (extradelay*5); const char *signame = "TERM"; VIR_DEBUG("vpid=%lld force=%d extradelay=%u", (long long)pid, force, extradelay); /* This loop sends SIGTERM, then waits a few iterations (10 seconds) * to see if it dies. If the process still hasn't exited, and * @force is requested, a SIGKILL will be sent, and this will * wait up to 30 seconds more for the process to exit before * returning. * * An extra delay can be passed by the caller for cases that are * expected to clean up slower than usual. * * Note that setting @force could result in dataloss for the process. */ for (i = 0; i < polldelay; i++) { int signum; if (i == 0) { signum = SIGTERM; /* kindly suggest it should exit */ } else if (i == 50 && force) { VIR_DEBUG("Timed out waiting after SIGTERM to process %lld, " "sending SIGKILL", (long long)pid); /* No SIGKILL kill on Win32 ! Use SIGABRT instead which our * virProcessKill proc will handle more or less like SIGKILL */ #ifdef WIN32 signum = SIGABRT; /* kill it after a grace period */ signame = "ABRT"; #else signum = SIGKILL; /* kill it after a grace period */ signame = "KILL"; #endif } else { signum = 0; /* Just check for existence */ } if (virProcessKill(pid, signum) < 0) { if (errno != ESRCH) { virReportSystemError(errno, _("Failed to terminate process %lld with SIG%s"), (long long)pid, signame); goto cleanup; } ret = signum == SIGTERM ? 0 : 1; goto cleanup; /* process is dead */ } usleep(200 * 1000); } virReportSystemError(EBUSY, _("Failed to terminate process %lld with SIG%s"), (long long)pid, signame); cleanup: return ret; }
int virNetDevExists(const char *ifname) { virReportSystemError(ENOSYS, _("Unable to check interface %s"), ifname); return -1; }
/* * qemuTPMEmulatorPrepareHost: * * @tpm: tpm definition * @logDir: directory where swtpm writes its logs into * @vmname: name of the VM * @swtpm_user: uid to run the swtpm with * @swtpm_group: gid to run the swtpm with * @swtpmStateDir: directory for swtpm's persistent state * @qemu_user: uid that qemu will run with; we share the socket file with it * @shortName: short and unique name of the domain * * Prepare the log directory for the swtpm and adjust ownership of it and the * log file we will be using. Prepare the state directory where we will share * the socket between tss and qemu users. */ static int qemuTPMEmulatorPrepareHost(virDomainTPMDefPtr tpm, const char *logDir, const char *vmname, uid_t swtpm_user, gid_t swtpm_group, const char *swtpmStateDir, uid_t qemu_user, const char *shortName) { int ret = -1; if (qemuTPMEmulatorInit() < 0) return -1; /* create log dir ... allow 'tss' user to cd into it */ if (virFileMakePathWithMode(logDir, 0711) < 0) return -1; /* ... and adjust ownership */ if (virDirCreate(logDir, 0730, swtpm_user, swtpm_group, VIR_DIR_CREATE_ALLOW_EXIST) < 0) goto cleanup; /* create logfile name ... */ if (!tpm->data.emulator.logfile && virAsprintf(&tpm->data.emulator.logfile, "%s/%s-swtpm.log", logDir, vmname) < 0) goto cleanup; /* ... and make sure it can be accessed by swtpm_user */ if (virFileExists(tpm->data.emulator.logfile) && chown(tpm->data.emulator.logfile, swtpm_user, swtpm_group) < 0) { virReportSystemError(errno, _("Could not chown on swtpm logfile %s"), tpm->data.emulator.logfile); goto cleanup; } /* create our swtpm state dir ... - QEMU user needs to be able to access the socket there - swtpm group needs to be able to create files there - in privileged mode 0570 would be enough, for non-privileged mode we need 0770 */ if (virDirCreate(swtpmStateDir, 0770, qemu_user, swtpm_group, VIR_DIR_CREATE_ALLOW_EXIST) < 0) goto cleanup; /* create the socket filename */ if (!tpm->data.emulator.source.data.nix.path && !(tpm->data.emulator.source.data.nix.path = qemuTPMCreateEmulatorSocket(swtpmStateDir, shortName))) goto cleanup; tpm->data.emulator.source.type = VIR_DOMAIN_CHR_TYPE_UNIX; ret = 0; cleanup: return ret; }
static char * umlBuildCommandLineChr(virDomainChrDefPtr def, const char *dev, virCommandPtr cmd) { char *ret = NULL; switch (def->source.type) { case VIR_DOMAIN_CHR_TYPE_NULL: if (virAsprintf(&ret, "%s%d=null", dev, def->target.port) < 0) return NULL; break; case VIR_DOMAIN_CHR_TYPE_PTY: if (virAsprintf(&ret, "%s%d=pts", dev, def->target.port) < 0) return NULL; break; case VIR_DOMAIN_CHR_TYPE_DEV: if (virAsprintf(&ret, "%s%d=tty:%s", dev, def->target.port, def->source.data.file.path) < 0) return NULL; break; case VIR_DOMAIN_CHR_TYPE_STDIO: if (virAsprintf(&ret, "%s%d=fd:0,fd:1", dev, def->target.port) < 0) return NULL; break; case VIR_DOMAIN_CHR_TYPE_TCP: if (def->source.data.tcp.listen != 1) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("only TCP listen is supported for chr device")); return NULL; } if (virAsprintf(&ret, "%s%d=port:%s", dev, def->target.port, def->source.data.tcp.service) < 0) return NULL; break; case VIR_DOMAIN_CHR_TYPE_FILE: { int fd_out; if ((fd_out = open(def->source.data.file.path, O_WRONLY | O_APPEND | O_CREAT, 0660)) < 0) { virReportSystemError(errno, _("failed to open chardev file: %s"), def->source.data.file.path); return NULL; } if (virAsprintf(&ret, "%s%d=null,fd:%d", dev, def->target.port, fd_out) < 0) { VIR_FORCE_CLOSE(fd_out); return NULL; } virCommandPassFD(cmd, fd_out, VIR_COMMAND_PASS_FD_CLOSE_PARENT); } break; case VIR_DOMAIN_CHR_TYPE_PIPE: /* XXX could open the pipe & just pass the FDs. Be wary of * the effects of blocking I/O, though. */ case VIR_DOMAIN_CHR_TYPE_VC: case VIR_DOMAIN_CHR_TYPE_UDP: case VIR_DOMAIN_CHR_TYPE_UNIX: default: virReportError(VIR_ERR_INTERNAL_ERROR, _("unsupported chr device type %d"), def->source.type); break; } return ret; }
int linuxNodeInfoCPUPopulate(FILE *cpuinfo, const char *sysfs_dir, virNodeInfoPtr nodeinfo) { char line[1024]; DIR *cpudir = NULL; struct dirent *cpudirent = NULL; unsigned int cpu; unsigned long core, sock, cur_threads; cpu_set_t core_mask; cpu_set_t socket_mask; int online; int ret = -1; char *sysfs_cpudir = NULL; unsigned int cpu_cores = 0; nodeinfo->cpus = 0; nodeinfo->mhz = 0; nodeinfo->cores = 0; /* Start with parsing /proc/cpuinfo; although it tends to have * fewer details. Hyperthreads are ignored at this stage. */ while (fgets(line, sizeof(line), cpuinfo) != NULL) { # if defined(__x86_64__) || \ defined(__amd64__) || \ defined(__i386__) char *buf = line; if (STRPREFIX(buf, "cpu MHz")) { char *p; unsigned int ui; buf += 9; while (*buf && c_isspace(*buf)) buf++; if (*buf != ':' || !buf[1]) { nodeReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("parsing cpu MHz from cpuinfo")); goto cleanup; } if (virStrToLong_ui(buf+1, &p, 10, &ui) == 0 /* Accept trailing fractional part. */ && (*p == '\0' || *p == '.' || c_isspace(*p))) nodeinfo->mhz = ui; } if (STRPREFIX(buf, "cpu cores")) { char *p; unsigned int ui; buf += 9; while (*buf && c_isspace(*buf)) buf++; if (*buf != ':' || !buf[1]) { nodeReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("parsing cpu cores from cpuinfo")); return -1; } if (virStrToLong_ui(buf+1, &p, 10, &ui) == 0 && (*p == '\0' || c_isspace(*p))) cpu_cores = ui; } # elif defined(__powerpc__) || \ defined(__powerpc64__) char *buf = line; if (STRPREFIX(buf, "clock")) { char *p; unsigned int ui; buf += 5; while (*buf && c_isspace(*buf)) buf++; if (*buf != ':' || !buf[1]) { nodeReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("parsing cpu MHz from cpuinfo")); goto cleanup; } if (virStrToLong_ui(buf+1, &p, 10, &ui) == 0 /* Accept trailing fractional part. */ && (*p == '\0' || *p == '.' || c_isspace(*p))) nodeinfo->mhz = ui; /* No other interesting infos are available in /proc/cpuinfo. * However, there is a line identifying processor's version, * identification and machine, but we don't want it to be caught * and parsed in next iteration, because it is not in expected * format and thus lead to error. */ } # else # warning Parser for /proc/cpuinfo needs to be adapted for your architecture # endif } /* OK, we've parsed clock speed out of /proc/cpuinfo. Get the * core, node, socket, thread and topology information from /sys */ if (virAsprintf(&sysfs_cpudir, "%s/cpu", sysfs_dir) < 0) { virReportOOMError(); goto cleanup; } cpudir = opendir(sysfs_cpudir); if (cpudir == NULL) { virReportSystemError(errno, _("cannot opendir %s"), sysfs_cpudir); goto cleanup; } CPU_ZERO(&core_mask); CPU_ZERO(&socket_mask); while ((cpudirent = readdir(cpudir))) { if (sscanf(cpudirent->d_name, "cpu%u", &cpu) != 1) continue; online = virNodeGetCpuValue(sysfs_cpudir, cpu, "online", true); if (online < 0) { closedir(cpudir); goto cleanup; } if (!online) continue; nodeinfo->cpus++; /* Parse core */ core = virNodeGetCpuValue(sysfs_cpudir, cpu, "topology/core_id", false); if (!CPU_ISSET(core, &core_mask)) { CPU_SET(core, &core_mask); nodeinfo->cores++; } /* Parse socket */ sock = virNodeParseSocket(sysfs_cpudir, cpu); if (!CPU_ISSET(sock, &socket_mask)) { CPU_SET(sock, &socket_mask); nodeinfo->sockets++; } cur_threads = virNodeCountThreadSiblings(sysfs_cpudir, cpu); if (cur_threads == 0) { closedir(cpudir); goto cleanup; } if (cur_threads > nodeinfo->threads) nodeinfo->threads = cur_threads; } if (errno) { virReportSystemError(errno, _("problem reading %s"), sysfs_cpudir); closedir(cpudir); goto cleanup; } if (closedir(cpudir) < 0) { virReportSystemError(errno, _("problem closing %s"), sysfs_cpudir); goto cleanup; } if ((nodeinfo->nodes = virNodeParseNode(sysfs_dir)) <= 0) goto cleanup; /* There should always be at least one cpu, socket, node, and thread. */ if (nodeinfo->cpus == 0) { nodeReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("no CPUs found")); goto cleanup; } if (nodeinfo->sockets == 0) { nodeReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("no sockets found")); goto cleanup; } if (nodeinfo->threads == 0) { nodeReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("no threads found")); goto cleanup; } /* Platform like AMD Magny Cours has two NUMA nodes each package, and * the two nodes share the same core ID set, it results in the cores * number calculated from sysfs is not the actual cores number. Use * "cpu cores" in /proc/cpuinfo as the cores number instead in this case. * More details about the problem: * https://www.redhat.com/archives/libvir-list/2012-May/msg00607.html */ if (cpu_cores && (cpu_cores > nodeinfo->cores)) nodeinfo->cores = cpu_cores; /* nodeinfo->sockets is supposed to be a number of sockets per NUMA node, * however if NUMA nodes are not composed of whole sockets, we just lie * about the number of NUMA nodes and force apps to check capabilities XML * for the actual NUMA topology. */ if (nodeinfo->sockets % nodeinfo->nodes == 0) nodeinfo->sockets /= nodeinfo->nodes; else nodeinfo->nodes = 1; ret = 0; cleanup: VIR_FREE(sysfs_cpudir); return ret; }
static char* virBhyveTapGetRealDeviceName(char *name) { /* This is an ugly hack, because if we rename * tap device to vnet%d, its device name will be * still /dev/tap%d, and bhyve tries to open /dev/tap%d, * so we have to find the real name */ char *ret = NULL; struct dirent *dp; char *devpath = NULL; int fd; DIR *dirp = opendir("/dev"); if (dirp == NULL) { virReportSystemError(errno, _("Failed to opendir path '%s'"), "/dev"); return NULL; } while ((dp = readdir(dirp)) != NULL) { if (STRPREFIX(dp->d_name, "tap")) { struct ifreq ifr; if (virAsprintf(&devpath, "/dev/%s", dp->d_name) < 0) { goto cleanup; } if ((fd = open(devpath, O_RDWR)) < 0) { virReportSystemError(errno, _("Unable to open '%s'"), devpath); goto cleanup; } if (ioctl(fd, TAPGIFNAME, (void *)&ifr) < 0) { virReportSystemError(errno, "%s", _("Unable to query tap interface name")); goto cleanup; } if (STREQ(name, ifr.ifr_name)) { /* we can ignore the return value * because we still have nothing * to do but return; */ ignore_value(VIR_STRDUP(ret, dp->d_name)); goto cleanup; } VIR_FREE(devpath); VIR_FORCE_CLOSE(fd); } errno = 0; } if (errno != 0) virReportSystemError(errno, "%s", _("Unable to iterate over TAP devices")); cleanup: VIR_FREE(devpath); VIR_FORCE_CLOSE(fd); closedir(dirp); return ret; }
/** * 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. */ virDrvOpenStatus xenInotifyOpen(virConnectPtr conn, virConnectAuthPtr auth ATTRIBUTE_UNUSED, unsigned int flags) { DIR *dh; struct dirent *ent; char *path; xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData; virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR); 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) { virReportOOMError(); 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 ) { virXenInotifyError(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; }
virLockManagerPluginPtr virLockManagerPluginNew(const char *name, const char *driverName, const char *configDir, unsigned int flags) { void *handle = NULL; virLockDriverPtr driver; virLockManagerPluginPtr plugin = NULL; char *modfile = NULL; char *configFile = NULL; VIR_DEBUG("name=%s driverName=%s configDir=%s flags=0x%x", name, driverName, configDir, flags); if (virAsprintf(&configFile, "%s/%s-%s.conf", configDir, driverName, name) < 0) return NULL; if (STREQ(name, "nop")) { driver = &virLockDriverNop; } else { if (!(modfile = virFileFindResourceFull(name, NULL, ".so", abs_top_builddir "/src/.libs", LIBDIR "/libvirt/lock-driver", "LIBVIRT_LOCK_MANAGER_PLUGIN_DIR"))) goto cleanup; VIR_DEBUG("Module load %s from %s", name, modfile); if (access(modfile, R_OK) < 0) { virReportSystemError(errno, _("Plugin %s not accessible"), modfile); goto cleanup; } handle = dlopen(modfile, RTLD_NOW | RTLD_LOCAL); if (!handle) { virReportError(VIR_ERR_SYSTEM_ERROR, _("Failed to load plugin %s: %s"), modfile, dlerror()); goto cleanup; } if (!(driver = dlsym(handle, "virLockDriverImpl"))) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Missing plugin initialization symbol 'virLockDriverImpl'")); goto cleanup; } } if (driver->drvInit(VIR_LOCK_MANAGER_VERSION, configFile, flags) < 0) goto cleanup; if (VIR_ALLOC(plugin) < 0) goto cleanup; plugin->driver = driver; plugin->handle = handle; plugin->refs = 1; if (VIR_STRDUP(plugin->name, name) < 0) goto cleanup; VIR_FREE(configFile); VIR_FREE(modfile); return plugin; cleanup: VIR_FREE(configFile); VIR_FREE(plugin); VIR_FREE(modfile); if (handle) dlclose(handle); return NULL; }
qemuMonitorTestPtr qemuMonitorTestNew(bool json, virCapsPtr caps) { qemuMonitorTestPtr test = NULL; virDomainChrSourceDef src; char *path = NULL; char *tmpdir_template = NULL; if (VIR_ALLOC(test) < 0) goto no_memory; if (virMutexInit(&test->lock) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", "Cannot initialize mutex"); VIR_FREE(test); return NULL; } if (!(tmpdir_template = strdup("/tmp/libvirt_XXXXXX"))) goto no_memory; if (!(test->tmpdir = mkdtemp(tmpdir_template))) { virReportSystemError(errno, "%s", "Failed to create temporary directory"); goto error; } tmpdir_template = NULL; if (virAsprintf(&path, "%s/qemumonitorjsontest.sock", test->tmpdir) < 0) goto no_memory; test->json = json; if (!(test->vm = virDomainObjNew(caps))) goto error; if (virNetSocketNewListenUNIX(path, 0700, getuid(), getgid(), &test->server) < 0) goto error; memset(&src, 0, sizeof(src)); src.type = VIR_DOMAIN_CHR_TYPE_UNIX; src.data.nix.path = (char *)path; src.data.nix.listen = false; if (virNetSocketListen(test->server, 1) < 0) goto error; if (!(test->mon = qemuMonitorOpen(test->vm, &src, json ? 1 : 0, &qemuCallbacks))) goto error; qemuMonitorLock(test->mon); if (virNetSocketAccept(test->server, &test->client) < 0) goto error; if (!test->client) goto error; if (qemuMonitorTestAddReponse(test, json ? QEMU_JSON_GREETING : QEMU_TEXT_GREETING) < 0) goto error; if (virNetSocketAddIOCallback(test->client, VIR_EVENT_HANDLE_WRITABLE, qemuMonitorTestIO, test, NULL) < 0) goto error; virMutexLock(&test->lock); if (virThreadCreate(&test->thread, true, qemuMonitorTestWorker, test) < 0) { virMutexUnlock(&test->lock); goto error; } test->running = true; virMutexUnlock(&test->lock); cleanup: VIR_FREE(path); return test; no_memory: virReportOOMError(); error: VIR_FREE(tmpdir_template); qemuMonitorTestFree(test); goto cleanup; }
/** * virDomainLxcEnterSecurityLabel: * @model: the security model to set * @label: the security label to apply * @oldlabel: filled with old security label * @flags: currently unused, pass 0 * * This API is LXC specific, so it will only work with hypervisor * connections to the LXC driver. * * Attaches the process to the security label specified * by @label. @label is interpreted relative to @model * Depending on the security driver, this may * not take effect until the next call to exec(). * * If @oldlabel is not NULL, it will be filled with info * about the current security label. This may let the * process be moved back to the previous label if no * exec() has yet been performed. * * Returns 0 on success, -1 on error */ int virDomainLxcEnterSecurityLabel(virSecurityModelPtr model, virSecurityLabelPtr label, virSecurityLabelPtr oldlabel, unsigned int flags) { virCheckFlagsGoto(0, error); virCheckNonNullArgGoto(model, error); virCheckNonNullArgGoto(label, error); if (oldlabel) memset(oldlabel, 0, sizeof(*oldlabel)); if (STREQ(model->model, "selinux")) { #ifdef WITH_SELINUX if (oldlabel) { security_context_t ctx; if (getcon(&ctx) < 0) { virReportSystemError(errno, _("unable to get PID %d security context"), getpid()); goto error; } if (strlen((char *) ctx) >= VIR_SECURITY_LABEL_BUFLEN) { virReportError(VIR_ERR_INTERNAL_ERROR, _("security label exceeds " "maximum length: %d"), VIR_SECURITY_LABEL_BUFLEN - 1); freecon(ctx); goto error; } strcpy(oldlabel->label, (char *) ctx); freecon(ctx); if ((oldlabel->enforcing = security_getenforce()) < 0) { virReportSystemError(errno, "%s", _("error calling security_getenforce()")); goto error; } } if (setexeccon(label->label) < 0) { virReportSystemError(errno, _("Cannot set context %s"), label->label); goto error; } #else virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", _("Support for SELinux is not enabled")); goto error; #endif } else { virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, _("Security model %s cannot be entered"), model->model); goto error; } return 0; error: virDispatchError(NULL); return -1; }
/* * sanlock plugin for the libvirt virLockManager API */ static int virLockManagerSanlockLoadConfig(const char *configFile) { virConfPtr conf; virConfValuePtr p; char *tmp; if (access(configFile, R_OK) == -1) { if (errno != ENOENT) { virReportSystemError(errno, _("Unable to access config file %s"), configFile); return -1; } return 0; } if (!(conf = virConfReadFile(configFile, 0))) return -1; #define CHECK_TYPE(name,typ) if (p && p->type != (typ)) { \ virReportError(VIR_ERR_INTERNAL_ERROR, \ "%s: %s: expected type " #typ, \ configFile, (name)); \ virConfFree(conf); \ return -1; \ } p = virConfGetValue(conf, "auto_disk_leases"); CHECK_TYPE("auto_disk_leases", VIR_CONF_LONG); if (p) driver->autoDiskLease = p->l; p = virConfGetValue(conf, "disk_lease_dir"); CHECK_TYPE("disk_lease_dir", VIR_CONF_STRING); if (p && p->str) { VIR_FREE(driver->autoDiskLeasePath); if (!(driver->autoDiskLeasePath = strdup(p->str))) { virReportOOMError(); virConfFree(conf); return -1; } } p = virConfGetValue(conf, "host_id"); CHECK_TYPE("host_id", VIR_CONF_LONG); if (p) driver->hostID = p->l; p = virConfGetValue(conf, "require_lease_for_disks"); CHECK_TYPE("require_lease_for_disks", VIR_CONF_LONG); if (p) driver->requireLeaseForDisks = p->l; else driver->requireLeaseForDisks = !driver->autoDiskLease; p = virConfGetValue(conf, "user"); CHECK_TYPE("user", VIR_CONF_STRING); if (p) { if (!(tmp = strdup(p->str))) { virReportOOMError(); virConfFree(conf); return -1; } if (virGetUserID(tmp, &driver->user) < 0) { VIR_FREE(tmp); virConfFree(conf); return -1; } VIR_FREE(tmp); } p = virConfGetValue(conf, "group"); CHECK_TYPE("group", VIR_CONF_STRING); if (p) { if (!(tmp = strdup(p->str))) { virReportOOMError(); virConfFree(conf); return -1; } if (virGetGroupID(tmp, &driver->group) < 0) { VIR_FREE(tmp); virConfFree(conf); return -1; } VIR_FREE(tmp); } virConfFree(conf); return 0; }
int virNetSocketNewListenUNIX(const char *path, mode_t mask, uid_t user, gid_t grp, virNetSocketPtr *retsock) { virSocketAddr addr; mode_t oldmask; int fd; *retsock = NULL; memset(&addr, 0, sizeof(addr)); addr.len = sizeof(addr.data.un); if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { virReportSystemError(errno, "%s", _("Failed to create socket")); goto error; } addr.data.un.sun_family = AF_UNIX; if (virStrcpyStatic(addr.data.un.sun_path, path) == NULL) { virReportSystemError(ENOMEM, _("Path %s too long for unix socket"), path); goto error; } if (addr.data.un.sun_path[0] == '@') addr.data.un.sun_path[0] = '\0'; else unlink(addr.data.un.sun_path); oldmask = umask(~mask); if (bind(fd, &addr.data.sa, addr.len) < 0) { umask(oldmask); virReportSystemError(errno, _("Failed to bind socket to '%s'"), path); goto error; } umask(oldmask); /* chown() doesn't work for abstract sockets but we use them only * if libvirtd runs unprivileged */ if (grp != 0 && chown(path, user, grp)) { virReportSystemError(errno, _("Failed to change ownership of '%s' to %d:%d"), path, (int) user, (int) grp); goto error; } if (!(*retsock = virNetSocketNew(&addr, NULL, false, fd, -1, 0))) goto error; return 0; error: if (path[0] != '@') unlink(path); VIR_FORCE_CLOSE(fd); return -1; }
virStorageBackendProbeTarget(virStorageSourcePtr target, char **backingStore, int *backingStoreFormat, virStorageEncryptionPtr *encryption) { int fd = -1; int ret = -1; virStorageFileMetadata *meta = NULL; struct stat sb; char *header = NULL; ssize_t len = VIR_STORAGE_MAX_HEADER; *backingStore = NULL; *backingStoreFormat = VIR_STORAGE_FILE_AUTO; if (encryption) *encryption = NULL; if ((ret = virStorageBackendVolOpen(target->path, &sb, VIR_STORAGE_VOL_FS_PROBE_FLAGS)) < 0) goto error; /* Take care to propagate ret, it is not always -1 */ fd = ret; if ((ret = virStorageBackendUpdateVolTargetInfoFD(target, fd, &sb)) < 0) { goto error; } if (S_ISDIR(sb.st_mode)) { target->format = VIR_STORAGE_FILE_DIR; } else { if ((len = virFileReadHeaderFD(fd, len, &header)) < 0) { virReportSystemError(errno, _("cannot read header '%s'"), target->path); goto error; } target->format = virStorageFileProbeFormatFromBuf(target->path, header, len); if (target->format < 0) { ret = -1; goto error; } if (!(meta = virStorageFileGetMetadataFromBuf(target->path, header, len, target->format))) { ret = -1; goto error; } } VIR_FORCE_CLOSE(fd); if (meta && meta->backingStore) { *backingStore = meta->backingStore; meta->backingStore = NULL; if (meta->backingStoreFormat == VIR_STORAGE_FILE_AUTO && meta->backingStoreIsFile) { if ((ret = virStorageFileProbeFormat(*backingStore, -1, -1)) < 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. */ virReportError(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 (meta && meta->capacity) target->capacity = meta->capacity; if (encryption && meta && meta->encryption) { *encryption = meta->encryption; meta->encryption = NULL; 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 */ } virBitmapFree(target->features); if (meta) { target->features = meta->features; meta->features = NULL; } if (meta && meta->compat) { VIR_FREE(target->compat); target->compat = meta->compat; meta->compat = NULL; } goto cleanup; error: VIR_FORCE_CLOSE(fd); cleanup: virStorageFileFreeMetadata(meta); VIR_FREE(header); return ret; }
static int virLXCCgroupSetupDeviceACL(virDomainDefPtr def, virCgroupPtr cgroup) { int ret = -1; int rc; size_t i; static virLXCCgroupDevicePolicy devices[] = { {'c', LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_NULL}, {'c', LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_ZERO}, {'c', LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_FULL}, {'c', LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_RANDOM}, {'c', LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_URANDOM}, {'c', LXC_DEV_MAJ_TTY, LXC_DEV_MIN_TTY}, {'c', LXC_DEV_MAJ_TTY, LXC_DEV_MIN_PTMX}, {0, 0, 0}}; rc = virCgroupDenyAllDevices(cgroup); if (rc != 0) { virReportSystemError(-rc, _("Unable to deny devices for domain %s"), def->name); goto cleanup; } for (i = 0; devices[i].type != 0; i++) { virLXCCgroupDevicePolicyPtr dev = &devices[i]; rc = virCgroupAllowDevice(cgroup, dev->type, dev->major, dev->minor, VIR_CGROUP_DEVICE_RWM); if (rc != 0) { virReportSystemError(-rc, _("Unable to allow device %c:%d:%d for domain %s"), dev->type, dev->major, dev->minor, def->name); goto cleanup; } } for (i = 0 ; i < def->nfss ; i++) { if (def->fss[i]->type != VIR_DOMAIN_FS_TYPE_BLOCK) continue; rc = virCgroupAllowDevicePath(cgroup, def->fss[i]->src, def->fss[i]->readonly ? VIR_CGROUP_DEVICE_READ : VIR_CGROUP_DEVICE_RW); if (rc != 0) { virReportSystemError(-rc, _("Unable to allow device %s for domain %s"), def->fss[i]->src, def->name); goto cleanup; } } rc = virCgroupAllowDeviceMajor(cgroup, 'c', LXC_DEV_MAJ_PTY, VIR_CGROUP_DEVICE_RWM); if (rc != 0) { virReportSystemError(-rc, _("Unable to allow PTY devices for domain %s"), def->name); goto cleanup; } ret = 0; cleanup: return ret; }
static virLockSpaceResourcePtr virLockSpaceResourceNew(virLockSpacePtr lockspace, const char *resname, unsigned int flags, pid_t owner) { virLockSpaceResourcePtr res; bool shared = !!(flags & VIR_LOCK_SPACE_ACQUIRE_SHARED); if (VIR_ALLOC(res) < 0) return NULL; res->fd = -1; res->flags = flags; if (VIR_STRDUP(res->name, resname) < 0) goto error; if (!(res->path = virLockSpaceGetResourcePath(lockspace, resname))) goto error; if (flags & VIR_LOCK_SPACE_ACQUIRE_AUTOCREATE) { while (1) { struct stat a, b; if ((res->fd = open(res->path, O_RDWR|O_CREAT, 0600)) < 0) { virReportSystemError(errno, _("Unable to open/create resource %s"), res->path); goto error; } if (virSetCloseExec(res->fd) < 0) { virReportSystemError(errno, _("Failed to set close-on-exec flag '%s'"), res->path); goto error; } if (fstat(res->fd, &b) < 0) { virReportSystemError(errno, _("Unable to check status of pid file '%s'"), res->path); goto error; } if (virFileLock(res->fd, shared, 0, 1, false) < 0) { if (errno == EACCES || errno == EAGAIN) { virReportError(VIR_ERR_RESOURCE_BUSY, _("Lockspace resource '%s' is locked"), resname); } else { virReportSystemError(errno, _("Unable to acquire lock on '%s'"), res->path); } goto error; } /* Now make sure the pidfile we locked is the same * one that now exists on the filesystem */ if (stat(res->path, &a) < 0) { char ebuf[1024] ATTRIBUTE_UNUSED; VIR_DEBUG("Resource '%s' disappeared: %s", res->path, virStrerror(errno, ebuf, sizeof(ebuf))); VIR_FORCE_CLOSE(res->fd); /* Someone else must be racing with us, so try again */ continue; } if (a.st_ino == b.st_ino) break; VIR_DEBUG("Resource '%s' was recreated", res->path); VIR_FORCE_CLOSE(res->fd); /* Someone else must be racing with us, so try again */ } } else {
/** * virRotatingFileWriterAppend: * @file: the file context * @buf: the data buffer * @len: the number of bytes in @buf * * Append the data in @buf to the file, performing rollover * of the files if their size would exceed the limit * * Returns the number of bytes written, or -1 on error */ ssize_t virRotatingFileWriterAppend(virRotatingFileWriterPtr file, const char *buf, size_t len) { ssize_t ret = 0; size_t i; while (len) { size_t towrite = len; bool forceRollover = false; if ((file->entry->pos + towrite) > file->maxlen) { towrite = file->maxlen - file->entry->pos; /* * If there's a newline in the last 80 chars * we're about to write, then break at that * point to avoid splitting lines across * separate files */ for (i = 0; i < towrite && i < 80; i++) { if (buf[towrite - i - 1] == '\n') { towrite -= i; forceRollover = true; break; } } } if (towrite) { if (safewrite(file->entry->fd, buf, towrite) != towrite) { virReportSystemError(errno, _("Unable to write to file %s"), file->basepath); return -1; } len -= towrite; buf += towrite; ret += towrite; file->entry->pos += towrite; file->entry->len += towrite; } if ((file->entry->pos == file->maxlen && len) || forceRollover) { virRotatingFileWriterEntryPtr tmp = file->entry; VIR_DEBUG("Hit max size %zu on %s (force=%d)\n", file->maxlen, file->basepath, forceRollover); if (virRotatingFileWriterRollover(file) < 0) return -1; if (!(file->entry = virRotatingFileWriterEntryNew(file->basepath, file->mode))) return -1; virRotatingFileWriterEntryFree(tmp); } } return ret; }
virHostCPUParseNode(const char *node, virArch arch, virBitmapPtr present_cpus_map, virBitmapPtr online_cpus_map, int threads_per_subcore, int *sockets, int *cores, int *threads, int *offline) { /* Biggest value we can expect to be used as either socket id * or core id. Bitmaps will need to be sized accordingly */ const int ID_MAX = 4095; int ret = -1; int processors = 0; DIR *cpudir = NULL; struct dirent *cpudirent = NULL; virBitmapPtr node_cpus_map = NULL; virBitmapPtr sockets_map = NULL; virBitmapPtr *cores_maps = NULL; int npresent_cpus = virBitmapSize(present_cpus_map); int sock_max = 0; int sock; int core; size_t i; int siblings; unsigned int cpu; int direrr; *threads = 0; *cores = 0; *sockets = 0; if (!(cpudir = opendir(node))) { virReportSystemError(errno, _("cannot opendir %s"), node); goto cleanup; } /* Keep track of the CPUs that belong to the current node */ if (!(node_cpus_map = virBitmapNew(npresent_cpus))) goto cleanup; /* enumerate sockets in the node */ if (!(sockets_map = virBitmapNew(ID_MAX + 1))) goto cleanup; while ((direrr = virDirRead(cpudir, &cpudirent, node)) > 0) { if (sscanf(cpudirent->d_name, "cpu%u", &cpu) != 1) continue; if (!virBitmapIsBitSet(present_cpus_map, cpu)) continue; /* Mark this CPU as part of the current node */ if (virBitmapSetBit(node_cpus_map, cpu) < 0) goto cleanup; if (!virBitmapIsBitSet(online_cpus_map, cpu)) continue; /* Parse socket */ if ((sock = virHostCPUParseSocket(node, arch, cpu)) < 0) goto cleanup; if (sock > ID_MAX) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Socket %d can't be handled (max socket is %d)"), sock, ID_MAX); goto cleanup; } if (virBitmapSetBit(sockets_map, sock) < 0) goto cleanup; if (sock > sock_max) sock_max = sock; } if (direrr < 0) goto cleanup; sock_max++; /* allocate cores maps for each socket */ if (VIR_ALLOC_N(cores_maps, sock_max) < 0) goto cleanup; for (i = 0; i < sock_max; i++) if (!(cores_maps[i] = virBitmapNew(ID_MAX + 1))) goto cleanup; /* Iterate over all CPUs in the node, in ascending order */ for (cpu = 0; cpu < npresent_cpus; cpu++) { /* Skip CPUs that are not part of the current node */ if (!virBitmapIsBitSet(node_cpus_map, cpu)) continue; if (!virBitmapIsBitSet(online_cpus_map, cpu)) { if (threads_per_subcore > 0 && cpu % threads_per_subcore != 0 && virBitmapIsBitSet(online_cpus_map, cpu - (cpu % threads_per_subcore))) { /* Secondary offline threads are counted as online when * subcores are in use and the corresponding primary * thread is online */ processors++; } else { /* But they are counted as offline otherwise */ (*offline)++; } continue; } processors++; /* Parse socket */ if ((sock = virHostCPUParseSocket(node, arch, cpu)) < 0) goto cleanup; if (!virBitmapIsBitSet(sockets_map, sock)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("CPU socket topology has changed")); goto cleanup; } /* Parse core */ if (ARCH_IS_S390(arch)) { /* logical cpu is equivalent to a core on s390 */ core = cpu; } else { if ((core = virHostCPUGetValue(node, cpu, "topology/core_id", 0)) < 0) goto cleanup; } if (core > ID_MAX) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Core %d can't be handled (max core is %d)"), core, ID_MAX); goto cleanup; } if (virBitmapSetBit(cores_maps[sock], core) < 0) goto cleanup; if (!(siblings = virHostCPUCountThreadSiblings(node, cpu))) goto cleanup; if (siblings > *threads) *threads = siblings; } /* finalize the returned data */ *sockets = virBitmapCountBits(sockets_map); for (i = 0; i < sock_max; i++) { if (!virBitmapIsBitSet(sockets_map, i)) continue; core = virBitmapCountBits(cores_maps[i]); if (core > *cores) *cores = core; } if (threads_per_subcore > 0) { /* The thread count ignores offline threads, which means that only * only primary threads have been considered so far. If subcores * are in use, we need to also account for secondary threads */ *threads *= threads_per_subcore; } ret = processors; cleanup: /* don't shadow a more serious error */ if (cpudir && closedir(cpudir) < 0 && ret >= 0) { virReportSystemError(errno, _("problem closing %s"), node); ret = -1; } if (cores_maps) for (i = 0; i < sock_max; i++) virBitmapFree(cores_maps[i]); VIR_FREE(cores_maps); virBitmapFree(sockets_map); virBitmapFree(node_cpus_map); return ret; }
/* * Workaround older glibc. While kernel may support the setns * syscall, the glibc wrapper might not exist. If that's the * case, use our own. */ # ifndef __NR_setns # if defined(__x86_64__) # define __NR_setns 308 # elif defined(__i386__) # define __NR_setns 346 # elif defined(__arm__) # define __NR_setns 375 # elif defined(__aarch64__) # define __NR_setns 375 # elif defined(__powerpc__) # define __NR_setns 350 # elif defined(__s390__) # define __NR_setns 339 # endif # endif # ifndef HAVE_SETNS # if defined(__NR_setns) # include <sys/syscall.h> static inline int setns(int fd, int nstype) { return syscall(__NR_setns, fd, nstype); } # else /* !__NR_setns */ # error Please determine the syscall number for setns on your architecture # endif # endif #else /* !__linux__ */ static inline int setns(int fd ATTRIBUTE_UNUSED, int nstype ATTRIBUTE_UNUSED) { virReportSystemError(ENOSYS, "%s", _("Namespaces are not supported on this platform.")); return -1; }
int virHostCPUGetInfoPopulateLinux(FILE *cpuinfo, virArch arch, unsigned int *cpus, unsigned int *mhz, unsigned int *nodes, unsigned int *sockets, unsigned int *cores, unsigned int *threads) { virBitmapPtr present_cpus_map = NULL; virBitmapPtr online_cpus_map = NULL; char line[1024]; DIR *nodedir = NULL; struct dirent *nodedirent = NULL; int nodecpus, nodecores, nodesockets, nodethreads, offline = 0; int threads_per_subcore = 0; unsigned int node; int ret = -1; char *sysfs_nodedir = NULL; char *sysfs_cpudir = NULL; int direrr; *mhz = 0; *cpus = *nodes = *sockets = *cores = *threads = 0; /* Start with parsing CPU clock speed from /proc/cpuinfo */ while (fgets(line, sizeof(line), cpuinfo) != NULL) { if (ARCH_IS_X86(arch)) { char *buf = line; if (STRPREFIX(buf, "cpu MHz")) { char *p; unsigned int ui; buf += 7; while (*buf && c_isspace(*buf)) buf++; if (*buf != ':' || !buf[1]) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("parsing cpu MHz from cpuinfo")); goto cleanup; } if (virStrToLong_ui(buf+1, &p, 10, &ui) == 0 && /* Accept trailing fractional part. */ (*p == '\0' || *p == '.' || c_isspace(*p))) *mhz = ui; } } else if (ARCH_IS_PPC(arch)) { char *buf = line; if (STRPREFIX(buf, "clock")) { char *p; unsigned int ui; buf += 5; while (*buf && c_isspace(*buf)) buf++; if (*buf != ':' || !buf[1]) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("parsing cpu MHz from cpuinfo")); goto cleanup; } if (virStrToLong_ui(buf+1, &p, 10, &ui) == 0 && /* Accept trailing fractional part. */ (*p == '\0' || *p == '.' || c_isspace(*p))) *mhz = ui; /* No other interesting infos are available in /proc/cpuinfo. * However, there is a line identifying processor's version, * identification and machine, but we don't want it to be caught * and parsed in next iteration, because it is not in expected * format and thus lead to error. */ } } else if (ARCH_IS_ARM(arch)) { char *buf = line; if (STRPREFIX(buf, "BogoMIPS")) { char *p; unsigned int ui; buf += 8; while (*buf && c_isspace(*buf)) buf++; if (*buf != ':' || !buf[1]) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("parsing cpu MHz from cpuinfo")); goto cleanup; } if (virStrToLong_ui(buf+1, &p, 10, &ui) == 0 /* Accept trailing fractional part. */ && (*p == '\0' || *p == '.' || c_isspace(*p))) *mhz = ui; } } else if (ARCH_IS_S390(arch)) { /* s390x has no realistic value for CPU speed, * assign a value of zero to signify this */ *mhz = 0; } else { VIR_WARN("Parser for /proc/cpuinfo needs to be adapted for your architecture"); break; } } /* Get information about what CPUs are present in the host and what * CPUs are online, so that we don't have to so for each node */ present_cpus_map = virHostCPUGetPresentBitmap(); if (!present_cpus_map) goto cleanup; online_cpus_map = virHostCPUGetOnlineBitmap(); if (!online_cpus_map) goto cleanup; /* OK, we've parsed clock speed out of /proc/cpuinfo. Get the * core, node, socket, thread and topology information from /sys */ if (virAsprintf(&sysfs_nodedir, "%s/node", sysfs_system_path) < 0) goto cleanup; if (!(nodedir = opendir(sysfs_nodedir))) { /* the host isn't probably running a NUMA architecture */ goto fallback; } /* PPC-KVM needs the secondary threads of a core to be offline on the * host. The kvm scheduler brings the secondary threads online in the * guest context. Moreover, P8 processor has split-core capability * where, there can be 1,2 or 4 subcores per core. The primaries of the * subcores alone will be online on the host for a subcore in the * host. Even though the actual threads per core for P8 processor is 8, * depending on the subcores_per_core = 1, 2 or 4, the threads per * subcore will vary accordingly to 8, 4 and 2 repectively. * So, On host threads_per_core what is arrived at from sysfs in the * current logic is actually the subcores_per_core. Threads per subcore * can only be obtained from the kvm device. For example, on P8 wih 1 * core having 8 threads, sub_cores_percore=4, the threads 0,2,4 & 6 * will be online. The sysfs reflects this and in the current logic * variable 'threads' will be 4 which is nothing but subcores_per_core. * If the user tampers the cpu online/offline states using chcpu or other * means, then it is an unsupported configuration for kvm. * The code below tries to keep in mind * - when the libvirtd is run inside a KVM guest or Phyp based guest. * - Or on the kvm host where user manually tampers the cpu states to * offline/online randomly. * On hosts other than POWER this will be 0, in which case a simpler * thread-counting logic will be used */ if ((threads_per_subcore = virHostCPUGetThreadsPerSubcore(arch)) < 0) goto cleanup; /* If the subcore configuration is not valid, just pretend subcores * are not in use and count threads one by one */ if (!virHostCPUHasValidSubcoreConfiguration(threads_per_subcore)) threads_per_subcore = 0; while ((direrr = virDirRead(nodedir, &nodedirent, sysfs_nodedir)) > 0) { if (sscanf(nodedirent->d_name, "node%u", &node) != 1) continue; (*nodes)++; if (virAsprintf(&sysfs_cpudir, "%s/node/%s", sysfs_system_path, nodedirent->d_name) < 0) goto cleanup; if ((nodecpus = virHostCPUParseNode(sysfs_cpudir, arch, present_cpus_map, online_cpus_map, threads_per_subcore, &nodesockets, &nodecores, &nodethreads, &offline)) < 0) goto cleanup; VIR_FREE(sysfs_cpudir); *cpus += nodecpus; if (nodesockets > *sockets) *sockets = nodesockets; if (nodecores > *cores) *cores = nodecores; if (nodethreads > *threads) *threads = nodethreads; } if (direrr < 0) goto cleanup; if (*cpus && *nodes) goto done; fallback: VIR_FREE(sysfs_cpudir); if (virAsprintf(&sysfs_cpudir, "%s/cpu", sysfs_system_path) < 0) goto cleanup; if ((nodecpus = virHostCPUParseNode(sysfs_cpudir, arch, present_cpus_map, online_cpus_map, threads_per_subcore, &nodesockets, &nodecores, &nodethreads, &offline)) < 0) goto cleanup; *nodes = 1; *cpus = nodecpus; *sockets = nodesockets; *cores = nodecores; *threads = nodethreads; done: /* There should always be at least one cpu, socket, node, and thread. */ if (*cpus == 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("no CPUs found")); goto cleanup; } if (*sockets == 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("no sockets found")); goto cleanup; } if (*threads == 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("no threads found")); goto cleanup; } /* Now check if the topology makes sense. There are machines that don't * expose their real number of nodes or for example the AMD Bulldozer * architecture that exposes their Clustered integer core modules as both * threads and cores. This approach throws off our detection. Unfortunately * the nodeinfo structure isn't designed to carry the full topology so * we're going to lie about the detected topology to notify the user * to check the host capabilities for the actual topology. */ if ((*nodes * *sockets * *cores * *threads) != (*cpus + offline)) { *nodes = 1; *sockets = 1; *cores = *cpus + offline; *threads = 1; } ret = 0; cleanup: /* don't shadow a more serious error */ if (nodedir && closedir(nodedir) < 0 && ret >= 0) { virReportSystemError(errno, _("problem closing %s"), sysfs_nodedir); ret = -1; } virBitmapFree(present_cpus_map); virBitmapFree(online_cpus_map); VIR_FREE(sysfs_nodedir); VIR_FREE(sysfs_cpudir); return ret; }
int virProcessSetAffinity(pid_t pid, virBitmapPtr map) { size_t i; VIR_DEBUG("Set process affinity on %lld", (long long)pid); # ifdef CPU_ALLOC /* New method dynamically allocates cpu mask, allowing unlimted cpus */ int numcpus = 1024; size_t masklen; cpu_set_t *mask; /* Not only may the statically allocated cpu_set_t be too small, * but there is no way to ask the kernel what size is large enough. * So you have no option but to pick a size, try, catch EINVAL, * enlarge, and re-try. * * http://lkml.org/lkml/2009/7/28/620 */ realloc: masklen = CPU_ALLOC_SIZE(numcpus); mask = CPU_ALLOC(numcpus); if (!mask) { virReportOOMError(); return -1; } CPU_ZERO_S(masklen, mask); for (i = 0; i < virBitmapSize(map); i++) { if (virBitmapIsBitSet(map, i)) CPU_SET_S(i, masklen, mask); } if (sched_setaffinity(pid, masklen, mask) < 0) { CPU_FREE(mask); if (errno == EINVAL && numcpus < (1024 << 8)) { /* 262144 cpus ought to be enough for anyone */ numcpus = numcpus << 2; goto realloc; } virReportSystemError(errno, _("cannot set CPU affinity on process %d"), pid); return -1; } CPU_FREE(mask); # else /* Legacy method uses a fixed size cpu mask, only allows up to 1024 cpus */ cpu_set_t mask; CPU_ZERO(&mask); for (i = 0; i < virBitmapSize(map); i++) { if (virBitmapIsBitSet(map, i)) CPU_SET(i, &mask); } if (sched_setaffinity(pid, sizeof(mask), &mask) < 0) { virReportSystemError(errno, _("cannot set CPU affinity on process %d"), pid); return -1; } # endif return 0; }
static int virHostCPUGetStatsFreeBSD(int cpuNum, virNodeCPUStatsPtr params, int *nparams) { const char *sysctl_name; long *cpu_times; struct clockinfo clkinfo; size_t i, j, cpu_times_size, clkinfo_size; int cpu_times_num, offset, hz, stathz, ret = -1; struct field_cpu_map { const char *field; int idx[CPUSTATES]; } cpu_map[] = { {VIR_NODE_CPU_STATS_KERNEL, {CP_SYS}}, {VIR_NODE_CPU_STATS_USER, {CP_USER, CP_NICE}}, {VIR_NODE_CPU_STATS_IDLE, {CP_IDLE}}, {VIR_NODE_CPU_STATS_INTR, {CP_INTR}}, {NULL, {0}} }; if ((*nparams) == 0) { *nparams = BSD_CPU_STATS_ALL; return 0; } if ((*nparams) != BSD_CPU_STATS_ALL) { virReportInvalidArg(*nparams, _("nparams in %s must be equal to %d"), __FUNCTION__, BSD_CPU_STATS_ALL); return -1; } clkinfo_size = sizeof(clkinfo); if (sysctlbyname("kern.clockrate", &clkinfo, &clkinfo_size, NULL, 0) < 0) { virReportSystemError(errno, _("sysctl failed for '%s'"), "kern.clockrate"); return -1; } stathz = clkinfo.stathz; hz = clkinfo.hz; if (cpuNum == VIR_NODE_CPU_STATS_ALL_CPUS) { sysctl_name = "kern.cp_time"; cpu_times_num = 1; offset = 0; } else { sysctl_name = "kern.cp_times"; cpu_times_num = virHostCPUGetCountAppleFreeBSD(); if (cpuNum >= cpu_times_num) { virReportInvalidArg(cpuNum, _("Invalid cpuNum in %s"), __FUNCTION__); return -1; } offset = cpu_times_num * CPUSTATES; } cpu_times_size = sizeof(long) * cpu_times_num * CPUSTATES; if (VIR_ALLOC_N(cpu_times, cpu_times_num * CPUSTATES) < 0) goto cleanup; if (sysctlbyname(sysctl_name, cpu_times, &cpu_times_size, NULL, 0) < 0) { virReportSystemError(errno, _("sysctl failed for '%s'"), sysctl_name); goto cleanup; } for (i = 0; cpu_map[i].field != NULL; i++) { virNodeCPUStatsPtr param = ¶ms[i]; if (virStrcpyStatic(param->field, cpu_map[i].field) == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Field '%s' too long for destination"), cpu_map[i].field); goto cleanup; } param->value = 0; for (j = 0; j < ARRAY_CARDINALITY(cpu_map[i].idx); j++) param->value += cpu_times[offset + cpu_map[i].idx[j]] * TICK_TO_NSEC; } ret = 0; cleanup: VIR_FREE(cpu_times); return ret; }
static int SELinuxLXCInitialize(virSecurityManagerPtr mgr) { virConfValuePtr scon = NULL; virConfValuePtr tcon = NULL; virConfValuePtr dcon = NULL; virConfPtr selinux_conf; virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr); selinux_conf = virConfReadFile(selinux_lxc_contexts_path(), 0); if (!selinux_conf) { virReportSystemError(errno, _("cannot open SELinux lxc contexts file '%s'"), selinux_lxc_contexts_path()); return -1; } scon = virConfGetValue(selinux_conf, "process"); if (! scon || scon->type != VIR_CONF_STRING || (! scon->str)) { virReportSystemError(errno, _("cannot read 'process' value from selinux lxc contexts file '%s'"), selinux_lxc_contexts_path()); goto error; } tcon = virConfGetValue(selinux_conf, "file"); if (! tcon || tcon->type != VIR_CONF_STRING || (! tcon->str)) { virReportSystemError(errno, _("cannot read 'file' value from selinux lxc contexts file '%s'"), selinux_lxc_contexts_path()); goto error; } dcon = virConfGetValue(selinux_conf, "content"); if (! dcon || dcon->type != VIR_CONF_STRING || (! dcon->str)) { virReportSystemError(errno, _("cannot read 'file' value from selinux lxc contexts file '%s'"), selinux_lxc_contexts_path()); goto error; } data->domain_context = strdup(scon->str); data->file_context = strdup(tcon->str); data->content_context = strdup(dcon->str); if (!data->domain_context || !data->file_context || !data->content_context) { virReportSystemError(errno, _("cannot allocate memory for LXC SELinux contexts '%s'"), selinux_lxc_contexts_path()); goto error; } virConfFree(selinux_conf); return 0; error: virConfFree(selinux_conf); VIR_FREE(data->domain_context); VIR_FREE(data->file_context); VIR_FREE(data->content_context); return -1; }
static virNetSocketPtr virNetSocketNew(virSocketAddrPtr localAddr, virSocketAddrPtr remoteAddr, bool isClient, int fd, int errfd, pid_t pid) { virNetSocketPtr sock; int no_slow_start = 1; VIR_DEBUG("localAddr=%p remoteAddr=%p fd=%d errfd=%d pid=%d", localAddr, remoteAddr, fd, errfd, pid); if (virSetCloseExec(fd) < 0) { virReportSystemError(errno, "%s", _("Unable to set close-on-exec flag")); return NULL; } if (virSetNonBlock(fd) < 0) { virReportSystemError(errno, "%s", _("Unable to enable non-blocking flag")); return NULL; } if (VIR_ALLOC(sock) < 0) { virReportOOMError(); return NULL; } if (virMutexInit(&sock->lock) < 0) { virReportSystemError(errno, "%s", _("Unable to initialize mutex")); VIR_FREE(sock); return NULL; } sock->refs = 1; if (localAddr) sock->localAddr = *localAddr; if (remoteAddr) sock->remoteAddr = *remoteAddr; sock->fd = fd; sock->errfd = errfd; sock->pid = pid; /* Disable nagle for TCP sockets */ if (sock->localAddr.data.sa.sa_family == AF_INET || sock->localAddr.data.sa.sa_family == AF_INET6) { if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &no_slow_start, sizeof(no_slow_start)) < 0) { virReportSystemError(errno, "%s", _("Unable to disable nagle algorithm")); goto error; } } if (localAddr && !(sock->localAddrStr = virSocketFormatAddrFull(localAddr, true, ";"))) goto error; if (remoteAddr && !(sock->remoteAddrStr = virSocketFormatAddrFull(remoteAddr, true, ";"))) goto error; sock->client = isClient; PROBE(RPC_SOCKET_NEW, "sock=%p refs=%d fd=%d errfd=%d pid=%d localAddr=%s, remoteAddr=%s", sock, sock->refs, fd, errfd, pid, NULLSTR(sock->localAddrStr), NULLSTR(sock->remoteAddrStr)); return sock; error: sock->fd = sock->errfd = -1; /* Caller owns fd/errfd on failure */ virNetSocketFree(sock); return NULL; }
int qemudLoadDriverConfig(struct qemud_driver *driver, const char *filename) { virConfPtr conf; virConfValuePtr p; char *user; char *group; int i; /* Setup critical defaults */ driver->dynamicOwnership = 1; driver->clearEmulatorCapabilities = 1; if (!(driver->vncListen = strdup("127.0.0.1"))) { virReportOOMError(); return -1; } if (!(driver->vncTLSx509certdir = strdup(SYSCONFDIR "/pki/libvirt-vnc"))) { virReportOOMError(); return -1; } if (!(driver->spiceListen = strdup("127.0.0.1"))) { virReportOOMError(); return -1; } if (!(driver->spiceTLSx509certdir = strdup(SYSCONFDIR "/pki/libvirt-spice"))) { virReportOOMError(); return -1; } #if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R /* For privileged driver, try and find hugepage mount automatically. * Non-privileged driver requires admin to create a dir for the * user, chown it, and then let user configure it manually */ if (driver->privileged && !(driver->hugetlbfs_mount = virFileFindMountPoint("hugetlbfs"))) { if (errno != ENOENT) { virReportSystemError(errno, "%s", _("unable to find hugetlbfs mountpoint")); return -1; } } #endif /* 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; } conf = virConfReadFile (filename, 0); if (!conf) { return -1; } #define CHECK_TYPE(name,typ) if (p && p->type != (typ)) { \ qemuReportError(VIR_ERR_INTERNAL_ERROR, \ "%s: %s: expected type " #typ, \ filename, (name)); \ virConfFree(conf); \ return -1; \ } p = virConfGetValue (conf, "vnc_auto_unix_socket"); CHECK_TYPE ("vnc_auto_unix_socket", VIR_CONF_LONG); if (p) driver->vncAutoUnixSocket = p->l; p = virConfGetValue (conf, "vnc_tls"); CHECK_TYPE ("vnc_tls", VIR_CONF_LONG); if (p) driver->vncTLS = p->l; p = virConfGetValue (conf, "vnc_tls_x509_verify"); CHECK_TYPE ("vnc_tls_x509_verify", VIR_CONF_LONG); if (p) driver->vncTLSx509verify = p->l; p = virConfGetValue (conf, "vnc_tls_x509_cert_dir"); CHECK_TYPE ("vnc_tls_x509_cert_dir", VIR_CONF_STRING); if (p && p->str) { VIR_FREE(driver->vncTLSx509certdir); if (!(driver->vncTLSx509certdir = strdup(p->str))) { virReportOOMError(); virConfFree(conf); return -1; } } p = virConfGetValue (conf, "vnc_listen"); CHECK_TYPE ("vnc_listen", VIR_CONF_STRING); if (p && p->str) { VIR_FREE(driver->vncListen); if (!(driver->vncListen = strdup(p->str))) { virReportOOMError(); virConfFree(conf); return -1; } } p = virConfGetValue (conf, "vnc_password"); CHECK_TYPE ("vnc_password", VIR_CONF_STRING); if (p && p->str) { VIR_FREE(driver->vncPassword); if (!(driver->vncPassword = strdup(p->str))) { virReportOOMError(); virConfFree(conf); return -1; } } p = virConfGetValue (conf, "security_driver"); CHECK_TYPE ("security_driver", VIR_CONF_STRING); if (p && p->str) { if (!(driver->securityDriverName = strdup(p->str))) { virReportOOMError(); virConfFree(conf); return -1; } } p = virConfGetValue (conf, "vnc_sasl"); CHECK_TYPE ("vnc_sasl", VIR_CONF_LONG); if (p) driver->vncSASL = p->l; p = virConfGetValue (conf, "vnc_sasl_dir"); CHECK_TYPE ("vnc_sasl_dir", VIR_CONF_STRING); if (p && p->str) { VIR_FREE(driver->vncSASLdir); if (!(driver->vncSASLdir = strdup(p->str))) { virReportOOMError(); virConfFree(conf); return -1; } } p = virConfGetValue (conf, "spice_tls"); CHECK_TYPE ("spice_tls", VIR_CONF_LONG); if (p) driver->spiceTLS = p->l; p = virConfGetValue (conf, "spice_tls_x509_cert_dir"); CHECK_TYPE ("spice_tls_x509_cert_dir", VIR_CONF_STRING); if (p && p->str) { VIR_FREE(driver->spiceTLSx509certdir); if (!(driver->spiceTLSx509certdir = strdup(p->str))) { virReportOOMError(); virConfFree(conf); return -1; } } p = virConfGetValue (conf, "spice_listen"); CHECK_TYPE ("spice_listen", VIR_CONF_STRING); if (p && p->str) { VIR_FREE(driver->spiceListen); if (!(driver->spiceListen = strdup(p->str))) { virReportOOMError(); virConfFree(conf); return -1; } } p = virConfGetValue (conf, "spice_password"); CHECK_TYPE ("spice_password", VIR_CONF_STRING); if (p && p->str) { VIR_FREE(driver->spicePassword); if (!(driver->spicePassword = strdup(p->str))) { virReportOOMError(); virConfFree(conf); return -1; } } p = virConfGetValue (conf, "user"); CHECK_TYPE ("user", VIR_CONF_STRING); if (!(user = strdup(p && p->str ? p->str : QEMU_USER))) { virReportOOMError(); virConfFree(conf); return -1; } if (virGetUserID(user, &driver->user) < 0) { VIR_FREE(user); virConfFree(conf); return -1; } VIR_FREE(user); p = virConfGetValue (conf, "group"); CHECK_TYPE ("group", VIR_CONF_STRING); if (!(group = strdup(p && p->str ? p->str : QEMU_GROUP))) { virReportOOMError(); virConfFree(conf); return -1; } if (virGetGroupID(group, &driver->group) < 0) { VIR_FREE(group); virConfFree(conf); return -1; } VIR_FREE(group); p = virConfGetValue (conf, "dynamic_ownership"); CHECK_TYPE ("dynamic_ownership", VIR_CONF_LONG); if (p) driver->dynamicOwnership = p->l; p = virConfGetValue (conf, "cgroup_controllers"); CHECK_TYPE ("cgroup_controllers", VIR_CONF_LIST); if (p) { virConfValuePtr pp; for (i = 0, pp = p->list; pp; ++i, pp = pp->next) { int ctl; if (pp->type != VIR_CONF_STRING) { VIR_ERROR0(_("cgroup_controllers must be a list of strings")); virConfFree(conf); return -1; } ctl = virCgroupControllerTypeFromString(pp->str); if (ctl < 0) { VIR_ERROR(_("Unknown cgroup controller '%s'"), pp->str); virConfFree(conf); return -1; } driver->cgroupControllers |= (1 << ctl); } } else { driver->cgroupControllers = (1 << VIR_CGROUP_CONTROLLER_CPU) | (1 << VIR_CGROUP_CONTROLLER_DEVICES) | (1 << VIR_CGROUP_CONTROLLER_MEMORY) | (1 << VIR_CGROUP_CONTROLLER_BLKIO); } for (i = 0 ; i < VIR_CGROUP_CONTROLLER_LAST ; i++) { if (driver->cgroupControllers & (1 << i)) { VIR_INFO("Configured cgroup controller '%s'", virCgroupControllerTypeToString(i)); } } 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(driver->cgroupDeviceACL, 1+len) < 0) { virReportOOMError(); virConfFree(conf); return -1; } for (i = 0, pp = p->list; pp; ++i, pp = pp->next) { if (pp->type != VIR_CONF_STRING) { VIR_ERROR0(_("cgroup_device_acl must be a list of strings")); virConfFree(conf); return -1; } driver->cgroupDeviceACL[i] = strdup (pp->str); if (driver->cgroupDeviceACL[i] == NULL) { virReportOOMError(); virConfFree(conf); return -1; } } driver->cgroupDeviceACL[i] = NULL; } p = virConfGetValue (conf, "save_image_format"); CHECK_TYPE ("save_image_format", VIR_CONF_STRING); if (p && p->str) { VIR_FREE(driver->saveImageFormat); if (!(driver->saveImageFormat = strdup(p->str))) { virReportOOMError(); virConfFree(conf); return -1; } } p = virConfGetValue (conf, "dump_image_format"); CHECK_TYPE ("dump_image_format", VIR_CONF_STRING); if (p && p->str) { VIR_FREE(driver->dumpImageFormat); if (!(driver->dumpImageFormat = strdup(p->str))) { virReportOOMError(); virConfFree(conf); return -1; } } p = virConfGetValue (conf, "auto_dump_path"); CHECK_TYPE ("auto_dump_path", VIR_CONF_STRING); if (p && p->str) { VIR_FREE(driver->autoDumpPath); if (!(driver->autoDumpPath = strdup(p->str))) { virReportOOMError(); virConfFree(conf); return -1; } } p = virConfGetValue (conf, "hugetlbfs_mount"); CHECK_TYPE ("hugetlbfs_mount", VIR_CONF_STRING); if (p && p->str) { VIR_FREE(driver->hugetlbfs_mount); if (!(driver->hugetlbfs_mount = strdup(p->str))) { virReportOOMError(); virConfFree(conf); return -1; } } p = virConfGetValue (conf, "mac_filter"); CHECK_TYPE ("mac_filter", VIR_CONF_LONG); if (p && p->l) { driver->macFilter = p->l; if (!(driver->ebtables = ebtablesContextNew("qemu"))) { driver->macFilter = 0; virReportSystemError(errno, _("failed to enable mac filter in '%s'"), __FILE__); } if ((errno = networkDisableAllFrames(driver))) { virReportSystemError(errno, _("failed to add rule to drop all frames in '%s'"), __FILE__); } } p = virConfGetValue (conf, "relaxed_acs_check"); CHECK_TYPE ("relaxed_acs_check", VIR_CONF_LONG); if (p) driver->relaxedACS = p->l; p = virConfGetValue (conf, "vnc_allow_host_audio"); CHECK_TYPE ("vnc_allow_host_audio", VIR_CONF_LONG); if (p) driver->vncAllowHostAudio = p->l; p = virConfGetValue (conf, "clear_emulator_capabilities"); CHECK_TYPE ("clear_emulator_capabilities", VIR_CONF_LONG); if (p) driver->clearEmulatorCapabilities = p->l; p = virConfGetValue (conf, "allow_disk_format_probing"); CHECK_TYPE ("allow_disk_format_probing", VIR_CONF_LONG); if (p) driver->allowDiskFormatProbing = p->l; p = virConfGetValue (conf, "set_process_name"); CHECK_TYPE ("set_process_name", VIR_CONF_LONG); if (p) driver->setProcessName = p->l; p = virConfGetValue(conf, "max_processes"); CHECK_TYPE("max_processes", VIR_CONF_LONG); if (p) driver->maxProcesses = p->l; virConfFree (conf); return 0; }
int virNetSocketNewListenTCP(const char *nodename, const char *service, virNetSocketPtr **retsocks, size_t *nretsocks) { virNetSocketPtr *socks = NULL; size_t nsocks = 0; struct addrinfo *ai = NULL; struct addrinfo hints; int fd = -1; int i; int addrInUse = false; *retsocks = NULL; *nretsocks = 0; memset(&hints, 0, sizeof hints); hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; hints.ai_socktype = SOCK_STREAM; int e = getaddrinfo(nodename, service, &hints, &ai); if (e != 0) { virNetError(VIR_ERR_SYSTEM_ERROR, _("Unable to resolve address '%s' service '%s': %s"), nodename, service, gai_strerror(e)); return -1; } struct addrinfo *runp = ai; while (runp) { virSocketAddr addr; memset(&addr, 0, sizeof(addr)); if ((fd = socket(runp->ai_family, runp->ai_socktype, runp->ai_protocol)) < 0) { virReportSystemError(errno, "%s", _("Unable to create socket")); goto error; } int opt = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof opt) < 0) { virReportSystemError(errno, "%s", _("Unable to enable port reuse")); goto error; } #ifdef IPV6_V6ONLY if (runp->ai_family == PF_INET6) { int on = 1; /* * Normally on Linux an INET6 socket will bind to the INET4 * address too. If getaddrinfo returns results with INET4 * first though, this will result in INET6 binding failing. * We can trivially cope with multiple server sockets, so * we force it to only listen on IPv6 */ if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&on, sizeof on) < 0) { virReportSystemError(errno, "%s", _("Unable to force bind to IPv6 only")); goto error; } } #endif if (bind(fd, runp->ai_addr, runp->ai_addrlen) < 0) { if (errno != EADDRINUSE) { virReportSystemError(errno, "%s", _("Unable to bind to port")); goto error; } addrInUse = true; VIR_FORCE_CLOSE(fd); runp = runp->ai_next; continue; } addr.len = sizeof(addr.data); if (getsockname(fd, &addr.data.sa, &addr.len) < 0) { virReportSystemError(errno, "%s", _("Unable to get local socket name")); goto error; } VIR_DEBUG("%p f=%d f=%d", &addr, runp->ai_family, addr.data.sa.sa_family); if (VIR_EXPAND_N(socks, nsocks, 1) < 0) { virReportOOMError(); goto error; } if (!(socks[nsocks-1] = virNetSocketNew(&addr, NULL, false, fd, -1, 0))) goto error; runp = runp->ai_next; fd = -1; } if (nsocks == 0 && addrInUse) { virReportSystemError(EADDRINUSE, "%s", _("Unable to bind to port")); goto error; } freeaddrinfo(ai); *retsocks = socks; *nretsocks = nsocks; return 0; error: for (i = 0 ; i < nsocks ; i++) virNetSocketFree(socks[i]); VIR_FREE(socks); freeaddrinfo(ai); VIR_FORCE_CLOSE(fd); return -1; }
int linuxNodeInfoCPUPopulate(FILE *cpuinfo, const char *sysfs_dir, virNodeInfoPtr nodeinfo) { char line[1024]; DIR *nodedir = NULL; struct dirent *nodedirent = NULL; int cpus, cores, socks, threads, offline = 0; unsigned int node; int ret = -1; char *sysfs_nodedir = NULL; char *sysfs_cpudir = NULL; /* Start with parsing CPU clock speed from /proc/cpuinfo */ while (fgets(line, sizeof(line), cpuinfo) != NULL) { # if defined(__x86_64__) || \ defined(__amd64__) || \ defined(__i386__) char *buf = line; if (STRPREFIX(buf, "cpu MHz")) { char *p; unsigned int ui; buf += 7; while (*buf && c_isspace(*buf)) buf++; if (*buf != ':' || !buf[1]) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("parsing cpu MHz from cpuinfo")); goto cleanup; } if (virStrToLong_ui(buf+1, &p, 10, &ui) == 0 && /* Accept trailing fractional part. */ (*p == '\0' || *p == '.' || c_isspace(*p))) nodeinfo->mhz = ui; } # elif defined(__powerpc__) || \ defined(__powerpc64__) char *buf = line; if (STRPREFIX(buf, "clock")) { char *p; unsigned int ui; buf += 5; while (*buf && c_isspace(*buf)) buf++; if (*buf != ':' || !buf[1]) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("parsing cpu MHz from cpuinfo")); goto cleanup; } if (virStrToLong_ui(buf+1, &p, 10, &ui) == 0 && /* Accept trailing fractional part. */ (*p == '\0' || *p == '.' || c_isspace(*p))) nodeinfo->mhz = ui; /* No other interesting infos are available in /proc/cpuinfo. * However, there is a line identifying processor's version, * identification and machine, but we don't want it to be caught * and parsed in next iteration, because it is not in expected * format and thus lead to error. */ } # elif defined(__arm__) char *buf = line; if (STRPREFIX(buf, "BogoMIPS")) { char *p; unsigned int ui; buf += 8; while (*buf && c_isspace(*buf)) buf++; if (*buf != ':' || !buf[1]) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("parsing cpu MHz from cpuinfo")); goto cleanup; } if (virStrToLong_ui(buf+1, &p, 10, &ui) == 0 /* Accept trailing fractional part. */ && (*p == '\0' || *p == '.' || c_isspace(*p))) nodeinfo->mhz = ui; } # elif defined(__s390__) || \ defined(__s390x__) /* s390x has no realistic value for CPU speed, * assign a value of zero to signify this */ nodeinfo->mhz = 0; # else # warning Parser for /proc/cpuinfo needs to be adapted for your architecture # endif } /* OK, we've parsed clock speed out of /proc/cpuinfo. Get the * core, node, socket, thread and topology information from /sys */ if (virAsprintf(&sysfs_nodedir, "%s/node", sysfs_dir) < 0) goto cleanup; if (!(nodedir = opendir(sysfs_nodedir))) { /* the host isn't probably running a NUMA architecture */ goto fallback; } errno = 0; while ((nodedirent = readdir(nodedir))) { if (sscanf(nodedirent->d_name, "node%u", &node) != 1) continue; nodeinfo->nodes++; if (virAsprintf(&sysfs_cpudir, "%s/node/%s", sysfs_dir, nodedirent->d_name) < 0) goto cleanup; if ((cpus = virNodeParseNode(sysfs_cpudir, &socks, &cores, &threads, &offline)) < 0) goto cleanup; VIR_FREE(sysfs_cpudir); nodeinfo->cpus += cpus; if (socks > nodeinfo->sockets) nodeinfo->sockets = socks; if (cores > nodeinfo->cores) nodeinfo->cores = cores; if (threads > nodeinfo->threads) nodeinfo->threads = threads; errno = 0; } if (errno) { virReportSystemError(errno, _("problem reading %s"), sysfs_nodedir); goto cleanup; } if (nodeinfo->cpus && nodeinfo->nodes) goto done; fallback: VIR_FREE(sysfs_cpudir); if (virAsprintf(&sysfs_cpudir, "%s/cpu", sysfs_dir) < 0) goto cleanup; if ((cpus = virNodeParseNode(sysfs_cpudir, &socks, &cores, &threads, &offline)) < 0) goto cleanup; nodeinfo->nodes = 1; nodeinfo->cpus = cpus; nodeinfo->sockets = socks; nodeinfo->cores = cores; nodeinfo->threads = threads; done: /* There should always be at least one cpu, socket, node, and thread. */ if (nodeinfo->cpus == 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("no CPUs found")); goto cleanup; } if (nodeinfo->sockets == 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("no sockets found")); goto cleanup; } if (nodeinfo->threads == 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("no threads found")); goto cleanup; } /* Now check if the topology makes sense. There are machines that don't * expose their real number of nodes or for example the AMD Bulldozer * architecture that exposes their Clustered integer core modules as both * threads and cores. This approach throws off our detection. Unfortunately * the nodeinfo structure isn't designed to carry the full topology so * we're going to lie about the detected topology to notify the user * to check the host capabilities for the actual topology. */ if ((nodeinfo->nodes * nodeinfo->sockets * nodeinfo->cores * nodeinfo->threads) != (nodeinfo->cpus + offline)) { nodeinfo->nodes = 1; nodeinfo->sockets = 1; nodeinfo->cores = nodeinfo->cpus + offline; nodeinfo->threads = 1; } ret = 0; cleanup: /* don't shadow a more serious error */ if (nodedir && closedir(nodedir) < 0 && ret >= 0) { virReportSystemError(errno, _("problem closing %s"), sysfs_nodedir); ret = -1; } VIR_FREE(sysfs_nodedir); VIR_FREE(sysfs_cpudir); return ret; }
static int virLockManagerSanlockCreateLease(struct sanlk_resource *res) { int fd = -1; struct stat st; int rv; if (stat(res->disks[0].path, &st) < 0) { VIR_DEBUG("Lockspace %s does not yet exist", res->disks[0].path); if ((fd = open(res->disks[0].path, O_WRONLY|O_CREAT|O_EXCL, 0600)) < 0) { if (errno != EEXIST) { virReportSystemError(errno, _("Unable to create lockspace %s"), res->disks[0].path); return -1; } VIR_DEBUG("Someone else just created lockspace %s", res->disks[0].path); } else { /* chown() the path to make sure sanlock can access it */ if ((driver->user != (uid_t) -1 || driver->group != (gid_t) -1) && (fchown(fd, driver->user, driver->group) < 0)) { virReportSystemError(errno, _("cannot chown '%s' to (%u, %u)"), res->disks[0].path, (unsigned int) driver->user, (unsigned int) driver->group); goto error_unlink; } if ((rv = sanlock_align(&res->disks[0])) < 0) { if (rv <= -200) virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to query sector size %s: error %d"), res->disks[0].path, rv); else virReportSystemError(-rv, _("Unable to query sector size %s"), res->disks[0].path); goto error_unlink; } /* * Pre allocate enough data for 1 block of leases at preferred alignment */ if (safezero(fd, 0, rv) < 0) { virReportSystemError(errno, _("Unable to allocate lease %s"), res->disks[0].path); goto error_unlink; } if (VIR_CLOSE(fd) < 0) { virReportSystemError(errno, _("Unable to save lease %s"), res->disks[0].path); goto error_unlink; } if ((rv = sanlock_init(NULL, res, 0, 0)) < 0) { if (rv <= -200) virReportError(VIR_ERR_INTERNAL_ERROR, _("Unable to initialize lease %s: error %d"), res->disks[0].path, rv); else virReportSystemError(-rv, _("Unable to initialize lease %s"), res->disks[0].path); goto error_unlink; } VIR_DEBUG("Lease %s has been initialized", res->disks[0].path); } } return 0; error_unlink: unlink(res->disks[0].path); VIR_FORCE_CLOSE(fd); return -1; }