/* This method shouldn't raise errors, since they'll overwrite * errors that the caller(s) are already dealing with */ static int SELinuxRestoreSecurityFileLabel(const char *path) { struct stat buf; security_context_t fcon = NULL; int rc = -1; char *newpath = NULL; char ebuf[1024]; VIR_INFO("Restoring SELinux context on '%s'", path); if (virFileResolveLink(path, &newpath) < 0) { VIR_WARN("cannot resolve symlink %s: %s", path, virStrerror(errno, ebuf, sizeof(ebuf))); goto err; } if (stat(newpath, &buf) != 0) { VIR_WARN("cannot stat %s: %s", newpath, virStrerror(errno, ebuf, sizeof(ebuf))); goto err; } if (getContext(newpath, buf.st_mode, &fcon) < 0) { VIR_WARN("cannot lookup default selinux label for %s", newpath); } else { rc = SELinuxSetFilecon(newpath, fcon); } err: freecon(fcon); VIR_FREE(newpath); return rc; }
static void virLockSpaceResourceFree(virLockSpaceResourcePtr res) { if (!res) return; if (res->lockHeld && (res->flags & VIR_LOCK_SPACE_ACQUIRE_AUTOCREATE)) { if (res->flags & VIR_LOCK_SPACE_ACQUIRE_SHARED) { /* We must upgrade to an exclusive lock to ensure * no one else still has it before trying to delete */ if (virFileLock(res->fd, false, 0, 1) < 0) { VIR_DEBUG("Could not upgrade shared lease to exclusive, not deleting"); } else { if (unlink(res->path) < 0 && errno != ENOENT) { char ebuf[1024]; VIR_WARN("Failed to unlink resource %s: %s", res->path, virStrerror(errno, ebuf, sizeof(ebuf))); } } } else { if (unlink(res->path) < 0 && errno != ENOENT) { char ebuf[1024]; VIR_WARN("Failed to unlink resource %s: %s", res->path, virStrerror(errno, ebuf, sizeof(ebuf))); } } } VIR_FORCE_CLOSE(res->fd); VIR_FREE(res->path); VIR_FREE(res->name); VIR_FREE(res); }
int virFileClose(int *fdptr, virFileCloseFlags flags) { int saved_errno = 0; int rc = 0; if (*fdptr < 0) return 0; if (flags & VIR_FILE_CLOSE_PRESERVE_ERRNO) saved_errno = errno; rc = close(*fdptr); if (!(flags & VIR_FILE_CLOSE_DONT_LOG)) { if (rc < 0) { if (errno == EBADF) { if (!(flags & VIR_FILE_CLOSE_IGNORE_EBADF)) VIR_WARN("Tried to close invalid fd %d", *fdptr); } else { char ebuf[1024] ATTRIBUTE_UNUSED; VIR_DEBUG("Failed to close fd %d: %s", *fdptr, virStrerror(errno, ebuf, sizeof(ebuf))); } } else { VIR_DEBUG("Closed fd %d", *fdptr); } }
/* * Call after adding all arguments and environment settings, but before * Run/RunAsync, to immediately output the environment and arguments of * cmd to logfd. If virCommandRun cannot succeed (because of an * out-of-memory condition while building cmd), nothing will be logged. */ void virCommandWriteArgLog(virCommandPtr cmd, int logfd) { int ioError = 0; size_t i; /* Any errors will be reported later by virCommandRun, which means * no command will be run, so there is nothing to log. */ if (!cmd || cmd->has_error) return; for (i = 0 ; i < cmd->nenv ; i++) { if (safewrite(logfd, cmd->env[i], strlen(cmd->env[i])) < 0) ioError = errno; if (safewrite(logfd, " ", 1) < 0) ioError = errno; } for (i = 0 ; i < cmd->nargs ; i++) { if (safewrite(logfd, cmd->args[i], strlen(cmd->args[i])) < 0) ioError = errno; if (safewrite(logfd, i == cmd->nargs - 1 ? "\n" : " ", 1) < 0) ioError = errno; } if (ioError) { char ebuf[1024]; VIR_WARN("Unable to write command %s args to logfile: %s", cmd->args[0], virStrerror(ioError, ebuf, sizeof ebuf)); } }
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; }
static int pciWrite(pciDevice *dev, unsigned pos, uint8_t *buf, unsigned buflen) { if (pciOpenConfig(dev) < 0) return -1; if (lseek(dev->fd, pos, SEEK_SET) != pos || safewrite(dev->fd, buf, buflen) != buflen) { char ebuf[1024]; VIR_WARN("Failed to write to '%s' : %s", dev->path, virStrerror(errno, ebuf, sizeof(ebuf))); return -1; } return 0; }
static void lxcProcessRemoveDomainStatus(virLXCDriverConfigPtr cfg, virDomainObjPtr vm) { char ebuf[1024]; char *file = NULL; if (virAsprintf(&file, "%s/%s.xml", cfg->stateDir, vm->def->name) < 0) return; if (unlink(file) < 0 && errno != ENOENT && errno != ENOTDIR) VIR_WARN("Failed to remove domain XML for %s: %s", vm->def->name, virStrerror(errno, ebuf, sizeof(ebuf))); VIR_FREE(file); }
/** * virUUIDGenerate: * @uuid: array of VIR_UUID_BUFLEN bytes to store the new UUID * * Generates a randomized unique identifier. * * Returns 0 in case of success and -1 in case of failure */ int virUUIDGenerate(unsigned char *uuid) { int err; if (uuid == NULL) return(-1); if ((err = virUUIDGenerateRandomBytes(uuid, VIR_UUID_BUFLEN))) { char ebuf[1024]; VIR_WARN("Falling back to pseudorandom UUID," " failed to generate random bytes: %s", virStrerror(err, ebuf, sizeof ebuf)); err = virUUIDGeneratePseudoRandomBytes(uuid, VIR_UUID_BUFLEN); } return(err); }
static int pciOpenConfig(pciDevice *dev) { int fd; if (dev->fd > 0) return 0; fd = open(dev->path, O_RDWR); if (fd < 0) { char ebuf[1024]; VIR_WARN("Failed to open config space file '%s': %s", dev->path, virStrerror(errno, ebuf, sizeof(ebuf))); return -1; } VIR_DEBUG("%s %s: opened %s", dev->id, dev->name, dev->path); dev->fd = fd; return 0; }
/** * virUUIDGenerate: * @uuid: array of VIR_UUID_BUFLEN bytes to store the new UUID * * Generates a randomized unique identifier. * * Returns 0 in case of success and -1 in case of failure */ int virUUIDGenerate(unsigned char *uuid) { int err; if (uuid == NULL) return -1; if ((err = virUUIDGenerateRandomBytes(uuid, VIR_UUID_BUFLEN))) { char ebuf[1024]; VIR_WARN("Falling back to pseudorandom UUID," " failed to generate random bytes: %s", virStrerror(err, ebuf, sizeof(ebuf))); err = virUUIDGeneratePseudoRandomBytes(uuid, VIR_UUID_BUFLEN); } /* * Make UUID RFC 4122 compliant. Following form will be used: * * xxxxxxxx-xxxx-Axxx-Bxxx-xxxxxxxxxxxx * * where * A is version defined in 4.1.3 of RFC * Msb0 Msb1 Msb2 Msb3 Version Description * 0 1 0 0 4 The randomly or pseudo- * randomly generated version * specified in this document. * * B is variant defined in 4.1.1 of RFC * Msb0 Msb1 Msb2 Description * 1 0 x The variant specified in this document. */ uuid[6] = (uuid[6] & 0x0F) | (4 << 4); uuid[8] = (uuid[8] & 0x3F) | (2 << 6); return err; }
static int daemonForkIntoBackground(const char *argv0) { int statuspipe[2]; if (pipe(statuspipe) < 0) return -1; pid_t pid = fork(); switch (pid) { case 0: { /* intermediate child */ int stdinfd = -1; int stdoutfd = -1; int nextpid; VIR_FORCE_CLOSE(statuspipe[0]); if ((stdinfd = open("/dev/null", O_RDONLY)) < 0) goto cleanup; if ((stdoutfd = open("/dev/null", O_WRONLY)) < 0) goto cleanup; if (dup2(stdinfd, STDIN_FILENO) != STDIN_FILENO) goto cleanup; if (dup2(stdoutfd, STDOUT_FILENO) != STDOUT_FILENO) goto cleanup; if (dup2(stdoutfd, STDERR_FILENO) != STDERR_FILENO) goto cleanup; if (stdinfd > STDERR_FILENO && VIR_CLOSE(stdinfd) < 0) goto cleanup; if (stdoutfd > STDERR_FILENO && VIR_CLOSE(stdoutfd) < 0) goto cleanup; if (setsid() < 0) goto cleanup; nextpid = fork(); switch (nextpid) { case 0: /* grandchild */ return statuspipe[1]; case -1: /* error */ goto cleanup; default: /* intermediate child succeeded */ _exit(EXIT_SUCCESS); } cleanup: VIR_FORCE_CLOSE(stdoutfd); VIR_FORCE_CLOSE(stdinfd); VIR_FORCE_CLOSE(statuspipe[1]); _exit(EXIT_FAILURE); } case -1: /* error in parent */ goto error; default: { /* parent */ int ret; char status; VIR_FORCE_CLOSE(statuspipe[1]); /* We wait to make sure the first child forked successfully */ if (virPidWait(pid, NULL) < 0) goto error; /* If we get here, then the grandchild was spawned, so we * must exit. Block until the second child initializes * successfully */ again: ret = read(statuspipe[0], &status, 1); if (ret == -1 && errno == EINTR) goto again; VIR_FORCE_CLOSE(statuspipe[0]); if (ret != 1) { char ebuf[1024]; fprintf(stderr, _("%s: error: unable to determine if daemon is " "running: %s\n"), argv0, virStrerror(errno, ebuf, sizeof(ebuf))); exit(EXIT_FAILURE); } else if (status != 0) { fprintf(stderr, _("%s: error: %s. Check /var/log/messages or run " "without --daemon for more info.\n"), argv0, virDaemonErrTypeToString(status)); exit(EXIT_FAILURE); } _exit(EXIT_SUCCESS); } } error: VIR_FORCE_CLOSE(statuspipe[0]); VIR_FORCE_CLOSE(statuspipe[1]); return -1; }
/** * virLXCProcessStart: * @conn: pointer to connection * @driver: pointer to driver structure * @vm: pointer to virtual machine structure * @autoDestroy: mark the domain for auto destruction * @reason: reason for switching vm to running state * * Starts a vm * * Returns 0 on success or -1 in case of error */ int virLXCProcessStart(virConnectPtr conn, virLXCDriverPtr driver, virDomainObjPtr vm, unsigned int nfiles, int *files, bool autoDestroy, virDomainRunningReason reason) { int rc = -1, r; size_t nttyFDs = 0; int *ttyFDs = NULL; size_t i; char *logfile = NULL; int logfd = -1; size_t nveths = 0; char **veths = NULL; int handshakefds[2] = { -1, -1 }; off_t pos = -1; char ebuf[1024]; char *timestamp; virCommandPtr cmd = NULL; virLXCDomainObjPrivatePtr priv = vm->privateData; virCapsPtr caps = NULL; virErrorPtr err = NULL; virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver); virCgroupPtr selfcgroup; int status; if (virCgroupNewSelf(&selfcgroup) < 0) return -1; if (!virCgroupHasController(selfcgroup, VIR_CGROUP_CONTROLLER_CPUACCT)) { virCgroupFree(&selfcgroup); virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unable to find 'cpuacct' cgroups controller mount")); return -1; } if (!virCgroupHasController(selfcgroup, VIR_CGROUP_CONTROLLER_DEVICES)) { virCgroupFree(&selfcgroup); virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unable to find 'devices' cgroups controller mount")); return -1; } if (!virCgroupHasController(selfcgroup, VIR_CGROUP_CONTROLLER_MEMORY)) { virCgroupFree(&selfcgroup); virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unable to find 'memory' cgroups controller mount")); return -1; } virCgroupFree(&selfcgroup); if (virFileMakePath(cfg->logDir) < 0) { virReportSystemError(errno, _("Cannot create log directory '%s'"), cfg->logDir); return -1; } if (!vm->def->resource) { virDomainResourceDefPtr res; if (VIR_ALLOC(res) < 0) goto cleanup; if (VIR_STRDUP(res->partition, "/machine") < 0) { VIR_FREE(res); goto cleanup; } vm->def->resource = res; } if (virAsprintf(&logfile, "%s/%s.log", cfg->logDir, vm->def->name) < 0) return -1; if (!(caps = virLXCDriverGetCapabilities(driver, false))) goto cleanup; /* Do this up front, so any part of the startup process can add * runtime state to vm->def that won't be persisted. This let's us * report implicit runtime defaults in the XML, like vnc listen/socket */ VIR_DEBUG("Setting current domain def as transient"); if (virDomainObjSetDefTransient(caps, driver->xmlopt, vm, true) < 0) goto cleanup; /* Run an early hook to set-up missing devices */ if (virHookPresent(VIR_HOOK_DRIVER_LXC)) { char *xml = virDomainDefFormat(vm->def, 0); int hookret; hookret = virHookCall(VIR_HOOK_DRIVER_LXC, vm->def->name, VIR_HOOK_LXC_OP_PREPARE, VIR_HOOK_SUBOP_BEGIN, NULL, xml, NULL); VIR_FREE(xml); /* * If the script raised an error abort the launch */ if (hookret < 0) goto cleanup; } if (virLXCProcessEnsureRootFS(vm) < 0) goto cleanup; /* Must be run before security labelling */ VIR_DEBUG("Preparing host devices"); if (virLXCPrepareHostDevices(driver, vm->def) < 0) goto cleanup; /* Here we open all the PTYs we need on the host OS side. * The LXC controller will open the guest OS side PTYs * and forward I/O between them. */ nttyFDs = vm->def->nconsoles; if (VIR_ALLOC_N(ttyFDs, nttyFDs) < 0) goto cleanup; for (i = 0; i < vm->def->nconsoles; i++) ttyFDs[i] = -1; /* If you are using a SecurityDriver with dynamic labelling, then generate a security label for isolation */ VIR_DEBUG("Generating domain security label (if required)"); if (vm->def->nseclabels && vm->def->seclabels[0]->type == VIR_DOMAIN_SECLABEL_DEFAULT) vm->def->seclabels[0]->type = VIR_DOMAIN_SECLABEL_NONE; if (virSecurityManagerGenLabel(driver->securityManager, vm->def) < 0) { virDomainAuditSecurityLabel(vm, false); goto cleanup; } virDomainAuditSecurityLabel(vm, true); VIR_DEBUG("Setting domain security labels"); if (virSecurityManagerSetAllLabel(driver->securityManager, vm->def, NULL) < 0) goto cleanup; for (i = 0; i < vm->def->nconsoles; i++) { char *ttyPath; if (vm->def->consoles[i]->source.type != VIR_DOMAIN_CHR_TYPE_PTY) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("Only PTY console types are supported")); goto cleanup; } if (virFileOpenTty(&ttyFDs[i], &ttyPath, 1) < 0) { virReportSystemError(errno, "%s", _("Failed to allocate tty")); goto cleanup; } VIR_FREE(vm->def->consoles[i]->source.data.file.path); vm->def->consoles[i]->source.data.file.path = ttyPath; VIR_FREE(vm->def->consoles[i]->info.alias); if (virAsprintf(&vm->def->consoles[i]->info.alias, "console%zu", i) < 0) goto cleanup; } if (virLXCProcessSetupInterfaces(conn, vm->def, &nveths, &veths) < 0) goto cleanup; /* Save the configuration for the controller */ if (virDomainSaveConfig(cfg->stateDir, vm->def) < 0) goto cleanup; if ((logfd = open(logfile, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR|S_IWUSR)) < 0) { virReportSystemError(errno, _("Failed to open '%s'"), logfile); goto cleanup; } if (pipe(handshakefds) < 0) { virReportSystemError(errno, "%s", _("Unable to create pipe")); goto cleanup; } if (!(cmd = virLXCProcessBuildControllerCmd(driver, vm, nveths, veths, ttyFDs, nttyFDs, files, nfiles, handshakefds[1]))) goto cleanup; virCommandSetOutputFD(cmd, &logfd); virCommandSetErrorFD(cmd, &logfd); /* now that we know it is about to start call the hook if present */ if (virHookPresent(VIR_HOOK_DRIVER_LXC)) { char *xml = virDomainDefFormat(vm->def, 0); int hookret; hookret = virHookCall(VIR_HOOK_DRIVER_LXC, vm->def->name, VIR_HOOK_LXC_OP_START, VIR_HOOK_SUBOP_BEGIN, NULL, xml, NULL); VIR_FREE(xml); /* * If the script raised an error abort the launch */ if (hookret < 0) goto cleanup; } /* Log timestamp */ if ((timestamp = virTimeStringNow()) == NULL) goto cleanup; if (safewrite(logfd, timestamp, strlen(timestamp)) < 0 || safewrite(logfd, START_POSTFIX, strlen(START_POSTFIX)) < 0) { VIR_WARN("Unable to write timestamp to logfile: %s", virStrerror(errno, ebuf, sizeof(ebuf))); } VIR_FREE(timestamp); /* Log generated command line */ virCommandWriteArgLog(cmd, logfd); if ((pos = lseek(logfd, 0, SEEK_END)) < 0) VIR_WARN("Unable to seek to end of logfile: %s", virStrerror(errno, ebuf, sizeof(ebuf))); virCommandRawStatus(cmd); if (virCommandRun(cmd, &status) < 0) goto cleanup; if (status != 0) { if (virLXCProcessReadLogOutput(vm, logfile, pos, ebuf, sizeof(ebuf)) <= 0) { if (WIFEXITED(status)) snprintf(ebuf, sizeof(ebuf), _("unexpected exit status %d"), WEXITSTATUS(status)); else snprintf(ebuf, sizeof(ebuf), "%s", _("terminated abnormally")); } virReportError(VIR_ERR_INTERNAL_ERROR, _("guest failed to start: %s"), ebuf); goto cleanup; } if (VIR_CLOSE(handshakefds[1]) < 0) { virReportSystemError(errno, "%s", _("could not close handshake fd")); goto cleanup; } /* Connect to the controller as a client *first* because * this will block until the child has written their * pid file out to disk & created their cgroup */ if (!(priv->monitor = virLXCProcessConnectMonitor(driver, vm))) { /* Intentionally overwrite the real monitor error message, * since a better one is almost always found in the logs */ if (virLXCProcessReadLogOutput(vm, logfile, pos, ebuf, sizeof(ebuf)) > 0) { virResetLastError(); virReportError(VIR_ERR_INTERNAL_ERROR, _("guest failed to start: %s"), ebuf); } goto cleanup; } /* And get its pid */ if ((r = virPidFileRead(cfg->stateDir, vm->def->name, &vm->pid)) < 0) { if (virLXCProcessReadLogOutput(vm, logfile, pos, ebuf, sizeof(ebuf)) > 0) virReportError(VIR_ERR_INTERNAL_ERROR, _("guest failed to start: %s"), ebuf); else virReportSystemError(-r, _("Failed to read pid file %s/%s.pid"), cfg->stateDir, vm->def->name); goto cleanup; } if (virCgroupNewDetectMachine(vm->def->name, "lxc", vm->pid, vm->def->resource ? vm->def->resource->partition : NULL, -1, &priv->cgroup) < 0) goto error; if (!priv->cgroup) { virReportError(VIR_ERR_INTERNAL_ERROR, _("No valid cgroup for machine %s"), vm->def->name); goto error; } priv->stopReason = VIR_DOMAIN_EVENT_STOPPED_FAILED; priv->wantReboot = false; vm->def->id = vm->pid; virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, reason); priv->doneStopEvent = false; if (virAtomicIntInc(&driver->nactive) == 1 && driver->inhibitCallback) driver->inhibitCallback(true, driver->inhibitOpaque); if (lxcContainerWaitForContinue(handshakefds[0]) < 0) { char out[1024]; if (!(virLXCProcessReadLogOutput(vm, logfile, pos, out, 1024) < 0)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("guest failed to start: %s"), out); } goto error; } if (autoDestroy && virCloseCallbacksSet(driver->closeCallbacks, vm, conn, lxcProcessAutoDestroy) < 0) goto error; if (virDomainObjSetDefTransient(caps, driver->xmlopt, vm, false) < 0) goto error; /* Write domain status to disk. * * XXX: Earlier we wrote the plain "live" domain XML to this * location for the benefit of libvirt_lxc. We're now overwriting * it with the live status XML instead. This is a (currently * harmless) inconsistency we should fix one day */ if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0) goto error; /* finally we can call the 'started' hook script if any */ if (virHookPresent(VIR_HOOK_DRIVER_LXC)) { char *xml = virDomainDefFormat(vm->def, 0); int hookret; hookret = virHookCall(VIR_HOOK_DRIVER_LXC, vm->def->name, VIR_HOOK_LXC_OP_STARTED, VIR_HOOK_SUBOP_BEGIN, NULL, xml, NULL); VIR_FREE(xml); /* * If the script raised an error abort the launch */ if (hookret < 0) goto error; } rc = 0; cleanup: if (rc != 0 && !err) err = virSaveLastError(); virCommandFree(cmd); if (VIR_CLOSE(logfd) < 0) { virReportSystemError(errno, "%s", _("could not close logfile")); rc = -1; } for (i = 0; i < nveths; i++) { if (rc != 0 && veths[i]) ignore_value(virNetDevVethDelete(veths[i])); VIR_FREE(veths[i]); } if (rc != 0) { if (vm->newDef) { virDomainDefFree(vm->newDef); vm->newDef = NULL; } if (priv->monitor) { virObjectUnref(priv->monitor); priv->monitor = NULL; } virDomainConfVMNWFilterTeardown(vm); virSecurityManagerRestoreAllLabel(driver->securityManager, vm->def, false); virSecurityManagerReleaseLabel(driver->securityManager, vm->def); /* Clear out dynamically assigned labels */ if (vm->def->nseclabels && vm->def->seclabels[0]->type == VIR_DOMAIN_SECLABEL_DYNAMIC) { VIR_FREE(vm->def->seclabels[0]->model); VIR_FREE(vm->def->seclabels[0]->label); VIR_FREE(vm->def->seclabels[0]->imagelabel); } } for (i = 0; i < nttyFDs; i++) VIR_FORCE_CLOSE(ttyFDs[i]); VIR_FREE(ttyFDs); VIR_FORCE_CLOSE(handshakefds[0]); VIR_FORCE_CLOSE(handshakefds[1]); VIR_FREE(logfile); virObjectUnref(cfg); virObjectUnref(caps); if (err) { virSetError(err); virFreeError(err); } return rc; error: err = virSaveLastError(); virLXCProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED); goto cleanup; }
libxlDriverConfigPtr libxlDriverConfigNew(void) { libxlDriverConfigPtr cfg; char *log_file = NULL; char ebuf[1024]; unsigned int free_mem; if (libxlConfigInitialize() < 0) return NULL; if (!(cfg = virObjectNew(libxlDriverConfigClass))) return NULL; if (VIR_STRDUP(cfg->configDir, LIBXL_CONFIG_DIR) < 0) goto error; if (VIR_STRDUP(cfg->autostartDir, LIBXL_AUTOSTART_DIR) < 0) goto error; if (VIR_STRDUP(cfg->logDir, LIBXL_LOG_DIR) < 0) goto error; if (VIR_STRDUP(cfg->stateDir, LIBXL_STATE_DIR) < 0) goto error; if (VIR_STRDUP(cfg->libDir, LIBXL_LIB_DIR) < 0) goto error; if (VIR_STRDUP(cfg->saveDir, LIBXL_SAVE_DIR) < 0) goto error; if (VIR_STRDUP(cfg->autoDumpDir, LIBXL_DUMP_DIR) < 0) goto error; if (virAsprintf(&log_file, "%s/libxl-driver.log", cfg->logDir) < 0) goto error; if (virFileMakePath(cfg->logDir) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("failed to create log dir '%s': %s"), cfg->logDir, virStrerror(errno, ebuf, sizeof(ebuf))); goto error; } if ((cfg->logger_file = fopen(log_file, "a")) == NULL) { VIR_ERROR(_("Failed to create log file '%s': %s"), log_file, virStrerror(errno, ebuf, sizeof(ebuf))); goto error; } VIR_FREE(log_file); cfg->logger = (xentoollog_logger *)xtl_createlogger_stdiostream(cfg->logger_file, XTL_DEBUG, 0); if (!cfg->logger) { VIR_ERROR(_("cannot create logger for libxenlight, disabling driver")); goto error; } if (libxl_ctx_alloc(&cfg->ctx, LIBXL_VERSION, 0, cfg->logger)) { VIR_ERROR(_("cannot initialize libxenlight context, probably not " "running in a Xen Dom0, disabling driver")); goto error; } if ((cfg->verInfo = libxl_get_version_info(cfg->ctx)) == NULL) { VIR_ERROR(_("cannot version information from libxenlight, " "disabling driver")); goto error; } cfg->version = (cfg->verInfo->xen_version_major * 1000000) + (cfg->verInfo->xen_version_minor * 1000); /* This will fill xenstore info about free and dom0 memory if missing, * should be called before starting first domain */ if (libxl_get_free_memory(cfg->ctx, &free_mem)) { VIR_ERROR(_("Unable to configure libxl's memory management parameters")); goto error; } /* setup autoballoon */ if (libxlGetAutoballoonConf(cfg, &cfg->autoballoon) < 0) goto error; return cfg; error: VIR_FREE(log_file); virObjectUnref(cfg); return NULL; }
int virPolkitCheckAuth(const char *actionid, pid_t pid, unsigned long long startTime ATTRIBUTE_UNUSED, uid_t uid, const char **details, bool allowInteraction ATTRIBUTE_UNUSED) { PolKitCaller *pkcaller = NULL; PolKitAction *pkaction = NULL; PolKitContext *pkcontext = NULL; PolKitError *pkerr = NULL; PolKitResult pkresult; DBusError err; DBusConnection *sysbus; int ret = -1; if (details) { virReportError(VIR_ERR_AUTH_FAILED, "%s", _("Details not supported with polkit v0")); return -1; } if (!(sysbus = virDBusGetSystemBus())) goto cleanup; VIR_INFO("Checking PID %lld running as %d", (long long) pid, uid); dbus_error_init(&err); if (!(pkcaller = polkit_caller_new_from_pid(sysbus, pid, &err))) { VIR_DEBUG("Failed to lookup policy kit caller: %s", err.message); dbus_error_free(&err); goto cleanup; } if (!(pkaction = polkit_action_new())) { char ebuf[1024]; VIR_DEBUG("Failed to create polkit action %s", virStrerror(errno, ebuf, sizeof(ebuf))); goto cleanup; } polkit_action_set_action_id(pkaction, actionid); if (!(pkcontext = polkit_context_new()) || !polkit_context_init(pkcontext, &pkerr)) { char ebuf[1024]; VIR_DEBUG("Failed to create polkit context %s", (pkerr ? polkit_error_get_error_message(pkerr) : virStrerror(errno, ebuf, sizeof(ebuf)))); if (pkerr) polkit_error_free(pkerr); dbus_error_free(&err); goto cleanup; } # if HAVE_POLKIT_CONTEXT_IS_CALLER_AUTHORIZED pkresult = polkit_context_is_caller_authorized(pkcontext, pkaction, pkcaller, 0, &pkerr); if (pkerr && polkit_error_is_set(pkerr)) { VIR_DEBUG("Policy kit failed to check authorization %d %s", polkit_error_get_error_code(pkerr), polkit_error_get_error_message(pkerr)); goto cleanup; } # else pkresult = polkit_context_can_caller_do_action(pkcontext, pkaction, pkcaller); # endif if (pkresult != POLKIT_RESULT_YES) { VIR_DEBUG("Policy kit denied action %s from pid %lld, uid %d, result: %s", actionid, (long long) pid, uid, polkit_result_to_string_representation(pkresult)); ret = -2; goto cleanup; } VIR_DEBUG("Policy allowed action %s from pid %lld, uid %d", actionid, (long long)pid, (int)uid); ret = 0; cleanup: if (ret < 0) { virResetLastError(); virReportError(VIR_ERR_AUTH_FAILED, "%s", _("authentication failed")); } if (pkcontext) polkit_context_unref(pkcontext); if (pkcaller) polkit_caller_unref(pkcaller); if (pkaction) polkit_action_unref(pkaction); return ret; }
int virPidFileAcquirePath(const char *path, pid_t pid) { int fd = -1; char pidstr[INT_BUFSIZE_BOUND(pid)]; if (path[0] == '\0') return 0; while (1) { struct stat a, b; if ((fd = open(path, O_WRONLY|O_CREAT, 0644)) < 0) { virReportSystemError(errno, _("Failed to open pid file '%s'"), path); return -1; } if (virSetCloseExec(fd) < 0) { virReportSystemError(errno, _("Failed to set close-on-exec flag '%s'"), path); VIR_FORCE_CLOSE(fd); return -1; } if (fstat(fd, &b) < 0) { virReportSystemError(errno, _("Unable to check status of pid file '%s'"), path); VIR_FORCE_CLOSE(fd); return -1; } if (virFileLock(fd, false, 0, 1) < 0) { virReportSystemError(errno, _("Failed to acquire pid file '%s'"), path); VIR_FORCE_CLOSE(fd); return -1; } /* Now make sure the pidfile we locked is the same * one that now exists on the filesystem */ if (stat(path, &a) < 0) { char ebuf[1024] ATTRIBUTE_UNUSED; VIR_DEBUG("Pid file '%s' disappeared: %s", path, virStrerror(errno, ebuf, sizeof(ebuf))); VIR_FORCE_CLOSE(fd); /* Someone else must be racing with us, so try agin */ continue; } if (a.st_ino == b.st_ino) break; VIR_DEBUG("Pid file '%s' was recreated", path); VIR_FORCE_CLOSE(fd); /* Someone else must be racing with us, so try agin */ }
static int virStorageBackendIQNFound(virStoragePoolObjPtr pool, char **ifacename) { int ret = IQN_MISSING, fd = -1; char ebuf[64]; FILE *fp = NULL; pid_t child = 0; char *line = NULL, *newline = NULL, *iqn = NULL, *token = NULL, *saveptr = NULL; const char *const prog[] = { ISCSIADM, "--mode", "iface", NULL }; if (VIR_ALLOC_N(line, LINE_SIZE) != 0) { ret = IQN_ERROR; virStorageReportError(VIR_ERR_INTERNAL_ERROR, _("Could not allocate memory for output of '%s'"), prog[0]); goto out; } memset(line, 0, LINE_SIZE); if (virExec(prog, NULL, NULL, &child, -1, &fd, NULL, VIR_EXEC_NONE) < 0) { virStorageReportError(VIR_ERR_INTERNAL_ERROR, _("Failed to run '%s' when looking for existing interface with IQN '%s'"), prog[0], pool->def->source.initiator.iqn); ret = IQN_ERROR; goto out; } if ((fp = fdopen(fd, "r")) == NULL) { virStorageReportError(VIR_ERR_INTERNAL_ERROR, _("Failed to open stream for file descriptor " "when reading output from '%s': '%s'"), prog[0], virStrerror(errno, ebuf, sizeof ebuf)); ret = IQN_ERROR; goto out; } while (fgets(line, LINE_SIZE, fp) != NULL) { newline = strrchr(line, '\n'); if (newline == NULL) { ret = IQN_ERROR; virStorageReportError(VIR_ERR_INTERNAL_ERROR, _("Unexpected line > %d characters " "when parsing output of '%s'"), LINE_SIZE, prog[0]); goto out; } *newline = '\0'; iqn = strrchr(line, ','); if (iqn == NULL) { continue; } iqn++; if (STREQ(iqn, pool->def->source.initiator.iqn)) { token = strtok_r(line, " ", &saveptr); *ifacename = strdup(token); if (*ifacename == NULL) { ret = IQN_ERROR; virReportOOMError(); goto out; } VIR_DEBUG("Found interface '%s' with IQN '%s'", *ifacename, iqn); ret = IQN_FOUND; break; } } out: if (ret == IQN_MISSING) { VIR_DEBUG("Could not find interface witn IQN '%s'", iqn); } VIR_FREE(line); if (fp != NULL) { fclose(fp); } else { if (fd != -1) { close(fd); } } return ret; }
static int qemuCapsInitGuest(virCapsPtr caps, virCapsPtr old_caps, const char *hostmachine, const struct qemu_arch_info *info, int hvm) { virCapsGuestPtr guest; int i; int haskvm = 0; int haskqemu = 0; char *kvmbin = NULL; char *binary = NULL; time_t binary_mtime; virCapsGuestMachinePtr *machines = NULL; int nmachines = 0; struct stat st; unsigned int ncpus; virBitmapPtr qemuCaps = NULL; int ret = -1; /* Check for existance of base emulator, or alternate base * which can be used with magic cpu choice */ binary = virFindFileInPath(info->binary); if (binary == NULL || !virFileIsExecutable(binary)) { VIR_FREE(binary); binary = virFindFileInPath(info->altbinary); } /* Can use acceleration for KVM/KQEMU if * - host & guest arches match * Or * - hostarch is x86_64 and guest arch is i686 * The latter simply needs "-cpu qemu32" */ if (STREQ(info->arch, hostmachine) || (STREQ(hostmachine, "x86_64") && STREQ(info->arch, "i686"))) { if (access("/dev/kvm", F_OK) == 0) { const char *const kvmbins[] = { "/usr/libexec/qemu-kvm", /* RHEL */ "qemu-kvm", /* Fedora */ "kvm" }; /* Upstream .spec */ for (i = 0; i < ARRAY_CARDINALITY(kvmbins); ++i) { kvmbin = virFindFileInPath(kvmbins[i]); if (!kvmbin) continue; haskvm = 1; if (!binary) binary = kvmbin; break; } } if (access("/dev/kqemu", F_OK) == 0) haskqemu = 1; } if (!binary) return 0; /* Ignore binary if extracting version info fails */ if (qemuCapsExtractVersionInfo(binary, info->arch, NULL, &qemuCaps) < 0) { ret = 0; goto cleanup; } if (stat(binary, &st) == 0) { binary_mtime = st.st_mtime; } else { char ebuf[1024]; VIR_WARN("Failed to stat %s, most peculiar : %s", binary, virStrerror(errno, ebuf, sizeof(ebuf))); binary_mtime = 0; } if (info->machine) { virCapsGuestMachinePtr machine; if (VIR_ALLOC(machine) < 0) { goto no_memory; } if (!(machine->name = strdup(info->machine))) { VIR_FREE(machine); goto no_memory; } nmachines = 1; if (VIR_ALLOC_N(machines, nmachines) < 0) { VIR_FREE(machine->name); VIR_FREE(machine); goto no_memory; } machines[0] = machine; } else { int probe = 1; if (old_caps && binary_mtime) probe = !qemuCapsGetOldMachines(hvm ? "hvm" : "xen", info->arch, info->wordsize, binary, binary_mtime, old_caps, &machines, &nmachines); if (probe && qemuCapsProbeMachineTypes(binary, &machines, &nmachines) < 0) goto error; } /* We register kvm as the base emulator too, since we can * just give -no-kvm to disable acceleration if required */ if ((guest = virCapabilitiesAddGuest(caps, hvm ? "hvm" : "xen", info->arch, info->wordsize, binary, NULL, nmachines, machines)) == NULL) goto error; machines = NULL; nmachines = 0; guest->arch.defaultInfo.emulator_mtime = binary_mtime; if (caps->host.cpu && qemuCapsProbeCPUModels(binary, NULL, info->arch, &ncpus, NULL) == 0 && ncpus > 0 && !virCapabilitiesAddGuestFeature(guest, "cpuselection", 1, 0)) goto error; if (qemuCapsGet(qemuCaps, QEMU_CAPS_BOOTINDEX) && !virCapabilitiesAddGuestFeature(guest, "deviceboot", 1, 0)) goto error; if (hvm) { if (virCapabilitiesAddGuestDomain(guest, "qemu", NULL, NULL, 0, NULL) == NULL) goto error; if (haskqemu && virCapabilitiesAddGuestDomain(guest, "kqemu", NULL, NULL, 0, NULL) == NULL) goto error; if (haskvm) { virCapsGuestDomainPtr dom; if (stat(kvmbin, &st) == 0) { binary_mtime = st.st_mtime; } else { char ebuf[1024]; VIR_WARN("Failed to stat %s, most peculiar : %s", binary, virStrerror(errno, ebuf, sizeof(ebuf))); binary_mtime = 0; } if (!STREQ(binary, kvmbin)) { int probe = 1; if (old_caps && binary_mtime) probe = !qemuCapsGetOldMachines("hvm", info->arch, info->wordsize, kvmbin, binary_mtime, old_caps, &machines, &nmachines); if (probe && qemuCapsProbeMachineTypes(kvmbin, &machines, &nmachines) < 0) goto error; } if ((dom = virCapabilitiesAddGuestDomain(guest, "kvm", kvmbin, NULL, nmachines, machines)) == NULL) { goto error; } machines = NULL; nmachines = 0; dom->info.emulator_mtime = binary_mtime; } } else { if (virCapabilitiesAddGuestDomain(guest, "kvm", NULL, NULL, 0, NULL) == NULL) goto error; } if (info->nflags) { for (i = 0 ; i < info->nflags ; i++) { if (virCapabilitiesAddGuestFeature(guest, info->flags[i].name, info->flags[i].default_on, info->flags[i].toggle) == NULL) goto error; } } ret = 0; cleanup: if (binary == kvmbin) { /* don't double free */ VIR_FREE(binary); } else { VIR_FREE(binary); VIR_FREE(kvmbin); } qemuCapsFree(qemuCaps); return ret; no_memory: virReportOOMError(); error: virCapabilitiesFreeMachines(machines, nmachines); goto cleanup; }
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 {
/** * qemuCreateInBridgePortWithHelper: * @cfg: the configuration object in which the helper name is looked up * @brname: the bridge name * @ifname: the returned interface name * @macaddr: the returned MAC address * @tapfd: file descriptor return value for the new tap device * @flags: OR of virNetDevTapCreateFlags: * VIR_NETDEV_TAP_CREATE_VNET_HDR * - Enable IFF_VNET_HDR on the tap device * * This function creates a new tap device on a bridge using an external * helper. The final name for the bridge will be stored in @ifname. * * Returns 0 in case of success or -1 on failure */ static int qemuCreateInBridgePortWithHelper(virQEMUDriverConfigPtr cfg, const char *brname, char **ifname, int *tapfd, unsigned int flags) { virCommandPtr cmd; char *errbuf = NULL, *cmdstr = NULL; int pair[2] = { -1, -1 }; if ((flags & ~VIR_NETDEV_TAP_CREATE_VNET_HDR) != VIR_NETDEV_TAP_CREATE_IFUP) return -1; if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) < 0) { virReportSystemError(errno, "%s", _("failed to create socket")); return -1; } if (!virFileIsExecutable(cfg->bridgeHelperName)) { virReportSystemError(errno, _("'%s' is not a suitable bridge helper"), cfg->bridgeHelperName); return -1; } cmd = virCommandNew(cfg->bridgeHelperName); if (flags & VIR_NETDEV_TAP_CREATE_VNET_HDR) virCommandAddArgFormat(cmd, "--use-vnet"); virCommandAddArgFormat(cmd, "--br=%s", brname); virCommandAddArgFormat(cmd, "--fd=%d", pair[1]); virCommandSetErrorBuffer(cmd, &errbuf); virCommandDoAsyncIO(cmd); virCommandPassFD(cmd, pair[1], VIR_COMMAND_PASS_FD_CLOSE_PARENT); virCommandClearCaps(cmd); #ifdef CAP_NET_ADMIN virCommandAllowCap(cmd, CAP_NET_ADMIN); #endif if (virCommandRunAsync(cmd, NULL) < 0) { *tapfd = -1; goto cleanup; } do { *tapfd = recvfd(pair[0], 0); } while (*tapfd < 0 && errno == EINTR); if (*tapfd < 0) { char ebuf[1024]; char *errstr = NULL; if (!(cmdstr = virCommandToString(cmd))) goto cleanup; virCommandAbort(cmd); if (errbuf && *errbuf && virAsprintf(&errstr, "\nstderr=%s", errbuf) < 0) goto cleanup; virReportError(VIR_ERR_INTERNAL_ERROR, _("%s: failed to communicate with bridge helper: %s%s"), cmdstr, virStrerror(errno, ebuf, sizeof(ebuf)), errstr ? errstr : ""); VIR_FREE(errstr); goto cleanup; } if (virNetDevTapGetName(*tapfd, ifname) < 0 || virCommandWait(cmd, NULL) < 0) { VIR_FORCE_CLOSE(*tapfd); *tapfd = -1; } cleanup: VIR_FREE(cmdstr); VIR_FREE(errbuf); virCommandFree(cmd); VIR_FORCE_CLOSE(pair[0]); return *tapfd < 0 ? -1 : 0; }
static int virStorageBackendIQNFound(const char *initiatoriqn, char **ifacename) { int ret = IQN_MISSING, fd = -1; char ebuf[64]; FILE *fp = NULL; char *line = NULL, *newline = NULL, *iqn = NULL, *token = NULL; virCommandPtr cmd = virCommandNewArgList(ISCSIADM, "--mode", "iface", NULL); if (VIR_ALLOC_N(line, LINE_SIZE) != 0) { ret = IQN_ERROR; virStorageReportError(VIR_ERR_INTERNAL_ERROR, _("Could not allocate memory for output of '%s'"), ISCSIADM); goto out; } memset(line, 0, LINE_SIZE); virCommandSetOutputFD(cmd, &fd); if (virCommandRunAsync(cmd, NULL) < 0) { ret = IQN_ERROR; goto out; } if ((fp = VIR_FDOPEN(fd, "r")) == NULL) { virStorageReportError(VIR_ERR_INTERNAL_ERROR, _("Failed to open stream for file descriptor " "when reading output from '%s': '%s'"), ISCSIADM, virStrerror(errno, ebuf, sizeof ebuf)); ret = IQN_ERROR; goto out; } while (fgets(line, LINE_SIZE, fp) != NULL) { newline = strrchr(line, '\n'); if (newline == NULL) { ret = IQN_ERROR; virStorageReportError(VIR_ERR_INTERNAL_ERROR, _("Unexpected line > %d characters " "when parsing output of '%s'"), LINE_SIZE, ISCSIADM); goto out; } *newline = '\0'; iqn = strrchr(line, ','); if (iqn == NULL) { continue; } iqn++; if (STREQ(iqn, initiatoriqn)) { token = strchr(line, ' '); if (!token) { ret = IQN_ERROR; virStorageReportError(VIR_ERR_INTERNAL_ERROR, _("Missing space when parsing output " "of '%s'"), ISCSIADM); goto out; } *ifacename = strndup(line, token - line); if (*ifacename == NULL) { ret = IQN_ERROR; virReportOOMError(); goto out; } VIR_DEBUG("Found interface '%s' with IQN '%s'", *ifacename, iqn); ret = IQN_FOUND; break; } } if (virCommandWait(cmd, NULL) < 0) ret = IQN_ERROR; out: if (ret == IQN_MISSING) { VIR_DEBUG("Could not find interface with IQN '%s'", iqn); } VIR_FREE(line); VIR_FORCE_FCLOSE(fp); VIR_FORCE_CLOSE(fd); virCommandFree(cmd); return ret; }