/* Remove the key-value pair tied to @key out of @object. If @value is * not NULL, the dropped value object is returned instead of freed. * Returns 1 on success, 0 if no key was found, and -1 on error. */ int virJSONValueObjectRemoveKey(virJSONValuePtr object, const char *key, virJSONValuePtr *value) { size_t i; if (value) *value = NULL; if (object->type != VIR_JSON_TYPE_OBJECT) return -1; for (i = 0; i < object->data.object.npairs; i++) { if (STREQ(object->data.object.pairs[i].key, key)) { if (value) { *value = object->data.object.pairs[i].value; object->data.object.pairs[i].value = NULL; } VIR_FREE(object->data.object.pairs[i].key); virJSONValueFree(object->data.object.pairs[i].value); VIR_DELETE_ELEMENT(object->data.object.pairs, i, object->data.object.npairs); return 1; } } return 0; }
static int xenInotifyXendDomainsDirRemoveEntry(virConnectPtr conn, const char *fname) { xenUnifiedPrivatePtr priv = conn->privateData; const char *uuidstr = fname + strlen(XEND_DOMAINS_DIR) + 1; unsigned char uuid[VIR_UUID_BUFLEN]; size_t i; if (virUUIDParse(uuidstr, uuid) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("parsing uuid %s"), uuidstr); return -1; } /* match and remove on uuid */ for (i = 0; i < priv->configInfoList->count; i++) { if (!memcmp(uuid, priv->configInfoList->doms[i]->uuid, VIR_UUID_BUFLEN)) { VIR_FREE(priv->configInfoList->doms[i]->name); VIR_FREE(priv->configInfoList->doms[i]); VIR_DELETE_ELEMENT(priv->configInfoList->doms, i, priv->configInfoList->count); return 0; } } return -1; }
/** * virObjectEventCallbackListRemoveID: * @conn: pointer to the connection * @cbList: the list * @callback: the callback to remove * * Internal function to remove a callback from a virObjectEventCallbackListPtr */ static int virObjectEventCallbackListRemoveID(virConnectPtr conn, virObjectEventCallbackListPtr cbList, int callbackID) { size_t i; for (i = 0; i < cbList->count; i++) { virObjectEventCallbackPtr cb = cbList->callbacks[i]; if (cb->callbackID == callbackID && cb->conn == conn) { int ret; ret = cb->filter ? 0 : (virObjectEventCallbackListCount(conn, cbList, cb->klass, cb->eventID, cb->uuid_filter ? cb->uuid : NULL, cb->remoteID >= 0) - 1); if (cb->freecb) (*cb->freecb)(cb->opaque); virObjectUnref(cb->conn); VIR_FREE(cb); VIR_DELETE_ELEMENT(cbList->callbacks, i, cbList->count); return ret; } } virReportError(VIR_ERR_INVALID_ARG, _("could not find event callback %d for deletion"), callbackID); return -1; }
int parallelsStorageVolDefRemove(virStoragePoolObjPtr privpool, virStorageVolDefPtr privvol) { int ret = -1; char *xml_path = NULL; size_t i; privpool->def->allocation -= privvol->target.allocation; privpool->def->available = (privpool->def->capacity - privpool->def->allocation); for (i = 0; i < privpool->volumes.count; i++) { if (privpool->volumes.objs[i] == privvol) { xml_path = parallelsAddFileExt(privvol->target.path, ".xml"); if (!xml_path) goto cleanup; if (unlink(xml_path)) { virReportError(VIR_ERR_OPERATION_FAILED, _("Can't remove file '%s'"), xml_path); goto cleanup; } virStorageVolDefFree(privvol); VIR_DELETE_ELEMENT(privpool->volumes.objs, i, privpool->volumes.count); break; } } ret = 0; cleanup: VIR_FREE(xml_path); return ret; }
virLogHandlerPtr virLogHandlerNewPostExecRestart(virJSONValuePtr object, bool privileged, virLogHandlerShutdownInhibitor inhibitor, void *opaque) { virLogHandlerPtr handler; virJSONValuePtr files; ssize_t n; size_t i; if (!(handler = virLogHandlerNew(privileged, inhibitor, opaque))) return NULL; if (!(files = virJSONValueObjectGet(object, "files"))) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Missing files data from JSON file")); goto error; } if ((n = virJSONValueArraySize(files)) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Malformed files data from JSON file")); goto error; } for (i = 0; i < n; i++) { virLogHandlerLogFilePtr file; virJSONValuePtr child = virJSONValueArrayGet(files, i); if (!(file = virLogHandlerLogFilePostExecRestart(handler, child))) goto error; if (VIR_APPEND_ELEMENT_COPY(handler->files, handler->nfiles, file) < 0) goto error; if ((file->watch = virEventAddHandle(file->pipefd, VIR_EVENT_HANDLE_READABLE, virLogHandlerDomainLogFileEvent, handler, NULL)) < 0) { VIR_DELETE_ELEMENT(handler->files, handler->nfiles - 1, handler->nfiles); goto error; } } return handler; error: virObjectUnref(handler); return NULL; }
static void virLogHandlerLogFileClose(virLogHandlerPtr handler, virLogHandlerLogFilePtr file) { size_t i; for (i = 0; i < handler->nfiles; i++) { if (handler->files[i] == file) { VIR_DELETE_ELEMENT(handler->files, i, handler->nfiles); virLogHandlerLogFileFree(file); break; } } }
virUSBDevicePtr virUSBDeviceListSteal(virUSBDeviceListPtr list, virUSBDevicePtr dev) { virUSBDevicePtr ret = NULL; size_t i; for (i = 0; i < list->count; i++) { if (list->devs[i]->bus == dev->bus && list->devs[i]->dev == dev->dev) { ret = list->devs[i]; VIR_DELETE_ELEMENT(list->devs, i, list->count); break; } } return ret; }
/* virDomainVirtioSerialAddrSetRemoveController * * Removes a virtio serial controller from the address set. */ void virDomainVirtioSerialAddrSetRemoveController(virDomainVirtioSerialAddrSetPtr addrs, virDomainControllerDefPtr cont) { ssize_t pos; if (cont->type != VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL) return; VIR_DEBUG("Removing virtio serial controller index %u " "from the address set", cont->idx); pos = virDomainVirtioSerialAddrFindController(addrs, cont->idx); if (pos >= 0) VIR_DELETE_ELEMENT(addrs->controllers, pos, addrs->ncontrollers); }
static int virObjectEventCallbackListPurgeMarked(virObjectEventCallbackListPtr cbList) { size_t n; for (n = 0; n < cbList->count; n++) { if (cbList->callbacks[n]->deleted) { virFreeCallback freecb = cbList->callbacks[n]->freecb; if (freecb) (*freecb)(cbList->callbacks[n]->opaque); virObjectEventCallbackFree(cbList->callbacks[n]); VIR_DELETE_ELEMENT(cbList->callbacks, n, cbList->count); n--; } } return 0; }
void virInterfaceRemove(virInterfaceObjListPtr interfaces, virInterfaceObjPtr iface) { size_t i; virInterfaceObjUnlock(iface); for (i = 0; i < interfaces->count; i++) { virInterfaceObjLock(interfaces->objs[i]); if (interfaces->objs[i] == iface) { virInterfaceObjUnlock(interfaces->objs[i]); virInterfaceObjFree(interfaces->objs[i]); VIR_DELETE_ELEMENT(interfaces->objs, i, interfaces->count); break; } virInterfaceObjUnlock(interfaces->objs[i]); } }
static int virJSONParserHandleEndArray(void *ctx) { virJSONParserPtr parser = ctx; virJSONParserStatePtr state; VIR_DEBUG("parser=%p", parser); if (!parser->nstate) return 0; state = &(parser->state[parser->nstate-1]); if (state->key) { VIR_FREE(state->key); return 0; } VIR_DELETE_ELEMENT(parser->state, parser->nstate - 1, parser->nstate); return 1; }
void virNWFilterObjListRemove(virNWFilterObjListPtr nwfilters, virNWFilterObjPtr obj) { size_t i; virNWFilterObjUnlock(obj); for (i = 0; i < nwfilters->count; i++) { virNWFilterObjLock(nwfilters->objs[i]); if (nwfilters->objs[i] == obj) { virNWFilterObjUnlock(nwfilters->objs[i]); virNWFilterObjFree(nwfilters->objs[i]); VIR_DELETE_ELEMENT(nwfilters->objs, i, nwfilters->count); break; } virNWFilterObjUnlock(nwfilters->objs[i]); } }
virSCSIDevicePtr virSCSIDeviceListSteal(virSCSIDeviceListPtr list, virSCSIDevicePtr dev) { virSCSIDevicePtr ret = NULL; size_t i; for (i = 0; i < list->count; i++) { if (list->devs[i]->adapter == dev->adapter && list->devs[i]->bus == dev->bus && list->devs[i]->target == dev->target && list->devs[i]->unit == dev->unit) { ret = list->devs[i]; VIR_DELETE_ELEMENT(list->devs, i, list->count); break; } } return ret; }
static int virNWFilterVarValueDelNthValue(virNWFilterVarValuePtr val, unsigned int pos) { switch (val->valType) { case NWFILTER_VALUE_TYPE_SIMPLE: return -1; case NWFILTER_VALUE_TYPE_ARRAY: if (pos < val->u.array.nValues) { VIR_FREE(val->u.array.values[pos]); VIR_DELETE_ELEMENT(val->u.array.values, pos, val->u.array.nValues); return 0; } break; case NWFILTER_VALUE_TYPE_LAST: break; } return -1; }
void virSCSIDeviceListDel(virSCSIDeviceListPtr list, virSCSIDevicePtr dev, const char *drvname, const char *domname) { virSCSIDevicePtr tmp = NULL; size_t i; for (i = 0; i < dev->n_used_by; i++) { if (STREQ_NULLABLE(dev->used_by[i]->drvname, drvname) && STREQ_NULLABLE(dev->used_by[i]->domname, domname)) { if (dev->n_used_by > 1) { virSCSIDeviceUsedByInfoFree(dev->used_by[i]); VIR_DELETE_ELEMENT(dev->used_by, i, dev->n_used_by); } else { tmp = virSCSIDeviceListSteal(list, dev); virSCSIDeviceFree(tmp); } break; } } }
/* * The caller must hold the lock on the privateData * associated with the 'conn' parameter. */ int xenStoreRemoveWatch(virConnectPtr conn, const char *path, const char *token) { size_t i; xenStoreWatchListPtr list; xenUnifiedPrivatePtr priv = conn->privateData; if (priv->xshandle == NULL) return -1; list = priv->xsWatchList; if (!list) return -1; for (i = 0; i < list->count; i++) { if (STREQ(list->watches[i]->path, path) && STREQ(list->watches[i]->token, token)) { if (!xs_unwatch(priv->xshandle, list->watches[i]->path, list->watches[i]->token)) { VIR_DEBUG("WARNING: Could not remove watch"); /* Not fatal, continue */ } VIR_FREE(list->watches[i]->path); VIR_FREE(list->watches[i]->token); VIR_FREE(list->watches[i]); VIR_DELETE_ELEMENT(list->watches, i, list->count); return 0; } } return -1; }
/** * virObjectEventCallbackListRemoveID: * @conn: pointer to the connection * @cbList: the list * @callback: the callback to remove * @doFreeCb: Inhibit calling the freecb * * Internal function to remove a callback from a virObjectEventCallbackListPtr */ static int virObjectEventCallbackListRemoveID(virConnectPtr conn, virObjectEventCallbackListPtr cbList, int callbackID, bool doFreeCb) { size_t i; for (i = 0; i < cbList->count; i++) { virObjectEventCallbackPtr cb = cbList->callbacks[i]; if (cb->callbackID == callbackID && cb->conn == conn) { int ret; ret = cb->filter ? 0 : (virObjectEventCallbackListCount(conn, cbList, cb->klass, cb->eventID, cb->key_filter ? cb->key : NULL, cb->remoteID >= 0) - 1); /* @doFreeCb inhibits calling @freecb from error paths in * register functions to ensure the caller of a failed register * function won't end up with a double free error */ if (doFreeCb && cb->freecb) (*cb->freecb)(cb->opaque); virObjectEventCallbackFree(cb); VIR_DELETE_ELEMENT(cbList->callbacks, i, cbList->count); return ret; } } virReportError(VIR_ERR_INVALID_ARG, _("could not find event callback %d for deletion"), callbackID); return -1; }
int virSecurityManagerGenLabel(virSecurityManagerPtr mgr, virDomainDefPtr vm) { int ret = -1; size_t i, j; virSecurityManagerPtr* sec_managers = NULL; virSecurityLabelDefPtr seclabel; bool generated = false; if (mgr == NULL || mgr->drv == NULL) return ret; if ((sec_managers = virSecurityManagerGetNested(mgr)) == NULL) return ret; virObjectLock(mgr); for (i = 0; i < vm->nseclabels; i++) { if (!vm->seclabels[i]->model) continue; for (j = 0; sec_managers[j]; j++) if (STREQ(vm->seclabels[i]->model, sec_managers[j]->drv->name)) break; if (!sec_managers[j]) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Unable to find security driver for label %s"), vm->seclabels[i]->model); goto cleanup; } } for (i = 0; sec_managers[i]; i++) { generated = false; seclabel = virDomainDefGetSecurityLabelDef(vm, sec_managers[i]->drv->name); if (!seclabel) { if (!(seclabel = virSecurityLabelDefNew(sec_managers[i]->drv->name))) goto cleanup; generated = seclabel->implicit = true; } if (seclabel->type == VIR_DOMAIN_SECLABEL_DEFAULT) { if (sec_managers[i]->defaultConfined) { seclabel->type = VIR_DOMAIN_SECLABEL_DYNAMIC; } else { seclabel->type = VIR_DOMAIN_SECLABEL_NONE; seclabel->norelabel = true; } } if (seclabel->type == VIR_DOMAIN_SECLABEL_NONE) { if (sec_managers[i]->requireConfined) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("Unconfined guests are not allowed on this host")); goto cleanup; } else if (vm->nseclabels && generated) { VIR_DEBUG("Skipping auto generated seclabel of type none"); virSecurityLabelDefFree(seclabel); seclabel = NULL; continue; } } if (!sec_managers[i]->drv->domainGenSecurityLabel) { virReportUnsupportedError(); virSecurityLabelDefFree(seclabel); seclabel = NULL; } else { /* The seclabel must be added to @vm prior calling domainGenSecurityLabel * which may require seclabel to be presented already */ if (generated && VIR_APPEND_ELEMENT(vm->seclabels, vm->nseclabels, seclabel) < 0) goto cleanup; if (sec_managers[i]->drv->domainGenSecurityLabel(sec_managers[i], vm) < 0) { if (VIR_DELETE_ELEMENT(vm->seclabels, vm->nseclabels -1, vm->nseclabels) < 0) vm->nseclabels--; goto cleanup; } seclabel = NULL; } } ret = 0; cleanup: virObjectUnlock(mgr); if (generated) virSecurityLabelDefFree(seclabel); VIR_FREE(sec_managers); return ret; }
/** * virLXCProcessStart: * @conn: pointer to connection * @driver: pointer to driver structure * @vm: pointer to virtual machine structure * @autoDestroy: mark the domain for auto destruction * @reason: reason for switching vm to running state * * Starts a vm * * Returns 0 on success or -1 in case of error */ int virLXCProcessStart(virConnectPtr conn, virLXCDriverPtr driver, virDomainObjPtr vm, unsigned int nfiles, int *files, bool autoDestroy, virDomainRunningReason reason) { int rc = -1, r; size_t nttyFDs = 0; int *ttyFDs = NULL; size_t i; char *logfile = NULL; int logfd = -1; size_t nveths = 0; char **veths = NULL; int handshakefds[2] = { -1, -1 }; off_t pos = -1; char ebuf[1024]; char *timestamp; virCommandPtr cmd = NULL; virLXCDomainObjPrivatePtr priv = vm->privateData; virCapsPtr caps = NULL; virErrorPtr err = NULL; virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver); virCgroupPtr selfcgroup; int status; char *pidfile = NULL; bool clearSeclabel = false; bool need_stop = false; 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 (vm->def->nconsoles == 0) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("At least one PTY console is required")); return -1; } for (i = 0; i < vm->def->nconsoles; i++) { if (vm->def->consoles[i]->source.type != VIR_DOMAIN_CHR_TYPE_PTY) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("Only PTY console types are supported")); return -1; } } 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) goto cleanup; if (!(pidfile = virPidFileBuildPath(cfg->stateDir, vm->def->name))) goto cleanup; 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)"); clearSeclabel = vm->def->nseclabels == 0 || vm->def->seclabels[0]->type == VIR_DOMAIN_SECLABEL_DEFAULT; if (vm->def->nseclabels && vm->def->seclabels[0]->type == VIR_DOMAIN_SECLABEL_DEFAULT) vm->def->seclabels[0]->type = VIR_DOMAIN_SECLABEL_NONE; if (virSecurityManagerCheckAllLabel(driver->securityManager, vm->def) < 0) goto cleanup; 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; VIR_DEBUG("Setting up consoles"); for (i = 0; i < vm->def->nconsoles; i++) { char *ttyPath; 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; } VIR_DEBUG("Setting up Interfaces"); if (virLXCProcessSetupInterfaces(conn, vm->def, &nveths, &veths) < 0) goto cleanup; VIR_DEBUG("Preparing to launch"); 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], logfd, pidfile))) goto cleanup; /* 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))); VIR_DEBUG("Launching container"); 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; } /* It has started running, so get its pid */ if ((r = virPidFileReadPath(pidfile, &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"), pidfile); goto cleanup; } need_stop = true; 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 (VIR_CLOSE(handshakefds[1]) < 0) { virReportSystemError(errno, "%s", _("could not close handshake fd")); goto cleanup; } if (virCommandHandshakeWait(cmd) < 0) goto cleanup; /* Write domain status to disk for the controller to * read when it starts */ if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0) goto cleanup; /* Allow the child to exec the controller */ if (virCommandHandshakeNotify(cmd) < 0) goto cleanup; 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 cleanup; } /* We know the cgroup must exist by this synchronization * point so lets detect that first, since it gives us a * more reliable way to kill everything off if something * goes wrong from here onwards ... */ if (virCgroupNewDetectMachine(vm->def->name, "lxc", vm->pid, vm->def->resource ? vm->def->resource->partition : NULL, -1, &priv->cgroup) < 0) goto cleanup; if (!priv->cgroup) { virReportError(VIR_ERR_INTERNAL_ERROR, _("No valid cgroup for machine %s"), vm->def->name); goto cleanup; } /* And we can get the first monitor connection now too */ 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; } if (autoDestroy && virCloseCallbacksSet(driver->closeCallbacks, vm, conn, lxcProcessAutoDestroy) < 0) goto cleanup; if (virDomainObjSetDefTransient(caps, driver->xmlopt, vm, false) < 0) goto cleanup; /* We don't need the temporary NIC names anymore, clear them */ virLXCProcessCleanInterfaces(vm->def); /* 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 cleanup; } rc = 0; cleanup: if (VIR_CLOSE(logfd) < 0) { virReportSystemError(errno, "%s", _("could not close logfile")); rc = -1; } if (rc != 0) { err = virSaveLastError(); if (need_stop) { virLXCProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED); } else { 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 || clearSeclabel)) { VIR_FREE(vm->def->seclabels[0]->model); VIR_FREE(vm->def->seclabels[0]->label); VIR_FREE(vm->def->seclabels[0]->imagelabel); VIR_DELETE_ELEMENT(vm->def->seclabels, 0, vm->def->nseclabels); } virLXCProcessCleanup(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED); } } virCommandFree(cmd); for (i = 0; i < nveths; i++) VIR_FREE(veths[i]); 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(pidfile); VIR_FREE(logfile); virObjectUnref(cfg); virObjectUnref(caps); if (err) { virSetError(err); virFreeError(err); } return rc; }