+++ /dev/null
-/*
- * uml_driver.c: core driver methods for managing UML guests
- *
- * Copyright (C) 2006-2015 Red Hat, Inc.
- * Copyright (C) 2006-2008 Daniel P. Berrange
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see
- * <http://www.gnu.org/licenses/>.
- */
-
-#include <config.h>
-
-#include <sys/types.h>
-#include <sys/poll.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <sys/utsname.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <pwd.h>
-#include <sys/wait.h>
-#include <sys/ioctl.h>
-#include <sys/inotify.h>
-#include <sys/un.h>
-
-#include "uml_driver.h"
-#include "uml_conf.h"
-#include "virbuffer.h"
-#include "virhostcpu.h"
-#include "virhostmem.h"
-#include "capabilities.h"
-#include "viralloc.h"
-#include "viruuid.h"
-#include "domain_conf.h"
-#include "domain_audit.h"
-#include "datatypes.h"
-#include "virlog.h"
-#include "domain_nwfilter.h"
-#include "virfile.h"
-#include "virfdstream.h"
-#include "configmake.h"
-#include "virnetdevtap.h"
-#include "virnodesuspend.h"
-#include "virprocess.h"
-#include "viruri.h"
-#include "virstring.h"
-#include "viraccessapicheck.h"
-
-#define VIR_FROM_THIS VIR_FROM_UML
-
-VIR_LOG_INIT("uml.uml_driver");
-
-typedef struct _umlDomainObjPrivate umlDomainObjPrivate;
-typedef umlDomainObjPrivate *umlDomainObjPrivatePtr;
-struct _umlDomainObjPrivate {
- int monitor;
- int monitorWatch;
-};
-
-static int umlProcessAutoDestroyInit(struct uml_driver *driver);
-static void umlProcessAutoDestroyRun(struct uml_driver *driver,
- virConnectPtr conn);
-static void umlProcessAutoDestroyShutdown(struct uml_driver *driver);
-static int umlProcessAutoDestroyAdd(struct uml_driver *driver,
- virDomainObjPtr vm,
- virConnectPtr conn);
-static int umlProcessAutoDestroyRemove(struct uml_driver *driver,
- virDomainObjPtr vm);
-
-
-static int umlStateCleanup(void);
-
-static void *umlDomainObjPrivateAlloc(void *opaque ATTRIBUTE_UNUSED)
-{
- umlDomainObjPrivatePtr priv;
-
- if (VIR_ALLOC(priv) < 0)
- return NULL;
-
- priv->monitor = -1;
- priv->monitorWatch = -1;
-
- return priv;
-}
-
-static void umlDomainObjPrivateFree(void *data)
-{
- umlDomainObjPrivatePtr priv = data;
-
- VIR_FREE(priv);
-}
-
-
-static void umlDriverLock(struct uml_driver *driver)
-{
- virMutexLock(&driver->lock);
-}
-static void umlDriverUnlock(struct uml_driver *driver)
-{
- virMutexUnlock(&driver->lock);
-}
-
-
-static int umlOpenMonitor(struct uml_driver *driver,
- virDomainObjPtr vm);
-static int umlReadPidFile(struct uml_driver *driver,
- virDomainObjPtr vm);
-
-static int umlStartVMDaemon(virConnectPtr conn,
- struct uml_driver *driver,
- virDomainObjPtr vm,
- bool autoDestroy);
-
-static void umlShutdownVMDaemon(struct uml_driver *driver,
- virDomainObjPtr vm,
- virDomainShutoffReason reason);
-
-
-static int umlMonitorCommand(const struct uml_driver *driver,
- const virDomainObj *vm,
- const char *cmd,
- char **reply);
-
-static struct uml_driver *uml_driver;
-
-static virDomainObjPtr
-umlDomObjFromDomainLocked(struct uml_driver *driver,
- const unsigned char *uuid)
-{
- virDomainObjPtr vm;
- char uuidstr[VIR_UUID_STRING_BUFLEN];
-
- if (!(vm = virDomainObjListFindByUUID(driver->domains, uuid))) {
- virUUIDFormat(uuid, uuidstr);
-
- virReportError(VIR_ERR_NO_DOMAIN,
- _("no domain with matching uuid '%s'"), uuidstr);
- return NULL;
- }
-
- return vm;
-}
-
-
-static virDomainObjPtr
-umlDomObjFromDomain(struct uml_driver *driver,
- const unsigned char *uuid)
-{
- virDomainObjPtr vm;
-
- umlDriverLock(driver);
- vm = umlDomObjFromDomainLocked(driver, uuid);
- umlDriverUnlock(driver);
- return vm;
-}
-
-
-struct umlAutostartData {
- struct uml_driver *driver;
- virConnectPtr conn;
-};
-
-static int
-umlAutostartDomain(virDomainObjPtr vm,
- void *opaque)
-{
- const struct umlAutostartData *data = opaque;
- int ret = 0;
- virObjectLock(vm);
- if (vm->autostart &&
- !virDomainObjIsActive(vm)) {
- virResetLastError();
- ret = umlStartVMDaemon(data->conn, data->driver, vm, false);
- virDomainAuditStart(vm, "booted", ret >= 0);
- if (ret < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR, _("Failed to autostart VM '%s': %s"),
- vm->def->name, virGetLastErrorMessage());
- } else {
- virObjectEventPtr event =
- virDomainEventLifecycleNewFromObj(vm,
- VIR_DOMAIN_EVENT_STARTED,
- VIR_DOMAIN_EVENT_STARTED_BOOTED);
- virObjectEventStateQueue(data->driver->domainEventState, event);
- }
- }
- virObjectUnlock(vm);
- return ret;
-}
-
-static void
-umlAutostartConfigs(struct uml_driver *driver)
-{
- /* XXX: Figure out a better way todo this. The domain
- * startup code needs a connection handle in order
- * to lookup the bridge associated with a virtual
- * network
- */
- virConnectPtr conn = virConnectOpen(driver->privileged ?
- "uml:///system" :
- "uml:///session");
- /* Ignoring NULL conn which is mostly harmless here */
-
- struct umlAutostartData data = { driver, conn };
-
- umlDriverLock(driver);
- virDomainObjListForEach(driver->domains, umlAutostartDomain, &data);
- umlDriverUnlock(driver);
-
- virObjectUnref(conn);
-}
-
-
-static int
-umlIdentifyOneChrPTY(struct uml_driver *driver,
- virDomainObjPtr dom,
- virDomainChrDefPtr def,
- const char *dev)
-{
- char *cmd;
- char *res = NULL;
- int retries = 0;
- if (virAsprintf(&cmd, "config %s%d", dev, def->target.port) < 0)
- return -1;
- requery:
- if (umlMonitorCommand(driver, dom, cmd, &res) < 0)
- return -1;
-
- if (res && STRPREFIX(res, "pts:")) {
- VIR_FREE(def->source->data.file.path);
- if (VIR_STRDUP(def->source->data.file.path, res + 4) < 0) {
- VIR_FREE(res);
- VIR_FREE(cmd);
- return -1;
- }
- } else if (!res || STRPREFIX(res, "pts")) {
- /* It can take a while to startup, so retry for
- up to 5 seconds */
- /* XXX should do this in a better non-blocking
- way somehow ...perhaps register a timer */
- if (retries++ < 50) {
- VIR_FREE(res);
- usleep(1000*10);
- goto requery;
- }
- }
-
- VIR_FREE(cmd);
- VIR_FREE(res);
- return 0;
-}
-
-static int
-umlIdentifyChrPTY(struct uml_driver *driver,
- virDomainObjPtr dom)
-{
- size_t i;
-
- for (i = 0; i < dom->def->nconsoles; i++)
- if (dom->def->consoles[i]->source->type == VIR_DOMAIN_CHR_TYPE_PTY)
- if (umlIdentifyOneChrPTY(driver, dom,
- dom->def->consoles[i], "con") < 0)
- return -1;
-
- for (i = 0; i < dom->def->nserials; i++)
- if (dom->def->serials[i]->source->type == VIR_DOMAIN_CHR_TYPE_PTY &&
- umlIdentifyOneChrPTY(driver, dom,
- dom->def->serials[i], "ssl") < 0)
- return -1;
-
- return 0;
-}
-
-static void
-umlInotifyEvent(int watch,
- int fd,
- int events ATTRIBUTE_UNUSED,
- void *data)
-{
- char buf[1024];
- struct inotify_event e;
- int got;
- char *tmp, *name;
- struct uml_driver *driver = data;
- virDomainObjPtr dom;
- virObjectEventPtr event = NULL;
-
- umlDriverLock(driver);
- if (watch != driver->inotifyWatch)
- goto cleanup;
-
- reread:
- got = read(fd, buf, sizeof(buf));
- if (got == -1) {
- if (errno == EINTR)
- goto reread;
- goto cleanup;
- }
-
- tmp = buf;
- while (got) {
- if (got < sizeof(e))
- goto cleanup; /* bad */
-
- memcpy(&e, tmp, sizeof(e));
- tmp += sizeof(e);
- got -= sizeof(e);
-
- if (got < e.len)
- goto cleanup;
-
- tmp += e.len;
- got -= e.len;
-
- name = (char *)&(e.name);
-
- dom = virDomainObjListFindByName(driver->domains, name);
-
- if (!dom)
- continue;
-
- if (e.mask & IN_DELETE) {
- VIR_DEBUG("Got inotify domain shutdown '%s'", name);
- if (!virDomainObjIsActive(dom)) {
- virDomainObjEndAPI(&dom);
- continue;
- }
-
- umlShutdownVMDaemon(driver, dom, VIR_DOMAIN_SHUTOFF_SHUTDOWN);
- virDomainAuditStop(dom, "shutdown");
- event = virDomainEventLifecycleNewFromObj(dom,
- VIR_DOMAIN_EVENT_STOPPED,
- VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN);
- if (!dom->persistent)
- virDomainObjListRemove(driver->domains, dom);
- } else if (e.mask & (IN_CREATE | IN_MODIFY)) {
- VIR_DEBUG("Got inotify domain startup '%s'", name);
- if (virDomainObjIsActive(dom)) {
- virDomainObjEndAPI(&dom);
- continue;
- }
-
- if (umlReadPidFile(driver, dom) < 0) {
- virDomainObjEndAPI(&dom);
- continue;
- }
-
- dom->def->id = driver->nextvmid++;
-
- if (!driver->nactive && driver->inhibitCallback)
- driver->inhibitCallback(true, driver->inhibitOpaque);
- driver->nactive++;
-
- virDomainObjSetState(dom, VIR_DOMAIN_RUNNING,
- VIR_DOMAIN_RUNNING_BOOTED);
-
- if (umlOpenMonitor(driver, dom) < 0) {
- VIR_WARN("Could not open monitor for new domain");
- umlShutdownVMDaemon(driver, dom,
- VIR_DOMAIN_SHUTOFF_FAILED);
- virDomainAuditStop(dom, "failed");
- event = virDomainEventLifecycleNewFromObj(dom,
- VIR_DOMAIN_EVENT_STOPPED,
- VIR_DOMAIN_EVENT_STOPPED_FAILED);
- if (!dom->persistent)
- virDomainObjListRemove(driver->domains, dom);
- } else if (umlIdentifyChrPTY(driver, dom) < 0) {
- VIR_WARN("Could not identify character devices for new domain");
- umlShutdownVMDaemon(driver, dom,
- VIR_DOMAIN_SHUTOFF_FAILED);
- virDomainAuditStop(dom, "failed");
- event = virDomainEventLifecycleNewFromObj(dom,
- VIR_DOMAIN_EVENT_STOPPED,
- VIR_DOMAIN_EVENT_STOPPED_FAILED);
- if (!dom->persistent)
- virDomainObjListRemove(driver->domains, dom);
- }
- }
- virDomainObjEndAPI(&dom);
- virObjectEventStateQueue(driver->domainEventState, event);
- event = NULL;
- }
-
- cleanup:
- umlDriverUnlock(driver);
-}
-
-
-static int
-umlDomainDeviceDefPostParse(virDomainDeviceDefPtr dev,
- const virDomainDef *def ATTRIBUTE_UNUSED,
- virCapsPtr caps ATTRIBUTE_UNUSED,
- unsigned int parseFlags ATTRIBUTE_UNUSED,
- void *opaque ATTRIBUTE_UNUSED,
- void *parseOpaque ATTRIBUTE_UNUSED)
-{
- if (dev->type == VIR_DOMAIN_DEVICE_CHR &&
- dev->data.chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE &&
- dev->data.chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_NONE)
- dev->data.chr->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_UML;
-
- /* forbid capabilities mode hostdev in this kind of hypervisor */
- if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV &&
- dev->data.hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("hostdev mode 'capabilities' is not "
- "supported in %s"),
- virDomainVirtTypeToString(def->virtType));
- return -1;
- }
-
- return 0;
-}
-
-
-static int
-umlDomainDefPostParse(virDomainDefPtr def ATTRIBUTE_UNUSED,
- virCapsPtr caps ATTRIBUTE_UNUSED,
- unsigned int parseFlags ATTRIBUTE_UNUSED,
- void *opaque ATTRIBUTE_UNUSED,
- void *parseOpaque ATTRIBUTE_UNUSED)
-{
- return 0;
-}
-
-
-virDomainDefParserConfig umlDriverDomainDefParserConfig = {
- .devicesPostParseCallback = umlDomainDeviceDefPostParse,
- .domainPostParseCallback = umlDomainDefPostParse,
-};
-
-
-/**
- * umlStartup:
- *
- * Initialization function for the Uml daemon
- */
-static int
-umlStateInitialize(bool privileged,
- virStateInhibitCallback callback,
- void *opaque)
-{
- char *base = NULL;
- char *userdir = NULL;
-
- virDomainXMLPrivateDataCallbacks privcb = {
- .alloc = umlDomainObjPrivateAlloc,
- .free = umlDomainObjPrivateFree,
- };
-
- if (VIR_ALLOC(uml_driver) < 0)
- return -1;
-
- uml_driver->privileged = privileged;
- uml_driver->inhibitCallback = callback;
- uml_driver->inhibitOpaque = opaque;
-
- if (virMutexInit(¨_driver->lock) < 0) {
- VIR_FREE(uml_driver);
- return -1;
- }
- umlDriverLock(uml_driver);
-
- /* Don't have a dom0 so start from 1 */
- uml_driver->nextvmid = 1;
- uml_driver->inotifyWatch = -1;
-
- if (!(uml_driver->domains = virDomainObjListNew()))
- goto error;
-
- uml_driver->domainEventState = virObjectEventStateNew();
- if (!uml_driver->domainEventState)
- goto error;
-
- userdir = virGetUserDirectory();
- if (!userdir)
- goto error;
-
- if (privileged) {
- if (virAsprintf(¨_driver->logDir,
- "%s/log/libvirt/uml", LOCALSTATEDIR) == -1)
- goto out_of_memory;
-
- if (VIR_STRDUP(base, SYSCONFDIR "/libvirt") < 0)
- goto error;
-
- if (virAsprintf(¨_driver->monitorDir,
- "%s/run/libvirt/uml-guest", LOCALSTATEDIR) == -1)
- goto out_of_memory;
- } else {
- base = virGetUserConfigDirectory();
- if (!base)
- goto error;
-
- if (virAsprintf(¨_driver->logDir,
- "%s/uml/log", base) == -1)
- goto out_of_memory;
-
- if (virAsprintf(¨_driver->monitorDir,
- "%s/.uml", userdir) == -1)
- goto out_of_memory;
- }
-
- /* Configuration paths are either $XDG_CONFIG_HOME/libvirt/uml/... (session) or
- * /etc/libvirt/uml/... (system).
- */
- if (virAsprintf(¨_driver->configDir, "%s/uml", base) == -1)
- goto out_of_memory;
-
- if (virAsprintf(¨_driver->autostartDir, "%s/uml/autostart", base) == -1)
- goto out_of_memory;
-
- VIR_FREE(base);
-
- if ((uml_driver->caps = umlCapsInit()) == NULL)
- goto out_of_memory;
-
- if (!(uml_driver->xmlopt = virDomainXMLOptionNew(¨DriverDomainDefParserConfig,
- &privcb, NULL, NULL, NULL)))
- goto error;
-
- if ((uml_driver->inotifyFD = inotify_init()) < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot initialize inotify"));
- goto error;
- }
-
- if (virFileMakePath(uml_driver->monitorDir) < 0) {
- virReportSystemError(errno, _("Failed to create monitor directory %s"),
- uml_driver->monitorDir);
- goto error;
- }
-
- VIR_INFO("Adding inotify watch on %s", uml_driver->monitorDir);
- if (inotify_add_watch(uml_driver->inotifyFD,
- uml_driver->monitorDir,
- IN_CREATE | IN_MODIFY | IN_DELETE) < 0) {
- virReportSystemError(errno, _("Failed to create inotify watch on %s"),
- uml_driver->monitorDir);
- goto error;
- }
-
- if ((uml_driver->inotifyWatch =
- virEventAddHandle(uml_driver->inotifyFD, POLLIN,
- umlInotifyEvent, uml_driver, NULL)) < 0)
- goto error;
-
- if (umlProcessAutoDestroyInit(uml_driver) < 0)
- goto error;
-
- if (virDomainObjListLoadAllConfigs(uml_driver->domains,
- uml_driver->configDir,
- uml_driver->autostartDir, false,
- uml_driver->caps,
- uml_driver->xmlopt,
- NULL, NULL) < 0)
- goto error;
-
- umlDriverUnlock(uml_driver);
-
- VIR_FREE(userdir);
-
- return 0;
-
- out_of_memory:
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("umlStartup: out of memory"));
-
- error:
- VIR_FREE(userdir);
- VIR_FREE(base);
- umlDriverUnlock(uml_driver);
- umlStateCleanup();
- return -1;
-}
-
-/**
- * umlStateAutoStart:
- *
- * Function to autostart the Uml daemons
- */
-static void
-umlStateAutoStart(void)
-{
- if (!uml_driver)
- return;
-
- umlAutostartConfigs(uml_driver);
-}
-
-static void umlNotifyLoadDomain(virDomainObjPtr vm, int newVM, void *opaque)
-{
- struct uml_driver *driver = opaque;
-
- if (newVM) {
- virObjectEventPtr event =
- virDomainEventLifecycleNewFromObj(vm,
- VIR_DOMAIN_EVENT_DEFINED,
- VIR_DOMAIN_EVENT_DEFINED_ADDED);
- virObjectEventStateQueue(driver->domainEventState, event);
- }
-}
-
-
-/**
- * umlStateReload:
- *
- * Function to restart the Uml daemon, it will recheck the configuration
- * files and update its state and the networking
- */
-static int
-umlStateReload(void)
-{
- if (!uml_driver)
- return 0;
-
- umlDriverLock(uml_driver);
- virDomainObjListLoadAllConfigs(uml_driver->domains,
- uml_driver->configDir,
- uml_driver->autostartDir, false,
- uml_driver->caps,
- uml_driver->xmlopt,
- umlNotifyLoadDomain, uml_driver);
- umlDriverUnlock(uml_driver);
-
- return 0;
-}
-
-
-static int
-umlShutdownOneVM(virDomainObjPtr dom, void *opaque)
-{
- struct uml_driver *driver = opaque;
-
- virObjectLock(dom);
- if (virDomainObjIsActive(dom)) {
- umlShutdownVMDaemon(driver, dom, VIR_DOMAIN_SHUTOFF_SHUTDOWN);
- virDomainAuditStop(dom, "shutdown");
- }
- virObjectUnlock(dom);
- return 0;
-}
-
-/**
- * umlStateCleanup:
- *
- * Shutdown the Uml daemon, it will stop all active domains and networks
- */
-static int
-umlStateCleanup(void)
-{
- if (!uml_driver)
- return -1;
-
- umlDriverLock(uml_driver);
- if (uml_driver->inotifyWatch != -1)
- virEventRemoveHandle(uml_driver->inotifyWatch);
- VIR_FORCE_CLOSE(uml_driver->inotifyFD);
- virObjectUnref(uml_driver->caps);
- virObjectUnref(uml_driver->xmlopt);
-
- /* shutdown active VMs
- * XXX allow them to stay around & reconnect */
- virDomainObjListForEach(uml_driver->domains, umlShutdownOneVM, uml_driver);
-
- virObjectUnref(uml_driver->domains);
-
- virObjectUnref(uml_driver->domainEventState);
-
- VIR_FREE(uml_driver->logDir);
- VIR_FREE(uml_driver->configDir);
- VIR_FREE(uml_driver->autostartDir);
- VIR_FREE(uml_driver->monitorDir);
-
- umlProcessAutoDestroyShutdown(uml_driver);
-
- umlDriverUnlock(uml_driver);
- virMutexDestroy(¨_driver->lock);
- VIR_FREE(uml_driver);
-
- return 0;
-}
-
-
-static int umlProcessAutoDestroyInit(struct uml_driver *driver)
-{
- if (!(driver->autodestroy = virHashCreate(5, NULL)))
- return -1;
-
- return 0;
-}
-
-struct umlProcessAutoDestroyData {
- struct uml_driver *driver;
- virConnectPtr conn;
-};
-
-static int umlProcessAutoDestroyDom(void *payload,
- const void *name,
- void *opaque)
-{
- struct umlProcessAutoDestroyData *data = opaque;
- virConnectPtr conn = payload;
- const char *uuidstr = name;
- unsigned char uuid[VIR_UUID_BUFLEN];
- virDomainObjPtr dom;
- virObjectEventPtr event = NULL;
-
- VIR_DEBUG("conn=%p uuidstr=%s thisconn=%p", conn, uuidstr, data->conn);
-
- if (data->conn != conn)
- return 0;
-
- if (virUUIDParse(uuidstr, uuid) < 0) {
- VIR_WARN("Failed to parse %s", uuidstr);
- return 0;
- }
-
- if (!(dom = virDomainObjListFindByUUID(data->driver->domains, uuid))) {
- VIR_DEBUG("No domain object to kill");
- return 0;
- }
-
- VIR_DEBUG("Killing domain");
- umlShutdownVMDaemon(data->driver, dom, VIR_DOMAIN_SHUTOFF_DESTROYED);
- virDomainAuditStop(dom, "destroyed");
- event = virDomainEventLifecycleNewFromObj(dom,
- VIR_DOMAIN_EVENT_STOPPED,
- VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
-
- if (!dom->persistent)
- virDomainObjListRemove(data->driver->domains, dom);
-
- virDomainObjEndAPI(&dom);
- virObjectEventStateQueue(data->driver->domainEventState, event);
- virHashRemoveEntry(data->driver->autodestroy, uuidstr);
- return 0;
-}
-
-/*
- * Precondition: driver is locked
- */
-static void umlProcessAutoDestroyRun(struct uml_driver *driver, virConnectPtr conn)
-{
- struct umlProcessAutoDestroyData data = {
- driver, conn
- };
- VIR_DEBUG("conn=%p", conn);
- virHashForEach(driver->autodestroy, umlProcessAutoDestroyDom, &data);
-}
-
-static void umlProcessAutoDestroyShutdown(struct uml_driver *driver)
-{
- virHashFree(driver->autodestroy);
-}
-
-static int umlProcessAutoDestroyAdd(struct uml_driver *driver,
- virDomainObjPtr vm,
- virConnectPtr conn)
-{
- char uuidstr[VIR_UUID_STRING_BUFLEN];
- virUUIDFormat(vm->def->uuid, uuidstr);
- VIR_DEBUG("vm=%s uuid=%s conn=%p", vm->def->name, uuidstr, conn);
- if (virHashAddEntry(driver->autodestroy, uuidstr, conn) < 0)
- return -1;
- return 0;
-}
-
-static int umlProcessAutoDestroyRemove(struct uml_driver *driver,
- virDomainObjPtr vm)
-{
- char uuidstr[VIR_UUID_STRING_BUFLEN];
- virUUIDFormat(vm->def->uuid, uuidstr);
- VIR_DEBUG("vm=%s uuid=%s", vm->def->name, uuidstr);
- if (virHashRemoveEntry(driver->autodestroy, uuidstr) < 0)
- return -1;
- return 0;
-}
-
-
-static int umlReadPidFile(struct uml_driver *driver,
- virDomainObjPtr vm)
-{
- int rc = -1;
- FILE *file;
- char *pidfile = NULL;
- int retries = 0;
-
- vm->pid = -1;
- if (virAsprintf(&pidfile, "%s/%s/pid",
- driver->monitorDir, vm->def->name) < 0)
- return -1;
-
- reopen:
- if (!(file = fopen(pidfile, "r"))) {
- if (errno == ENOENT &&
- retries++ < 50) {
- usleep(1000 * 100);
- goto reopen;
- }
- goto cleanup;
- }
-
- if (fscanf(file, "%d", &vm->pid) != 1) {
- errno = EINVAL;
- VIR_FORCE_FCLOSE(file);
- goto cleanup;
- }
-
- if (VIR_FCLOSE(file) < 0)
- goto cleanup;
-
- rc = 0;
-
- cleanup:
- if (rc != 0)
- virReportSystemError(errno,
- _("failed to read pid: %s"),
- pidfile);
- VIR_FREE(pidfile);
- return rc;
-}
-
-static int umlMonitorAddress(const struct uml_driver *driver,
- const virDomainObj *vm,
- struct sockaddr_un *addr)
-{
- char *sockname;
- int retval = 0;
-
- if (virAsprintf(&sockname, "%s/%s/mconsole",
- driver->monitorDir, vm->def->name) < 0)
- return -1;
-
- memset(addr, 0, sizeof(*addr));
- addr->sun_family = AF_UNIX;
- if (virStrcpyStatic(addr->sun_path, sockname) < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Unix path %s too long for destination"), sockname);
- retval = -1;
- }
- VIR_FREE(sockname);
- return retval;
-}
-
-static int umlOpenMonitor(struct uml_driver *driver,
- virDomainObjPtr vm)
-{
- struct sockaddr_un addr;
- struct stat sb;
- int retries = 0;
- umlDomainObjPrivatePtr priv = vm->privateData;
-
- if (umlMonitorAddress(driver, vm, &addr) < 0)
- return -1;
-
- VIR_DEBUG("Dest address for monitor is '%s'", addr.sun_path);
- restat:
- if (stat(addr.sun_path, &sb) < 0) {
- if (errno == ENOENT &&
- retries++ < 50) {
- usleep(1000 * 100);
- goto restat;
- }
- return -1;
- }
-
- if ((priv->monitor = socket(PF_UNIX, SOCK_DGRAM, 0)) < 0) {
- virReportSystemError(errno,
- "%s", _("cannot open socket"));
- return -1;
- }
-
- memset(addr.sun_path, 0, sizeof(addr.sun_path));
- snprintf(addr.sun_path + 1, sizeof(addr.sun_path) - 1,
- "libvirt-uml-%u", vm->pid);
- VIR_DEBUG("Reply address for monitor is '%s'", addr.sun_path+1);
- if (bind(priv->monitor, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
- virReportSystemError(errno,
- "%s", _("cannot bind socket"));
- VIR_FORCE_CLOSE(priv->monitor);
- return -1;
- }
-
- return 0;
-}
-
-
-#define MONITOR_MAGIC 0xcafebabe
-#define MONITOR_BUFLEN 512
-#define MONITOR_VERSION 2
-
-struct monitor_request {
- uint32_t magic;
- uint32_t version;
- uint32_t length;
- char data[MONITOR_BUFLEN];
-};
-
-struct monitor_response {
- uint32_t error;
- uint32_t extra;
- uint32_t length;
- char data[MONITOR_BUFLEN];
-};
-
-
-static int umlMonitorCommand(const struct uml_driver *driver,
- const virDomainObj *vm,
- const char *cmd,
- char **reply)
-{
- struct monitor_request req;
- struct monitor_response res;
- char *retdata = NULL;
- int retlen = 0, ret = 0;
- struct sockaddr_un addr;
- unsigned int addrlen;
- umlDomainObjPrivatePtr priv = vm->privateData;
-
- VIR_DEBUG("Run command '%s'", cmd);
-
- *reply = NULL;
-
- if (umlMonitorAddress(driver, vm, &addr) < 0)
- return -1;
-
- memset(&req, 0, sizeof(req));
- req.magic = MONITOR_MAGIC;
- req.version = MONITOR_VERSION;
- req.length = strlen(cmd);
- if (req.length > (MONITOR_BUFLEN-1)) {
- virReportSystemError(EINVAL,
- _("cannot send too long command %s (%d bytes)"),
- cmd, req.length);
- return -1;
- }
- if (virStrcpyStatic(req.data, cmd) < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Command %s too long for destination"), cmd);
- return -1;
- }
-
- if (sendto(priv->monitor, &req, sizeof(req), 0,
- (struct sockaddr *)&addr, sizeof(addr)) != sizeof(req)) {
- virReportSystemError(errno,
- _("cannot send command %s"),
- cmd);
- return -1;
- }
-
- do {
- ssize_t nbytes;
- addrlen = sizeof(addr);
- nbytes = recvfrom(priv->monitor, &res, sizeof(res), 0,
- (struct sockaddr *)&addr, &addrlen);
- if (nbytes < 0) {
- if (errno == EAGAIN || errno == EINTR)
- continue;
- virReportSystemError(errno, _("cannot read reply %s"), cmd);
- goto error;
- }
- /* Ensure res.length is safe to read before validating its value. */
- if (nbytes < offsetof(struct monitor_request, data) ||
- nbytes < offsetof(struct monitor_request, data) + res.length) {
- virReportSystemError(0, _("incomplete reply %s"), cmd);
- goto error;
- }
-
- if (VIR_REALLOC_N(retdata, retlen + res.length) < 0)
- goto error;
- memcpy(retdata + retlen, res.data, res.length);
- retlen += res.length - 1;
- retdata[retlen] = '\0';
-
- if (res.error)
- ret = -1;
-
- } while (res.extra);
-
- VIR_DEBUG("Command reply is '%s'", NULLSTR(retdata));
-
- if (ret < 0)
- VIR_FREE(retdata);
- else
- *reply = retdata;
-
- return ret;
-
- error:
- VIR_FREE(retdata);
- return -1;
-}
-
-
-static void umlCleanupTapDevices(virDomainObjPtr vm)
-{
- size_t i;
-
- for (i = 0; i < vm->def->nnets; i++) {
- virDomainNetDefPtr def = vm->def->nets[i];
-
- if (def->type != VIR_DOMAIN_NET_TYPE_BRIDGE &&
- def->type != VIR_DOMAIN_NET_TYPE_NETWORK)
- continue;
-
- ignore_value(virNetDevTapDelete(def->ifname,
- def->backend.tap));
- }
-}
-
-static int umlStartVMDaemon(virConnectPtr conn,
- struct uml_driver *driver,
- virDomainObjPtr vm,
- bool autoDestroy)
-{
- int ret = -1;
- char *logfile;
- int logfd = -1;
- umlDomainObjPrivatePtr priv = vm->privateData;
- virCommandPtr cmd = NULL;
- size_t i;
-
- if (virDomainObjIsActive(vm)) {
- virReportError(VIR_ERR_OPERATION_INVALID, "%s",
- _("VM is already active"));
- return -1;
- }
-
- if (!vm->def->os.kernel) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("no kernel specified"));
- return -1;
- }
- /* Make sure the binary we are about to try exec'ing exists.
- * Technically we could catch the exec() failure, but that's
- * in a sub-process so its hard to feed back a useful error
- */
- if (!virFileIsExecutable(vm->def->os.kernel)) {
- virReportSystemError(errno,
- _("Cannot find UML kernel %s"),
- vm->def->os.kernel);
- return -1;
- }
-
- if (virFileMakePath(driver->logDir) < 0) {
- virReportSystemError(errno,
- _("cannot create log directory %s"),
- driver->logDir);
- return -1;
- }
-
- if (virAsprintf(&logfile, "%s/%s.log",
- driver->logDir, vm->def->name) < 0)
- return -1;
-
- if ((logfd = open(logfile, O_CREAT | O_TRUNC | O_WRONLY,
- S_IRUSR | S_IWUSR)) < 0) {
- virReportSystemError(errno,
- _("failed to create logfile %s"),
- logfile);
- VIR_FREE(logfile);
- return -1;
- }
- VIR_FREE(logfile);
-
- if (virSetCloseExec(logfd) < 0) {
- virReportSystemError(errno, "%s",
- _("Unable to set VM logfile close-on-exec flag"));
- VIR_FORCE_CLOSE(logfd);
- return -1;
- }
-
- /* Do this upfront, 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(driver->caps, driver->xmlopt, vm) < 0) {
- VIR_FORCE_CLOSE(logfd);
- return -1;
- }
-
- if (!(cmd = umlBuildCommandLine(conn, driver, vm)))
- goto cleanup;
-
- for (i = 0; i < vm->def->nconsoles; i++) {
- VIR_FREE(vm->def->consoles[i]->info.alias);
- if (virAsprintf(&vm->def->consoles[i]->info.alias, "console%zu", i) < 0)
- goto cleanup;
- }
-
- virCommandWriteArgLog(cmd, logfd);
-
- priv->monitor = -1;
-
- virCommandClearCaps(cmd);
- virCommandSetOutputFD(cmd, &logfd);
- virCommandSetErrorFD(cmd, &logfd);
- virCommandDaemonize(cmd);
-
- if (virCommandRun(cmd, NULL) < 0)
- goto cleanup;
-
- if (autoDestroy &&
- umlProcessAutoDestroyAdd(driver, vm, conn) < 0)
- goto cleanup;
-
- ret = 0;
- cleanup:
- VIR_FORCE_CLOSE(logfd);
- virCommandFree(cmd);
-
- if (ret < 0) {
- virDomainConfVMNWFilterTeardown(vm);
- umlCleanupTapDevices(vm);
- virDomainObjRemoveTransientDef(vm);
- }
-
- /* NB we don't mark it running here - we do that async
- with inotify */
- /* XXX what if someone else tries to start it again
- before we get the inotification ? Sounds like
- trouble.... */
- /* XXX this is bad for events too. must fix this better */
-
- return ret;
-}
-
-static void umlShutdownVMDaemon(struct uml_driver *driver,
- virDomainObjPtr vm,
- virDomainShutoffReason reason)
-{
- int ret;
- umlDomainObjPrivatePtr priv = vm->privateData;
-
- if (!virDomainObjIsActive(vm))
- return;
-
- virProcessKill(vm->pid, SIGTERM);
-
- VIR_FORCE_CLOSE(priv->monitor);
-
- if ((ret = waitpid(vm->pid, NULL, 0)) != vm->pid) {
- VIR_WARN("Got unexpected pid %d != %d",
- ret, vm->pid);
- }
-
- vm->pid = -1;
- vm->def->id = -1;
- virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF, reason);
-
- virDomainConfVMNWFilterTeardown(vm);
- umlCleanupTapDevices(vm);
-
- /* Stop autodestroy in case guest is restarted */
- umlProcessAutoDestroyRemove(driver, vm);
-
- virDomainObjRemoveTransientDef(vm);
-
- driver->nactive--;
- if (!driver->nactive && driver->inhibitCallback)
- driver->inhibitCallback(false, driver->inhibitOpaque);
-}
-
-
-static int umlConnectURIProbe(char **uri)
-{
- if (uml_driver == NULL)
- return 0;
-
- return VIR_STRDUP(*uri, uml_driver->privileged ?
- "uml:///system" :
- "uml:///session");
-}
-
-
-static virDrvOpenStatus umlConnectOpen(virConnectPtr conn,
- virConnectAuthPtr auth ATTRIBUTE_UNUSED,
- virConfPtr conf ATTRIBUTE_UNUSED,
- unsigned int flags)
-{
- virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);
-
- /* URI was good, but driver isn't active */
- if (uml_driver == NULL) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("uml state driver is not active"));
- return VIR_DRV_OPEN_ERROR;
- }
-
- /* Check path and tell them correct path if they made a mistake */
- if (uml_driver->privileged) {
- if (STRNEQ(conn->uri->path, "/system") &&
- STRNEQ(conn->uri->path, "/session")) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("unexpected UML URI path '%s', try uml:///system"),
- conn->uri->path);
- return VIR_DRV_OPEN_ERROR;
- }
- } else {
- if (STRNEQ(conn->uri->path, "/session")) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("unexpected UML URI path '%s', try uml:///session"),
- conn->uri->path);
- return VIR_DRV_OPEN_ERROR;
- }
- }
-
- if (virConnectOpenEnsureACL(conn) < 0)
- return VIR_DRV_OPEN_ERROR;
-
- conn->privateData = uml_driver;
-
- return VIR_DRV_OPEN_SUCCESS;
-}
-
-static int umlConnectClose(virConnectPtr conn)
-{
- struct uml_driver *driver = conn->privateData;
-
- umlDriverLock(driver);
- umlProcessAutoDestroyRun(driver, conn);
- umlDriverUnlock(driver);
-
- conn->privateData = NULL;
-
- return 0;
-}
-
-static const char *umlConnectGetType(virConnectPtr conn) {
- if (virConnectGetTypeEnsureACL(conn) < 0)
- return NULL;
-
- return "UML";
-}
-
-
-static int umlConnectIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED)
-{
- /* Trivially secure, since always inside the daemon */
- return 1;
-}
-
-
-static int umlConnectIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED)
-{
- /* Not encrypted, but remote driver takes care of that */
- return 0;
-}
-
-
-static int umlConnectIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED)
-{
- return 1;
-}
-
-
-static char *umlConnectGetCapabilities(virConnectPtr conn) {
- struct uml_driver *driver = (struct uml_driver *)conn->privateData;
- char *xml;
-
- if (virConnectGetCapabilitiesEnsureACL(conn) < 0)
- return NULL;
-
- umlDriverLock(driver);
- xml = virCapabilitiesFormatXML(driver->caps);
- umlDriverUnlock(driver);
-
- return xml;
-}
-
-
-
-static int umlGetProcessInfo(unsigned long long *cpuTime, pid_t pid)
-{
- char *proc;
- FILE *pidinfo;
- unsigned long long usertime, systime;
-
- if (virAsprintf(&proc, "/proc/%lld/stat", (long long)pid) < 0)
- return -1;
-
- if (!(pidinfo = fopen(proc, "r"))) {
- /* VM probably shut down, so fake 0 */
- *cpuTime = 0;
- VIR_FREE(proc);
- return 0;
- }
-
- VIR_FREE(proc);
-
- if (fscanf(pidinfo, "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %llu %llu", &usertime, &systime) != 2) {
- umlDebug("not enough arg");
- VIR_FORCE_FCLOSE(pidinfo);
- return -1;
- }
-
- /* We got jiffies
- * We want nanoseconds
- * _SC_CLK_TCK is jiffies per second
- * So calculate thus....
- */
- *cpuTime = 1000ull * 1000ull * 1000ull * (usertime + systime) / (unsigned long long)sysconf(_SC_CLK_TCK);
-
- umlDebug("Got %llu %llu %llu", usertime, systime, *cpuTime);
-
- VIR_FORCE_FCLOSE(pidinfo);
-
- return 0;
-}
-
-
-static virDomainPtr umlDomainLookupByID(virConnectPtr conn,
- int id)
-{
- struct uml_driver *driver = (struct uml_driver *)conn->privateData;
- virDomainObjPtr vm;
- virDomainPtr dom = NULL;
-
- umlDriverLock(driver);
- vm = virDomainObjListFindByID(driver->domains, id);
- umlDriverUnlock(driver);
-
- if (!vm) {
- virReportError(VIR_ERR_NO_DOMAIN,
- _("no domain with matching id '%d'"), id);
- goto cleanup;
- }
-
- if (virDomainLookupByIDEnsureACL(conn, vm->def) < 0)
- goto cleanup;
-
- dom = virGetDomain(conn, vm->def->name, vm->def->uuid, vm->def->id);
-
- cleanup:
- virDomainObjEndAPI(&vm);
- return dom;
-}
-
-static virDomainPtr umlDomainLookupByUUID(virConnectPtr conn,
- const unsigned char *uuid)
-{
- struct uml_driver *driver = (struct uml_driver *)conn->privateData;
- virDomainObjPtr vm;
- virDomainPtr dom = NULL;
-
- if (!(vm = umlDomObjFromDomain(driver, uuid)))
- return NULL;
-
- if (virDomainLookupByUUIDEnsureACL(conn, vm->def) < 0)
- goto cleanup;
-
- dom = virGetDomain(conn, vm->def->name, vm->def->uuid, vm->def->id);
-
- cleanup:
- virDomainObjEndAPI(&vm);
- return dom;
-}
-
-static virDomainPtr umlDomainLookupByName(virConnectPtr conn,
- const char *name)
-{
- struct uml_driver *driver = (struct uml_driver *)conn->privateData;
- virDomainObjPtr vm;
- virDomainPtr dom = NULL;
-
- umlDriverLock(driver);
- vm = virDomainObjListFindByName(driver->domains, name);
- umlDriverUnlock(driver);
-
- if (!vm) {
- virReportError(VIR_ERR_NO_DOMAIN,
- _("no domain with matching name '%s'"), name);
- goto cleanup;
- }
-
- if (virDomainLookupByNameEnsureACL(conn, vm->def) < 0)
- goto cleanup;
-
- dom = virGetDomain(conn, vm->def->name, vm->def->uuid, vm->def->id);
-
- cleanup:
- virDomainObjEndAPI(&vm);
- return dom;
-}
-
-
-static int umlDomainIsActive(virDomainPtr dom)
-{
- struct uml_driver *driver = dom->conn->privateData;
- virDomainObjPtr obj;
- int ret = -1;
-
- if (!(obj = umlDomObjFromDomain(driver, dom->uuid)))
- return -1;
-
- if (virDomainIsActiveEnsureACL(dom->conn, obj->def) < 0)
- goto cleanup;
-
- ret = virDomainObjIsActive(obj);
-
- cleanup:
- virDomainObjEndAPI(&obj);
- return ret;
-}
-
-
-static int umlDomainIsPersistent(virDomainPtr dom)
-{
- struct uml_driver *driver = dom->conn->privateData;
- virDomainObjPtr obj;
- int ret = -1;
-
- if (!(obj = umlDomObjFromDomain(driver, dom->uuid)))
- return -1;
-
- if (virDomainIsPersistentEnsureACL(dom->conn, obj->def) < 0)
- goto cleanup;
-
- ret = obj->persistent;
-
- cleanup:
- virDomainObjEndAPI(&obj);
- return ret;
-}
-
-static int umlDomainIsUpdated(virDomainPtr dom)
-{
- struct uml_driver *driver = dom->conn->privateData;
- virDomainObjPtr obj;
- int ret = -1;
-
- if (!(obj = umlDomObjFromDomain(driver, dom->uuid)))
- return -1;
-
- if (virDomainIsUpdatedEnsureACL(dom->conn, obj->def) < 0)
- goto cleanup;
-
- ret = obj->updated;
-
- cleanup:
- virDomainObjEndAPI(&obj);
- return ret;
-}
-
-static int umlConnectGetVersion(virConnectPtr conn, unsigned long *version)
-{
- struct uml_driver *driver = conn->privateData;
- struct utsname ut;
- int ret = -1;
-
- if (virConnectGetVersionEnsureACL(conn) < 0)
- return -1;
-
- umlDriverLock(driver);
-
- if (driver->umlVersion == 0) {
- uname(&ut);
-
- if (virParseVersionString(ut.release, &driver->umlVersion, true) < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("cannot parse version %s"), ut.release);
- goto cleanup;
- }
- }
-
- *version = driver->umlVersion;
- ret = 0;
-
- cleanup:
- umlDriverUnlock(driver);
- return ret;
-}
-
-
-static char *umlConnectGetHostname(virConnectPtr conn)
-{
- if (virConnectGetHostnameEnsureACL(conn) < 0)
- return NULL;
-
- return virGetHostname();
-}
-
-
-static int umlConnectListDomains(virConnectPtr conn, int *ids, int nids)
-{
- struct uml_driver *driver = conn->privateData;
- int n;
-
- if (virConnectListDomainsEnsureACL(conn) < 0)
- return -1;
-
- umlDriverLock(driver);
- n = virDomainObjListGetActiveIDs(driver->domains, ids, nids,
- virConnectListDomainsCheckACL, conn);
- umlDriverUnlock(driver);
-
- return n;
-}
-static int umlConnectNumOfDomains(virConnectPtr conn)
-{
- struct uml_driver *driver = conn->privateData;
- int n;
-
- if (virConnectNumOfDomainsEnsureACL(conn) < 0)
- return -1;
-
- umlDriverLock(driver);
- n = virDomainObjListNumOfDomains(driver->domains, true,
- virConnectNumOfDomainsCheckACL, conn);
- umlDriverUnlock(driver);
-
- return n;
-}
-static virDomainPtr umlDomainCreateXML(virConnectPtr conn, const char *xml,
- unsigned int flags)
-{
- struct uml_driver *driver = conn->privateData;
- virDomainDefPtr def;
- virDomainObjPtr vm = NULL;
- virDomainPtr dom = NULL;
- virObjectEventPtr event = NULL;
- unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
-
- virCheckFlags(VIR_DOMAIN_START_AUTODESTROY |
- VIR_DOMAIN_START_VALIDATE, NULL);
-
- if (flags & VIR_DOMAIN_START_VALIDATE)
- parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA;
-
- virNWFilterReadLockFilterUpdates();
- umlDriverLock(driver);
- if (!(def = virDomainDefParseString(xml, driver->caps, driver->xmlopt,
- NULL, parse_flags)))
- goto cleanup;
-
- if (virDomainCreateXMLEnsureACL(conn, def) < 0)
- goto cleanup;
-
- if (!(vm = virDomainObjListAdd(driver->domains, def,
- driver->xmlopt,
- VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
- VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
- NULL)))
- goto cleanup;
- def = NULL;
-
- if (umlStartVMDaemon(conn, driver, vm,
- (flags & VIR_DOMAIN_START_AUTODESTROY)) < 0) {
- virDomainAuditStart(vm, "booted", false);
- if (!vm->persistent)
- virDomainObjListRemove(driver->domains, vm);
- goto cleanup;
- }
- virDomainAuditStart(vm, "booted", true);
- event = virDomainEventLifecycleNewFromObj(vm,
- VIR_DOMAIN_EVENT_STARTED,
- VIR_DOMAIN_EVENT_STARTED_BOOTED);
-
- dom = virGetDomain(conn, vm->def->name, vm->def->uuid, vm->def->id);
-
- cleanup:
- virDomainDefFree(def);
- virDomainObjEndAPI(&vm);
- virObjectEventStateQueue(driver->domainEventState, event);
- umlDriverUnlock(driver);
- virNWFilterUnlockFilterUpdates();
- return dom;
-}
-
-
-static int umlDomainShutdownFlags(virDomainPtr dom,
- unsigned int flags)
-{
- struct uml_driver *driver = dom->conn->privateData;
- virDomainObjPtr vm;
- char *info = NULL;
- int ret = -1;
-
- virCheckFlags(0, -1);
-
- if (!(vm = umlDomObjFromDomain(driver, dom->uuid)))
- return -1;
-
- if (virDomainShutdownFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
- goto cleanup;
-
-#if 0
- if (umlMonitorCommand(driver, vm, "system_powerdown", &info) < 0) {
- virReportError(VIR_ERR_OPERATION_FAILED, "%s",
- _("shutdown operation failed"));
- goto cleanup;
- }
- ret = 0;
-#endif
-
- cleanup:
- VIR_FREE(info);
- virDomainObjEndAPI(&vm);
- return ret;
-}
-
-static int
-umlDomainShutdown(virDomainPtr dom)
-{
- return umlDomainShutdownFlags(dom, 0);
-}
-
-static int
-umlDomainDestroyFlags(virDomainPtr dom,
- unsigned int flags)
-{
- struct uml_driver *driver = dom->conn->privateData;
- virDomainObjPtr vm;
- virObjectEventPtr event = NULL;
- int ret = -1;
-
- virCheckFlags(0, -1);
-
- umlDriverLock(driver);
- if (!(vm = umlDomObjFromDomainLocked(driver, dom->uuid)))
- return -1;
-
- if (virDomainDestroyFlagsEnsureACL(dom->conn, vm->def) < 0)
- goto cleanup;
-
- umlShutdownVMDaemon(driver, vm, VIR_DOMAIN_SHUTOFF_DESTROYED);
- virDomainAuditStop(vm, "destroyed");
- event = virDomainEventLifecycleNewFromObj(vm,
- VIR_DOMAIN_EVENT_STOPPED,
- VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
- if (!vm->persistent)
- virDomainObjListRemove(driver->domains, vm);
- ret = 0;
-
- cleanup:
- virDomainObjEndAPI(&vm);
- virObjectEventStateQueue(driver->domainEventState, event);
- umlDriverUnlock(driver);
- return ret;
-}
-
-
-static int umlDomainDestroy(virDomainPtr dom)
-{
- return umlDomainDestroyFlags(dom, 0);
-}
-
-
-static char *umlDomainGetOSType(virDomainPtr dom) {
- struct uml_driver *driver = dom->conn->privateData;
- virDomainObjPtr vm;
- char *type = NULL;
-
- if (!(vm = umlDomObjFromDomain(driver, dom->uuid)))
- return NULL;
-
- if (virDomainGetOSTypeEnsureACL(dom->conn, vm->def) < 0)
- goto cleanup;
-
- if (VIR_STRDUP(type, virDomainOSTypeToString(vm->def->os.type)) < 0)
- goto cleanup;
-
- cleanup:
- virDomainObjEndAPI(&vm);
- return type;
-}
-
-/* Returns max memory in kb, 0 if error */
-static unsigned long long
-umlDomainGetMaxMemory(virDomainPtr dom)
-{
- struct uml_driver *driver = dom->conn->privateData;
- virDomainObjPtr vm;
- unsigned long long ret = 0;
-
- if (!(vm = umlDomObjFromDomain(driver, dom->uuid)))
- return -1;
-
- if (virDomainGetMaxMemoryEnsureACL(dom->conn, vm->def) < 0)
- goto cleanup;
-
- ret = virDomainDefGetMemoryTotal(vm->def);
-
- cleanup:
- virDomainObjEndAPI(&vm);
- return ret;
-}
-
-static int umlDomainSetMaxMemory(virDomainPtr dom, unsigned long newmax)
-{
- struct uml_driver *driver = dom->conn->privateData;
- virDomainObjPtr vm;
- int ret = -1;
-
- if (!(vm = umlDomObjFromDomain(driver, dom->uuid)))
- return -1;
-
- if (virDomainSetMaxMemoryEnsureACL(dom->conn, vm->def) < 0)
- goto cleanup;
-
- if (newmax < vm->def->mem.cur_balloon) {
- virReportError(VIR_ERR_INVALID_ARG, "%s",
- _("cannot set max memory lower than current memory"));
- goto cleanup;
- }
-
- virDomainDefSetMemoryTotal(vm->def, newmax);
- ret = 0;
-
- cleanup:
- virDomainObjEndAPI(&vm);
- return ret;
-}
-
-static int umlDomainSetMemory(virDomainPtr dom, unsigned long newmem)
-{
- struct uml_driver *driver = dom->conn->privateData;
- virDomainObjPtr vm;
- int ret = -1;
-
- if (!(vm = umlDomObjFromDomain(driver, dom->uuid)))
- return -1;
-
- if (virDomainSetMemoryEnsureACL(dom->conn, vm->def) < 0)
- goto cleanup;
-
- if (virDomainObjIsActive(vm)) {
- virReportError(VIR_ERR_OPERATION_INVALID, "%s",
- _("cannot set memory of an active domain"));
- goto cleanup;
- }
-
- if (newmem > virDomainDefGetMemoryTotal(vm->def)) {
- virReportError(VIR_ERR_INVALID_ARG, "%s",
- _("cannot set memory higher than max memory"));
- goto cleanup;
- }
-
- vm->def->mem.cur_balloon = newmem;
- ret = 0;
-
- cleanup:
- virDomainObjEndAPI(&vm);
- return ret;
-}
-
-static int umlDomainGetInfo(virDomainPtr dom,
- virDomainInfoPtr info)
-{
- struct uml_driver *driver = dom->conn->privateData;
- virDomainObjPtr vm;
- int ret = -1;
-
- if (!(vm = umlDomObjFromDomain(driver, dom->uuid)))
- return -1;
-
- if (virDomainGetInfoEnsureACL(dom->conn, vm->def) < 0)
- goto cleanup;
-
- info->state = virDomainObjGetState(vm, NULL);
-
- if (!virDomainObjIsActive(vm)) {
- info->cpuTime = 0;
- } else {
- if (umlGetProcessInfo(&(info->cpuTime), vm->pid) < 0) {
- virReportError(VIR_ERR_OPERATION_FAILED, "%s",
- _("cannot read cputime for domain"));
- goto cleanup;
- }
- }
-
- info->maxMem = virDomainDefGetMemoryTotal(vm->def);
- info->memory = vm->def->mem.cur_balloon;
- info->nrVirtCpu = virDomainDefGetVcpus(vm->def);
- ret = 0;
-
- cleanup:
- virDomainObjEndAPI(&vm);
- return ret;
-}
-
-
-static int
-umlDomainGetState(virDomainPtr dom,
- int *state,
- int *reason,
- unsigned int flags)
-{
- struct uml_driver *driver = dom->conn->privateData;
- virDomainObjPtr vm;
- int ret = -1;
-
- virCheckFlags(0, -1);
-
- if (!(vm = umlDomObjFromDomain(driver, dom->uuid)))
- return -1;
-
- if (virDomainGetStateEnsureACL(dom->conn, vm->def) < 0)
- goto cleanup;
-
- *state = virDomainObjGetState(vm, reason);
- ret = 0;
-
- cleanup:
- virDomainObjEndAPI(&vm);
- return ret;
-}
-
-
-static char *umlDomainGetXMLDesc(virDomainPtr dom,
- unsigned int flags)
-{
- struct uml_driver *driver = dom->conn->privateData;
- virDomainObjPtr vm;
- char *ret = NULL;
-
- /* Flags checked by virDomainDefFormat */
-
- umlDriverLock(driver);
- if (!(vm = umlDomObjFromDomainLocked(driver, dom->uuid)))
- goto cleanup;
-
- if (virDomainGetXMLDescEnsureACL(dom->conn, vm->def, flags) < 0)
- goto cleanup;
-
- ret = virDomainDefFormat((flags & VIR_DOMAIN_XML_INACTIVE) && vm->newDef ?
- vm->newDef : vm->def, driver->caps,
- virDomainDefFormatConvertXMLFlags(flags));
-
- cleanup:
- virDomainObjEndAPI(&vm);
- return ret;
-}
-
-
-static int umlConnectListDefinedDomains(virConnectPtr conn,
- char **const names, int nnames) {
- struct uml_driver *driver = conn->privateData;
- int n;
-
- if (virConnectListDefinedDomainsEnsureACL(conn) < 0)
- return -1;
-
- umlDriverLock(driver);
- n = virDomainObjListGetInactiveNames(driver->domains, names, nnames,
- virConnectListDefinedDomainsCheckACL, conn);
- umlDriverUnlock(driver);
-
- return n;
-}
-
-static int umlConnectNumOfDefinedDomains(virConnectPtr conn)
-{
- struct uml_driver *driver = conn->privateData;
- int n;
-
- if (virConnectNumOfDefinedDomainsEnsureACL(conn) < 0)
- return -1;
-
- umlDriverLock(driver);
- n = virDomainObjListNumOfDomains(driver->domains, false,
- virConnectNumOfDefinedDomainsCheckACL, conn);
- umlDriverUnlock(driver);
-
- return n;
-}
-
-
-static int umlDomainCreateWithFlags(virDomainPtr dom, unsigned int flags)
-{
- struct uml_driver *driver = dom->conn->privateData;
- virDomainObjPtr vm;
- virObjectEventPtr event = NULL;
- int ret = -1;
-
- virCheckFlags(VIR_DOMAIN_START_AUTODESTROY, -1);
-
- virNWFilterReadLockFilterUpdates();
- umlDriverLock(driver);
- if (!(vm = umlDomObjFromDomainLocked(driver, dom->uuid)))
- goto cleanup;
-
- if (virDomainCreateWithFlagsEnsureACL(dom->conn, vm->def) < 0)
- goto cleanup;
-
- ret = umlStartVMDaemon(dom->conn, driver, vm,
- (flags & VIR_DOMAIN_START_AUTODESTROY));
- virDomainAuditStart(vm, "booted", ret >= 0);
- if (ret == 0)
- event = virDomainEventLifecycleNewFromObj(vm,
- VIR_DOMAIN_EVENT_STARTED,
- VIR_DOMAIN_EVENT_STARTED_BOOTED);
-
- cleanup:
- virDomainObjEndAPI(&vm);
- virObjectEventStateQueue(driver->domainEventState, event);
- umlDriverUnlock(driver);
- virNWFilterUnlockFilterUpdates();
- return ret;
-}
-
-static int umlDomainCreate(virDomainPtr dom)
-{
- return umlDomainCreateWithFlags(dom, 0);
-}
-
-static virDomainPtr
-umlDomainDefineXMLFlags(virConnectPtr conn, const char *xml, unsigned int flags)
-{
- struct uml_driver *driver = conn->privateData;
- virDomainDefPtr def;
- virDomainObjPtr vm = NULL;
- virDomainPtr dom = NULL;
- unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
-
- virCheckFlags(VIR_DOMAIN_DEFINE_VALIDATE, NULL);
-
- if (flags & VIR_DOMAIN_DEFINE_VALIDATE)
- parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA;
-
- umlDriverLock(driver);
- if (!(def = virDomainDefParseString(xml, driver->caps, driver->xmlopt,
- NULL, parse_flags)))
- goto cleanup;
-
- if (virXMLCheckIllegalChars("name", def->name, "\n") < 0)
- goto cleanup;
-
- if (virDomainDefineXMLFlagsEnsureACL(conn, def) < 0)
- goto cleanup;
-
- if (!(vm = virDomainObjListAdd(driver->domains, def,
- driver->xmlopt,
- 0, NULL)))
- goto cleanup;
- def = NULL;
- vm->persistent = 1;
-
- if (virDomainSaveConfig(driver->configDir, driver->caps,
- vm->newDef ? vm->newDef : vm->def) < 0) {
- virDomainObjListRemove(driver->domains, vm);
- goto cleanup;
- }
-
- dom = virGetDomain(conn, vm->def->name, vm->def->uuid, vm->def->id);
-
- cleanup:
- virDomainDefFree(def);
- virDomainObjEndAPI(&vm);
- umlDriverUnlock(driver);
- return dom;
-}
-
-static virDomainPtr
-umlDomainDefineXML(virConnectPtr conn, const char *xml)
-{
- return umlDomainDefineXMLFlags(conn, xml, 0);
-}
-
-static int umlDomainUndefineFlags(virDomainPtr dom,
- unsigned int flags)
-{
- struct uml_driver *driver = dom->conn->privateData;
- virDomainObjPtr vm;
- int ret = -1;
-
- virCheckFlags(0, -1);
-
- umlDriverLock(driver);
- if (!(vm = umlDomObjFromDomainLocked(driver, dom->uuid)))
- goto cleanup;
-
- if (virDomainUndefineFlagsEnsureACL(dom->conn, vm->def) < 0)
- goto cleanup;
-
- if (!vm->persistent) {
- virReportError(VIR_ERR_OPERATION_INVALID, "%s",
- _("cannot undefine transient domain"));
- goto cleanup;
- }
-
- if (virDomainDeleteConfig(driver->configDir, driver->autostartDir, vm) < 0)
- goto cleanup;
-
- if (virDomainObjIsActive(vm))
- vm->persistent = 0;
- else
- virDomainObjListRemove(driver->domains, vm);
-
- ret = 0;
-
- cleanup:
- virDomainObjEndAPI(&vm);
- umlDriverUnlock(driver);
- return ret;
-}
-
-
-static int umlDomainUndefine(virDomainPtr dom)
-{
- return umlDomainUndefineFlags(dom, 0);
-}
-
-static int umlDomainAttachUmlDisk(struct uml_driver *driver,
- virDomainObjPtr vm,
- virDomainDiskDefPtr disk)
-{
- size_t i;
- char *cmd = NULL;
- char *reply = NULL;
-
- for (i = 0; i < vm->def->ndisks; i++) {
- if (STREQ(vm->def->disks[i]->dst, disk->dst)) {
- virReportError(VIR_ERR_OPERATION_FAILED,
- _("target %s already exists"), disk->dst);
- return -1;
- }
- }
-
- if (!virDomainDiskGetSource(disk)) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- "%s", _("disk source path is missing"));
- goto error;
- }
-
- if (virAsprintf(&cmd, "config %s=%s", disk->dst,
- virDomainDiskGetSource(disk)) < 0)
- return -1;
-
- if (umlMonitorCommand(driver, vm, cmd, &reply) < 0)
- goto error;
-
- if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0)
- goto error;
-
- virDomainDiskInsertPreAlloced(vm->def, disk);
-
- VIR_FREE(reply);
- VIR_FREE(cmd);
-
- return 0;
-
- error:
-
- VIR_FREE(reply);
- VIR_FREE(cmd);
-
- return -1;
-}
-
-
-static int umlDomainAttachDevice(virDomainPtr dom, const char *xml)
-{
- struct uml_driver *driver = dom->conn->privateData;
- virDomainObjPtr vm;
- virDomainDeviceDefPtr dev = NULL;
- int ret = -1;
-
- umlDriverLock(driver);
-
- if (!(vm = umlDomObjFromDomainLocked(driver, dom->uuid)))
- goto cleanup;
-
- if (virDomainAttachDeviceEnsureACL(dom->conn, vm->def) < 0)
- goto cleanup;
-
- if (!virDomainObjIsActive(vm)) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- "%s", _("cannot attach device on inactive domain"));
- goto cleanup;
- }
-
- dev = virDomainDeviceDefParse(xml, vm->def, driver->caps, driver->xmlopt,
- VIR_DOMAIN_DEF_PARSE_INACTIVE);
-
- if (dev == NULL)
- goto cleanup;
-
- if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
- if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_UML) {
- ret = umlDomainAttachUmlDisk(driver, vm, dev->data.disk);
- if (ret == 0)
- dev->data.disk = NULL;
- } else {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("disk bus '%s' cannot be hotplugged."),
- virDomainDiskBusTypeToString(dev->data.disk->bus));
- }
- } else {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("device type '%s' cannot be attached"),
- virDomainDeviceTypeToString(dev->type));
- goto cleanup;
- }
-
- cleanup:
-
- virDomainDeviceDefFree(dev);
- virDomainObjEndAPI(&vm);
- umlDriverUnlock(driver);
- return ret;
-}
-
-
-static int
-umlDomainAttachDeviceFlags(virDomainPtr dom,
- const char *xml,
- unsigned int flags)
-{
- virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG, -1);
-
- if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- "%s", _("cannot modify the persistent configuration of a domain"));
- return -1;
- }
-
- return umlDomainAttachDevice(dom, xml);
-}
-
-
-static int umlDomainDetachUmlDisk(struct uml_driver *driver,
- virDomainObjPtr vm,
- virDomainDeviceDefPtr dev)
-{
- size_t i;
- int ret = -1;
- virDomainDiskDefPtr detach = NULL;
- char *cmd;
- char *reply;
-
- for (i = 0; i < vm->def->ndisks; i++) {
- if (STREQ(vm->def->disks[i]->dst, dev->data.disk->dst))
- break;
- }
-
- if (i == vm->def->ndisks) {
- virReportError(VIR_ERR_OPERATION_FAILED,
- _("disk %s not found"), dev->data.disk->dst);
- return -1;
- }
-
- detach = vm->def->disks[i];
-
- if (virAsprintf(&cmd, "remove %s", detach->dst) < 0)
- return -1;
-
- if (umlMonitorCommand(driver, vm, cmd, &reply) < 0)
- goto cleanup;
-
- virDomainDiskRemove(vm->def, i);
-
- virDomainDiskDefFree(detach);
-
- ret = 0;
-
- VIR_FREE(reply);
-
- cleanup:
- VIR_FREE(cmd);
-
- return ret;
-}
-
-
-static int umlDomainDetachDevice(virDomainPtr dom, const char *xml)
-{
- struct uml_driver *driver = dom->conn->privateData;
- virDomainObjPtr vm;
- virDomainDeviceDefPtr dev = NULL;
- int ret = -1;
-
- umlDriverLock(driver);
- if (!(vm = umlDomObjFromDomainLocked(driver, dom->uuid)))
- goto cleanup;
-
- if (virDomainDetachDeviceEnsureACL(dom->conn, vm->def) < 0)
- goto cleanup;
-
- if (!virDomainObjIsActive(vm)) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- "%s", _("cannot detach device on inactive domain"));
- goto cleanup;
- }
-
- dev = virDomainDeviceDefParse(xml, vm->def, driver->caps, driver->xmlopt,
- VIR_DOMAIN_DEF_PARSE_INACTIVE |
- VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE);
- if (dev == NULL)
- goto cleanup;
-
- if (dev->type == VIR_DOMAIN_DEVICE_DISK &&
- dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
- if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_UML)
- ret = umlDomainDetachUmlDisk(driver, vm, dev);
- else
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("This type of disk cannot be hot unplugged"));
- } else {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- "%s", _("This type of device cannot be hot unplugged"));
- }
-
- cleanup:
- virDomainDeviceDefFree(dev);
- virDomainObjEndAPI(&vm);
- umlDriverUnlock(driver);
- return ret;
-}
-
-
-static int
-umlDomainDetachDeviceFlags(virDomainPtr dom,
- const char *xml,
- unsigned int flags)
-{
- virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG, -1);
-
- if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- "%s", _("cannot modify the persistent configuration of a domain"));
- return -1;
- }
-
- return umlDomainDetachDevice(dom, xml);
-}
-
-
-static int umlDomainGetAutostart(virDomainPtr dom,
- int *autostart)
-{
- struct uml_driver *driver = dom->conn->privateData;
- virDomainObjPtr vm;
- int ret = -1;
-
- umlDriverLock(driver);
- if (!(vm = umlDomObjFromDomainLocked(driver, dom->uuid)))
- goto cleanup;
-
- if (virDomainGetAutostartEnsureACL(dom->conn, vm->def) < 0)
- goto cleanup;
-
- *autostart = vm->autostart;
- ret = 0;
-
- cleanup:
- virDomainObjEndAPI(&vm);
- umlDriverUnlock(driver);
- return ret;
-}
-
-static int umlDomainSetAutostart(virDomainPtr dom,
- int autostart)
-{
- struct uml_driver *driver = dom->conn->privateData;
- virDomainObjPtr vm;
- char *configFile = NULL, *autostartLink = NULL;
- int ret = -1;
-
- umlDriverLock(driver);
- if (!(vm = umlDomObjFromDomainLocked(driver, dom->uuid)))
- goto cleanup;
-
- if (virDomainSetAutostartEnsureACL(dom->conn, vm->def) < 0)
- goto cleanup;
-
- if (!vm->persistent) {
- virReportError(VIR_ERR_OPERATION_INVALID, "%s",
- _("cannot set autostart for transient domain"));
- goto cleanup;
- }
-
- autostart = (autostart != 0);
-
- if (vm->autostart != autostart) {
- if ((configFile = virDomainConfigFile(driver->configDir, vm->def->name)) == NULL)
- goto cleanup;
- if ((autostartLink = virDomainConfigFile(driver->autostartDir, vm->def->name)) == NULL)
- goto cleanup;
-
- if (autostart) {
- if (virFileMakePath(driver->autostartDir) < 0) {
- virReportSystemError(errno,
- _("cannot create autostart directory %s"),
- driver->autostartDir);
- goto cleanup;
- }
-
- if (symlink(configFile, autostartLink) < 0) {
- virReportSystemError(errno,
- _("Failed to create symlink '%s to '%s'"),
- autostartLink, configFile);
- goto cleanup;
- }
- } else {
- if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
- virReportSystemError(errno,
- _("Failed to delete symlink '%s'"),
- autostartLink);
- goto cleanup;
- }
- }
-
- vm->autostart = autostart;
- }
- ret = 0;
-
- cleanup:
- VIR_FREE(configFile);
- VIR_FREE(autostartLink);
- virDomainObjEndAPI(&vm);
- umlDriverUnlock(driver);
- return ret;
-}
-
-
-static int
-umlDomainBlockPeek(virDomainPtr dom,
- const char *path,
- unsigned long long offset, size_t size,
- void *buffer,
- unsigned int flags)
-{
- struct uml_driver *driver = dom->conn->privateData;
- virDomainObjPtr vm;
- int fd = -1, ret = -1;
- const char *actual;
-
- virCheckFlags(0, -1);
-
- if (!(vm = umlDomObjFromDomain(driver, dom->uuid)))
- return -1;
-
- if (virDomainBlockPeekEnsureACL(dom->conn, vm->def) < 0)
- goto cleanup;
-
- if (!path || path[0] == '\0') {
- virReportError(VIR_ERR_INVALID_ARG, "%s",
- _("NULL or empty path"));
- goto cleanup;
- }
-
- /* Check the path belongs to this domain. */
- if (!(actual = virDomainDiskPathByName(vm->def, path))) {
- virReportError(VIR_ERR_INVALID_ARG,
- _("invalid path '%s'"), path);
- goto cleanup;
- }
- path = actual;
-
- /* The path is correct, now try to open it and get its size. */
- fd = open(path, O_RDONLY);
- if (fd == -1) {
- virReportSystemError(errno,
- _("cannot open %s"), path);
- goto cleanup;
- }
-
- /* Seek and read. */
- /* NB. Because we configure with AC_SYS_LARGEFILE, off_t should
- * be 64 bits on all platforms.
- */
- if (lseek(fd, offset, SEEK_SET) == (off_t)-1 ||
- saferead(fd, buffer, size) == (ssize_t)-1) {
- virReportSystemError(errno,
- _("cannot read %s"), path);
- goto cleanup;
- }
-
- ret = 0;
-
- cleanup:
- VIR_FORCE_CLOSE(fd);
- virDomainObjEndAPI(&vm);
- return ret;
-}
-
-
-static int
-umlDomainOpenConsole(virDomainPtr dom,
- const char *dev_name,
- virStreamPtr st,
- unsigned int flags)
-{
- struct uml_driver *driver = dom->conn->privateData;
- virDomainObjPtr vm = NULL;
- int ret = -1;
- virDomainChrDefPtr chr = NULL;
- size_t i;
-
- virCheckFlags(0, -1);
-
- umlDriverLock(driver);
- if (!(vm = umlDomObjFromDomainLocked(driver, dom->uuid)))
- goto cleanup;
-
- if (virDomainOpenConsoleEnsureACL(dom->conn, vm->def) < 0)
- goto cleanup;
-
- if (virDomainObjCheckActive(vm) < 0)
- goto cleanup;
-
- if (dev_name) {
- for (i = 0; i < vm->def->nconsoles; i++) {
- if (vm->def->consoles[i]->info.alias &&
- STREQ(vm->def->consoles[i]->info.alias, dev_name)) {
- chr = vm->def->consoles[i];
- break;
- }
- }
- } else {
- if (vm->def->nconsoles)
- chr = vm->def->consoles[0];
- else if (vm->def->nserials)
- chr = vm->def->serials[0];
- }
-
- if (!chr) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("cannot find console device '%s'"),
- dev_name ? dev_name : _("default"));
- goto cleanup;
- }
-
- if (chr->source->type != VIR_DOMAIN_CHR_TYPE_PTY) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("character device %s is not using a PTY"),
- dev_name ? dev_name : NULLSTR(chr->info.alias));
- goto cleanup;
- }
-
- if (virFDStreamOpenFile(st, chr->source->data.file.path,
- 0, 0, O_RDWR) < 0)
- goto cleanup;
-
- ret = 0;
- cleanup:
- virDomainObjEndAPI(&vm);
- umlDriverUnlock(driver);
- return ret;
-}
-
-
-static int
-umlConnectDomainEventRegister(virConnectPtr conn,
- virConnectDomainEventCallback callback,
- void *opaque,
- virFreeCallback freecb)
-{
- struct uml_driver *driver = conn->privateData;
- int ret = 0;
-
- if (virConnectDomainEventRegisterEnsureACL(conn) < 0)
- return -1;
-
- umlDriverLock(driver);
- if (virDomainEventStateRegister(conn,
- driver->domainEventState,
- callback, opaque, freecb) < 0)
- ret = -1;
- umlDriverUnlock(driver);
-
- return ret;
-}
-
-static int
-umlConnectDomainEventDeregister(virConnectPtr conn,
- virConnectDomainEventCallback callback)
-{
- struct uml_driver *driver = conn->privateData;
- int ret = 0;
-
- if (virConnectDomainEventDeregisterEnsureACL(conn) < 0)
- return -1;
-
- umlDriverLock(driver);
- if (virDomainEventStateDeregister(conn,
- driver->domainEventState,
- callback) < 0)
- ret = -1;
- umlDriverUnlock(driver);
-
- return ret;
-}
-
-static int
-umlConnectDomainEventRegisterAny(virConnectPtr conn,
- virDomainPtr dom,
- int eventID,
- virConnectDomainEventGenericCallback callback,
- void *opaque,
- virFreeCallback freecb)
-{
- struct uml_driver *driver = conn->privateData;
- int ret;
-
- if (virConnectDomainEventRegisterAnyEnsureACL(conn) < 0)
- return -1;
-
- umlDriverLock(driver);
- if (virDomainEventStateRegisterID(conn,
- driver->domainEventState,
- dom, eventID,
- callback, opaque, freecb, &ret) < 0)
- ret = -1;
- umlDriverUnlock(driver);
-
- return ret;
-}
-
-
-static int
-umlConnectDomainEventDeregisterAny(virConnectPtr conn,
- int callbackID)
-{
- struct uml_driver *driver = conn->privateData;
- int ret = 0;
-
- if (virConnectDomainEventDeregisterAnyEnsureACL(conn) < 0)
- return -1;
-
- umlDriverLock(driver);
- if (virObjectEventStateDeregisterID(conn,
- driver->domainEventState,
- callbackID, true) < 0)
- ret = -1;
- umlDriverUnlock(driver);
-
- return ret;
-}
-
-
-static int umlConnectListAllDomains(virConnectPtr conn,
- virDomainPtr **domains,
- unsigned int flags)
-{
- struct uml_driver *driver = conn->privateData;
- int ret = -1;
-
- virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
-
- if (virConnectListAllDomainsEnsureACL(conn) < 0)
- return -1;
-
- umlDriverLock(driver);
- ret = virDomainObjListExport(driver->domains, conn, domains,
- virConnectListAllDomainsCheckACL, flags);
- umlDriverUnlock(driver);
-
- return ret;
-}
-
-
-static int
-umlNodeGetInfo(virConnectPtr conn,
- virNodeInfoPtr nodeinfo)
-{
- if (virNodeGetInfoEnsureACL(conn) < 0)
- return -1;
-
- return virCapabilitiesGetNodeInfo(nodeinfo);
-}
-
-
-static int
-umlNodeGetCPUStats(virConnectPtr conn,
- int cpuNum,
- virNodeCPUStatsPtr params,
- int *nparams,
- unsigned int flags)
-{
- if (virNodeGetCPUStatsEnsureACL(conn) < 0)
- return -1;
-
- return virHostCPUGetStats(cpuNum, params, nparams, flags);
-}
-
-
-static int
-umlNodeGetMemoryStats(virConnectPtr conn,
- int cellNum,
- virNodeMemoryStatsPtr params,
- int *nparams,
- unsigned int flags)
-{
- if (virNodeGetMemoryStatsEnsureACL(conn) < 0)
- return -1;
-
- return virHostMemGetStats(cellNum, params, nparams, flags);
-}
-
-
-static int
-umlNodeGetCellsFreeMemory(virConnectPtr conn,
- unsigned long long *freeMems,
- int startCell,
- int maxCells)
-{
- if (virNodeGetCellsFreeMemoryEnsureACL(conn) < 0)
- return -1;
-
- return virHostMemGetCellsFree(freeMems, startCell, maxCells);
-}
-
-
-static unsigned long long
-umlNodeGetFreeMemory(virConnectPtr conn)
-{
- unsigned long long freeMem;
-
- if (virNodeGetFreeMemoryEnsureACL(conn) < 0)
- return 0;
-
- if (virHostMemGetInfo(NULL, &freeMem) < 0)
- return 0;
-
- return freeMem;
-}
-
-
-static int
-umlNodeGetMemoryParameters(virConnectPtr conn,
- virTypedParameterPtr params,
- int *nparams,
- unsigned int flags)
-{
- if (virNodeGetMemoryParametersEnsureACL(conn) < 0)
- return -1;
-
- return virHostMemGetParameters(params, nparams, flags);
-}
-
-
-static int
-umlNodeSetMemoryParameters(virConnectPtr conn,
- virTypedParameterPtr params,
- int nparams,
- unsigned int flags)
-{
- if (virNodeSetMemoryParametersEnsureACL(conn) < 0)
- return -1;
-
- return virHostMemSetParameters(params, nparams, flags);
-}
-
-
-static int
-umlNodeGetCPUMap(virConnectPtr conn,
- unsigned char **cpumap,
- unsigned int *online,
- unsigned int flags)
-{
- if (virNodeGetCPUMapEnsureACL(conn) < 0)
- return -1;
-
- return virHostCPUGetMap(cpumap, online, flags);
-}
-
-
-static int
-umlNodeSuspendForDuration(virConnectPtr conn,
- unsigned int target,
- unsigned long long duration,
- unsigned int flags)
-{
- if (virNodeSuspendForDurationEnsureACL(conn) < 0)
- return -1;
-
- return virNodeSuspend(target, duration, flags);
-}
-
-
-static int
-umlNodeGetFreePages(virConnectPtr conn,
- unsigned int npages,
- unsigned int *pages,
- int startCell,
- unsigned int cellCount,
- unsigned long long *counts,
- unsigned int flags)
-{
- virCheckFlags(0, -1);
-
- if (virNodeGetFreePagesEnsureACL(conn) < 0)
- return -1;
-
- return virHostMemGetFreePages(npages, pages, startCell, cellCount, counts);
-}
-
-
-static int
-umlNodeAllocPages(virConnectPtr conn,
- unsigned int npages,
- unsigned int *pageSizes,
- unsigned long long *pageCounts,
- int startCell,
- unsigned int cellCount,
- unsigned int flags)
-{
- bool add = !(flags & VIR_NODE_ALLOC_PAGES_SET);
-
- virCheckFlags(VIR_NODE_ALLOC_PAGES_SET, -1);
-
- if (virNodeAllocPagesEnsureACL(conn) < 0)
- return -1;
-
- return virHostMemAllocPages(npages, pageSizes, pageCounts,
- startCell, cellCount, add);
-}
-
-
-static int
-umlDomainHasManagedSaveImage(virDomainPtr dom, unsigned int flags)
-{
- struct uml_driver *driver = dom->conn->privateData;
- int ret = -1;
- virDomainObjPtr vm;
-
- virCheckFlags(0, -1);
-
- if (!(vm = umlDomObjFromDomain(driver, dom->uuid)))
- return -1;
-
- if (virDomainHasManagedSaveImageEnsureACL(dom->conn, vm->def) < 0)
- goto cleanup;
-
- ret = 0;
-
- cleanup:
- virDomainObjEndAPI(&vm);
- return ret;
-}
-
-
-static virHypervisorDriver umlHypervisorDriver = {
- .name = "UML",
- .connectURIProbe = umlConnectURIProbe,
- .connectOpen = umlConnectOpen, /* 0.5.0 */
- .connectClose = umlConnectClose, /* 0.5.0 */
- .connectGetType = umlConnectGetType, /* 0.5.0 */
- .connectGetVersion = umlConnectGetVersion, /* 0.5.0 */
- .connectGetHostname = umlConnectGetHostname, /* 0.5.0 */
- .nodeGetInfo = umlNodeGetInfo, /* 0.5.0 */
- .connectGetCapabilities = umlConnectGetCapabilities, /* 0.5.0 */
- .connectListDomains = umlConnectListDomains, /* 0.5.0 */
- .connectNumOfDomains = umlConnectNumOfDomains, /* 0.5.0 */
- .connectListAllDomains = umlConnectListAllDomains, /* 0.9.13 */
- .domainCreateXML = umlDomainCreateXML, /* 0.5.0 */
- .domainLookupByID = umlDomainLookupByID, /* 0.5.0 */
- .domainLookupByUUID = umlDomainLookupByUUID, /* 0.5.0 */
- .domainLookupByName = umlDomainLookupByName, /* 0.5.0 */
- .domainShutdown = umlDomainShutdown, /* 0.5.0 */
- .domainShutdownFlags = umlDomainShutdownFlags, /* 0.9.10 */
- .domainDestroy = umlDomainDestroy, /* 0.5.0 */
- .domainDestroyFlags = umlDomainDestroyFlags, /* 0.9.4 */
- .domainGetOSType = umlDomainGetOSType, /* 0.5.0 */
- .domainGetMaxMemory = umlDomainGetMaxMemory, /* 0.5.0 */
- .domainSetMaxMemory = umlDomainSetMaxMemory, /* 0.5.0 */
- .domainSetMemory = umlDomainSetMemory, /* 0.5.0 */
- .domainGetInfo = umlDomainGetInfo, /* 0.5.0 */
- .domainGetState = umlDomainGetState, /* 0.9.2 */
- .domainGetXMLDesc = umlDomainGetXMLDesc, /* 0.5.0 */
- .connectListDefinedDomains = umlConnectListDefinedDomains, /* 0.5.0 */
- .connectNumOfDefinedDomains = umlConnectNumOfDefinedDomains, /* 0.5.0 */
- .domainCreate = umlDomainCreate, /* 0.5.0 */
- .domainCreateWithFlags = umlDomainCreateWithFlags, /* 0.8.2 */
- .domainDefineXML = umlDomainDefineXML, /* 0.5.0 */
- .domainDefineXMLFlags = umlDomainDefineXMLFlags, /* 1.2.12 */
- .domainUndefine = umlDomainUndefine, /* 0.5.0 */
- .domainUndefineFlags = umlDomainUndefineFlags, /* 0.9.4 */
- .domainAttachDevice = umlDomainAttachDevice, /* 0.8.4 */
- .domainAttachDeviceFlags = umlDomainAttachDeviceFlags, /* 0.8.4 */
- .domainDetachDevice = umlDomainDetachDevice, /* 0.8.4 */
- .domainDetachDeviceFlags = umlDomainDetachDeviceFlags, /* 0.8.4 */
- .domainGetAutostart = umlDomainGetAutostart, /* 0.5.0 */
- .domainSetAutostart = umlDomainSetAutostart, /* 0.5.0 */
- .domainBlockPeek = umlDomainBlockPeek, /* 0.5.0 */
- .nodeGetCPUStats = umlNodeGetCPUStats, /* 0.9.3 */
- .nodeGetMemoryStats = umlNodeGetMemoryStats, /* 0.9.3 */
- .nodeGetCellsFreeMemory = umlNodeGetCellsFreeMemory, /* 0.5.0 */
- .nodeGetFreeMemory = umlNodeGetFreeMemory, /* 0.5.0 */
- .nodeGetCPUMap = umlNodeGetCPUMap, /* 1.0.0 */
- .connectDomainEventRegister = umlConnectDomainEventRegister, /* 0.9.4 */
- .connectDomainEventDeregister = umlConnectDomainEventDeregister, /* 0.9.4 */
- .connectIsEncrypted = umlConnectIsEncrypted, /* 0.7.3 */
- .connectIsSecure = umlConnectIsSecure, /* 0.7.3 */
- .domainIsActive = umlDomainIsActive, /* 0.7.3 */
- .domainIsPersistent = umlDomainIsPersistent, /* 0.7.3 */
- .domainIsUpdated = umlDomainIsUpdated, /* 0.8.6 */
- .connectDomainEventRegisterAny = umlConnectDomainEventRegisterAny, /* 0.9.4 */
- .connectDomainEventDeregisterAny = umlConnectDomainEventDeregisterAny, /* 0.9.4 */
- .domainOpenConsole = umlDomainOpenConsole, /* 0.8.6 */
- .connectIsAlive = umlConnectIsAlive, /* 0.9.8 */
- .nodeSuspendForDuration = umlNodeSuspendForDuration, /* 0.9.8 */
- .nodeGetMemoryParameters = umlNodeGetMemoryParameters, /* 0.10.2 */
- .nodeSetMemoryParameters = umlNodeSetMemoryParameters, /* 0.10.2 */
- .nodeGetFreePages = umlNodeGetFreePages, /* 1.2.6 */
- .nodeAllocPages = umlNodeAllocPages, /* 1.2.9 */
- .domainHasManagedSaveImage = umlDomainHasManagedSaveImage, /* 1.2.13 */
-};
-
-static virConnectDriver umlConnectDriver = {
- .localOnly = true,
- .uriSchemes = (const char *[]){ "uml", NULL },
- .hypervisorDriver = ¨HypervisorDriver,
-};
-
-static virStateDriver umlStateDriver = {
- .name = "UML",
- .stateInitialize = umlStateInitialize,
- .stateAutoStart = umlStateAutoStart,
- .stateCleanup = umlStateCleanup,
- .stateReload = umlStateReload,
-};
-
-int umlRegister(void)
-{
- if (virRegisterConnectDriver(¨ConnectDriver,
- true) < 0)
- return -1;
- if (virRegisterStateDriver(¨StateDriver) < 0)
- return -1;
- return 0;
-}