2008-11-19 16:58:23 +00:00
|
|
|
/*
|
|
|
|
* uml_driver.c: core driver methods for managing UML guests
|
|
|
|
*
|
2009-02-05 16:28:15 +00:00
|
|
|
* Copyright (C) 2006, 2007, 2008, 2009 Red Hat, Inc.
|
2008-11-19 16:58:23 +00:00
|
|
|
* 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, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
*
|
|
|
|
* Author: Daniel P. Berrange <berrange@redhat.com>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/poll.h>
|
|
|
|
#include <dirent.h>
|
|
|
|
#include <limits.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <strings.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <sys/utsname.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <paths.h>
|
|
|
|
#include <pwd.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <sys/wait.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <sys/inotify.h>
|
Move xen driver code into src/xen/ directory
* src/Makefile.am, src/proxy_internal.c, src/proxy_internal.h
src/sexpr.c, src/sexpr.h, src/xen_unified.c, src/xen_unified.h,
src/xen_internal.c, src/xen_internal.h, src/xen_inotify.c,
src/xen_inotify.h, src/xend_internal.c, src/xend_internal.h,
src/xm_internal.c, src/xm_internal.h, src/xs_internal.c,
src/xs_internal.h: Move to src/xen/ directory
* proxy/Makefile.am, proxy/libvirt_proxy.c, src/Makefile.am,
src/libvirt.c, tests/sexpr2xmltest.c, tests/statstest.c,
tests/xencapstest.c, tests/xmconfigtest.c, tests/xml2sexprtest.c:
Adapt to changed xen location
* src/stats_linux.h, src/stats_linux.c: Remove xen specific block
stats APIs
* src/qemu_driver.c, src/uml_driver.c: Add missing sys/un.h include
uncovered after change to stats_linux.h
* src/xen/block_stats.h, src/xen/block_stats.c: Add xen specific
block stats APIs
2009-09-15 15:38:33 +00:00
|
|
|
#include <sys/un.h>
|
2008-11-19 16:58:23 +00:00
|
|
|
|
|
|
|
#include "uml_driver.h"
|
|
|
|
#include "uml_conf.h"
|
|
|
|
#include "event.h"
|
|
|
|
#include "buf.h"
|
|
|
|
#include "util.h"
|
|
|
|
#include "nodeinfo.h"
|
|
|
|
#include "stats_linux.h"
|
|
|
|
#include "capabilities.h"
|
|
|
|
#include "memory.h"
|
|
|
|
#include "uuid.h"
|
|
|
|
#include "domain_conf.h"
|
|
|
|
#include "datatypes.h"
|
2008-12-22 10:48:59 +00:00
|
|
|
#include "logging.h"
|
2008-11-19 16:58:23 +00:00
|
|
|
|
2009-01-20 17:13:33 +00:00
|
|
|
#define VIR_FROM_THIS VIR_FROM_UML
|
|
|
|
|
2008-11-19 16:58:23 +00:00
|
|
|
/* For storing short-lived temporary files. */
|
|
|
|
#define TEMPDIR LOCAL_STATE_DIR "/cache/libvirt"
|
|
|
|
|
|
|
|
static int umlShutdown(void);
|
|
|
|
|
2008-12-04 21:14:39 +00:00
|
|
|
static void umlDriverLock(struct uml_driver *driver)
|
|
|
|
{
|
2009-01-15 19:56:05 +00:00
|
|
|
virMutexLock(&driver->lock);
|
2008-12-04 21:14:39 +00:00
|
|
|
}
|
|
|
|
static void umlDriverUnlock(struct uml_driver *driver)
|
|
|
|
{
|
2009-01-15 19:56:05 +00:00
|
|
|
virMutexUnlock(&driver->lock);
|
2008-12-04 21:14:39 +00:00
|
|
|
}
|
|
|
|
|
2008-11-19 16:58:23 +00:00
|
|
|
|
|
|
|
static int umlOpenMonitor(virConnectPtr conn,
|
|
|
|
struct uml_driver *driver,
|
|
|
|
virDomainObjPtr vm);
|
|
|
|
static int umlReadPidFile(virConnectPtr conn,
|
|
|
|
struct uml_driver *driver,
|
|
|
|
virDomainObjPtr vm);
|
|
|
|
|
|
|
|
static int umlSetCloseExec(int fd) {
|
|
|
|
int flags;
|
|
|
|
if ((flags = fcntl(fd, F_GETFD)) < 0)
|
|
|
|
goto error;
|
|
|
|
flags |= FD_CLOEXEC;
|
|
|
|
if ((fcntl(fd, F_SETFD, flags)) < 0)
|
|
|
|
goto error;
|
|
|
|
return 0;
|
|
|
|
error:
|
2009-06-25 15:02:10 +00:00
|
|
|
VIR_ERROR0(_("Failed to set close-on-exec file descriptor flag"));
|
2008-11-19 16:58:23 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int umlStartVMDaemon(virConnectPtr conn,
|
|
|
|
struct uml_driver *driver,
|
|
|
|
virDomainObjPtr vm);
|
|
|
|
|
|
|
|
static void umlShutdownVMDaemon(virConnectPtr conn,
|
|
|
|
struct uml_driver *driver,
|
|
|
|
virDomainObjPtr vm);
|
|
|
|
|
|
|
|
|
|
|
|
static int umlMonitorCommand (virConnectPtr conn,
|
|
|
|
const struct uml_driver *driver,
|
|
|
|
const virDomainObjPtr vm,
|
|
|
|
const char *cmd,
|
|
|
|
char **reply);
|
|
|
|
|
|
|
|
static struct uml_driver *uml_driver = NULL;
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
umlAutostartConfigs(struct uml_driver *driver) {
|
|
|
|
unsigned int i;
|
2008-12-08 11:18:47 +00:00
|
|
|
/* 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
|
|
|
|
*/
|
2009-06-12 13:20:13 +00:00
|
|
|
virConnectPtr conn = virConnectOpen(driver->privileged ?
|
|
|
|
"uml:///system" :
|
|
|
|
"uml:///session");
|
2008-12-08 11:18:47 +00:00
|
|
|
/* Ignoring NULL conn which is mostly harmless here */
|
2008-11-19 16:58:23 +00:00
|
|
|
|
|
|
|
for (i = 0 ; i < driver->domains.count ; i++) {
|
|
|
|
if (driver->domains.objs[i]->autostart &&
|
|
|
|
!virDomainIsActive(driver->domains.objs[i]) &&
|
2008-12-08 11:18:47 +00:00
|
|
|
umlStartVMDaemon(conn, driver, driver->domains.objs[i]) < 0) {
|
2008-11-19 16:58:23 +00:00
|
|
|
virErrorPtr err = virGetLastError();
|
2009-06-25 15:02:10 +00:00
|
|
|
VIR_ERROR(_("Failed to autostart VM '%s': %s"),
|
2008-11-19 16:58:23 +00:00
|
|
|
driver->domains.objs[i]->def->name, err->message);
|
|
|
|
}
|
|
|
|
}
|
2008-12-08 11:18:47 +00:00
|
|
|
|
2009-03-16 10:30:04 +00:00
|
|
|
if (conn)
|
|
|
|
virConnectClose(conn);
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
umlIdentifyOneChrPTY(virConnectPtr conn,
|
|
|
|
struct uml_driver *driver,
|
|
|
|
virDomainObjPtr dom,
|
|
|
|
virDomainChrDefPtr def,
|
|
|
|
const char *dev)
|
|
|
|
{
|
|
|
|
char *cmd;
|
|
|
|
char *res = NULL;
|
|
|
|
int retries = 0;
|
2008-12-23 13:03:29 +00:00
|
|
|
if (virAsprintf(&cmd, "config %s%d", dev, def->dstPort) < 0) {
|
2009-01-20 17:13:33 +00:00
|
|
|
virReportOOMError(conn);
|
2008-11-19 16:58:23 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
requery:
|
2009-06-03 10:55:33 +00:00
|
|
|
if (umlMonitorCommand(NULL, driver, dom, cmd, &res) < 0)
|
|
|
|
return -1;
|
2008-11-19 16:58:23 +00:00
|
|
|
|
2009-06-03 10:55:33 +00:00
|
|
|
if (res && STRPREFIX(res, "pts:")) {
|
2008-11-19 16:58:23 +00:00
|
|
|
VIR_FREE(def->data.file.path);
|
|
|
|
if ((def->data.file.path = strdup(res + 4)) == NULL) {
|
2009-01-20 17:13:33 +00:00
|
|
|
virReportOOMError(conn);
|
2008-11-19 16:58:23 +00:00
|
|
|
VIR_FREE(res);
|
|
|
|
VIR_FREE(cmd);
|
|
|
|
return -1;
|
|
|
|
}
|
2009-06-03 10:55:33 +00:00
|
|
|
} else if (!res || STRPREFIX(res, "pts")) {
|
2008-11-19 16:58:23 +00:00
|
|
|
/* It can take a while to startup, so retry for
|
|
|
|
upto 5 seconds */
|
|
|
|
/* XXX should do this in a better non-blocking
|
|
|
|
way somehow ...perhaps register a timer */
|
|
|
|
if (retries++ < 50) {
|
|
|
|
usleep(1000*10);
|
|
|
|
goto requery;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VIR_FREE(cmd);
|
|
|
|
VIR_FREE(res);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
umlIdentifyChrPTY(virConnectPtr conn,
|
|
|
|
struct uml_driver *driver,
|
|
|
|
virDomainObjPtr dom)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (dom->def->console &&
|
|
|
|
dom->def->console->type == VIR_DOMAIN_CHR_TYPE_PTY)
|
|
|
|
if (umlIdentifyOneChrPTY(conn, driver, dom,
|
|
|
|
dom->def->console, "con") < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
for (i = 0 ; i < dom->def->nserials; i++)
|
|
|
|
if (dom->def->serials[i]->type == VIR_DOMAIN_CHR_TYPE_PTY &&
|
|
|
|
umlIdentifyOneChrPTY(conn, 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;
|
|
|
|
|
2008-12-04 21:14:39 +00:00
|
|
|
umlDriverLock(driver);
|
2008-11-19 16:58:23 +00:00
|
|
|
if (watch != driver->inotifyWatch)
|
2008-12-04 21:14:39 +00:00
|
|
|
goto cleanup;
|
2008-11-19 16:58:23 +00:00
|
|
|
|
|
|
|
reread:
|
|
|
|
got = read(fd, buf, sizeof(buf));
|
|
|
|
if (got == -1) {
|
|
|
|
if (errno == EINTR)
|
|
|
|
goto reread;
|
2008-12-04 21:14:39 +00:00
|
|
|
goto cleanup;
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
tmp = buf;
|
|
|
|
while (got) {
|
|
|
|
if (got < sizeof(struct inotify_event))
|
2008-12-04 21:14:39 +00:00
|
|
|
goto cleanup; /* bad */
|
2008-11-19 16:58:23 +00:00
|
|
|
|
|
|
|
e = (struct inotify_event *)tmp;
|
|
|
|
tmp += sizeof(struct inotify_event);
|
|
|
|
got -= sizeof(struct inotify_event);
|
|
|
|
|
|
|
|
if (got < e->len)
|
2008-12-04 21:14:39 +00:00
|
|
|
goto cleanup;
|
2008-11-19 16:58:23 +00:00
|
|
|
|
|
|
|
tmp += e->len;
|
|
|
|
got -= e->len;
|
|
|
|
|
|
|
|
name = (char *)&(e->name);
|
|
|
|
|
|
|
|
dom = virDomainFindByName(&driver->domains, name);
|
|
|
|
|
|
|
|
if (!dom) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (e->mask & IN_DELETE) {
|
2009-06-03 10:55:33 +00:00
|
|
|
VIR_DEBUG("Got inotify domain shutdown '%s'", name);
|
2008-11-19 16:58:23 +00:00
|
|
|
if (!virDomainIsActive(dom)) {
|
2008-12-04 21:14:39 +00:00
|
|
|
virDomainObjUnlock(dom);
|
2008-11-19 16:58:23 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2009-06-03 10:55:33 +00:00
|
|
|
umlShutdownVMDaemon(NULL, driver, dom);
|
2008-11-19 16:58:23 +00:00
|
|
|
} else if (e->mask & (IN_CREATE | IN_MODIFY)) {
|
2009-06-03 10:55:33 +00:00
|
|
|
VIR_DEBUG("Got inotify domain startup '%s'", name);
|
2008-11-19 16:58:23 +00:00
|
|
|
if (virDomainIsActive(dom)) {
|
2008-12-04 21:14:39 +00:00
|
|
|
virDomainObjUnlock(dom);
|
2008-11-19 16:58:23 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (umlReadPidFile(NULL, driver, dom) < 0) {
|
2008-12-04 21:14:39 +00:00
|
|
|
virDomainObjUnlock(dom);
|
2008-11-19 16:58:23 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
dom->def->id = driver->nextvmid++;
|
|
|
|
dom->state = VIR_DOMAIN_RUNNING;
|
|
|
|
|
2009-06-03 10:55:33 +00:00
|
|
|
if (umlOpenMonitor(NULL, driver, dom) < 0) {
|
|
|
|
VIR_WARN0("Could not open monitor for new domain");
|
2008-11-19 16:58:23 +00:00
|
|
|
umlShutdownVMDaemon(NULL, driver, dom);
|
2009-06-03 10:55:33 +00:00
|
|
|
} else if (umlIdentifyChrPTY(NULL, driver, dom) < 0) {
|
|
|
|
VIR_WARN0("Could not identify charater devices for new domain");
|
2008-11-19 16:58:23 +00:00
|
|
|
umlShutdownVMDaemon(NULL, driver, dom);
|
2009-06-03 10:55:33 +00:00
|
|
|
}
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
2008-12-04 21:14:39 +00:00
|
|
|
virDomainObjUnlock(dom);
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
2008-12-04 21:14:39 +00:00
|
|
|
|
|
|
|
cleanup:
|
|
|
|
umlDriverUnlock(driver);
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* umlStartup:
|
|
|
|
*
|
|
|
|
* Initialization function for the Uml daemon
|
|
|
|
*/
|
|
|
|
static int
|
2009-06-12 13:20:13 +00:00
|
|
|
umlStartup(int privileged) {
|
2008-11-19 16:58:23 +00:00
|
|
|
uid_t uid = geteuid();
|
|
|
|
char *base = NULL;
|
|
|
|
char driverConf[PATH_MAX];
|
2009-01-22 19:41:48 +00:00
|
|
|
char *userdir = NULL;
|
2008-11-19 16:58:23 +00:00
|
|
|
|
|
|
|
if (VIR_ALLOC(uml_driver) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2009-06-12 13:20:13 +00:00
|
|
|
uml_driver->privileged = privileged;
|
|
|
|
|
2009-01-15 19:56:05 +00:00
|
|
|
if (virMutexInit(¨_driver->lock) < 0) {
|
|
|
|
VIR_FREE(uml_driver);
|
|
|
|
return -1;
|
|
|
|
}
|
2008-12-04 21:14:39 +00:00
|
|
|
umlDriverLock(uml_driver);
|
|
|
|
|
2008-11-19 16:58:23 +00:00
|
|
|
/* Don't have a dom0 so start from 1 */
|
|
|
|
uml_driver->nextvmid = 1;
|
2009-01-29 17:50:00 +00:00
|
|
|
uml_driver->inotifyWatch = -1;
|
2008-11-19 16:58:23 +00:00
|
|
|
|
2009-01-22 19:41:48 +00:00
|
|
|
userdir = virGetUserDirectory(NULL, uid);
|
|
|
|
if (!userdir)
|
2008-12-04 21:14:39 +00:00
|
|
|
goto error;
|
2008-11-19 16:58:23 +00:00
|
|
|
|
2009-06-12 13:20:13 +00:00
|
|
|
if (privileged) {
|
2008-12-23 13:03:29 +00:00
|
|
|
if (virAsprintf(¨_driver->logDir,
|
|
|
|
"%s/log/libvirt/uml", LOCAL_STATE_DIR) == -1)
|
2008-11-19 16:58:23 +00:00
|
|
|
goto out_of_memory;
|
|
|
|
|
|
|
|
if ((base = strdup (SYSCONF_DIR "/libvirt")) == NULL)
|
|
|
|
goto out_of_memory;
|
|
|
|
} else {
|
2009-01-22 19:41:48 +00:00
|
|
|
|
2008-12-23 13:03:29 +00:00
|
|
|
if (virAsprintf(¨_driver->logDir,
|
2009-01-22 19:41:48 +00:00
|
|
|
"%s/.libvirt/uml/log", userdir) == -1)
|
2008-11-19 16:58:23 +00:00
|
|
|
goto out_of_memory;
|
|
|
|
|
2009-01-22 19:41:48 +00:00
|
|
|
if (virAsprintf(&base, "%s/.libvirt", userdir) == -1)
|
2008-11-19 16:58:23 +00:00
|
|
|
goto out_of_memory;
|
|
|
|
}
|
|
|
|
|
2008-12-23 13:03:29 +00:00
|
|
|
if (virAsprintf(¨_driver->monitorDir,
|
2009-01-22 19:41:48 +00:00
|
|
|
"%s/.uml", userdir) == -1)
|
2008-11-19 16:58:23 +00:00
|
|
|
goto out_of_memory;
|
|
|
|
|
|
|
|
/* Configuration paths are either ~/.libvirt/uml/... (session) or
|
|
|
|
* /etc/libvirt/uml/... (system).
|
|
|
|
*/
|
|
|
|
if (snprintf (driverConf, sizeof(driverConf), "%s/uml.conf", base) == -1)
|
|
|
|
goto out_of_memory;
|
|
|
|
driverConf[sizeof(driverConf)-1] = '\0';
|
|
|
|
|
2008-12-23 13:03:29 +00:00
|
|
|
if (virAsprintf(¨_driver->configDir, "%s/uml", base) == -1)
|
2008-11-19 16:58:23 +00:00
|
|
|
goto out_of_memory;
|
|
|
|
|
2008-12-23 13:03:29 +00:00
|
|
|
if (virAsprintf(¨_driver->autostartDir, "%s/uml/autostart", base) == -1)
|
2008-11-19 16:58:23 +00:00
|
|
|
goto out_of_memory;
|
|
|
|
|
|
|
|
VIR_FREE(base);
|
|
|
|
|
|
|
|
if ((uml_driver->caps = umlCapsInit()) == NULL)
|
|
|
|
goto out_of_memory;
|
|
|
|
|
|
|
|
|
|
|
|
if ((uml_driver->inotifyFD = inotify_init()) < 0) {
|
2009-06-25 15:02:10 +00:00
|
|
|
VIR_ERROR0(_("cannot initialize inotify"));
|
2008-12-04 21:14:39 +00:00
|
|
|
goto error;
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (virFileMakePath(uml_driver->monitorDir) < 0) {
|
2009-02-05 16:28:30 +00:00
|
|
|
char ebuf[1024];
|
2009-06-25 15:02:10 +00:00
|
|
|
VIR_ERROR(_("Failed to create monitor directory %s: %s"),
|
2009-02-05 16:28:30 +00:00
|
|
|
uml_driver->monitorDir, virStrerror(errno, ebuf, sizeof ebuf));
|
2008-12-04 21:14:39 +00:00
|
|
|
goto error;
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
|
2009-06-03 10:55:33 +00:00
|
|
|
VIR_INFO("Adding inotify watch on %s", uml_driver->monitorDir);
|
2008-12-02 11:23:27 +00:00
|
|
|
if (inotify_add_watch(uml_driver->inotifyFD,
|
|
|
|
uml_driver->monitorDir,
|
|
|
|
IN_CREATE | IN_MODIFY | IN_DELETE) < 0) {
|
2008-12-04 21:14:39 +00:00
|
|
|
goto error;
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
|
2008-12-02 11:23:27 +00:00
|
|
|
if ((uml_driver->inotifyWatch =
|
|
|
|
virEventAddHandle(uml_driver->inotifyFD, POLLIN,
|
2008-12-04 21:14:39 +00:00
|
|
|
umlInotifyEvent, uml_driver, NULL)) < 0)
|
|
|
|
goto error;
|
2008-11-19 16:58:23 +00:00
|
|
|
|
|
|
|
if (virDomainLoadAllConfigs(NULL,
|
|
|
|
uml_driver->caps,
|
|
|
|
¨_driver->domains,
|
|
|
|
uml_driver->configDir,
|
|
|
|
uml_driver->autostartDir,
|
2009-06-12 11:38:50 +00:00
|
|
|
0, NULL, NULL) < 0)
|
2008-12-04 21:14:39 +00:00
|
|
|
goto error;
|
|
|
|
|
2008-11-19 16:58:23 +00:00
|
|
|
umlAutostartConfigs(uml_driver);
|
|
|
|
|
2008-12-04 21:14:39 +00:00
|
|
|
umlDriverUnlock(uml_driver);
|
2009-01-22 19:41:48 +00:00
|
|
|
VIR_FREE(userdir);
|
|
|
|
|
2008-11-19 16:58:23 +00:00
|
|
|
return 0;
|
|
|
|
|
2008-12-04 21:14:39 +00:00
|
|
|
out_of_memory:
|
2009-06-25 15:02:10 +00:00
|
|
|
VIR_ERROR0(_("umlStartup: out of memory"));
|
2008-12-04 21:14:39 +00:00
|
|
|
|
|
|
|
error:
|
2009-01-22 19:41:48 +00:00
|
|
|
VIR_FREE(userdir);
|
2008-11-19 16:58:23 +00:00
|
|
|
VIR_FREE(base);
|
2008-12-04 21:14:39 +00:00
|
|
|
umlDriverUnlock(uml_driver);
|
|
|
|
umlShutdown();
|
2008-11-19 16:58:23 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* umlReload:
|
|
|
|
*
|
|
|
|
* Function to restart the Uml daemon, it will recheck the configuration
|
|
|
|
* files and update its state and the networking
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
umlReload(void) {
|
|
|
|
if (!uml_driver)
|
|
|
|
return 0;
|
|
|
|
|
2008-12-04 21:14:39 +00:00
|
|
|
umlDriverLock(uml_driver);
|
2008-11-19 16:58:23 +00:00
|
|
|
virDomainLoadAllConfigs(NULL,
|
|
|
|
uml_driver->caps,
|
|
|
|
¨_driver->domains,
|
|
|
|
uml_driver->configDir,
|
|
|
|
uml_driver->autostartDir,
|
2009-06-12 11:38:50 +00:00
|
|
|
0, NULL, NULL);
|
2008-11-19 16:58:23 +00:00
|
|
|
|
|
|
|
umlAutostartConfigs(uml_driver);
|
2008-12-04 21:14:39 +00:00
|
|
|
umlDriverUnlock(uml_driver);
|
2008-11-19 16:58:23 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* umlActive:
|
|
|
|
*
|
|
|
|
* Checks if the Uml daemon is active, i.e. has an active domain or
|
|
|
|
* an active network
|
|
|
|
*
|
|
|
|
* Returns 1 if active, 0 otherwise
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
umlActive(void) {
|
|
|
|
unsigned int i;
|
2008-12-04 21:14:39 +00:00
|
|
|
int active = 0;
|
2008-11-19 16:58:23 +00:00
|
|
|
|
|
|
|
if (!uml_driver)
|
|
|
|
return 0;
|
|
|
|
|
2008-12-04 21:14:39 +00:00
|
|
|
umlDriverLock(uml_driver);
|
|
|
|
for (i = 0 ; i < uml_driver->domains.count ; i++) {
|
|
|
|
virDomainObjLock(uml_driver->domains.objs[i]);
|
2008-11-19 16:58:23 +00:00
|
|
|
if (virDomainIsActive(uml_driver->domains.objs[i]))
|
2008-12-04 21:14:39 +00:00
|
|
|
active = 1;
|
|
|
|
virDomainObjUnlock(uml_driver->domains.objs[i]);
|
|
|
|
}
|
|
|
|
umlDriverUnlock(uml_driver);
|
2008-11-19 16:58:23 +00:00
|
|
|
|
2008-12-04 21:14:39 +00:00
|
|
|
return active;
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* umlShutdown:
|
|
|
|
*
|
|
|
|
* Shutdown the Uml daemon, it will stop all active domains and networks
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
umlShutdown(void) {
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
if (!uml_driver)
|
|
|
|
return -1;
|
|
|
|
|
2008-12-04 21:14:39 +00:00
|
|
|
umlDriverLock(uml_driver);
|
2009-01-29 17:50:00 +00:00
|
|
|
if (uml_driver->inotifyWatch != -1)
|
|
|
|
virEventRemoveHandle(uml_driver->inotifyWatch);
|
2008-11-19 16:58:23 +00:00
|
|
|
close(uml_driver->inotifyFD);
|
|
|
|
virCapabilitiesFree(uml_driver->caps);
|
|
|
|
|
|
|
|
/* shutdown active VMs */
|
|
|
|
for (i = 0 ; i < uml_driver->domains.count ; i++) {
|
|
|
|
virDomainObjPtr dom = uml_driver->domains.objs[i];
|
2008-12-04 21:14:39 +00:00
|
|
|
virDomainObjLock(dom);
|
2008-11-19 16:58:23 +00:00
|
|
|
if (virDomainIsActive(dom))
|
|
|
|
umlShutdownVMDaemon(NULL, uml_driver, dom);
|
2008-12-04 21:14:39 +00:00
|
|
|
virDomainObjUnlock(dom);
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virDomainObjListFree(¨_driver->domains);
|
|
|
|
|
|
|
|
VIR_FREE(uml_driver->logDir);
|
|
|
|
VIR_FREE(uml_driver->configDir);
|
|
|
|
VIR_FREE(uml_driver->autostartDir);
|
|
|
|
VIR_FREE(uml_driver->monitorDir);
|
|
|
|
|
|
|
|
if (uml_driver->brctl)
|
|
|
|
brShutdown(uml_driver->brctl);
|
|
|
|
|
2008-12-04 21:14:39 +00:00
|
|
|
umlDriverUnlock(uml_driver);
|
2009-01-15 19:56:05 +00:00
|
|
|
virMutexDestroy(¨_driver->lock);
|
2008-11-19 16:58:23 +00:00
|
|
|
VIR_FREE(uml_driver);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int umlReadPidFile(virConnectPtr conn,
|
|
|
|
struct uml_driver *driver,
|
|
|
|
virDomainObjPtr vm)
|
|
|
|
{
|
|
|
|
int rc = -1;
|
|
|
|
FILE *file;
|
|
|
|
char *pidfile = NULL;
|
|
|
|
int retries = 0;
|
|
|
|
|
|
|
|
vm->pid = -1;
|
2008-12-23 13:03:29 +00:00
|
|
|
if (virAsprintf(&pidfile, "%s/%s/pid",
|
|
|
|
driver->monitorDir, vm->def->name) < 0) {
|
2009-01-20 17:13:33 +00:00
|
|
|
virReportOOMError(conn);
|
2008-11-19 16:58:23 +00:00
|
|
|
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;
|
2009-03-16 10:41:37 +00:00
|
|
|
fclose(file);
|
2008-11-19 16:58:23 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fclose(file) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
rc = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
if (rc != 0)
|
2009-01-20 17:13:33 +00:00
|
|
|
virReportSystemError(conn, errno,
|
|
|
|
_("failed to read pid: %s"),
|
|
|
|
pidfile);
|
2008-11-19 16:58:23 +00:00
|
|
|
VIR_FREE(pidfile);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int umlMonitorAddress(virConnectPtr conn,
|
|
|
|
const struct uml_driver *driver,
|
|
|
|
virDomainObjPtr vm,
|
|
|
|
struct sockaddr_un *addr) {
|
|
|
|
char *sockname;
|
|
|
|
|
2008-12-23 13:03:29 +00:00
|
|
|
if (virAsprintf(&sockname, "%s/%s/mconsole",
|
|
|
|
driver->monitorDir, vm->def->name) < 0) {
|
2009-01-20 17:13:33 +00:00
|
|
|
virReportOOMError(conn);
|
2008-11-19 16:58:23 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(addr, 0, sizeof *addr);
|
|
|
|
addr->sun_family = AF_UNIX;
|
|
|
|
strncpy(addr->sun_path, sockname, sizeof(addr->sun_path)-1);
|
|
|
|
NUL_TERMINATE(addr->sun_path);
|
|
|
|
VIR_FREE(sockname);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int umlOpenMonitor(virConnectPtr conn,
|
|
|
|
struct uml_driver *driver,
|
|
|
|
virDomainObjPtr vm) {
|
|
|
|
struct sockaddr_un addr;
|
|
|
|
struct stat sb;
|
|
|
|
int retries = 0;
|
|
|
|
|
|
|
|
if (umlMonitorAddress(conn, driver, vm, &addr) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2009-06-03 10:55:33 +00:00
|
|
|
VIR_DEBUG("Dest address for monitor is '%s'", addr.sun_path);
|
2008-11-19 16:58:23 +00:00
|
|
|
restat:
|
|
|
|
if (stat(addr.sun_path, &sb) < 0) {
|
|
|
|
if (errno == ENOENT &&
|
2009-06-03 10:55:33 +00:00
|
|
|
retries++ < 50) {
|
2008-11-19 16:58:23 +00:00
|
|
|
usleep(1000 * 100);
|
|
|
|
goto restat;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((vm->monitor = socket(PF_UNIX, SOCK_DGRAM, 0)) < 0) {
|
2009-01-20 17:13:33 +00:00
|
|
|
virReportSystemError(conn, errno,
|
|
|
|
"%s", _("cannot open socket"));
|
2008-11-19 16:58:23 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(addr.sun_path, 0, sizeof addr.sun_path);
|
2009-06-03 10:55:33 +00:00
|
|
|
sprintf(addr.sun_path + 1, "libvirt-uml-%u", vm->pid);
|
|
|
|
VIR_DEBUG("Reply address for monitor is '%s'", addr.sun_path+1);
|
2008-11-19 16:58:23 +00:00
|
|
|
if (bind(vm->monitor, (struct sockaddr *)&addr, sizeof addr) < 0) {
|
2009-01-20 17:13:33 +00:00
|
|
|
virReportSystemError(conn, errno,
|
|
|
|
"%s", _("cannot bind socket"));
|
2008-11-19 16:58:23 +00:00
|
|
|
close(vm->monitor);
|
|
|
|
vm->monitor = -1;
|
|
|
|
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(virConnectPtr conn,
|
|
|
|
const struct uml_driver *driver,
|
|
|
|
const virDomainObjPtr 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;
|
|
|
|
|
2009-06-03 10:55:33 +00:00
|
|
|
VIR_DEBUG("Run command '%s'", cmd);
|
|
|
|
|
2008-11-19 16:58:23 +00:00
|
|
|
*reply = NULL;
|
|
|
|
|
|
|
|
if (umlMonitorAddress(conn, 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)) {
|
2009-01-20 17:13:33 +00:00
|
|
|
virReportSystemError(conn, EINVAL,
|
|
|
|
_("cannot send too long command %s (%d bytes)"),
|
|
|
|
cmd, req.length);
|
2008-11-19 16:58:23 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
strncpy(req.data, cmd, req.length);
|
|
|
|
req.data[req.length] = '\0';
|
|
|
|
|
|
|
|
if (sendto(vm->monitor, &req, sizeof req, 0,
|
|
|
|
(struct sockaddr *)&addr, sizeof addr) != (sizeof req)) {
|
2009-01-20 17:13:33 +00:00
|
|
|
virReportSystemError(conn, errno,
|
|
|
|
_("cannot send command %s"),
|
|
|
|
cmd);
|
2008-11-19 16:58:23 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
do {
|
|
|
|
addrlen = sizeof(addr);
|
|
|
|
if (recvfrom(vm->monitor, &res, sizeof res, 0,
|
|
|
|
(struct sockaddr *)&addr, &addrlen) < 0) {
|
2009-01-20 17:13:33 +00:00
|
|
|
virReportSystemError(conn, errno,
|
|
|
|
_("cannot read reply %s"),
|
|
|
|
cmd);
|
2008-11-19 16:58:23 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VIR_REALLOC_N(retdata, retlen + res.length) < 0) {
|
2009-01-20 17:13:33 +00:00
|
|
|
virReportOOMError(conn);
|
2008-11-19 16:58:23 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
memcpy(retdata + retlen, res.data, res.length);
|
|
|
|
retlen += res.length - 1;
|
|
|
|
retdata[retlen] = '\0';
|
|
|
|
|
|
|
|
if (res.error)
|
|
|
|
ret = -1;
|
|
|
|
|
|
|
|
} while (res.extra);
|
|
|
|
|
2009-06-03 10:55:33 +00:00
|
|
|
VIR_DEBUG("Command reply is '%s'", NULLSTR(retdata));
|
|
|
|
|
2008-11-19 16:58:23 +00:00
|
|
|
*reply = retdata;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
error:
|
|
|
|
VIR_FREE(retdata);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-06-03 11:13:33 +00:00
|
|
|
static int umlCleanupTapDevices(virConnectPtr conn ATTRIBUTE_UNUSED,
|
|
|
|
virDomainObjPtr vm) {
|
|
|
|
int i;
|
|
|
|
int err;
|
|
|
|
int ret = 0;
|
|
|
|
brControl *brctl = NULL;
|
|
|
|
VIR_ERROR0("Cleanup tap");
|
|
|
|
if (brInit(&brctl) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
VIR_ERROR("Cleanup '%s'", def->ifname);
|
|
|
|
err = brDeleteTap(brctl, def->ifname);
|
|
|
|
if (err) {
|
|
|
|
VIR_ERROR("Cleanup failed %d", err);
|
|
|
|
ret = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
VIR_ERROR0("Cleanup tap done");
|
|
|
|
brShutdown(brctl);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2008-11-19 16:58:23 +00:00
|
|
|
static int umlStartVMDaemon(virConnectPtr conn,
|
|
|
|
struct uml_driver *driver,
|
|
|
|
virDomainObjPtr vm) {
|
|
|
|
const char **argv = NULL, **tmp;
|
|
|
|
const char **progenv = NULL;
|
2008-12-18 11:58:28 +00:00
|
|
|
int i, ret;
|
|
|
|
pid_t pid;
|
2008-11-19 16:58:23 +00:00
|
|
|
char *logfile;
|
|
|
|
int logfd = -1;
|
|
|
|
struct stat sb;
|
|
|
|
fd_set keepfd;
|
2009-02-05 16:28:30 +00:00
|
|
|
char ebuf[1024];
|
2008-11-19 16:58:23 +00:00
|
|
|
|
|
|
|
FD_ZERO(&keepfd);
|
|
|
|
|
|
|
|
if (virDomainIsActive(vm)) {
|
|
|
|
umlReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("VM is already active"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!vm->def->os.kernel) {
|
|
|
|
umlReportError(conn, NULL, NULL, 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 (stat(vm->def->os.kernel, &sb) < 0) {
|
2009-01-20 17:13:33 +00:00
|
|
|
virReportSystemError(conn, errno,
|
|
|
|
_("Cannot find UML kernel %s"),
|
|
|
|
vm->def->os.kernel);
|
2008-11-19 16:58:23 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virFileMakePath(driver->logDir) < 0) {
|
2009-01-20 17:13:33 +00:00
|
|
|
virReportSystemError(conn, errno,
|
|
|
|
_("cannot create log directory %s"),
|
|
|
|
driver->logDir);
|
2008-11-19 16:58:23 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2008-12-23 13:03:29 +00:00
|
|
|
if (virAsprintf(&logfile, "%s/%s.log",
|
|
|
|
driver->logDir, vm->def->name) < 0) {
|
2009-01-20 17:13:33 +00:00
|
|
|
virReportOOMError(conn);
|
2008-11-19 16:58:23 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((logfd = open(logfile, O_CREAT | O_TRUNC | O_WRONLY,
|
|
|
|
S_IRUSR | S_IWUSR)) < 0) {
|
2009-01-20 17:13:33 +00:00
|
|
|
virReportSystemError(conn, errno,
|
|
|
|
_("failed to create logfile %s"),
|
|
|
|
logfile);
|
2008-11-19 16:58:23 +00:00
|
|
|
VIR_FREE(logfile);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
VIR_FREE(logfile);
|
|
|
|
|
|
|
|
if (umlSetCloseExec(logfd) < 0) {
|
2009-01-20 17:13:33 +00:00
|
|
|
virReportSystemError(conn, errno,
|
|
|
|
"%s", _("Unable to set VM logfile close-on-exec flag"));
|
2008-11-19 16:58:23 +00:00
|
|
|
close(logfd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (umlBuildCommandLine(conn, driver, vm,
|
2009-06-03 11:13:33 +00:00
|
|
|
&argv, &progenv) < 0) {
|
2008-11-19 16:58:23 +00:00
|
|
|
close(logfd);
|
2009-06-03 11:13:33 +00:00
|
|
|
umlCleanupTapDevices(conn, vm);
|
2008-11-19 16:58:23 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
tmp = progenv;
|
|
|
|
while (*tmp) {
|
|
|
|
if (safewrite(logfd, *tmp, strlen(*tmp)) < 0)
|
2009-06-25 15:02:10 +00:00
|
|
|
VIR_WARN(_("Unable to write envv to logfile: %s"),
|
2009-02-05 16:28:30 +00:00
|
|
|
virStrerror(errno, ebuf, sizeof ebuf));
|
2008-11-19 16:58:23 +00:00
|
|
|
if (safewrite(logfd, " ", 1) < 0)
|
2009-06-25 15:02:10 +00:00
|
|
|
VIR_WARN(_("Unable to write envv to logfile: %s"),
|
2009-02-05 16:28:30 +00:00
|
|
|
virStrerror(errno, ebuf, sizeof ebuf));
|
2008-11-19 16:58:23 +00:00
|
|
|
tmp++;
|
|
|
|
}
|
|
|
|
tmp = argv;
|
|
|
|
while (*tmp) {
|
|
|
|
if (safewrite(logfd, *tmp, strlen(*tmp)) < 0)
|
2009-06-25 15:02:10 +00:00
|
|
|
VIR_WARN(_("Unable to write argv to logfile: %s"),
|
2009-02-05 16:28:30 +00:00
|
|
|
virStrerror(errno, ebuf, sizeof ebuf));
|
2008-11-19 16:58:23 +00:00
|
|
|
if (safewrite(logfd, " ", 1) < 0)
|
2009-06-25 15:02:10 +00:00
|
|
|
VIR_WARN(_("Unable to write argv to logfile: %s"),
|
2009-02-05 16:28:30 +00:00
|
|
|
virStrerror(errno, ebuf, sizeof ebuf));
|
2008-11-19 16:58:23 +00:00
|
|
|
tmp++;
|
|
|
|
}
|
|
|
|
if (safewrite(logfd, "\n", 1) < 0)
|
2009-06-25 15:02:10 +00:00
|
|
|
VIR_WARN(_("Unable to write argv to logfile: %s"),
|
2009-02-05 16:28:30 +00:00
|
|
|
virStrerror(errno, ebuf, sizeof ebuf));
|
2008-11-19 16:58:23 +00:00
|
|
|
|
|
|
|
vm->monitor = -1;
|
|
|
|
|
2009-05-11 13:34:37 +00:00
|
|
|
ret = virExecDaemonize(conn, argv, progenv, &keepfd, &pid,
|
|
|
|
-1, &logfd, &logfd,
|
2009-06-29 17:00:52 +00:00
|
|
|
VIR_EXEC_CLEAR_CAPS,
|
|
|
|
NULL, NULL, NULL);
|
2008-11-19 16:58:23 +00:00
|
|
|
close(logfd);
|
|
|
|
|
|
|
|
for (i = 0 ; argv[i] ; i++)
|
|
|
|
VIR_FREE(argv[i]);
|
|
|
|
VIR_FREE(argv);
|
|
|
|
|
|
|
|
for (i = 0 ; progenv[i] ; i++)
|
|
|
|
VIR_FREE(progenv[i]);
|
|
|
|
VIR_FREE(progenv);
|
|
|
|
|
2009-06-03 11:13:33 +00:00
|
|
|
if (ret < 0)
|
|
|
|
umlCleanupTapDevices(conn, vm);
|
2008-11-19 16:58:23 +00:00
|
|
|
|
|
|
|
/* NB we don't mark it running here - we do that async
|
|
|
|
with inotify */
|
2009-06-03 11:13:33 +00:00
|
|
|
/* XXX what if someone else tries to start it again
|
|
|
|
before we get the inotification ? Sounds like
|
|
|
|
trouble.... */
|
2008-11-19 16:58:23 +00:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void umlShutdownVMDaemon(virConnectPtr conn ATTRIBUTE_UNUSED,
|
|
|
|
struct uml_driver *driver ATTRIBUTE_UNUSED,
|
|
|
|
virDomainObjPtr vm)
|
|
|
|
{
|
|
|
|
int ret;
|
2009-06-03 10:55:33 +00:00
|
|
|
if (!virDomainIsActive(vm))
|
2008-11-19 16:58:23 +00:00
|
|
|
return;
|
|
|
|
|
2009-06-03 10:55:33 +00:00
|
|
|
virKillProcess(vm->pid, SIGTERM);
|
2008-11-19 16:58:23 +00:00
|
|
|
|
|
|
|
if (vm->monitor != -1)
|
|
|
|
close(vm->monitor);
|
|
|
|
vm->monitor = -1;
|
|
|
|
|
|
|
|
if ((ret = waitpid(vm->pid, NULL, 0)) != vm->pid) {
|
2009-06-25 15:02:10 +00:00
|
|
|
VIR_WARN(_("Got unexpected pid %d != %d"),
|
2008-11-19 16:58:23 +00:00
|
|
|
ret, vm->pid);
|
|
|
|
}
|
|
|
|
|
|
|
|
vm->pid = -1;
|
|
|
|
vm->def->id = -1;
|
|
|
|
vm->state = VIR_DOMAIN_SHUTOFF;
|
|
|
|
VIR_FREE(vm->vcpupids);
|
|
|
|
vm->nvcpupids = 0;
|
|
|
|
|
2009-06-03 11:13:33 +00:00
|
|
|
umlCleanupTapDevices(conn, vm);
|
|
|
|
|
2008-11-19 16:58:23 +00:00
|
|
|
if (vm->newDef) {
|
|
|
|
virDomainDefFree(vm->def);
|
|
|
|
vm->def = vm->newDef;
|
|
|
|
vm->def->id = -1;
|
|
|
|
vm->newDef = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static virDrvOpenStatus umlOpen(virConnectPtr conn,
|
|
|
|
virConnectAuthPtr auth ATTRIBUTE_UNUSED,
|
|
|
|
int flags ATTRIBUTE_UNUSED) {
|
2009-06-12 12:06:15 +00:00
|
|
|
if (conn->uri == NULL) {
|
|
|
|
if (uml_driver == NULL)
|
|
|
|
return VIR_DRV_OPEN_DECLINED;
|
2008-11-19 16:58:23 +00:00
|
|
|
|
2009-06-12 13:20:13 +00:00
|
|
|
conn->uri = xmlParseURI(uml_driver->privileged ?
|
2009-06-12 12:06:15 +00:00
|
|
|
"uml:///system" :
|
|
|
|
"uml:///session");
|
|
|
|
if (!conn->uri) {
|
|
|
|
virReportOOMError(conn);
|
|
|
|
return VIR_DRV_OPEN_ERROR;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (conn->uri->scheme == NULL ||
|
|
|
|
STRNEQ (conn->uri->scheme, "uml"))
|
|
|
|
return VIR_DRV_OPEN_DECLINED;
|
|
|
|
|
|
|
|
/* Allow remote driver to deal with URIs with hostname server */
|
|
|
|
if (conn->uri->server != NULL)
|
|
|
|
return VIR_DRV_OPEN_DECLINED;
|
2008-11-19 16:58:23 +00:00
|
|
|
|
|
|
|
|
2009-06-12 12:06:15 +00:00
|
|
|
/* Check path and tell them correct path if they made a mistake */
|
2009-06-12 13:20:13 +00:00
|
|
|
if (uml_driver->privileged) {
|
2008-11-19 16:58:23 +00:00
|
|
|
if (STRNEQ (conn->uri->path, "/system") &&
|
2009-06-12 12:06:15 +00:00
|
|
|
STRNEQ (conn->uri->path, "/session")) {
|
|
|
|
umlReportError(conn, NULL, NULL, 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")) {
|
|
|
|
umlReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unexpected UML URI path '%s', try uml:///session"),
|
|
|
|
conn->uri->path);
|
|
|
|
return VIR_DRV_OPEN_ERROR;
|
|
|
|
}
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
2009-06-12 12:06:15 +00:00
|
|
|
|
|
|
|
/* URI was good, but driver isn't active */
|
|
|
|
if (uml_driver == NULL) {
|
|
|
|
umlReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("uml state driver is not active"));
|
2008-11-19 16:58:23 +00:00
|
|
|
return VIR_DRV_OPEN_ERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
conn->privateData = uml_driver;
|
|
|
|
|
|
|
|
return VIR_DRV_OPEN_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int umlClose(virConnectPtr conn) {
|
2008-12-04 21:13:58 +00:00
|
|
|
/*struct uml_driver *driver = conn->privateData;*/
|
2008-11-19 16:58:23 +00:00
|
|
|
|
|
|
|
conn->privateData = NULL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *umlGetType(virConnectPtr conn ATTRIBUTE_UNUSED) {
|
|
|
|
return "UML";
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static char *umlGetCapabilities(virConnectPtr conn) {
|
|
|
|
struct uml_driver *driver = (struct uml_driver *)conn->privateData;
|
|
|
|
char *xml;
|
|
|
|
|
2008-12-04 21:14:39 +00:00
|
|
|
umlDriverLock(driver);
|
2008-12-04 21:13:58 +00:00
|
|
|
if ((xml = virCapabilitiesFormatXML(driver->caps)) == NULL)
|
2009-01-20 17:13:33 +00:00
|
|
|
virReportOOMError(conn);
|
2008-12-04 21:14:39 +00:00
|
|
|
umlDriverUnlock(driver);
|
2008-11-19 16:58:23 +00:00
|
|
|
|
|
|
|
return xml;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int umlGetProcessInfo(unsigned long long *cpuTime, int pid) {
|
|
|
|
char proc[PATH_MAX];
|
|
|
|
FILE *pidinfo;
|
|
|
|
unsigned long long usertime, systime;
|
|
|
|
|
|
|
|
if (snprintf(proc, sizeof(proc), "/proc/%d/stat", pid) >= (int)sizeof(proc)) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(pidinfo = fopen(proc, "r"))) {
|
|
|
|
/*printf("cannot read pid info");*/
|
|
|
|
/* VM probably shut down, so fake 0 */
|
|
|
|
*cpuTime = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
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");
|
2009-03-16 10:41:37 +00:00
|
|
|
fclose(pidinfo);
|
2008-11-19 16:58:23 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We got jiffies
|
|
|
|
* We want nanoseconds
|
|
|
|
* _SC_CLK_TCK is jiffies per second
|
|
|
|
* So calulate thus....
|
|
|
|
*/
|
|
|
|
*cpuTime = 1000ull * 1000ull * 1000ull * (usertime + systime) / (unsigned long long)sysconf(_SC_CLK_TCK);
|
|
|
|
|
|
|
|
umlDebug("Got %llu %llu %llu", usertime, systime, *cpuTime);
|
|
|
|
|
|
|
|
fclose(pidinfo);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static virDomainPtr umlDomainLookupByID(virConnectPtr conn,
|
|
|
|
int id) {
|
|
|
|
struct uml_driver *driver = (struct uml_driver *)conn->privateData;
|
2008-12-04 21:13:58 +00:00
|
|
|
virDomainObjPtr vm;
|
|
|
|
virDomainPtr dom = NULL;
|
2008-11-19 16:58:23 +00:00
|
|
|
|
2008-12-04 21:14:39 +00:00
|
|
|
umlDriverLock(driver);
|
2008-12-04 21:13:58 +00:00
|
|
|
vm = virDomainFindByID(&driver->domains, id);
|
2008-12-04 21:14:39 +00:00
|
|
|
umlDriverUnlock(driver);
|
|
|
|
|
2008-11-19 16:58:23 +00:00
|
|
|
if (!vm) {
|
|
|
|
umlReportError(conn, NULL, NULL, VIR_ERR_NO_DOMAIN, NULL);
|
2008-12-04 21:13:58 +00:00
|
|
|
goto cleanup;
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
|
|
|
|
if (dom) dom->id = vm->def->id;
|
2008-12-04 21:13:58 +00:00
|
|
|
|
|
|
|
cleanup:
|
2008-12-04 21:14:39 +00:00
|
|
|
if (vm)
|
|
|
|
virDomainObjUnlock(vm);
|
2008-11-19 16:58:23 +00:00
|
|
|
return dom;
|
|
|
|
}
|
2008-12-04 21:13:58 +00:00
|
|
|
|
2008-11-19 16:58:23 +00:00
|
|
|
static virDomainPtr umlDomainLookupByUUID(virConnectPtr conn,
|
|
|
|
const unsigned char *uuid) {
|
|
|
|
struct uml_driver *driver = (struct uml_driver *)conn->privateData;
|
2008-12-04 21:13:58 +00:00
|
|
|
virDomainObjPtr vm;
|
|
|
|
virDomainPtr dom = NULL;
|
2008-11-19 16:58:23 +00:00
|
|
|
|
2008-12-04 21:14:39 +00:00
|
|
|
umlDriverLock(driver);
|
2008-12-04 21:13:58 +00:00
|
|
|
vm = virDomainFindByUUID(&driver->domains, uuid);
|
2008-12-04 21:14:39 +00:00
|
|
|
umlDriverUnlock(driver);
|
|
|
|
|
2008-11-19 16:58:23 +00:00
|
|
|
if (!vm) {
|
|
|
|
umlReportError(conn, NULL, NULL, VIR_ERR_NO_DOMAIN, NULL);
|
2008-12-04 21:13:58 +00:00
|
|
|
goto cleanup;
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
|
|
|
|
if (dom) dom->id = vm->def->id;
|
2008-12-04 21:13:58 +00:00
|
|
|
|
|
|
|
cleanup:
|
2008-12-04 21:14:39 +00:00
|
|
|
if (vm)
|
|
|
|
virDomainObjUnlock(vm);
|
2008-11-19 16:58:23 +00:00
|
|
|
return dom;
|
|
|
|
}
|
2008-12-04 21:13:58 +00:00
|
|
|
|
2008-11-19 16:58:23 +00:00
|
|
|
static virDomainPtr umlDomainLookupByName(virConnectPtr conn,
|
|
|
|
const char *name) {
|
|
|
|
struct uml_driver *driver = (struct uml_driver *)conn->privateData;
|
2008-12-04 21:13:58 +00:00
|
|
|
virDomainObjPtr vm;
|
|
|
|
virDomainPtr dom = NULL;
|
2008-11-19 16:58:23 +00:00
|
|
|
|
2008-12-04 21:14:39 +00:00
|
|
|
umlDriverLock(driver);
|
2008-12-04 21:13:58 +00:00
|
|
|
vm = virDomainFindByName(&driver->domains, name);
|
2008-12-04 21:14:39 +00:00
|
|
|
umlDriverUnlock(driver);
|
|
|
|
|
2008-11-19 16:58:23 +00:00
|
|
|
if (!vm) {
|
|
|
|
umlReportError(conn, NULL, NULL, VIR_ERR_NO_DOMAIN, NULL);
|
2008-12-04 21:13:58 +00:00
|
|
|
goto cleanup;
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
|
|
|
|
if (dom) dom->id = vm->def->id;
|
2008-12-04 21:13:58 +00:00
|
|
|
|
|
|
|
cleanup:
|
2008-12-04 21:14:39 +00:00
|
|
|
if (vm)
|
|
|
|
virDomainObjUnlock(vm);
|
2008-11-19 16:58:23 +00:00
|
|
|
return dom;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int umlGetVersion(virConnectPtr conn, unsigned long *version) {
|
2008-12-04 21:14:39 +00:00
|
|
|
struct uml_driver *driver = conn->privateData;
|
2008-11-19 16:58:23 +00:00
|
|
|
struct utsname ut;
|
|
|
|
int major, minor, micro;
|
2008-12-04 21:14:39 +00:00
|
|
|
int ret = -1;
|
2008-11-19 16:58:23 +00:00
|
|
|
|
|
|
|
uname(&ut);
|
|
|
|
|
2008-12-04 21:14:39 +00:00
|
|
|
umlDriverLock(driver);
|
2008-11-19 16:58:23 +00:00
|
|
|
if (sscanf(ut.release, "%u.%u.%u",
|
|
|
|
&major, &minor, µ) != 3) {
|
|
|
|
umlReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot parse version %s"), ut.release);
|
2008-12-04 21:14:39 +00:00
|
|
|
goto cleanup;
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
|
2008-12-04 21:14:39 +00:00
|
|
|
*version = driver->umlVersion;
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
umlDriverUnlock(driver);
|
|
|
|
return ret;
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
|
|
|
umlGetHostname (virConnectPtr conn)
|
|
|
|
{
|
2009-01-07 10:43:16 +00:00
|
|
|
char *result;
|
2008-11-19 16:58:23 +00:00
|
|
|
|
2009-01-07 10:43:16 +00:00
|
|
|
result = virGetHostname();
|
|
|
|
if (result == NULL) {
|
2009-01-20 17:13:33 +00:00
|
|
|
virReportSystemError(conn, errno,
|
|
|
|
"%s", _("cannot lookup hostname"));
|
2008-11-19 16:58:23 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
/* Caller frees this string. */
|
2009-01-07 10:43:16 +00:00
|
|
|
return result;
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int umlListDomains(virConnectPtr conn, int *ids, int nids) {
|
2008-12-04 21:13:58 +00:00
|
|
|
struct uml_driver *driver = conn->privateData;
|
2008-11-19 16:58:23 +00:00
|
|
|
int got = 0, i;
|
|
|
|
|
2008-12-04 21:14:39 +00:00
|
|
|
umlDriverLock(driver);
|
|
|
|
for (i = 0 ; i < driver->domains.count && got < nids ; i++) {
|
|
|
|
virDomainObjLock(driver->domains.objs[i]);
|
2008-11-19 16:58:23 +00:00
|
|
|
if (virDomainIsActive(driver->domains.objs[i]))
|
|
|
|
ids[got++] = driver->domains.objs[i]->def->id;
|
2008-12-04 21:14:39 +00:00
|
|
|
virDomainObjUnlock(driver->domains.objs[i]);
|
|
|
|
}
|
|
|
|
umlDriverUnlock(driver);
|
2008-11-19 16:58:23 +00:00
|
|
|
|
|
|
|
return got;
|
|
|
|
}
|
|
|
|
static int umlNumDomains(virConnectPtr conn) {
|
2008-12-04 21:13:58 +00:00
|
|
|
struct uml_driver *driver = conn->privateData;
|
2008-11-19 16:58:23 +00:00
|
|
|
int n = 0, i;
|
|
|
|
|
2008-12-04 21:14:39 +00:00
|
|
|
umlDriverLock(driver);
|
|
|
|
for (i = 0 ; i < driver->domains.count ; i++) {
|
|
|
|
virDomainObjLock(driver->domains.objs[i]);
|
2008-11-19 16:58:23 +00:00
|
|
|
if (virDomainIsActive(driver->domains.objs[i]))
|
|
|
|
n++;
|
2008-12-04 21:14:39 +00:00
|
|
|
virDomainObjUnlock(driver->domains.objs[i]);
|
|
|
|
}
|
|
|
|
umlDriverUnlock(driver);
|
2008-11-19 16:58:23 +00:00
|
|
|
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
static virDomainPtr umlDomainCreate(virConnectPtr conn, const char *xml,
|
|
|
|
unsigned int flags ATTRIBUTE_UNUSED) {
|
2008-12-04 21:13:58 +00:00
|
|
|
struct uml_driver *driver = conn->privateData;
|
2008-11-19 16:58:23 +00:00
|
|
|
virDomainDefPtr def;
|
2008-12-04 21:14:39 +00:00
|
|
|
virDomainObjPtr vm = NULL;
|
2008-12-04 21:13:58 +00:00
|
|
|
virDomainPtr dom = NULL;
|
2008-11-19 16:58:23 +00:00
|
|
|
|
2008-12-04 21:14:39 +00:00
|
|
|
umlDriverLock(driver);
|
2009-01-08 13:54:20 +00:00
|
|
|
if (!(def = virDomainDefParseString(conn, driver->caps, xml,
|
|
|
|
VIR_DOMAIN_XML_INACTIVE)))
|
2008-12-04 21:13:58 +00:00
|
|
|
goto cleanup;
|
2008-11-19 16:58:23 +00:00
|
|
|
|
|
|
|
vm = virDomainFindByName(&driver->domains, def->name);
|
|
|
|
if (vm) {
|
|
|
|
umlReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("domain '%s' is already defined"),
|
|
|
|
def->name);
|
2008-12-04 21:13:58 +00:00
|
|
|
goto cleanup;
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
vm = virDomainFindByUUID(&driver->domains, def->uuid);
|
|
|
|
if (vm) {
|
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
|
|
|
|
|
|
|
virUUIDFormat(def->uuid, uuidstr);
|
|
|
|
umlReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("domain with uuid '%s' is already defined"),
|
|
|
|
uuidstr);
|
2008-12-04 21:13:58 +00:00
|
|
|
goto cleanup;
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!(vm = virDomainAssignDef(conn,
|
|
|
|
&driver->domains,
|
2008-12-04 21:13:58 +00:00
|
|
|
def)))
|
|
|
|
goto cleanup;
|
|
|
|
def = NULL;
|
2008-11-19 16:58:23 +00:00
|
|
|
|
|
|
|
if (umlStartVMDaemon(conn, driver, vm) < 0) {
|
|
|
|
virDomainRemoveInactive(&driver->domains,
|
|
|
|
vm);
|
2008-12-04 21:13:58 +00:00
|
|
|
vm = NULL;
|
|
|
|
goto cleanup;
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
|
|
|
|
if (dom) dom->id = vm->def->id;
|
2008-12-04 21:13:58 +00:00
|
|
|
|
|
|
|
cleanup:
|
|
|
|
virDomainDefFree(def);
|
2008-12-04 21:14:39 +00:00
|
|
|
if (vm)
|
|
|
|
virDomainObjUnlock(vm);
|
|
|
|
umlDriverUnlock(driver);
|
2008-11-19 16:58:23 +00:00
|
|
|
return dom;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int umlDomainShutdown(virDomainPtr dom) {
|
2008-12-04 21:13:58 +00:00
|
|
|
struct uml_driver *driver = dom->conn->privateData;
|
|
|
|
virDomainObjPtr vm;
|
2008-12-01 11:08:16 +00:00
|
|
|
char *info = NULL;
|
2008-12-04 21:13:58 +00:00
|
|
|
int ret = -1;
|
2008-11-19 16:58:23 +00:00
|
|
|
|
2008-12-04 21:14:39 +00:00
|
|
|
umlDriverLock(driver);
|
2008-12-04 21:13:58 +00:00
|
|
|
vm = virDomainFindByID(&driver->domains, dom->id);
|
2008-12-04 21:14:39 +00:00
|
|
|
umlDriverUnlock(driver);
|
2008-11-19 16:58:23 +00:00
|
|
|
if (!vm) {
|
|
|
|
umlReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN,
|
|
|
|
_("no domain with matching id %d"), dom->id);
|
2008-12-04 21:13:58 +00:00
|
|
|
goto cleanup;
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
if (umlMonitorCommand(driver, vm, "system_powerdown", &info) < 0) {
|
|
|
|
umlReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
|
|
|
|
"%s", _("shutdown operation failed"));
|
2008-12-04 21:13:58 +00:00
|
|
|
goto cleanup;
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
2008-12-04 21:13:58 +00:00
|
|
|
ret = 0;
|
2008-11-19 16:58:23 +00:00
|
|
|
#endif
|
|
|
|
|
2008-12-04 21:13:58 +00:00
|
|
|
cleanup:
|
|
|
|
VIR_FREE(info);
|
2008-12-04 21:14:39 +00:00
|
|
|
if (vm)
|
|
|
|
virDomainObjUnlock(vm);
|
2008-12-04 21:13:58 +00:00
|
|
|
return ret;
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int umlDomainDestroy(virDomainPtr dom) {
|
2008-12-04 21:13:58 +00:00
|
|
|
struct uml_driver *driver = dom->conn->privateData;
|
|
|
|
virDomainObjPtr vm;
|
|
|
|
int ret = -1;
|
2008-11-19 16:58:23 +00:00
|
|
|
|
2008-12-04 21:14:39 +00:00
|
|
|
umlDriverLock(driver);
|
2008-12-04 21:13:58 +00:00
|
|
|
vm = virDomainFindByID(&driver->domains, dom->id);
|
2008-11-19 16:58:23 +00:00
|
|
|
if (!vm) {
|
|
|
|
umlReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN,
|
|
|
|
_("no domain with matching id %d"), dom->id);
|
2008-12-04 21:13:58 +00:00
|
|
|
goto cleanup;
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
umlShutdownVMDaemon(dom->conn, driver, vm);
|
2008-12-04 21:13:58 +00:00
|
|
|
if (!vm->persistent) {
|
2008-11-19 16:58:23 +00:00
|
|
|
virDomainRemoveInactive(&driver->domains,
|
|
|
|
vm);
|
2008-12-04 21:13:58 +00:00
|
|
|
vm = NULL;
|
|
|
|
}
|
|
|
|
ret = 0;
|
2008-11-19 16:58:23 +00:00
|
|
|
|
2008-12-04 21:13:58 +00:00
|
|
|
cleanup:
|
2008-12-04 21:14:39 +00:00
|
|
|
if (vm)
|
|
|
|
virDomainObjUnlock(vm);
|
|
|
|
umlDriverUnlock(driver);
|
2008-12-04 21:13:58 +00:00
|
|
|
return ret;
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static char *umlDomainGetOSType(virDomainPtr dom) {
|
2008-12-04 21:13:58 +00:00
|
|
|
struct uml_driver *driver = dom->conn->privateData;
|
|
|
|
virDomainObjPtr vm;
|
|
|
|
char *type = NULL;
|
2008-11-19 16:58:23 +00:00
|
|
|
|
2008-12-04 21:14:39 +00:00
|
|
|
umlDriverLock(driver);
|
2008-12-04 21:13:58 +00:00
|
|
|
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
|
2008-12-04 21:14:39 +00:00
|
|
|
umlDriverUnlock(driver);
|
2008-11-19 16:58:23 +00:00
|
|
|
if (!vm) {
|
|
|
|
umlReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN,
|
|
|
|
"%s", _("no domain with matching uuid"));
|
2008-12-04 21:13:58 +00:00
|
|
|
goto cleanup;
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
|
2008-12-04 21:13:58 +00:00
|
|
|
if (!(type = strdup(vm->def->os.type)))
|
2009-01-20 17:13:33 +00:00
|
|
|
virReportOOMError(dom->conn);
|
2008-12-04 21:13:58 +00:00
|
|
|
|
|
|
|
cleanup:
|
2008-12-04 21:14:39 +00:00
|
|
|
if (vm)
|
|
|
|
virDomainObjUnlock(vm);
|
2008-11-19 16:58:23 +00:00
|
|
|
return type;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Returns max memory in kb, 0 if error */
|
|
|
|
static unsigned long umlDomainGetMaxMemory(virDomainPtr dom) {
|
2008-12-04 21:13:58 +00:00
|
|
|
struct uml_driver *driver = dom->conn->privateData;
|
|
|
|
virDomainObjPtr vm;
|
|
|
|
unsigned long ret = 0;
|
2008-11-19 16:58:23 +00:00
|
|
|
|
2008-12-04 21:14:39 +00:00
|
|
|
umlDriverLock(driver);
|
2008-12-04 21:13:58 +00:00
|
|
|
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
|
2008-12-04 21:14:39 +00:00
|
|
|
umlDriverUnlock(driver);
|
|
|
|
|
2008-11-19 16:58:23 +00:00
|
|
|
if (!vm) {
|
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
|
|
|
|
|
|
|
virUUIDFormat(dom->uuid, uuidstr);
|
|
|
|
umlReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN,
|
2008-12-04 21:13:58 +00:00
|
|
|
_("no domain with matching uuid '%s'"), uuidstr);
|
|
|
|
goto cleanup;
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
2008-12-04 21:13:58 +00:00
|
|
|
ret = vm->def->maxmem;
|
2008-11-19 16:58:23 +00:00
|
|
|
|
2008-12-04 21:13:58 +00:00
|
|
|
cleanup:
|
2008-12-04 21:14:39 +00:00
|
|
|
if (vm)
|
|
|
|
virDomainObjUnlock(vm);
|
2008-12-04 21:13:58 +00:00
|
|
|
return ret;
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int umlDomainSetMaxMemory(virDomainPtr dom, unsigned long newmax) {
|
2008-12-04 21:13:58 +00:00
|
|
|
struct uml_driver *driver = dom->conn->privateData;
|
|
|
|
virDomainObjPtr vm;
|
|
|
|
int ret = -1;
|
2008-11-19 16:58:23 +00:00
|
|
|
|
2008-12-04 21:14:39 +00:00
|
|
|
umlDriverLock(driver);
|
2008-12-04 21:13:58 +00:00
|
|
|
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
|
2008-12-04 21:14:39 +00:00
|
|
|
umlDriverUnlock(driver);
|
|
|
|
|
2008-11-19 16:58:23 +00:00
|
|
|
if (!vm) {
|
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
|
|
|
|
|
|
|
virUUIDFormat(dom->uuid, uuidstr);
|
|
|
|
umlReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN,
|
|
|
|
_("no domain with matching uuid '%s'"), uuidstr);
|
2008-12-04 21:13:58 +00:00
|
|
|
goto cleanup;
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (newmax < vm->def->memory) {
|
|
|
|
umlReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_ARG,
|
|
|
|
"%s", _("cannot set max memory lower than current memory"));
|
2008-12-04 21:13:58 +00:00
|
|
|
goto cleanup;
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
vm->def->maxmem = newmax;
|
2008-12-04 21:13:58 +00:00
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
2008-12-04 21:14:39 +00:00
|
|
|
if (vm)
|
|
|
|
virDomainObjUnlock(vm);
|
2008-12-04 21:13:58 +00:00
|
|
|
return ret;
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int umlDomainSetMemory(virDomainPtr dom, unsigned long newmem) {
|
2008-12-04 21:13:58 +00:00
|
|
|
struct uml_driver *driver = dom->conn->privateData;
|
|
|
|
virDomainObjPtr vm;
|
|
|
|
int ret = -1;
|
2008-11-19 16:58:23 +00:00
|
|
|
|
2008-12-04 21:14:39 +00:00
|
|
|
umlDriverLock(driver);
|
2008-12-04 21:13:58 +00:00
|
|
|
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
|
2008-12-04 21:14:39 +00:00
|
|
|
umlDriverUnlock(driver);
|
|
|
|
|
2008-11-19 16:58:23 +00:00
|
|
|
if (!vm) {
|
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
|
|
|
|
|
|
|
virUUIDFormat(dom->uuid, uuidstr);
|
|
|
|
umlReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN,
|
|
|
|
_("no domain with matching uuid '%s'"), uuidstr);
|
2008-12-04 21:13:58 +00:00
|
|
|
goto cleanup;
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (virDomainIsActive(vm)) {
|
|
|
|
umlReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
|
|
|
|
"%s", _("cannot set memory of an active domain"));
|
2008-12-04 21:13:58 +00:00
|
|
|
goto cleanup;
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (newmem > vm->def->maxmem) {
|
|
|
|
umlReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_ARG,
|
|
|
|
"%s", _("cannot set memory higher than max memory"));
|
2008-12-04 21:13:58 +00:00
|
|
|
goto cleanup;
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
vm->def->memory = newmem;
|
2008-12-04 21:13:58 +00:00
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
2008-12-04 21:14:39 +00:00
|
|
|
if (vm)
|
|
|
|
virDomainObjUnlock(vm);
|
2008-12-04 21:13:58 +00:00
|
|
|
return ret;
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int umlDomainGetInfo(virDomainPtr dom,
|
|
|
|
virDomainInfoPtr info) {
|
2008-12-04 21:13:58 +00:00
|
|
|
struct uml_driver *driver = dom->conn->privateData;
|
|
|
|
virDomainObjPtr vm;
|
|
|
|
int ret = -1;
|
|
|
|
|
2008-12-04 21:14:39 +00:00
|
|
|
umlDriverLock(driver);
|
2008-12-04 21:13:58 +00:00
|
|
|
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
|
2008-12-04 21:14:39 +00:00
|
|
|
umlDriverUnlock(driver);
|
|
|
|
|
2008-11-19 16:58:23 +00:00
|
|
|
if (!vm) {
|
|
|
|
umlReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN,
|
2008-12-04 21:13:58 +00:00
|
|
|
"%s", _("no domain with matching uuid"));
|
|
|
|
goto cleanup;
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
info->state = vm->state;
|
|
|
|
|
|
|
|
if (!virDomainIsActive(vm)) {
|
|
|
|
info->cpuTime = 0;
|
|
|
|
} else {
|
|
|
|
if (umlGetProcessInfo(&(info->cpuTime), vm->pid) < 0) {
|
2008-12-04 21:13:58 +00:00
|
|
|
umlReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
|
|
|
|
"%s", _("cannot read cputime for domain"));
|
|
|
|
goto cleanup;
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
info->maxMem = vm->def->maxmem;
|
|
|
|
info->memory = vm->def->memory;
|
|
|
|
info->nrVirtCpu = vm->def->vcpus;
|
2008-12-04 21:13:58 +00:00
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
2008-12-04 21:14:39 +00:00
|
|
|
if (vm)
|
|
|
|
virDomainObjUnlock(vm);
|
2008-12-04 21:13:58 +00:00
|
|
|
return ret;
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static char *umlDomainDumpXML(virDomainPtr dom,
|
|
|
|
int flags ATTRIBUTE_UNUSED) {
|
2008-12-04 21:13:58 +00:00
|
|
|
struct uml_driver *driver = dom->conn->privateData;
|
|
|
|
virDomainObjPtr vm;
|
|
|
|
char *ret = NULL;
|
|
|
|
|
2008-12-04 21:14:39 +00:00
|
|
|
umlDriverLock(driver);
|
2008-12-04 21:13:58 +00:00
|
|
|
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
|
2008-12-04 21:14:39 +00:00
|
|
|
umlDriverUnlock(driver);
|
|
|
|
|
2008-11-19 16:58:23 +00:00
|
|
|
if (!vm) {
|
|
|
|
umlReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN,
|
|
|
|
"%s", _("no domain with matching uuid"));
|
2008-12-04 21:13:58 +00:00
|
|
|
goto cleanup;
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
|
2008-12-04 21:13:58 +00:00
|
|
|
ret = virDomainDefFormat(dom->conn,
|
|
|
|
(flags & VIR_DOMAIN_XML_INACTIVE) && vm->newDef ?
|
|
|
|
vm->newDef : vm->def,
|
|
|
|
flags);
|
|
|
|
|
|
|
|
cleanup:
|
2008-12-04 21:14:39 +00:00
|
|
|
if (vm)
|
|
|
|
virDomainObjUnlock(vm);
|
2008-12-04 21:13:58 +00:00
|
|
|
return ret;
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int umlListDefinedDomains(virConnectPtr conn,
|
|
|
|
char **const names, int nnames) {
|
2008-12-04 21:13:58 +00:00
|
|
|
struct uml_driver *driver = conn->privateData;
|
2008-11-19 16:58:23 +00:00
|
|
|
int got = 0, i;
|
|
|
|
|
2008-12-04 21:14:39 +00:00
|
|
|
umlDriverLock(driver);
|
2008-11-19 16:58:23 +00:00
|
|
|
for (i = 0 ; i < driver->domains.count && got < nnames ; i++) {
|
2008-12-04 21:14:39 +00:00
|
|
|
virDomainObjLock(driver->domains.objs[i]);
|
2008-11-19 16:58:23 +00:00
|
|
|
if (!virDomainIsActive(driver->domains.objs[i])) {
|
|
|
|
if (!(names[got++] = strdup(driver->domains.objs[i]->def->name))) {
|
2009-01-20 17:13:33 +00:00
|
|
|
virReportOOMError(conn);
|
2008-12-04 21:14:39 +00:00
|
|
|
virDomainObjUnlock(driver->domains.objs[i]);
|
2008-11-19 16:58:23 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
2008-12-04 21:14:39 +00:00
|
|
|
virDomainObjUnlock(driver->domains.objs[i]);
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
2008-12-04 21:14:39 +00:00
|
|
|
umlDriverUnlock(driver);
|
2008-11-19 16:58:23 +00:00
|
|
|
|
|
|
|
return got;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
for (i = 0 ; i < got ; i++)
|
|
|
|
VIR_FREE(names[i]);
|
2008-12-04 21:14:39 +00:00
|
|
|
umlDriverUnlock(driver);
|
2008-11-19 16:58:23 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int umlNumDefinedDomains(virConnectPtr conn) {
|
2008-12-04 21:13:58 +00:00
|
|
|
struct uml_driver *driver = conn->privateData;
|
2008-11-19 16:58:23 +00:00
|
|
|
int n = 0, i;
|
|
|
|
|
2008-12-04 21:14:39 +00:00
|
|
|
umlDriverLock(driver);
|
|
|
|
for (i = 0 ; i < driver->domains.count ; i++) {
|
|
|
|
virDomainObjLock(driver->domains.objs[i]);
|
2008-11-19 16:58:23 +00:00
|
|
|
if (!virDomainIsActive(driver->domains.objs[i]))
|
|
|
|
n++;
|
2008-12-04 21:14:39 +00:00
|
|
|
virDomainObjUnlock(driver->domains.objs[i]);
|
|
|
|
}
|
|
|
|
umlDriverUnlock(driver);
|
2008-11-19 16:58:23 +00:00
|
|
|
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int umlDomainStart(virDomainPtr dom) {
|
2008-12-04 21:13:58 +00:00
|
|
|
struct uml_driver *driver = dom->conn->privateData;
|
|
|
|
virDomainObjPtr vm;
|
|
|
|
int ret = -1;
|
2008-11-19 16:58:23 +00:00
|
|
|
|
2008-12-04 21:14:39 +00:00
|
|
|
umlDriverLock(driver);
|
2008-12-04 21:13:58 +00:00
|
|
|
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
|
2008-12-04 21:14:39 +00:00
|
|
|
|
2008-11-19 16:58:23 +00:00
|
|
|
if (!vm) {
|
|
|
|
umlReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN,
|
|
|
|
"%s", _("no domain with matching uuid"));
|
2008-12-04 21:13:58 +00:00
|
|
|
goto cleanup;
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
|
2008-12-04 21:13:58 +00:00
|
|
|
ret = umlStartVMDaemon(dom->conn, driver, vm);
|
|
|
|
|
|
|
|
cleanup:
|
2008-12-04 21:14:39 +00:00
|
|
|
if (vm)
|
|
|
|
virDomainObjUnlock(vm);
|
|
|
|
umlDriverUnlock(driver);
|
2008-12-04 21:13:58 +00:00
|
|
|
return ret;
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static virDomainPtr umlDomainDefine(virConnectPtr conn, const char *xml) {
|
2008-12-04 21:13:58 +00:00
|
|
|
struct uml_driver *driver = conn->privateData;
|
2008-11-19 16:58:23 +00:00
|
|
|
virDomainDefPtr def;
|
2008-12-04 21:14:39 +00:00
|
|
|
virDomainObjPtr vm = NULL;
|
2008-12-04 21:13:58 +00:00
|
|
|
virDomainPtr dom = NULL;
|
2008-11-19 16:58:23 +00:00
|
|
|
|
2008-12-04 21:14:39 +00:00
|
|
|
umlDriverLock(driver);
|
2009-01-08 13:54:20 +00:00
|
|
|
if (!(def = virDomainDefParseString(conn, driver->caps, xml,
|
|
|
|
VIR_DOMAIN_XML_INACTIVE)))
|
2008-12-04 21:13:58 +00:00
|
|
|
goto cleanup;
|
2008-11-19 16:58:23 +00:00
|
|
|
|
|
|
|
if (!(vm = virDomainAssignDef(conn,
|
|
|
|
&driver->domains,
|
2008-12-04 21:13:58 +00:00
|
|
|
def)))
|
|
|
|
goto cleanup;
|
|
|
|
def = NULL;
|
2008-11-19 16:58:23 +00:00
|
|
|
vm->persistent = 1;
|
|
|
|
|
|
|
|
if (virDomainSaveConfig(conn,
|
|
|
|
driver->configDir,
|
|
|
|
vm->newDef ? vm->newDef : vm->def) < 0) {
|
|
|
|
virDomainRemoveInactive(&driver->domains,
|
|
|
|
vm);
|
2008-12-04 21:14:39 +00:00
|
|
|
vm = NULL;
|
2008-12-04 21:13:58 +00:00
|
|
|
goto cleanup;
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
|
|
|
|
if (dom) dom->id = vm->def->id;
|
2008-12-04 21:13:58 +00:00
|
|
|
|
|
|
|
cleanup:
|
|
|
|
virDomainDefFree(def);
|
2008-12-04 21:14:39 +00:00
|
|
|
if (vm)
|
|
|
|
virDomainObjUnlock(vm);
|
|
|
|
umlDriverUnlock(driver);
|
2008-11-19 16:58:23 +00:00
|
|
|
return dom;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int umlDomainUndefine(virDomainPtr dom) {
|
2008-12-04 21:13:58 +00:00
|
|
|
struct uml_driver *driver = dom->conn->privateData;
|
|
|
|
virDomainObjPtr vm;
|
|
|
|
int ret = -1;
|
2008-11-19 16:58:23 +00:00
|
|
|
|
2008-12-04 21:14:39 +00:00
|
|
|
umlDriverLock(driver);
|
2008-12-04 21:13:58 +00:00
|
|
|
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
|
2008-11-19 16:58:23 +00:00
|
|
|
if (!vm) {
|
|
|
|
umlReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN,
|
|
|
|
"%s", _("no domain with matching uuid"));
|
2008-12-04 21:13:58 +00:00
|
|
|
goto cleanup;
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (virDomainIsActive(vm)) {
|
|
|
|
umlReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("cannot delete active domain"));
|
2008-12-04 21:13:58 +00:00
|
|
|
goto cleanup;
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!vm->persistent) {
|
|
|
|
umlReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("cannot undefine transient domain"));
|
2008-12-04 21:13:58 +00:00
|
|
|
goto cleanup;
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (virDomainDeleteConfig(dom->conn, driver->configDir, driver->autostartDir, vm) < 0)
|
2008-12-04 21:13:58 +00:00
|
|
|
goto cleanup;
|
2008-11-19 16:58:23 +00:00
|
|
|
|
|
|
|
virDomainRemoveInactive(&driver->domains,
|
|
|
|
vm);
|
2008-12-04 21:14:39 +00:00
|
|
|
vm = NULL;
|
2008-12-04 21:13:58 +00:00
|
|
|
ret = 0;
|
2008-11-19 16:58:23 +00:00
|
|
|
|
2008-12-04 21:13:58 +00:00
|
|
|
cleanup:
|
2008-12-04 21:14:39 +00:00
|
|
|
if (vm)
|
|
|
|
virDomainObjUnlock(vm);
|
|
|
|
umlDriverUnlock(driver);
|
2008-12-04 21:13:58 +00:00
|
|
|
return ret;
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int umlDomainGetAutostart(virDomainPtr dom,
|
|
|
|
int *autostart) {
|
2008-12-04 21:13:58 +00:00
|
|
|
struct uml_driver *driver = dom->conn->privateData;
|
|
|
|
virDomainObjPtr vm;
|
|
|
|
int ret = -1;
|
2008-11-19 16:58:23 +00:00
|
|
|
|
2008-12-04 21:14:39 +00:00
|
|
|
umlDriverLock(driver);
|
2008-12-04 21:13:58 +00:00
|
|
|
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
|
2008-12-04 21:14:39 +00:00
|
|
|
|
2008-11-19 16:58:23 +00:00
|
|
|
if (!vm) {
|
|
|
|
umlReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN,
|
|
|
|
"%s", _("no domain with matching uuid"));
|
2008-12-04 21:13:58 +00:00
|
|
|
goto cleanup;
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
*autostart = vm->autostart;
|
2008-12-04 21:13:58 +00:00
|
|
|
ret = 0;
|
2008-11-19 16:58:23 +00:00
|
|
|
|
2008-12-04 21:13:58 +00:00
|
|
|
cleanup:
|
2008-12-04 21:14:39 +00:00
|
|
|
if (vm)
|
|
|
|
virDomainObjUnlock(vm);
|
2009-05-19 11:06:25 +00:00
|
|
|
umlDriverUnlock(driver);
|
2008-12-04 21:13:58 +00:00
|
|
|
return ret;
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int umlDomainSetAutostart(virDomainPtr dom,
|
|
|
|
int autostart) {
|
2008-12-04 21:13:58 +00:00
|
|
|
struct uml_driver *driver = dom->conn->privateData;
|
2008-12-04 21:14:39 +00:00
|
|
|
virDomainObjPtr vm;
|
2008-11-19 16:58:23 +00:00
|
|
|
char *configFile = NULL, *autostartLink = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
|
2008-12-04 21:14:39 +00:00
|
|
|
umlDriverLock(driver);
|
|
|
|
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
|
|
|
|
|
2008-11-19 16:58:23 +00:00
|
|
|
if (!vm) {
|
|
|
|
umlReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN,
|
|
|
|
"%s", _("no domain with matching uuid"));
|
2008-12-04 21:13:58 +00:00
|
|
|
goto cleanup;
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!vm->persistent) {
|
|
|
|
umlReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("cannot set autostart for transient domain"));
|
2008-12-04 21:13:58 +00:00
|
|
|
goto cleanup;
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
autostart = (autostart != 0);
|
|
|
|
|
2008-12-04 21:13:58 +00:00
|
|
|
if (vm->autostart != autostart) {
|
|
|
|
if ((configFile = virDomainConfigFile(dom->conn, driver->configDir, vm->def->name)) == NULL)
|
|
|
|
goto cleanup;
|
|
|
|
if ((autostartLink = virDomainConfigFile(dom->conn, driver->autostartDir, vm->def->name)) == NULL)
|
|
|
|
goto cleanup;
|
2008-11-19 16:58:23 +00:00
|
|
|
|
2008-12-04 21:13:58 +00:00
|
|
|
if (autostart) {
|
|
|
|
int err;
|
2008-11-19 16:58:23 +00:00
|
|
|
|
2008-12-04 21:13:58 +00:00
|
|
|
if ((err = virFileMakePath(driver->autostartDir))) {
|
2009-01-20 17:13:33 +00:00
|
|
|
virReportSystemError(dom->conn, err,
|
|
|
|
_("cannot create autostart directory %s"),
|
|
|
|
driver->autostartDir);
|
2008-12-04 21:13:58 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2008-11-19 16:58:23 +00:00
|
|
|
|
2008-12-04 21:13:58 +00:00
|
|
|
if (symlink(configFile, autostartLink) < 0) {
|
2009-01-20 17:13:33 +00:00
|
|
|
virReportSystemError(dom->conn, errno,
|
|
|
|
_("Failed to create symlink '%s to '%s'"),
|
|
|
|
autostartLink, configFile);
|
2008-12-04 21:13:58 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
|
2009-01-20 17:13:33 +00:00
|
|
|
virReportSystemError(dom->conn, errno,
|
|
|
|
_("Failed to delete symlink '%s'"),
|
|
|
|
autostartLink);
|
2008-12-04 21:13:58 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
|
2008-12-04 21:13:58 +00:00
|
|
|
vm->autostart = autostart;
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(configFile);
|
|
|
|
VIR_FREE(autostartLink);
|
2008-12-04 21:14:39 +00:00
|
|
|
if (vm)
|
|
|
|
virDomainObjUnlock(vm);
|
2009-05-19 11:06:25 +00:00
|
|
|
umlDriverUnlock(driver);
|
2008-11-19 16:58:23 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
umlDomainBlockPeek (virDomainPtr dom,
|
|
|
|
const char *path,
|
|
|
|
unsigned long long offset, size_t size,
|
|
|
|
void *buffer,
|
|
|
|
unsigned int flags ATTRIBUTE_UNUSED)
|
|
|
|
{
|
2008-12-04 21:13:58 +00:00
|
|
|
struct uml_driver *driver = dom->conn->privateData;
|
|
|
|
virDomainObjPtr vm;
|
|
|
|
int fd = -1, ret = -1, i;
|
2008-11-19 16:58:23 +00:00
|
|
|
|
2008-12-04 21:14:39 +00:00
|
|
|
umlDriverLock(driver);
|
2008-12-04 21:13:58 +00:00
|
|
|
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
|
2008-12-04 21:14:39 +00:00
|
|
|
umlDriverUnlock(driver);
|
|
|
|
|
2008-11-19 16:58:23 +00:00
|
|
|
if (!vm) {
|
|
|
|
umlReportError (dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN,
|
2008-12-10 16:35:00 +00:00
|
|
|
"%s", _("no domain with matching uuid"));
|
2008-12-04 21:13:58 +00:00
|
|
|
goto cleanup;
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!path || path[0] == '\0') {
|
|
|
|
umlReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_ARG,
|
2008-12-10 16:35:00 +00:00
|
|
|
"%s", _("NULL or empty path"));
|
2008-12-04 21:13:58 +00:00
|
|
|
goto cleanup;
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Check the path belongs to this domain. */
|
|
|
|
for (i = 0 ; i < vm->def->ndisks ; i++) {
|
|
|
|
if (vm->def->disks[i]->src != NULL &&
|
2008-12-04 21:13:58 +00:00
|
|
|
STREQ (vm->def->disks[i]->src, path)) {
|
|
|
|
ret = 0;
|
|
|
|
break;
|
|
|
|
}
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
|
2008-12-04 21:13:58 +00:00
|
|
|
if (ret == 0) {
|
|
|
|
ret = -1;
|
|
|
|
/* The path is correct, now try to open it and get its size. */
|
|
|
|
fd = open (path, O_RDONLY);
|
|
|
|
if (fd == -1) {
|
2009-01-20 17:13:33 +00:00
|
|
|
virReportSystemError(dom->conn, errno,
|
|
|
|
_("cannot open %s"), path);
|
2008-12-04 21:13:58 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2008-11-19 16:58:23 +00:00
|
|
|
|
2008-12-04 21:13:58 +00:00
|
|
|
/* 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) {
|
2009-01-20 17:13:33 +00:00
|
|
|
virReportSystemError(dom->conn, errno,
|
|
|
|
_("cannot read %s"), path);
|
2008-12-04 21:13:58 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
} else {
|
|
|
|
umlReportError (dom->conn, dom, NULL, VIR_ERR_INVALID_ARG,
|
2008-12-10 16:35:00 +00:00
|
|
|
"%s", _("invalid path"));
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
|
|
|
|
2008-12-04 21:13:58 +00:00
|
|
|
cleanup:
|
2008-11-19 16:58:23 +00:00
|
|
|
if (fd >= 0) close (fd);
|
2008-12-04 21:14:39 +00:00
|
|
|
if (vm)
|
|
|
|
virDomainObjUnlock(vm);
|
2008-11-19 16:58:23 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static virDriver umlDriver = {
|
|
|
|
VIR_DRV_UML,
|
|
|
|
"UML",
|
|
|
|
umlOpen, /* open */
|
|
|
|
umlClose, /* close */
|
|
|
|
NULL, /* supports_feature */
|
|
|
|
umlGetType, /* type */
|
|
|
|
umlGetVersion, /* version */
|
2009-03-31 15:47:16 +00:00
|
|
|
umlGetHostname, /* getHostname */
|
2008-11-19 16:58:23 +00:00
|
|
|
NULL, /* getMaxVcpus */
|
2009-06-03 13:28:02 +00:00
|
|
|
nodeGetInfo, /* nodeGetInfo */
|
2008-11-19 16:58:23 +00:00
|
|
|
umlGetCapabilities, /* getCapabilities */
|
|
|
|
umlListDomains, /* listDomains */
|
|
|
|
umlNumDomains, /* numOfDomains */
|
|
|
|
umlDomainCreate, /* domainCreateXML */
|
|
|
|
umlDomainLookupByID, /* domainLookupByID */
|
|
|
|
umlDomainLookupByUUID, /* domainLookupByUUID */
|
|
|
|
umlDomainLookupByName, /* domainLookupByName */
|
|
|
|
NULL, /* domainSuspend */
|
|
|
|
NULL, /* domainResume */
|
|
|
|
umlDomainShutdown, /* domainShutdown */
|
|
|
|
NULL, /* domainReboot */
|
|
|
|
umlDomainDestroy, /* domainDestroy */
|
|
|
|
umlDomainGetOSType, /* domainGetOSType */
|
|
|
|
umlDomainGetMaxMemory, /* domainGetMaxMemory */
|
|
|
|
umlDomainSetMaxMemory, /* domainSetMaxMemory */
|
|
|
|
umlDomainSetMemory, /* domainSetMemory */
|
|
|
|
umlDomainGetInfo, /* domainGetInfo */
|
|
|
|
NULL, /* domainSave */
|
|
|
|
NULL, /* domainRestore */
|
|
|
|
NULL, /* domainCoreDump */
|
|
|
|
NULL, /* domainSetVcpus */
|
|
|
|
NULL, /* domainPinVcpu */
|
|
|
|
NULL, /* domainGetVcpus */
|
|
|
|
NULL, /* domainGetMaxVcpus */
|
2009-03-03 09:14:28 +00:00
|
|
|
NULL, /* domainGetSecurityLabel */
|
|
|
|
NULL, /* nodeGetSecurityModel */
|
2008-11-19 16:58:23 +00:00
|
|
|
umlDomainDumpXML, /* domainDumpXML */
|
2009-09-06 14:03:06 +00:00
|
|
|
NULL, /* domainXMLFromNative */
|
|
|
|
NULL, /* domainXMLToNative */
|
2009-03-31 15:47:16 +00:00
|
|
|
umlListDefinedDomains, /* listDefinedDomains */
|
|
|
|
umlNumDefinedDomains, /* numOfDefinedDomains */
|
2008-11-19 16:58:23 +00:00
|
|
|
umlDomainStart, /* domainCreate */
|
|
|
|
umlDomainDefine, /* domainDefineXML */
|
|
|
|
umlDomainUndefine, /* domainUndefine */
|
|
|
|
NULL, /* domainAttachDevice */
|
|
|
|
NULL, /* domainDetachDevice */
|
|
|
|
umlDomainGetAutostart, /* domainGetAutostart */
|
|
|
|
umlDomainSetAutostart, /* domainSetAutostart */
|
|
|
|
NULL, /* domainGetSchedulerType */
|
|
|
|
NULL, /* domainGetSchedulerParameters */
|
|
|
|
NULL, /* domainSetSchedulerParameters */
|
|
|
|
NULL, /* domainMigratePrepare */
|
|
|
|
NULL, /* domainMigratePerform */
|
|
|
|
NULL, /* domainMigrateFinish */
|
|
|
|
NULL, /* domainBlockStats */
|
|
|
|
NULL, /* domainInterfaceStats */
|
|
|
|
umlDomainBlockPeek, /* domainBlockPeek */
|
|
|
|
NULL, /* domainMemoryPeek */
|
2009-08-27 18:13:11 +00:00
|
|
|
nodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */
|
|
|
|
nodeGetFreeMemory, /* getFreeMemory */
|
2008-11-19 16:58:23 +00:00
|
|
|
NULL, /* domainEventRegister */
|
2009-03-31 15:47:16 +00:00
|
|
|
NULL, /* domainEventDeregister */
|
2008-11-19 16:58:23 +00:00
|
|
|
NULL, /* domainMigratePrepare2 */
|
|
|
|
NULL, /* domainMigrateFinish2 */
|
2009-03-31 15:47:16 +00:00
|
|
|
NULL, /* nodeDeviceDettach */
|
2009-03-02 16:25:13 +00:00
|
|
|
NULL, /* nodeDeviceReAttach */
|
|
|
|
NULL, /* nodeDeviceReset */
|
2008-11-19 16:58:23 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static virStateDriver umlStateDriver = {
|
|
|
|
.initialize = umlStartup,
|
|
|
|
.cleanup = umlShutdown,
|
|
|
|
.reload = umlReload,
|
|
|
|
.active = umlActive,
|
|
|
|
};
|
|
|
|
|
|
|
|
int umlRegister(void) {
|
|
|
|
virRegisterDriver(¨Driver);
|
|
|
|
virRegisterStateDriver(¨StateDriver);
|
|
|
|
return 0;
|
|
|
|
}
|