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
/* Ensure res.length is safe to read before validating its value. */
741
if (nbytes < offsetof(struct monitor_request, data) ||
742
nbytes < offsetof(struct monitor_request, data) + res.length) {
743
virReportSystemError(0, _("incomplete reply %s"), cmd);
747
if (VIR_REALLOC_N(retdata, retlen + res.length) < 0) {
751
memcpy(retdata + retlen, res.data, res.length);
752
retlen += res.length - 1;
753
retdata[retlen] = '\0';
760
VIR_DEBUG("Command reply is '%s'", NULLSTR(retdata));
775
static int umlCleanupTapDevices(virConnectPtr conn ATTRIBUTE_UNUSED,
776
virDomainObjPtr vm) {
780
brControl *brctl = NULL;
781
VIR_ERROR0(_("Cleanup tap"));
782
if (brInit(&brctl) < 0)
785
for (i = 0 ; i < vm->def->nnets ; i++) {
786
virDomainNetDefPtr def = vm->def->nets[i];
788
if (def->type != VIR_DOMAIN_NET_TYPE_BRIDGE &&
789
def->type != VIR_DOMAIN_NET_TYPE_NETWORK)
792
VIR_ERROR(_("Cleanup '%s'"), def->ifname);
793
err = brDeleteTap(brctl, def->ifname);
795
VIR_ERROR(_("Cleanup failed %d"), err);
799
VIR_ERROR0(_("Cleanup tap done"));
804
static int umlStartVMDaemon(virConnectPtr conn,
805
struct uml_driver *driver,
806
virDomainObjPtr vm) {
807
const char **argv = NULL, **tmp;
808
const char **progenv = NULL;
816
umlDomainObjPrivatePtr priv = vm->privateData;
820
if (virDomainObjIsActive(vm)) {
821
umlReportError(VIR_ERR_INTERNAL_ERROR, "%s",
822
_("VM is already active"));
826
if (!vm->def->os.kernel) {
827
umlReportError(VIR_ERR_INTERNAL_ERROR, "%s",
828
_("no kernel specified"));
831
/* Make sure the binary we are about to try exec'ing exists.
832
* Technically we could catch the exec() failure, but that's
833
* in a sub-process so its hard to feed back a useful error
835
if (stat(vm->def->os.kernel, &sb) < 0) {
836
virReportSystemError(errno,
837
_("Cannot find UML kernel %s"),
842
if (virFileMakePath(driver->logDir) != 0) {
843
virReportSystemError(errno,
844
_("cannot create log directory %s"),
849
if (virAsprintf(&logfile, "%s/%s.log",
850
driver->logDir, vm->def->name) < 0) {
855
if ((logfd = open(logfile, O_CREAT | O_TRUNC | O_WRONLY,
856
S_IRUSR | S_IWUSR)) < 0) {
857
virReportSystemError(errno,
858
_("failed to create logfile %s"),
865
if (umlSetCloseExec(logfd) < 0) {
866
virReportSystemError(errno,
867
"%s", _("Unable to set VM logfile close-on-exec flag"));
872
if (umlBuildCommandLine(conn, driver, vm,
873
&argv, &progenv) < 0) {
875
umlCleanupTapDevices(conn, vm);
881
if (safewrite(logfd, *tmp, strlen(*tmp)) < 0)
882
VIR_WARN("Unable to write envv to logfile: %s",
883
virStrerror(errno, ebuf, sizeof ebuf));
884
if (safewrite(logfd, " ", 1) < 0)
885
VIR_WARN("Unable to write envv to logfile: %s",
886
virStrerror(errno, ebuf, sizeof ebuf));
891
if (safewrite(logfd, *tmp, strlen(*tmp)) < 0)
892
VIR_WARN("Unable to write argv to logfile: %s",
893
virStrerror(errno, ebuf, sizeof ebuf));
894
if (safewrite(logfd, " ", 1) < 0)
895
VIR_WARN("Unable to write argv to logfile: %s",
896
virStrerror(errno, ebuf, sizeof ebuf));
899
if (safewrite(logfd, "\n", 1) < 0)
900
VIR_WARN("Unable to write argv to logfile: %s",
901
virStrerror(errno, ebuf, sizeof ebuf));
905
ret = virExecDaemonize(argv, progenv, &keepfd, &pid,
911
for (i = 0 ; argv[i] ; i++)
915
for (i = 0 ; progenv[i] ; i++)
916
VIR_FREE(progenv[i]);
920
umlCleanupTapDevices(conn, vm);
922
/* NB we don't mark it running here - we do that async
924
/* XXX what if someone else tries to start it again
925
before we get the inotification ? Sounds like
931
static void umlShutdownVMDaemon(virConnectPtr conn ATTRIBUTE_UNUSED,
932
struct uml_driver *driver ATTRIBUTE_UNUSED,
936
umlDomainObjPrivatePtr priv = vm->privateData;
938
if (!virDomainObjIsActive(vm))
941
virKillProcess(vm->pid, SIGTERM);
943
if (priv->monitor != -1)
944
close(priv->monitor);
947
if ((ret = waitpid(vm->pid, NULL, 0)) != vm->pid) {
948
VIR_WARN("Got unexpected pid %d != %d",
954
vm->state = VIR_DOMAIN_SHUTOFF;
956
umlCleanupTapDevices(conn, vm);
959
virDomainDefFree(vm->def);
960
vm->def = vm->newDef;
967
static virDrvOpenStatus umlOpen(virConnectPtr conn,
968
virConnectAuthPtr auth ATTRIBUTE_UNUSED,
969
int flags ATTRIBUTE_UNUSED) {
970
if (conn->uri == NULL) {
971
if (uml_driver == NULL)
972
return VIR_DRV_OPEN_DECLINED;
974
conn->uri = xmlParseURI(uml_driver->privileged ?
979
return VIR_DRV_OPEN_ERROR;
982
if (conn->uri->scheme == NULL ||
983
STRNEQ (conn->uri->scheme, "uml"))
984
return VIR_DRV_OPEN_DECLINED;
986
/* Allow remote driver to deal with URIs with hostname server */
987
if (conn->uri->server != NULL)
988
return VIR_DRV_OPEN_DECLINED;
991
/* Check path and tell them correct path if they made a mistake */
992
if (uml_driver->privileged) {
993
if (STRNEQ (conn->uri->path, "/system") &&
994
STRNEQ (conn->uri->path, "/session")) {
995
umlReportError(VIR_ERR_INTERNAL_ERROR,
996
_("unexpected UML URI path '%s', try uml:///system"),
998
return VIR_DRV_OPEN_ERROR;
1001
if (STRNEQ (conn->uri->path, "/session")) {
1002
umlReportError(VIR_ERR_INTERNAL_ERROR,
1003
_("unexpected UML URI path '%s', try uml:///session"),
1005
return VIR_DRV_OPEN_ERROR;
1009
/* URI was good, but driver isn't active */
1010
if (uml_driver == NULL) {
1011
umlReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1012
_("uml state driver is not active"));
1013
return VIR_DRV_OPEN_ERROR;
1017
conn->privateData = uml_driver;
1019
return VIR_DRV_OPEN_SUCCESS;
1022
static int umlClose(virConnectPtr conn) {
1023
/*struct uml_driver *driver = conn->privateData;*/
1025
conn->privateData = NULL;
1030
static const char *umlGetType(virConnectPtr conn ATTRIBUTE_UNUSED) {
1035
static int umlIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED)
1037
/* Trivially secure, since always inside the daemon */
1042
static int umlIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED)
1044
/* Not encrypted, but remote driver takes care of that */
1049
static char *umlGetCapabilities(virConnectPtr conn) {
1050
struct uml_driver *driver = (struct uml_driver *)conn->privateData;
1053
umlDriverLock(driver);
1054
if ((xml = virCapabilitiesFormatXML(driver->caps)) == NULL)
1055
virReportOOMError();
1056
umlDriverUnlock(driver);
1063
static int umlGetProcessInfo(unsigned long long *cpuTime, int pid) {
1064
char proc[PATH_MAX];
1066
unsigned long long usertime, systime;
1068
if (snprintf(proc, sizeof(proc), "/proc/%d/stat", pid) >= (int)sizeof(proc)) {
1072
if (!(pidinfo = fopen(proc, "r"))) {
1073
/*printf("cannot read pid info");*/
1074
/* VM probably shut down, so fake 0 */
1079
if (fscanf(pidinfo, "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %llu %llu", &usertime, &systime) != 2) {
1080
umlDebug("not enough arg");
1086
* We want nanoseconds
1087
* _SC_CLK_TCK is jiffies per second
1088
* So calulate thus....
1090
*cpuTime = 1000ull * 1000ull * 1000ull * (usertime + systime) / (unsigned long long)sysconf(_SC_CLK_TCK);
1092
umlDebug("Got %llu %llu %llu", usertime, systime, *cpuTime);
1100
static virDomainPtr umlDomainLookupByID(virConnectPtr conn,
1102
struct uml_driver *driver = (struct uml_driver *)conn->privateData;
1104
virDomainPtr dom = NULL;
1106
umlDriverLock(driver);
1107
vm = virDomainFindByID(&driver->domains, id);
1108
umlDriverUnlock(driver);
1111
umlReportError(VIR_ERR_NO_DOMAIN, NULL);
1115
dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
1116
if (dom) dom->id = vm->def->id;
1120
virDomainObjUnlock(vm);
1124
static virDomainPtr umlDomainLookupByUUID(virConnectPtr conn,
1125
const unsigned char *uuid) {
1126
struct uml_driver *driver = (struct uml_driver *)conn->privateData;
1128
virDomainPtr dom = NULL;
1130
umlDriverLock(driver);
1131
vm = virDomainFindByUUID(&driver->domains, uuid);
1132
umlDriverUnlock(driver);
1135
umlReportError(VIR_ERR_NO_DOMAIN, NULL);
1139
dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
1140
if (dom) dom->id = vm->def->id;
1144
virDomainObjUnlock(vm);
1148
static virDomainPtr umlDomainLookupByName(virConnectPtr conn,
1150
struct uml_driver *driver = (struct uml_driver *)conn->privateData;
1152
virDomainPtr dom = NULL;
1154
umlDriverLock(driver);
1155
vm = virDomainFindByName(&driver->domains, name);
1156
umlDriverUnlock(driver);
1159
umlReportError(VIR_ERR_NO_DOMAIN, NULL);
1163
dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
1164
if (dom) dom->id = vm->def->id;
1168
virDomainObjUnlock(vm);
1173
static int umlDomainIsActive(virDomainPtr dom)
1175
struct uml_driver *driver = dom->conn->privateData;
1176
virDomainObjPtr obj;
1179
umlDriverLock(driver);
1180
obj = virDomainFindByUUID(&driver->domains, dom->uuid);
1181
umlDriverUnlock(driver);
1183
umlReportError(VIR_ERR_NO_DOMAIN, NULL);
1186
ret = virDomainObjIsActive(obj);
1190
virDomainObjUnlock(obj);
1195
static int umlDomainIsPersistent(virDomainPtr dom)
1197
struct uml_driver *driver = dom->conn->privateData;
1198
virDomainObjPtr obj;
1201
umlDriverLock(driver);
1202
obj = virDomainFindByUUID(&driver->domains, dom->uuid);
1203
umlDriverUnlock(driver);
1205
umlReportError(VIR_ERR_NO_DOMAIN, NULL);
1208
ret = obj->persistent;
1212
virDomainObjUnlock(obj);
1217
static int umlGetVersion(virConnectPtr conn, unsigned long *version) {
1218
struct uml_driver *driver = conn->privateData;
1222
umlDriverLock(driver);
1224
if (driver->umlVersion == 0) {
1227
if (virParseVersionString(ut.release, &driver->umlVersion) < 0) {
1228
umlReportError(VIR_ERR_INTERNAL_ERROR,
1229
_("cannot parse version %s"), ut.release);
1234
*version = driver->umlVersion;
1238
umlDriverUnlock(driver);
1242
static int umlListDomains(virConnectPtr conn, int *ids, int nids) {
1243
struct uml_driver *driver = conn->privateData;
1246
umlDriverLock(driver);
1247
n = virDomainObjListGetActiveIDs(&driver->domains, ids, nids);
1248
umlDriverUnlock(driver);
1252
static int umlNumDomains(virConnectPtr conn) {
1253
struct uml_driver *driver = conn->privateData;
1256
umlDriverLock(driver);
1257
n = virDomainObjListNumOfDomains(&driver->domains, 1);
1258
umlDriverUnlock(driver);
1262
static virDomainPtr umlDomainCreate(virConnectPtr conn, const char *xml,
1263
unsigned int flags) {
1264
struct uml_driver *driver = conn->privateData;
1265
virDomainDefPtr def;
1266
virDomainObjPtr vm = NULL;
1267
virDomainPtr dom = NULL;
1269
virCheckFlags(0, NULL);
1271
umlDriverLock(driver);
1272
if (!(def = virDomainDefParseString(driver->caps, xml,
1273
VIR_DOMAIN_XML_INACTIVE)))
1276
if (virDomainObjIsDuplicate(&driver->domains, def, 1) < 0)
1279
if (!(vm = virDomainAssignDef(driver->caps,
1285
if (umlStartVMDaemon(conn, driver, vm) < 0) {
1286
virDomainRemoveInactive(&driver->domains,
1292
dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
1293
if (dom) dom->id = vm->def->id;
1296
virDomainDefFree(def);
1298
virDomainObjUnlock(vm);
1299
umlDriverUnlock(driver);
1304
static int umlDomainShutdown(virDomainPtr dom) {
1305
struct uml_driver *driver = dom->conn->privateData;
1310
umlDriverLock(driver);
1311
vm = virDomainFindByID(&driver->domains, dom->id);
1312
umlDriverUnlock(driver);
1314
umlReportError(VIR_ERR_INVALID_DOMAIN,
1315
_("no domain with matching id %d"), dom->id);
1320
if (umlMonitorCommand(driver, vm, "system_powerdown", &info) < 0) {
1321
umlReportError(VIR_ERR_OPERATION_FAILED, "%s",
1322
_("shutdown operation failed"));
1331
virDomainObjUnlock(vm);
1336
static int umlDomainDestroy(virDomainPtr dom) {
1337
struct uml_driver *driver = dom->conn->privateData;
1341
umlDriverLock(driver);
1342
vm = virDomainFindByID(&driver->domains, dom->id);
1344
umlReportError(VIR_ERR_INVALID_DOMAIN,
1345
_("no domain with matching id %d"), dom->id);
1349
umlShutdownVMDaemon(dom->conn, driver, vm);
1350
if (!vm->persistent) {
1351
virDomainRemoveInactive(&driver->domains,
1359
virDomainObjUnlock(vm);
1360
umlDriverUnlock(driver);
1365
static char *umlDomainGetOSType(virDomainPtr dom) {
1366
struct uml_driver *driver = dom->conn->privateData;
1370
umlDriverLock(driver);
1371
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1372
umlDriverUnlock(driver);
1374
umlReportError(VIR_ERR_INVALID_DOMAIN, "%s",
1375
_("no domain with matching uuid"));
1379
if (!(type = strdup(vm->def->os.type)))
1380
virReportOOMError();
1384
virDomainObjUnlock(vm);
1388
/* Returns max memory in kb, 0 if error */
1389
static unsigned long umlDomainGetMaxMemory(virDomainPtr dom) {
1390
struct uml_driver *driver = dom->conn->privateData;
1392
unsigned long ret = 0;
1394
umlDriverLock(driver);
1395
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1396
umlDriverUnlock(driver);
1399
char uuidstr[VIR_UUID_STRING_BUFLEN];
1401
virUUIDFormat(dom->uuid, uuidstr);
1402
umlReportError(VIR_ERR_INVALID_DOMAIN,
1403
_("no domain with matching uuid '%s'"), uuidstr);
1406
ret = vm->def->maxmem;
1410
virDomainObjUnlock(vm);
1414
static int umlDomainSetMaxMemory(virDomainPtr dom, unsigned long newmax) {
1415
struct uml_driver *driver = dom->conn->privateData;
1419
umlDriverLock(driver);
1420
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1421
umlDriverUnlock(driver);
1424
char uuidstr[VIR_UUID_STRING_BUFLEN];
1426
virUUIDFormat(dom->uuid, uuidstr);
1427
umlReportError(VIR_ERR_INVALID_DOMAIN,
1428
_("no domain with matching uuid '%s'"), uuidstr);
1432
if (newmax < vm->def->memory) {
1433
umlReportError(VIR_ERR_INVALID_ARG, "%s",
1434
_("cannot set max memory lower than current memory"));
1438
vm->def->maxmem = newmax;
1443
virDomainObjUnlock(vm);
1447
static int umlDomainSetMemory(virDomainPtr dom, unsigned long newmem) {
1448
struct uml_driver *driver = dom->conn->privateData;
1452
umlDriverLock(driver);
1453
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1454
umlDriverUnlock(driver);
1457
char uuidstr[VIR_UUID_STRING_BUFLEN];
1459
virUUIDFormat(dom->uuid, uuidstr);
1460
umlReportError(VIR_ERR_INVALID_DOMAIN,
1461
_("no domain with matching uuid '%s'"), uuidstr);
1465
if (virDomainObjIsActive(vm)) {
1466
umlReportError(VIR_ERR_NO_SUPPORT, "%s",
1467
_("cannot set memory of an active domain"));
1471
if (newmem > vm->def->maxmem) {
1472
umlReportError(VIR_ERR_INVALID_ARG, "%s",
1473
_("cannot set memory higher than max memory"));
1477
vm->def->memory = newmem;
1482
virDomainObjUnlock(vm);
1486
static int umlDomainGetInfo(virDomainPtr dom,
1487
virDomainInfoPtr info) {
1488
struct uml_driver *driver = dom->conn->privateData;
1492
umlDriverLock(driver);
1493
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1494
umlDriverUnlock(driver);
1497
umlReportError(VIR_ERR_INVALID_DOMAIN, "%s",
1498
_("no domain with matching uuid"));
1502
info->state = vm->state;
1504
if (!virDomainObjIsActive(vm)) {
1507
if (umlGetProcessInfo(&(info->cpuTime), vm->pid) < 0) {
1508
umlReportError(VIR_ERR_OPERATION_FAILED, "%s",
1509
_("cannot read cputime for domain"));
1514
info->maxMem = vm->def->maxmem;
1515
info->memory = vm->def->memory;
1516
info->nrVirtCpu = vm->def->vcpus;
1521
virDomainObjUnlock(vm);
1526
static char *umlDomainDumpXML(virDomainPtr dom,
1527
int flags ATTRIBUTE_UNUSED) {
1528
struct uml_driver *driver = dom->conn->privateData;
1532
umlDriverLock(driver);
1533
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1534
umlDriverUnlock(driver);
1537
umlReportError(VIR_ERR_INVALID_DOMAIN, "%s",
1538
_("no domain with matching uuid"));
1542
ret = virDomainDefFormat((flags & VIR_DOMAIN_XML_INACTIVE) && vm->newDef ?
1543
vm->newDef : vm->def,
1548
virDomainObjUnlock(vm);
1553
static int umlListDefinedDomains(virConnectPtr conn,
1554
char **const names, int nnames) {
1555
struct uml_driver *driver = conn->privateData;
1558
umlDriverLock(driver);
1559
n = virDomainObjListGetInactiveNames(&driver->domains, names, nnames);
1560
umlDriverUnlock(driver);
1565
static int umlNumDefinedDomains(virConnectPtr conn) {
1566
struct uml_driver *driver = conn->privateData;
1569
umlDriverLock(driver);
1570
n = virDomainObjListNumOfDomains(&driver->domains, 0);
1571
umlDriverUnlock(driver);
1577
static int umlDomainStartWithFlags(virDomainPtr dom, unsigned int flags) {
1578
struct uml_driver *driver = dom->conn->privateData;
1582
virCheckFlags(0, -1);
1584
umlDriverLock(driver);
1585
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1588
umlReportError(VIR_ERR_INVALID_DOMAIN, "%s",
1589
_("no domain with matching uuid"));
1593
ret = umlStartVMDaemon(dom->conn, driver, vm);
1597
virDomainObjUnlock(vm);
1598
umlDriverUnlock(driver);
1602
static int umlDomainStart(virDomainPtr dom) {
1603
return umlDomainStartWithFlags(dom, 0);
1606
static virDomainPtr umlDomainDefine(virConnectPtr conn, const char *xml) {
1607
struct uml_driver *driver = conn->privateData;
1608
virDomainDefPtr def;
1609
virDomainObjPtr vm = NULL;
1610
virDomainPtr dom = NULL;
1612
umlDriverLock(driver);
1613
if (!(def = virDomainDefParseString(driver->caps, xml,
1614
VIR_DOMAIN_XML_INACTIVE)))
1617
if (virDomainObjIsDuplicate(&driver->domains, def, 0) < 0)
1620
if (!(vm = virDomainAssignDef(driver->caps,
1627
if (virDomainSaveConfig(driver->configDir,
1628
vm->newDef ? vm->newDef : vm->def) < 0) {
1629
virDomainRemoveInactive(&driver->domains,
1635
dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
1636
if (dom) dom->id = vm->def->id;
1639
virDomainDefFree(def);
1641
virDomainObjUnlock(vm);
1642
umlDriverUnlock(driver);
1646
static int umlDomainUndefine(virDomainPtr dom) {
1647
struct uml_driver *driver = dom->conn->privateData;
1651
umlDriverLock(driver);
1652
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1654
umlReportError(VIR_ERR_INVALID_DOMAIN, "%s",
1655
_("no domain with matching uuid"));
1659
if (virDomainObjIsActive(vm)) {
1660
umlReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1661
_("cannot delete active domain"));
1665
if (!vm->persistent) {
1666
umlReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1667
_("cannot undefine transient domain"));
1671
if (virDomainDeleteConfig(driver->configDir, driver->autostartDir, vm) < 0)
1674
virDomainRemoveInactive(&driver->domains,
1681
virDomainObjUnlock(vm);
1682
umlDriverUnlock(driver);
1688
static int umlDomainGetAutostart(virDomainPtr dom,
1690
struct uml_driver *driver = dom->conn->privateData;
1694
umlDriverLock(driver);
1695
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1698
umlReportError(VIR_ERR_INVALID_DOMAIN, "%s",
1699
_("no domain with matching uuid"));
1703
*autostart = vm->autostart;
1708
virDomainObjUnlock(vm);
1709
umlDriverUnlock(driver);
1713
static int umlDomainSetAutostart(virDomainPtr dom,
1715
struct uml_driver *driver = dom->conn->privateData;
1717
char *configFile = NULL, *autostartLink = NULL;
1720
umlDriverLock(driver);
1721
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1724
umlReportError(VIR_ERR_INVALID_DOMAIN, "%s",
1725
_("no domain with matching uuid"));
1729
if (!vm->persistent) {
1730
umlReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1731
_("cannot set autostart for transient domain"));
1735
autostart = (autostart != 0);
1737
if (vm->autostart != autostart) {
1738
if ((configFile = virDomainConfigFile(driver->configDir, vm->def->name)) == NULL)
1740
if ((autostartLink = virDomainConfigFile(driver->autostartDir, vm->def->name)) == NULL)
1746
if ((err = virFileMakePath(driver->autostartDir))) {
1747
virReportSystemError(err,
1748
_("cannot create autostart directory %s"),
1749
driver->autostartDir);
1753
if (symlink(configFile, autostartLink) < 0) {
1754
virReportSystemError(errno,
1755
_("Failed to create symlink '%s to '%s'"),
1756
autostartLink, configFile);
1760
if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
1761
virReportSystemError(errno,
1762
_("Failed to delete symlink '%s'"),
1768
vm->autostart = autostart;
1773
VIR_FREE(configFile);
1774
VIR_FREE(autostartLink);
1776
virDomainObjUnlock(vm);
1777
umlDriverUnlock(driver);
1783
umlDomainBlockPeek (virDomainPtr dom,
1785
unsigned long long offset, size_t size,
1787
unsigned int flags ATTRIBUTE_UNUSED)
1789
struct uml_driver *driver = dom->conn->privateData;
1791
int fd = -1, ret = -1, i;
1793
umlDriverLock(driver);
1794
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1795
umlDriverUnlock(driver);
1798
umlReportError(VIR_ERR_INVALID_DOMAIN, "%s",
1799
_("no domain with matching uuid"));
1803
if (!path || path[0] == '\0') {
1804
umlReportError(VIR_ERR_INVALID_ARG, "%s",
1805
_("NULL or empty path"));
1809
/* Check the path belongs to this domain. */
1810
for (i = 0 ; i < vm->def->ndisks ; i++) {
1811
if (vm->def->disks[i]->src != NULL &&
1812
STREQ (vm->def->disks[i]->src, path)) {
1820
/* The path is correct, now try to open it and get its size. */
1821
fd = open (path, O_RDONLY);
1823
virReportSystemError(errno,
1824
_("cannot open %s"), path);
1828
/* Seek and read. */
1829
/* NB. Because we configure with AC_SYS_LARGEFILE, off_t should
1830
* be 64 bits on all platforms.
1832
if (lseek (fd, offset, SEEK_SET) == (off_t) -1 ||
1833
saferead (fd, buffer, size) == (ssize_t) -1) {
1834
virReportSystemError(errno,
1835
_("cannot read %s"), path);
1841
umlReportError(VIR_ERR_INVALID_ARG, "%s",
1846
if (fd >= 0) close (fd);
1848
virDomainObjUnlock(vm);
1854
static virDriver umlDriver = {
1858
umlClose, /* close */
1859
NULL, /* supports_feature */
1860
umlGetType, /* type */
1861
umlGetVersion, /* version */
1862
NULL, /* libvirtVersion (impl. in libvirt.c) */
1863
virGetHostname, /* getHostname */
1864
NULL, /* getMaxVcpus */
1865
nodeGetInfo, /* nodeGetInfo */
1866
umlGetCapabilities, /* getCapabilities */
1867
umlListDomains, /* listDomains */
1868
umlNumDomains, /* numOfDomains */
1869
umlDomainCreate, /* domainCreateXML */
1870
umlDomainLookupByID, /* domainLookupByID */
1871
umlDomainLookupByUUID, /* domainLookupByUUID */
1872
umlDomainLookupByName, /* domainLookupByName */
1873
NULL, /* domainSuspend */
1874
NULL, /* domainResume */
1875
umlDomainShutdown, /* domainShutdown */
1876
NULL, /* domainReboot */
1877
umlDomainDestroy, /* domainDestroy */
1878
umlDomainGetOSType, /* domainGetOSType */
1879
umlDomainGetMaxMemory, /* domainGetMaxMemory */
1880
umlDomainSetMaxMemory, /* domainSetMaxMemory */
1881
umlDomainSetMemory, /* domainSetMemory */
1882
umlDomainGetInfo, /* domainGetInfo */
1883
NULL, /* domainSave */
1884
NULL, /* domainRestore */
1885
NULL, /* domainCoreDump */
1886
NULL, /* domainSetVcpus */
1887
NULL, /* domainPinVcpu */
1888
NULL, /* domainGetVcpus */
1889
NULL, /* domainGetMaxVcpus */
1890
NULL, /* domainGetSecurityLabel */
1891
NULL, /* nodeGetSecurityModel */
1892
umlDomainDumpXML, /* domainDumpXML */
1893
NULL, /* domainXMLFromNative */
1894
NULL, /* domainXMLToNative */
1895
umlListDefinedDomains, /* listDefinedDomains */
1896
umlNumDefinedDomains, /* numOfDefinedDomains */
1897
umlDomainStart, /* domainCreate */
1898
umlDomainStartWithFlags, /* domainCreateWithFlags */
1899
umlDomainDefine, /* domainDefineXML */
1900
umlDomainUndefine, /* domainUndefine */
1901
NULL, /* domainAttachDevice */
1902
NULL, /* domainAttachDeviceFlags */
1903
NULL, /* domainDetachDevice */
1904
NULL, /* domainDetachDeviceFlags */
1905
NULL, /* domainUpdateDeviceFlags */
1906
umlDomainGetAutostart, /* domainGetAutostart */
1907
umlDomainSetAutostart, /* domainSetAutostart */
1908
NULL, /* domainGetSchedulerType */
1909
NULL, /* domainGetSchedulerParameters */
1910
NULL, /* domainSetSchedulerParameters */
1911
NULL, /* domainMigratePrepare */
1912
NULL, /* domainMigratePerform */
1913
NULL, /* domainMigrateFinish */
1914
NULL, /* domainBlockStats */
1915
NULL, /* domainInterfaceStats */
1916
NULL, /* domainMemoryStats */
1917
umlDomainBlockPeek, /* domainBlockPeek */
1918
NULL, /* domainMemoryPeek */
1919
NULL, /* domainGetBlockInfo */
1920
nodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */
1921
nodeGetFreeMemory, /* getFreeMemory */
1922
NULL, /* domainEventRegister */
1923
NULL, /* domainEventDeregister */
1924
NULL, /* domainMigratePrepare2 */
1925
NULL, /* domainMigrateFinish2 */
1926
NULL, /* nodeDeviceDettach */
1927
NULL, /* nodeDeviceReAttach */
1928
NULL, /* nodeDeviceReset */
1929
NULL, /* domainMigratePrepareTunnel */
1930
umlIsEncrypted, /* isEncrypted */
1931
umlIsSecure, /* isSecure */
1932
umlDomainIsActive, /* domainIsActive */
1933
umlDomainIsPersistent, /* domainIsPersistent */
1934
NULL, /* cpuCompare */
1935
NULL, /* cpuBaseline */
1936
NULL, /* domainGetJobInfo */
1937
NULL, /* domainAbortJob */
1938
NULL, /* domainMigrateSetMaxDowntime */
1939
NULL, /* domainEventRegisterAny */
1940
NULL, /* domainEventDeregisterAny */
1941
NULL, /* domainManagedSave */
1942
NULL, /* domainHasManagedSaveImage */
1943
NULL, /* domainManagedSaveRemove */
1944
NULL, /* domainSnapshotCreateXML */
1945
NULL, /* domainSnapshotDumpXML */
1946
NULL, /* domainSnapshotNum */
1947
NULL, /* domainSnapshotListNames */
1948
NULL, /* domainSnapshotLookupByName */
1949
NULL, /* domainHasCurrentSnapshot */
1950
NULL, /* domainSnapshotCurrent */
1951
NULL, /* domainRevertToSnapshot */
1952
NULL, /* domainSnapshotDelete */
1953
NULL, /* qemuDomainMonitorCommand */
1957
static virStateDriver umlStateDriver = {
1959
.initialize = umlStartup,
1960
.cleanup = umlShutdown,
1961
.reload = umlReload,
1962
.active = umlActive,
1965
int umlRegister(void) {
1966
virRegisterDriver(¨Driver);
1967
virRegisterStateDriver(¨StateDriver);