2
* uml_driver.c: core driver methods for managing UML guests
4
* Copyright (C) 2006-2010 Red Hat, Inc.
5
* Copyright (C) 2006-2008 Daniel P. Berrange
7
* This library is free software; you can redistribute it and/or
8
* modify it under the terms of the GNU Lesser General Public
9
* License as published by the Free Software Foundation; either
10
* version 2.1 of the License, or (at your option) any later version.
12
* This library is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
* Lesser General Public License for more details.
17
* You should have received a copy of the GNU Lesser General Public
18
* License along with this library; if not, write to the Free Software
19
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
* Author: Daniel P. Berrange <berrange@redhat.com>
26
#include <sys/types.h>
36
#include <sys/utsname.h>
44
#include <sys/ioctl.h>
45
#include <sys/inotify.h>
48
#include "uml_driver.h"
54
#include "stats_linux.h"
55
#include "capabilities.h"
58
#include "domain_conf.h"
59
#include "datatypes.h"
62
#define VIR_FROM_THIS VIR_FROM_UML
64
/* For storing short-lived temporary files. */
65
#define TEMPDIR LOCAL_STATE_DIR "/cache/libvirt"
67
typedef struct _umlDomainObjPrivate umlDomainObjPrivate;
68
typedef umlDomainObjPrivate *umlDomainObjPrivatePtr;
69
struct _umlDomainObjPrivate {
75
static int umlShutdown(void);
77
static void *umlDomainObjPrivateAlloc(void)
79
umlDomainObjPrivatePtr priv;
81
if (VIR_ALLOC(priv) < 0)
85
priv->monitorWatch = -1;
90
static void umlDomainObjPrivateFree(void *data)
92
umlDomainObjPrivatePtr priv = data;
98
static void umlDriverLock(struct uml_driver *driver)
100
virMutexLock(&driver->lock);
102
static void umlDriverUnlock(struct uml_driver *driver)
104
virMutexUnlock(&driver->lock);
108
static int umlOpenMonitor(struct uml_driver *driver,
110
static int umlReadPidFile(struct uml_driver *driver,
113
static int umlSetCloseExec(int fd) {
115
if ((flags = fcntl(fd, F_GETFD)) < 0)
118
if ((fcntl(fd, F_SETFD, flags)) < 0)
122
VIR_ERROR0(_("Failed to set close-on-exec file descriptor flag"));
126
static int umlStartVMDaemon(virConnectPtr conn,
127
struct uml_driver *driver,
130
static void umlShutdownVMDaemon(virConnectPtr conn,
131
struct uml_driver *driver,
135
static int umlMonitorCommand(const struct uml_driver *driver,
136
const virDomainObjPtr vm,
140
static struct uml_driver *uml_driver = NULL;
142
struct umlAutostartData {
143
struct uml_driver *driver;
148
umlAutostartDomain(void *payload, const char *name ATTRIBUTE_UNUSED, void *opaque)
150
virDomainObjPtr vm = payload;
151
const struct umlAutostartData *data = opaque;
153
virDomainObjLock(vm);
155
!virDomainObjIsActive(vm)) {
157
if (umlStartVMDaemon(data->conn, data->driver, vm) < 0) {
158
virErrorPtr err = virGetLastError();
159
VIR_ERROR(_("Failed to autostart VM '%s': %s"),
160
vm->def->name, err ? err->message : _("unknown error"));
163
virDomainObjUnlock(vm);
167
umlAutostartConfigs(struct uml_driver *driver) {
168
/* XXX: Figure out a better way todo this. The domain
169
* startup code needs a connection handle in order
170
* to lookup the bridge associated with a virtual
173
virConnectPtr conn = virConnectOpen(driver->privileged ?
176
/* Ignoring NULL conn which is mostly harmless here */
178
struct umlAutostartData data = { driver, conn };
180
virHashForEach(driver->domains.objs, umlAutostartDomain, &data);
183
virConnectClose(conn);
188
umlIdentifyOneChrPTY(struct uml_driver *driver,
190
virDomainChrDefPtr def,
196
if (virAsprintf(&cmd, "config %s%d", dev, def->target.port) < 0) {
201
if (umlMonitorCommand(driver, dom, cmd, &res) < 0)
204
if (res && STRPREFIX(res, "pts:")) {
205
VIR_FREE(def->data.file.path);
206
if ((def->data.file.path = strdup(res + 4)) == NULL) {
212
} else if (!res || STRPREFIX(res, "pts")) {
213
/* It can take a while to startup, so retry for
215
/* XXX should do this in a better non-blocking
216
way somehow ...perhaps register a timer */
217
if (retries++ < 50) {
229
umlIdentifyChrPTY(struct uml_driver *driver,
234
if (dom->def->console &&
235
dom->def->console->type == VIR_DOMAIN_CHR_TYPE_PTY)
236
if (umlIdentifyOneChrPTY(driver, dom,
237
dom->def->console, "con") < 0)
240
for (i = 0 ; i < dom->def->nserials; i++)
241
if (dom->def->serials[i]->type == VIR_DOMAIN_CHR_TYPE_PTY &&
242
umlIdentifyOneChrPTY(driver, dom,
243
dom->def->serials[i], "ssl") < 0)
250
umlInotifyEvent(int watch,
252
int events ATTRIBUTE_UNUSED,
256
struct inotify_event *e;
259
struct uml_driver *driver = data;
262
umlDriverLock(driver);
263
if (watch != driver->inotifyWatch)
267
got = read(fd, buf, sizeof(buf));
276
if (got < sizeof(struct inotify_event))
277
goto cleanup; /* bad */
279
e = (struct inotify_event *)tmp;
280
tmp += sizeof(struct inotify_event);
281
got -= sizeof(struct inotify_event);
289
name = (char *)&(e->name);
291
dom = virDomainFindByName(&driver->domains, name);
297
if (e->mask & IN_DELETE) {
298
VIR_DEBUG("Got inotify domain shutdown '%s'", name);
299
if (!virDomainObjIsActive(dom)) {
300
virDomainObjUnlock(dom);
304
umlShutdownVMDaemon(NULL, driver, dom);
305
} else if (e->mask & (IN_CREATE | IN_MODIFY)) {
306
VIR_DEBUG("Got inotify domain startup '%s'", name);
307
if (virDomainObjIsActive(dom)) {
308
virDomainObjUnlock(dom);
312
if (umlReadPidFile(driver, dom) < 0) {
313
virDomainObjUnlock(dom);
317
dom->def->id = driver->nextvmid++;
318
dom->state = VIR_DOMAIN_RUNNING;
320
if (umlOpenMonitor(driver, dom) < 0) {
321
VIR_WARN0("Could not open monitor for new domain");
322
umlShutdownVMDaemon(NULL, driver, dom);
323
} else if (umlIdentifyChrPTY(driver, dom) < 0) {
324
VIR_WARN0("Could not identify charater devices for new domain");
325
umlShutdownVMDaemon(NULL, driver, dom);
328
virDomainObjUnlock(dom);
332
umlDriverUnlock(driver);
338
* Initialization function for the Uml daemon
341
umlStartup(int privileged) {
342
uid_t uid = geteuid();
344
char driverConf[PATH_MAX];
345
char *userdir = NULL;
347
if (VIR_ALLOC(uml_driver) < 0)
350
uml_driver->privileged = privileged;
352
if (virMutexInit(¨_driver->lock) < 0) {
353
VIR_FREE(uml_driver);
356
umlDriverLock(uml_driver);
358
/* Don't have a dom0 so start from 1 */
359
uml_driver->nextvmid = 1;
360
uml_driver->inotifyWatch = -1;
362
if (virDomainObjListInit(¨_driver->domains) < 0)
365
userdir = virGetUserDirectory(uid);
370
if (virAsprintf(¨_driver->logDir,
371
"%s/log/libvirt/uml", LOCAL_STATE_DIR) == -1)
374
if ((base = strdup (SYSCONF_DIR "/libvirt")) == NULL)
378
if (virAsprintf(¨_driver->logDir,
379
"%s/.libvirt/uml/log", userdir) == -1)
382
if (virAsprintf(&base, "%s/.libvirt", userdir) == -1)
386
if (virAsprintf(¨_driver->monitorDir,
387
"%s/.uml", userdir) == -1)
390
/* Configuration paths are either ~/.libvirt/uml/... (session) or
391
* /etc/libvirt/uml/... (system).
393
if (snprintf (driverConf, sizeof(driverConf), "%s/uml.conf", base) == -1)
395
driverConf[sizeof(driverConf)-1] = '\0';
397
if (virAsprintf(¨_driver->configDir, "%s/uml", base) == -1)
400
if (virAsprintf(¨_driver->autostartDir, "%s/uml/autostart", base) == -1)
405
if ((uml_driver->caps = umlCapsInit()) == NULL)
408
uml_driver->caps->privateDataAllocFunc = umlDomainObjPrivateAlloc;
409
uml_driver->caps->privateDataFreeFunc = umlDomainObjPrivateFree;
411
if ((uml_driver->inotifyFD = inotify_init()) < 0) {
412
VIR_ERROR0(_("cannot initialize inotify"));
416
if (virFileMakePath(uml_driver->monitorDir) != 0) {
418
VIR_ERROR(_("Failed to create monitor directory %s: %s"),
419
uml_driver->monitorDir, virStrerror(errno, ebuf, sizeof ebuf));
423
VIR_INFO("Adding inotify watch on %s", uml_driver->monitorDir);
424
if (inotify_add_watch(uml_driver->inotifyFD,
425
uml_driver->monitorDir,
426
IN_CREATE | IN_MODIFY | IN_DELETE) < 0) {
430
if ((uml_driver->inotifyWatch =
431
virEventAddHandle(uml_driver->inotifyFD, POLLIN,
432
umlInotifyEvent, uml_driver, NULL)) < 0)
435
if (virDomainLoadAllConfigs(uml_driver->caps,
436
¨_driver->domains,
437
uml_driver->configDir,
438
uml_driver->autostartDir,
442
umlAutostartConfigs(uml_driver);
444
umlDriverUnlock(uml_driver);
450
VIR_ERROR0(_("umlStartup: out of memory"));
455
umlDriverUnlock(uml_driver);
463
* Function to restart the Uml daemon, it will recheck the configuration
464
* files and update its state and the networking
471
umlDriverLock(uml_driver);
472
virDomainLoadAllConfigs(uml_driver->caps,
473
¨_driver->domains,
474
uml_driver->configDir,
475
uml_driver->autostartDir,
478
umlAutostartConfigs(uml_driver);
479
umlDriverUnlock(uml_driver);
487
* Checks if the Uml daemon is active, i.e. has an active domain or
490
* Returns 1 if active, 0 otherwise
499
umlDriverLock(uml_driver);
500
active = virDomainObjListNumOfDomains(¨_driver->domains, 1);
501
umlDriverUnlock(uml_driver);
507
umlShutdownOneVM(void *payload, const char *name ATTRIBUTE_UNUSED, void *opaque)
509
virDomainObjPtr dom = payload;
510
struct uml_driver *driver = opaque;
512
virDomainObjLock(dom);
513
if (virDomainObjIsActive(dom))
514
umlShutdownVMDaemon(NULL, driver, dom);
515
virDomainObjUnlock(dom);
521
* Shutdown the Uml daemon, it will stop all active domains and networks
528
umlDriverLock(uml_driver);
529
if (uml_driver->inotifyWatch != -1)
530
virEventRemoveHandle(uml_driver->inotifyWatch);
531
close(uml_driver->inotifyFD);
532
virCapabilitiesFree(uml_driver->caps);
534
/* shutdown active VMs
535
* XXX allow them to stay around & reconnect */
536
virHashForEach(uml_driver->domains.objs, umlShutdownOneVM, uml_driver);
538
virDomainObjListDeinit(¨_driver->domains);
540
VIR_FREE(uml_driver->logDir);
541
VIR_FREE(uml_driver->configDir);
542
VIR_FREE(uml_driver->autostartDir);
543
VIR_FREE(uml_driver->monitorDir);
545
if (uml_driver->brctl)
546
brShutdown(uml_driver->brctl);
548
umlDriverUnlock(uml_driver);
549
virMutexDestroy(¨_driver->lock);
550
VIR_FREE(uml_driver);
556
static int umlReadPidFile(struct uml_driver *driver,
561
char *pidfile = NULL;
565
if (virAsprintf(&pidfile, "%s/%s/pid",
566
driver->monitorDir, vm->def->name) < 0) {
572
if (!(file = fopen(pidfile, "r"))) {
573
if (errno == ENOENT &&
581
if (fscanf(file, "%d", &vm->pid) != 1) {
587
if (fclose(file) < 0)
594
virReportSystemError(errno,
595
_("failed to read pid: %s"),
601
static int umlMonitorAddress(const struct uml_driver *driver,
603
struct sockaddr_un *addr) {
607
if (virAsprintf(&sockname, "%s/%s/mconsole",
608
driver->monitorDir, vm->def->name) < 0) {
613
memset(addr, 0, sizeof *addr);
614
addr->sun_family = AF_UNIX;
615
if (virStrcpyStatic(addr->sun_path, sockname) == NULL) {
616
umlReportError(VIR_ERR_INTERNAL_ERROR,
617
_("Unix path %s too long for destination"), sockname);
624
static int umlOpenMonitor(struct uml_driver *driver,
625
virDomainObjPtr vm) {
626
struct sockaddr_un addr;
629
umlDomainObjPrivatePtr priv = vm->privateData;
631
if (umlMonitorAddress(driver, vm, &addr) < 0)
634
VIR_DEBUG("Dest address for monitor is '%s'", addr.sun_path);
636
if (stat(addr.sun_path, &sb) < 0) {
637
if (errno == ENOENT &&
645
if ((priv->monitor = socket(PF_UNIX, SOCK_DGRAM, 0)) < 0) {
646
virReportSystemError(errno,
647
"%s", _("cannot open socket"));
651
memset(addr.sun_path, 0, sizeof addr.sun_path);
652
sprintf(addr.sun_path + 1, "libvirt-uml-%u", vm->pid);
653
VIR_DEBUG("Reply address for monitor is '%s'", addr.sun_path+1);
654
if (bind(priv->monitor, (struct sockaddr *)&addr, sizeof addr) < 0) {
655
virReportSystemError(errno,
656
"%s", _("cannot bind socket"));
657
close(priv->monitor);
666
#define MONITOR_MAGIC 0xcafebabe
667
#define MONITOR_BUFLEN 512
668
#define MONITOR_VERSION 2
670
struct monitor_request {
674
char data[MONITOR_BUFLEN];
677
struct monitor_response {
681
char data[MONITOR_BUFLEN];
685
static int umlMonitorCommand(const struct uml_driver *driver,
686
const virDomainObjPtr vm,
690
struct monitor_request req;
691
struct monitor_response res;
692
char *retdata = NULL;
693
int retlen = 0, ret = 0;
694
struct sockaddr_un addr;
695
unsigned int addrlen;
696
umlDomainObjPrivatePtr priv = vm->privateData;
698
VIR_DEBUG("Run command '%s'", cmd);
702
if (umlMonitorAddress(driver, vm, &addr) < 0)
705
memset(&req, 0, sizeof(req));
706
req.magic = MONITOR_MAGIC;
707
req.version = MONITOR_VERSION;
708
req.length = strlen(cmd);
709
if (req.length > (MONITOR_BUFLEN-1)) {
710
virReportSystemError(EINVAL,
711
_("cannot send too long command %s (%d bytes)"),
715
if (virStrcpyStatic(req.data, cmd) == NULL) {
716
umlReportError(VIR_ERR_INTERNAL_ERROR,
717
_("Command %s too long for destination"), cmd);
721
if (sendto(priv->monitor, &req, sizeof req, 0,
722
(struct sockaddr *)&addr, sizeof addr) != (sizeof req)) {
723
virReportSystemError(errno,
724
_("cannot send command %s"),
731
addrlen = sizeof(addr);
732
nbytes = recvfrom(priv->monitor, &res, sizeof res, 0,
733
(struct sockaddr *)&addr, &addrlen);
735
if (errno == EAGAIN || errno == EINTR)
737
virReportSystemError(errno, _("cannot read reply %s"), cmd);
740
if (nbytes < sizeof res) {
741
virReportSystemError(0, _("incomplete reply %s"), cmd);
744
if (sizeof res.data < res.length) {
745
virReportSystemError(0, _("invalid length in reply %s"), cmd);
749
if (VIR_REALLOC_N(retdata, retlen + res.length) < 0) {
753
memcpy(retdata + retlen, res.data, res.length);
754
retlen += res.length - 1;
755
retdata[retlen] = '\0';
762
VIR_DEBUG("Command reply is '%s'", NULLSTR(retdata));
777
static int umlCleanupTapDevices(virConnectPtr conn ATTRIBUTE_UNUSED,
778
virDomainObjPtr vm) {
782
brControl *brctl = NULL;
783
VIR_ERROR0(_("Cleanup tap"));
784
if (brInit(&brctl) < 0)
787
for (i = 0 ; i < vm->def->nnets ; i++) {
788
virDomainNetDefPtr def = vm->def->nets[i];
790
if (def->type != VIR_DOMAIN_NET_TYPE_BRIDGE &&
791
def->type != VIR_DOMAIN_NET_TYPE_NETWORK)
794
VIR_ERROR(_("Cleanup '%s'"), def->ifname);
795
err = brDeleteTap(brctl, def->ifname);
797
VIR_ERROR(_("Cleanup failed %d"), err);
801
VIR_ERROR0(_("Cleanup tap done"));
806
static int umlStartVMDaemon(virConnectPtr conn,
807
struct uml_driver *driver,
808
virDomainObjPtr vm) {
809
const char **argv = NULL, **tmp;
810
const char **progenv = NULL;
818
umlDomainObjPrivatePtr priv = vm->privateData;
822
if (virDomainObjIsActive(vm)) {
823
umlReportError(VIR_ERR_INTERNAL_ERROR, "%s",
824
_("VM is already active"));
828
if (!vm->def->os.kernel) {
829
umlReportError(VIR_ERR_INTERNAL_ERROR, "%s",
830
_("no kernel specified"));
833
/* Make sure the binary we are about to try exec'ing exists.
834
* Technically we could catch the exec() failure, but that's
835
* in a sub-process so its hard to feed back a useful error
837
if (stat(vm->def->os.kernel, &sb) < 0) {
838
virReportSystemError(errno,
839
_("Cannot find UML kernel %s"),
844
if (virFileMakePath(driver->logDir) != 0) {
845
virReportSystemError(errno,
846
_("cannot create log directory %s"),
851
if (virAsprintf(&logfile, "%s/%s.log",
852
driver->logDir, vm->def->name) < 0) {
857
if ((logfd = open(logfile, O_CREAT | O_TRUNC | O_WRONLY,
858
S_IRUSR | S_IWUSR)) < 0) {
859
virReportSystemError(errno,
860
_("failed to create logfile %s"),
867
if (umlSetCloseExec(logfd) < 0) {
868
virReportSystemError(errno,
869
"%s", _("Unable to set VM logfile close-on-exec flag"));
874
if (umlBuildCommandLine(conn, driver, vm,
875
&argv, &progenv) < 0) {
877
umlCleanupTapDevices(conn, vm);
883
if (safewrite(logfd, *tmp, strlen(*tmp)) < 0)
884
VIR_WARN("Unable to write envv to logfile: %s",
885
virStrerror(errno, ebuf, sizeof ebuf));
886
if (safewrite(logfd, " ", 1) < 0)
887
VIR_WARN("Unable to write envv to logfile: %s",
888
virStrerror(errno, ebuf, sizeof ebuf));
893
if (safewrite(logfd, *tmp, strlen(*tmp)) < 0)
894
VIR_WARN("Unable to write argv to logfile: %s",
895
virStrerror(errno, ebuf, sizeof ebuf));
896
if (safewrite(logfd, " ", 1) < 0)
897
VIR_WARN("Unable to write argv to logfile: %s",
898
virStrerror(errno, ebuf, sizeof ebuf));
901
if (safewrite(logfd, "\n", 1) < 0)
902
VIR_WARN("Unable to write argv to logfile: %s",
903
virStrerror(errno, ebuf, sizeof ebuf));
907
ret = virExecDaemonize(argv, progenv, &keepfd, &pid,
913
for (i = 0 ; argv[i] ; i++)
917
for (i = 0 ; progenv[i] ; i++)
918
VIR_FREE(progenv[i]);
922
umlCleanupTapDevices(conn, vm);
924
/* NB we don't mark it running here - we do that async
926
/* XXX what if someone else tries to start it again
927
before we get the inotification ? Sounds like
933
static void umlShutdownVMDaemon(virConnectPtr conn ATTRIBUTE_UNUSED,
934
struct uml_driver *driver ATTRIBUTE_UNUSED,
938
umlDomainObjPrivatePtr priv = vm->privateData;
940
if (!virDomainObjIsActive(vm))
943
virKillProcess(vm->pid, SIGTERM);
945
if (priv->monitor != -1)
946
close(priv->monitor);
949
if ((ret = waitpid(vm->pid, NULL, 0)) != vm->pid) {
950
VIR_WARN("Got unexpected pid %d != %d",
956
vm->state = VIR_DOMAIN_SHUTOFF;
958
umlCleanupTapDevices(conn, vm);
961
virDomainDefFree(vm->def);
962
vm->def = vm->newDef;
969
static virDrvOpenStatus umlOpen(virConnectPtr conn,
970
virConnectAuthPtr auth ATTRIBUTE_UNUSED,
971
int flags ATTRIBUTE_UNUSED) {
972
if (conn->uri == NULL) {
973
if (uml_driver == NULL)
974
return VIR_DRV_OPEN_DECLINED;
976
conn->uri = xmlParseURI(uml_driver->privileged ?
981
return VIR_DRV_OPEN_ERROR;
984
if (conn->uri->scheme == NULL ||
985
STRNEQ (conn->uri->scheme, "uml"))
986
return VIR_DRV_OPEN_DECLINED;
988
/* Allow remote driver to deal with URIs with hostname server */
989
if (conn->uri->server != NULL)
990
return VIR_DRV_OPEN_DECLINED;
993
/* Check path and tell them correct path if they made a mistake */
994
if (uml_driver->privileged) {
995
if (STRNEQ (conn->uri->path, "/system") &&
996
STRNEQ (conn->uri->path, "/session")) {
997
umlReportError(VIR_ERR_INTERNAL_ERROR,
998
_("unexpected UML URI path '%s', try uml:///system"),
1000
return VIR_DRV_OPEN_ERROR;
1003
if (STRNEQ (conn->uri->path, "/session")) {
1004
umlReportError(VIR_ERR_INTERNAL_ERROR,
1005
_("unexpected UML URI path '%s', try uml:///session"),
1007
return VIR_DRV_OPEN_ERROR;
1011
/* URI was good, but driver isn't active */
1012
if (uml_driver == NULL) {
1013
umlReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1014
_("uml state driver is not active"));
1015
return VIR_DRV_OPEN_ERROR;
1019
conn->privateData = uml_driver;
1021
return VIR_DRV_OPEN_SUCCESS;
1024
static int umlClose(virConnectPtr conn) {
1025
/*struct uml_driver *driver = conn->privateData;*/
1027
conn->privateData = NULL;
1032
static const char *umlGetType(virConnectPtr conn ATTRIBUTE_UNUSED) {
1037
static int umlIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED)
1039
/* Trivially secure, since always inside the daemon */
1044
static int umlIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED)
1046
/* Not encrypted, but remote driver takes care of that */
1051
static char *umlGetCapabilities(virConnectPtr conn) {
1052
struct uml_driver *driver = (struct uml_driver *)conn->privateData;
1055
umlDriverLock(driver);
1056
if ((xml = virCapabilitiesFormatXML(driver->caps)) == NULL)
1057
virReportOOMError();
1058
umlDriverUnlock(driver);
1065
static int umlGetProcessInfo(unsigned long long *cpuTime, int pid) {
1066
char proc[PATH_MAX];
1068
unsigned long long usertime, systime;
1070
if (snprintf(proc, sizeof(proc), "/proc/%d/stat", pid) >= (int)sizeof(proc)) {
1074
if (!(pidinfo = fopen(proc, "r"))) {
1075
/*printf("cannot read pid info");*/
1076
/* VM probably shut down, so fake 0 */
1081
if (fscanf(pidinfo, "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %llu %llu", &usertime, &systime) != 2) {
1082
umlDebug("not enough arg");
1088
* We want nanoseconds
1089
* _SC_CLK_TCK is jiffies per second
1090
* So calulate thus....
1092
*cpuTime = 1000ull * 1000ull * 1000ull * (usertime + systime) / (unsigned long long)sysconf(_SC_CLK_TCK);
1094
umlDebug("Got %llu %llu %llu", usertime, systime, *cpuTime);
1102
static virDomainPtr umlDomainLookupByID(virConnectPtr conn,
1104
struct uml_driver *driver = (struct uml_driver *)conn->privateData;
1106
virDomainPtr dom = NULL;
1108
umlDriverLock(driver);
1109
vm = virDomainFindByID(&driver->domains, id);
1110
umlDriverUnlock(driver);
1113
umlReportError(VIR_ERR_NO_DOMAIN, NULL);
1117
dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
1118
if (dom) dom->id = vm->def->id;
1122
virDomainObjUnlock(vm);
1126
static virDomainPtr umlDomainLookupByUUID(virConnectPtr conn,
1127
const unsigned char *uuid) {
1128
struct uml_driver *driver = (struct uml_driver *)conn->privateData;
1130
virDomainPtr dom = NULL;
1132
umlDriverLock(driver);
1133
vm = virDomainFindByUUID(&driver->domains, uuid);
1134
umlDriverUnlock(driver);
1137
umlReportError(VIR_ERR_NO_DOMAIN, NULL);
1141
dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
1142
if (dom) dom->id = vm->def->id;
1146
virDomainObjUnlock(vm);
1150
static virDomainPtr umlDomainLookupByName(virConnectPtr conn,
1152
struct uml_driver *driver = (struct uml_driver *)conn->privateData;
1154
virDomainPtr dom = NULL;
1156
umlDriverLock(driver);
1157
vm = virDomainFindByName(&driver->domains, name);
1158
umlDriverUnlock(driver);
1161
umlReportError(VIR_ERR_NO_DOMAIN, NULL);
1165
dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
1166
if (dom) dom->id = vm->def->id;
1170
virDomainObjUnlock(vm);
1175
static int umlDomainIsActive(virDomainPtr dom)
1177
struct uml_driver *driver = dom->conn->privateData;
1178
virDomainObjPtr obj;
1181
umlDriverLock(driver);
1182
obj = virDomainFindByUUID(&driver->domains, dom->uuid);
1183
umlDriverUnlock(driver);
1185
umlReportError(VIR_ERR_NO_DOMAIN, NULL);
1188
ret = virDomainObjIsActive(obj);
1192
virDomainObjUnlock(obj);
1197
static int umlDomainIsPersistent(virDomainPtr dom)
1199
struct uml_driver *driver = dom->conn->privateData;
1200
virDomainObjPtr obj;
1203
umlDriverLock(driver);
1204
obj = virDomainFindByUUID(&driver->domains, dom->uuid);
1205
umlDriverUnlock(driver);
1207
umlReportError(VIR_ERR_NO_DOMAIN, NULL);
1210
ret = obj->persistent;
1214
virDomainObjUnlock(obj);
1219
static int umlGetVersion(virConnectPtr conn, unsigned long *version) {
1220
struct uml_driver *driver = conn->privateData;
1224
umlDriverLock(driver);
1226
if (driver->umlVersion == 0) {
1229
if (virParseVersionString(ut.release, &driver->umlVersion) < 0) {
1230
umlReportError(VIR_ERR_INTERNAL_ERROR,
1231
_("cannot parse version %s"), ut.release);
1236
*version = driver->umlVersion;
1240
umlDriverUnlock(driver);
1244
static int umlListDomains(virConnectPtr conn, int *ids, int nids) {
1245
struct uml_driver *driver = conn->privateData;
1248
umlDriverLock(driver);
1249
n = virDomainObjListGetActiveIDs(&driver->domains, ids, nids);
1250
umlDriverUnlock(driver);
1254
static int umlNumDomains(virConnectPtr conn) {
1255
struct uml_driver *driver = conn->privateData;
1258
umlDriverLock(driver);
1259
n = virDomainObjListNumOfDomains(&driver->domains, 1);
1260
umlDriverUnlock(driver);
1264
static virDomainPtr umlDomainCreate(virConnectPtr conn, const char *xml,
1265
unsigned int flags) {
1266
struct uml_driver *driver = conn->privateData;
1267
virDomainDefPtr def;
1268
virDomainObjPtr vm = NULL;
1269
virDomainPtr dom = NULL;
1271
virCheckFlags(0, NULL);
1273
umlDriverLock(driver);
1274
if (!(def = virDomainDefParseString(driver->caps, xml,
1275
VIR_DOMAIN_XML_INACTIVE)))
1278
if (virDomainObjIsDuplicate(&driver->domains, def, 1) < 0)
1281
if (!(vm = virDomainAssignDef(driver->caps,
1287
if (umlStartVMDaemon(conn, driver, vm) < 0) {
1288
virDomainRemoveInactive(&driver->domains,
1294
dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
1295
if (dom) dom->id = vm->def->id;
1298
virDomainDefFree(def);
1300
virDomainObjUnlock(vm);
1301
umlDriverUnlock(driver);
1306
static int umlDomainShutdown(virDomainPtr dom) {
1307
struct uml_driver *driver = dom->conn->privateData;
1312
umlDriverLock(driver);
1313
vm = virDomainFindByID(&driver->domains, dom->id);
1314
umlDriverUnlock(driver);
1316
umlReportError(VIR_ERR_INVALID_DOMAIN,
1317
_("no domain with matching id %d"), dom->id);
1322
if (umlMonitorCommand(driver, vm, "system_powerdown", &info) < 0) {
1323
umlReportError(VIR_ERR_OPERATION_FAILED, "%s",
1324
_("shutdown operation failed"));
1333
virDomainObjUnlock(vm);
1338
static int umlDomainDestroy(virDomainPtr dom) {
1339
struct uml_driver *driver = dom->conn->privateData;
1343
umlDriverLock(driver);
1344
vm = virDomainFindByID(&driver->domains, dom->id);
1346
umlReportError(VIR_ERR_INVALID_DOMAIN,
1347
_("no domain with matching id %d"), dom->id);
1351
umlShutdownVMDaemon(dom->conn, driver, vm);
1352
if (!vm->persistent) {
1353
virDomainRemoveInactive(&driver->domains,
1361
virDomainObjUnlock(vm);
1362
umlDriverUnlock(driver);
1367
static char *umlDomainGetOSType(virDomainPtr dom) {
1368
struct uml_driver *driver = dom->conn->privateData;
1372
umlDriverLock(driver);
1373
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1374
umlDriverUnlock(driver);
1376
umlReportError(VIR_ERR_INVALID_DOMAIN, "%s",
1377
_("no domain with matching uuid"));
1381
if (!(type = strdup(vm->def->os.type)))
1382
virReportOOMError();
1386
virDomainObjUnlock(vm);
1390
/* Returns max memory in kb, 0 if error */
1391
static unsigned long umlDomainGetMaxMemory(virDomainPtr dom) {
1392
struct uml_driver *driver = dom->conn->privateData;
1394
unsigned long ret = 0;
1396
umlDriverLock(driver);
1397
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1398
umlDriverUnlock(driver);
1401
char uuidstr[VIR_UUID_STRING_BUFLEN];
1403
virUUIDFormat(dom->uuid, uuidstr);
1404
umlReportError(VIR_ERR_INVALID_DOMAIN,
1405
_("no domain with matching uuid '%s'"), uuidstr);
1408
ret = vm->def->maxmem;
1412
virDomainObjUnlock(vm);
1416
static int umlDomainSetMaxMemory(virDomainPtr dom, unsigned long newmax) {
1417
struct uml_driver *driver = dom->conn->privateData;
1421
umlDriverLock(driver);
1422
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1423
umlDriverUnlock(driver);
1426
char uuidstr[VIR_UUID_STRING_BUFLEN];
1428
virUUIDFormat(dom->uuid, uuidstr);
1429
umlReportError(VIR_ERR_INVALID_DOMAIN,
1430
_("no domain with matching uuid '%s'"), uuidstr);
1434
if (newmax < vm->def->memory) {
1435
umlReportError(VIR_ERR_INVALID_ARG, "%s",
1436
_("cannot set max memory lower than current memory"));
1440
vm->def->maxmem = newmax;
1445
virDomainObjUnlock(vm);
1449
static int umlDomainSetMemory(virDomainPtr dom, unsigned long newmem) {
1450
struct uml_driver *driver = dom->conn->privateData;
1454
umlDriverLock(driver);
1455
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1456
umlDriverUnlock(driver);
1459
char uuidstr[VIR_UUID_STRING_BUFLEN];
1461
virUUIDFormat(dom->uuid, uuidstr);
1462
umlReportError(VIR_ERR_INVALID_DOMAIN,
1463
_("no domain with matching uuid '%s'"), uuidstr);
1467
if (virDomainObjIsActive(vm)) {
1468
umlReportError(VIR_ERR_NO_SUPPORT, "%s",
1469
_("cannot set memory of an active domain"));
1473
if (newmem > vm->def->maxmem) {
1474
umlReportError(VIR_ERR_INVALID_ARG, "%s",
1475
_("cannot set memory higher than max memory"));
1479
vm->def->memory = newmem;
1484
virDomainObjUnlock(vm);
1488
static int umlDomainGetInfo(virDomainPtr dom,
1489
virDomainInfoPtr info) {
1490
struct uml_driver *driver = dom->conn->privateData;
1494
umlDriverLock(driver);
1495
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1496
umlDriverUnlock(driver);
1499
umlReportError(VIR_ERR_INVALID_DOMAIN, "%s",
1500
_("no domain with matching uuid"));
1504
info->state = vm->state;
1506
if (!virDomainObjIsActive(vm)) {
1509
if (umlGetProcessInfo(&(info->cpuTime), vm->pid) < 0) {
1510
umlReportError(VIR_ERR_OPERATION_FAILED, "%s",
1511
_("cannot read cputime for domain"));
1516
info->maxMem = vm->def->maxmem;
1517
info->memory = vm->def->memory;
1518
info->nrVirtCpu = vm->def->vcpus;
1523
virDomainObjUnlock(vm);
1528
static char *umlDomainDumpXML(virDomainPtr dom,
1529
int flags ATTRIBUTE_UNUSED) {
1530
struct uml_driver *driver = dom->conn->privateData;
1534
umlDriverLock(driver);
1535
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1536
umlDriverUnlock(driver);
1539
umlReportError(VIR_ERR_INVALID_DOMAIN, "%s",
1540
_("no domain with matching uuid"));
1544
ret = virDomainDefFormat((flags & VIR_DOMAIN_XML_INACTIVE) && vm->newDef ?
1545
vm->newDef : vm->def,
1550
virDomainObjUnlock(vm);
1555
static int umlListDefinedDomains(virConnectPtr conn,
1556
char **const names, int nnames) {
1557
struct uml_driver *driver = conn->privateData;
1560
umlDriverLock(driver);
1561
n = virDomainObjListGetInactiveNames(&driver->domains, names, nnames);
1562
umlDriverUnlock(driver);
1567
static int umlNumDefinedDomains(virConnectPtr conn) {
1568
struct uml_driver *driver = conn->privateData;
1571
umlDriverLock(driver);
1572
n = virDomainObjListNumOfDomains(&driver->domains, 0);
1573
umlDriverUnlock(driver);
1579
static int umlDomainStartWithFlags(virDomainPtr dom, unsigned int flags) {
1580
struct uml_driver *driver = dom->conn->privateData;
1584
virCheckFlags(0, -1);
1586
umlDriverLock(driver);
1587
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1590
umlReportError(VIR_ERR_INVALID_DOMAIN, "%s",
1591
_("no domain with matching uuid"));
1595
ret = umlStartVMDaemon(dom->conn, driver, vm);
1599
virDomainObjUnlock(vm);
1600
umlDriverUnlock(driver);
1604
static int umlDomainStart(virDomainPtr dom) {
1605
return umlDomainStartWithFlags(dom, 0);
1608
static virDomainPtr umlDomainDefine(virConnectPtr conn, const char *xml) {
1609
struct uml_driver *driver = conn->privateData;
1610
virDomainDefPtr def;
1611
virDomainObjPtr vm = NULL;
1612
virDomainPtr dom = NULL;
1614
umlDriverLock(driver);
1615
if (!(def = virDomainDefParseString(driver->caps, xml,
1616
VIR_DOMAIN_XML_INACTIVE)))
1619
if (virDomainObjIsDuplicate(&driver->domains, def, 0) < 0)
1622
if (!(vm = virDomainAssignDef(driver->caps,
1629
if (virDomainSaveConfig(driver->configDir,
1630
vm->newDef ? vm->newDef : vm->def) < 0) {
1631
virDomainRemoveInactive(&driver->domains,
1637
dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
1638
if (dom) dom->id = vm->def->id;
1641
virDomainDefFree(def);
1643
virDomainObjUnlock(vm);
1644
umlDriverUnlock(driver);
1648
static int umlDomainUndefine(virDomainPtr dom) {
1649
struct uml_driver *driver = dom->conn->privateData;
1653
umlDriverLock(driver);
1654
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1656
umlReportError(VIR_ERR_INVALID_DOMAIN, "%s",
1657
_("no domain with matching uuid"));
1661
if (virDomainObjIsActive(vm)) {
1662
umlReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1663
_("cannot delete active domain"));
1667
if (!vm->persistent) {
1668
umlReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1669
_("cannot undefine transient domain"));
1673
if (virDomainDeleteConfig(driver->configDir, driver->autostartDir, vm) < 0)
1676
virDomainRemoveInactive(&driver->domains,
1683
virDomainObjUnlock(vm);
1684
umlDriverUnlock(driver);
1690
static int umlDomainGetAutostart(virDomainPtr dom,
1692
struct uml_driver *driver = dom->conn->privateData;
1696
umlDriverLock(driver);
1697
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1700
umlReportError(VIR_ERR_INVALID_DOMAIN, "%s",
1701
_("no domain with matching uuid"));
1705
*autostart = vm->autostart;
1710
virDomainObjUnlock(vm);
1711
umlDriverUnlock(driver);
1715
static int umlDomainSetAutostart(virDomainPtr dom,
1717
struct uml_driver *driver = dom->conn->privateData;
1719
char *configFile = NULL, *autostartLink = NULL;
1722
umlDriverLock(driver);
1723
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1726
umlReportError(VIR_ERR_INVALID_DOMAIN, "%s",
1727
_("no domain with matching uuid"));
1731
if (!vm->persistent) {
1732
umlReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1733
_("cannot set autostart for transient domain"));
1737
autostart = (autostart != 0);
1739
if (vm->autostart != autostart) {
1740
if ((configFile = virDomainConfigFile(driver->configDir, vm->def->name)) == NULL)
1742
if ((autostartLink = virDomainConfigFile(driver->autostartDir, vm->def->name)) == NULL)
1748
if ((err = virFileMakePath(driver->autostartDir))) {
1749
virReportSystemError(err,
1750
_("cannot create autostart directory %s"),
1751
driver->autostartDir);
1755
if (symlink(configFile, autostartLink) < 0) {
1756
virReportSystemError(errno,
1757
_("Failed to create symlink '%s to '%s'"),
1758
autostartLink, configFile);
1762
if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
1763
virReportSystemError(errno,
1764
_("Failed to delete symlink '%s'"),
1770
vm->autostart = autostart;
1775
VIR_FREE(configFile);
1776
VIR_FREE(autostartLink);
1778
virDomainObjUnlock(vm);
1779
umlDriverUnlock(driver);
1785
umlDomainBlockPeek (virDomainPtr dom,
1787
unsigned long long offset, size_t size,
1789
unsigned int flags ATTRIBUTE_UNUSED)
1791
struct uml_driver *driver = dom->conn->privateData;
1793
int fd = -1, ret = -1, i;
1795
umlDriverLock(driver);
1796
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1797
umlDriverUnlock(driver);
1800
umlReportError(VIR_ERR_INVALID_DOMAIN, "%s",
1801
_("no domain with matching uuid"));
1805
if (!path || path[0] == '\0') {
1806
umlReportError(VIR_ERR_INVALID_ARG, "%s",
1807
_("NULL or empty path"));
1811
/* Check the path belongs to this domain. */
1812
for (i = 0 ; i < vm->def->ndisks ; i++) {
1813
if (vm->def->disks[i]->src != NULL &&
1814
STREQ (vm->def->disks[i]->src, path)) {
1822
/* The path is correct, now try to open it and get its size. */
1823
fd = open (path, O_RDONLY);
1825
virReportSystemError(errno,
1826
_("cannot open %s"), path);
1830
/* Seek and read. */
1831
/* NB. Because we configure with AC_SYS_LARGEFILE, off_t should
1832
* be 64 bits on all platforms.
1834
if (lseek (fd, offset, SEEK_SET) == (off_t) -1 ||
1835
saferead (fd, buffer, size) == (ssize_t) -1) {
1836
virReportSystemError(errno,
1837
_("cannot read %s"), path);
1843
umlReportError(VIR_ERR_INVALID_ARG, "%s",
1848
if (fd >= 0) close (fd);
1850
virDomainObjUnlock(vm);
1856
static virDriver umlDriver = {
1860
umlClose, /* close */
1861
NULL, /* supports_feature */
1862
umlGetType, /* type */
1863
umlGetVersion, /* version */
1864
NULL, /* libvirtVersion (impl. in libvirt.c) */
1865
virGetHostname, /* getHostname */
1866
NULL, /* getMaxVcpus */
1867
nodeGetInfo, /* nodeGetInfo */
1868
umlGetCapabilities, /* getCapabilities */
1869
umlListDomains, /* listDomains */
1870
umlNumDomains, /* numOfDomains */
1871
umlDomainCreate, /* domainCreateXML */
1872
umlDomainLookupByID, /* domainLookupByID */
1873
umlDomainLookupByUUID, /* domainLookupByUUID */
1874
umlDomainLookupByName, /* domainLookupByName */
1875
NULL, /* domainSuspend */
1876
NULL, /* domainResume */
1877
umlDomainShutdown, /* domainShutdown */
1878
NULL, /* domainReboot */
1879
umlDomainDestroy, /* domainDestroy */
1880
umlDomainGetOSType, /* domainGetOSType */
1881
umlDomainGetMaxMemory, /* domainGetMaxMemory */
1882
umlDomainSetMaxMemory, /* domainSetMaxMemory */
1883
umlDomainSetMemory, /* domainSetMemory */
1884
umlDomainGetInfo, /* domainGetInfo */
1885
NULL, /* domainSave */
1886
NULL, /* domainRestore */
1887
NULL, /* domainCoreDump */
1888
NULL, /* domainSetVcpus */
1889
NULL, /* domainPinVcpu */
1890
NULL, /* domainGetVcpus */
1891
NULL, /* domainGetMaxVcpus */
1892
NULL, /* domainGetSecurityLabel */
1893
NULL, /* nodeGetSecurityModel */
1894
umlDomainDumpXML, /* domainDumpXML */
1895
NULL, /* domainXMLFromNative */
1896
NULL, /* domainXMLToNative */
1897
umlListDefinedDomains, /* listDefinedDomains */
1898
umlNumDefinedDomains, /* numOfDefinedDomains */
1899
umlDomainStart, /* domainCreate */
1900
umlDomainStartWithFlags, /* domainCreateWithFlags */
1901
umlDomainDefine, /* domainDefineXML */
1902
umlDomainUndefine, /* domainUndefine */
1903
NULL, /* domainAttachDevice */
1904
NULL, /* domainAttachDeviceFlags */
1905
NULL, /* domainDetachDevice */
1906
NULL, /* domainDetachDeviceFlags */
1907
NULL, /* domainUpdateDeviceFlags */
1908
umlDomainGetAutostart, /* domainGetAutostart */
1909
umlDomainSetAutostart, /* domainSetAutostart */
1910
NULL, /* domainGetSchedulerType */
1911
NULL, /* domainGetSchedulerParameters */
1912
NULL, /* domainSetSchedulerParameters */
1913
NULL, /* domainMigratePrepare */
1914
NULL, /* domainMigratePerform */
1915
NULL, /* domainMigrateFinish */
1916
NULL, /* domainBlockStats */
1917
NULL, /* domainInterfaceStats */
1918
NULL, /* domainMemoryStats */
1919
umlDomainBlockPeek, /* domainBlockPeek */
1920
NULL, /* domainMemoryPeek */
1921
NULL, /* domainGetBlockInfo */
1922
nodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */
1923
nodeGetFreeMemory, /* getFreeMemory */
1924
NULL, /* domainEventRegister */
1925
NULL, /* domainEventDeregister */
1926
NULL, /* domainMigratePrepare2 */
1927
NULL, /* domainMigrateFinish2 */
1928
NULL, /* nodeDeviceDettach */
1929
NULL, /* nodeDeviceReAttach */
1930
NULL, /* nodeDeviceReset */
1931
NULL, /* domainMigratePrepareTunnel */
1932
umlIsEncrypted, /* isEncrypted */
1933
umlIsSecure, /* isSecure */
1934
umlDomainIsActive, /* domainIsActive */
1935
umlDomainIsPersistent, /* domainIsPersistent */
1936
NULL, /* cpuCompare */
1937
NULL, /* cpuBaseline */
1938
NULL, /* domainGetJobInfo */
1939
NULL, /* domainAbortJob */
1940
NULL, /* domainMigrateSetMaxDowntime */
1941
NULL, /* domainEventRegisterAny */
1942
NULL, /* domainEventDeregisterAny */
1943
NULL, /* domainManagedSave */
1944
NULL, /* domainHasManagedSaveImage */
1945
NULL, /* domainManagedSaveRemove */
1946
NULL, /* domainSnapshotCreateXML */
1947
NULL, /* domainSnapshotDumpXML */
1948
NULL, /* domainSnapshotNum */
1949
NULL, /* domainSnapshotListNames */
1950
NULL, /* domainSnapshotLookupByName */
1951
NULL, /* domainHasCurrentSnapshot */
1952
NULL, /* domainSnapshotCurrent */
1953
NULL, /* domainRevertToSnapshot */
1954
NULL, /* domainSnapshotDelete */
1955
NULL, /* qemuDomainMonitorCommand */
1959
static virStateDriver umlStateDriver = {
1961
.initialize = umlStartup,
1962
.cleanup = umlShutdown,
1963
.reload = umlReload,
1964
.active = umlActive,
1967
int umlRegister(void) {
1968
virRegisterDriver(¨Driver);
1969
virRegisterStateDriver(¨StateDriver);