Merge lp:~ubuntu-branches/ubuntu/maverick/libvirt/maverick-201009142019 into lp:ubuntu/maverick/libvirt

Proposed by James Westby
Status: Merged
Merged at revision: 103
Proposed branch: lp:~ubuntu-branches/ubuntu/maverick/libvirt/maverick-201009142019
Merge into: lp:ubuntu/maverick/libvirt
Diff against target: 3065 lines (+2918/-58) (has conflicts)
4 files modified
.pc/9025-Add-nwfilter-support-to-UML-driver.patch/src/uml/uml_conf.c (+601/-0)
.pc/9025-Add-nwfilter-support-to-UML-driver.patch/src/uml/uml_driver.c (+2205/-0)
debian/patches/9024-Explicitly-pass-uml_dir-argument-to-user-mode-linux.patch (+0/-58)
debian/patches/9025-Add-nwfilter-support-to-UML-driver.patch (+112/-0)
Conflict adding file .pc/9025-Add-nwfilter-support-to-UML-driver.patch.  Moved existing file to .pc/9025-Add-nwfilter-support-to-UML-driver.patch.moved.
Conflict adding file debian/patches/9025-Add-nwfilter-support-to-UML-driver.patch.  Moved existing file to debian/patches/9025-Add-nwfilter-support-to-UML-driver.patch.moved.
To merge this branch: bzr merge lp:~ubuntu-branches/ubuntu/maverick/libvirt/maverick-201009142019

Description of the change

The package history in the archive and the history in the bzr branch differ. As the archive is authoritative the history of lp:ubuntu/maverick/libvirt now reflects that and the old bzr branch has been pushed to lp:~ubuntu-branches/ubuntu/maverick/libvirt/maverick-201009142019. A merge should be performed if necessary.

To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory '.pc/9025-Add-nwfilter-support-to-UML-driver.patch'
2=== renamed directory '.pc/9025-Add-nwfilter-support-to-UML-driver.patch' => '.pc/9025-Add-nwfilter-support-to-UML-driver.patch.moved'
3=== added file '.pc/9025-Add-nwfilter-support-to-UML-driver.patch/.timestamp'
4=== added directory '.pc/9025-Add-nwfilter-support-to-UML-driver.patch/src'
5=== added directory '.pc/9025-Add-nwfilter-support-to-UML-driver.patch/src/uml'
6=== added file '.pc/9025-Add-nwfilter-support-to-UML-driver.patch/src/uml/uml_conf.c'
7--- .pc/9025-Add-nwfilter-support-to-UML-driver.patch/src/uml/uml_conf.c 1970-01-01 00:00:00 +0000
8+++ .pc/9025-Add-nwfilter-support-to-UML-driver.patch/src/uml/uml_conf.c 2010-09-14 20:26:05 +0000
9@@ -0,0 +1,601 @@
10+/*
11+ * uml_conf.c: UML driver configuration
12+ *
13+ * Copyright (C) 2006-2009 Red Hat, Inc.
14+ * Copyright (C) 2006 Daniel P. Berrange
15+ *
16+ * This library is free software; you can redistribute it and/or
17+ * modify it under the terms of the GNU Lesser General Public
18+ * License as published by the Free Software Foundation; either
19+ * version 2.1 of the License, or (at your option) any later version.
20+ *
21+ * This library is distributed in the hope that it will be useful,
22+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
23+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24+ * Lesser General Public License for more details.
25+ *
26+ * You should have received a copy of the GNU Lesser General Public
27+ * License along with this library; if not, write to the Free Software
28+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29+ *
30+ * Author: Daniel P. Berrange <berrange@redhat.com>
31+ */
32+
33+#include <config.h>
34+
35+#include <dirent.h>
36+#include <string.h>
37+#include <limits.h>
38+#include <sys/types.h>
39+#include <sys/stat.h>
40+#include <stdlib.h>
41+#include <unistd.h>
42+#include <errno.h>
43+#include <fcntl.h>
44+#include <sys/wait.h>
45+#include <arpa/inet.h>
46+#include <sys/utsname.h>
47+
48+#include "uml_conf.h"
49+#include "uuid.h"
50+#include "buf.h"
51+#include "conf.h"
52+#include "util.h"
53+#include "memory.h"
54+#include "nodeinfo.h"
55+#include "verify.h"
56+#include "bridge.h"
57+#include "logging.h"
58+
59+#define VIR_FROM_THIS VIR_FROM_UML
60+
61+#define umlLog(level, msg, ...) \
62+ virLogMessage(__FILE__, level, 0, msg, __VA_ARGS__)
63+
64+virCapsPtr umlCapsInit(void) {
65+ struct utsname utsname;
66+ virCapsPtr caps;
67+ virCapsGuestPtr guest;
68+
69+ /* Really, this never fails - look at the man-page. */
70+ uname (&utsname);
71+
72+ if ((caps = virCapabilitiesNew(utsname.machine,
73+ 0, 0)) == NULL)
74+ goto error;
75+
76+ /* Some machines have problematic NUMA toplogy causing
77+ * unexpected failures. We don't want to break the QEMU
78+ * driver in this scenario, so log errors & carry on
79+ */
80+ if (nodeCapsInitNUMA(caps) < 0) {
81+ virCapabilitiesFreeNUMAInfo(caps);
82+ VIR_WARN0("Failed to query host NUMA topology, disabling NUMA capabilities");
83+ }
84+
85+ if (virGetHostUUID(caps->host.host_uuid)) {
86+ umlReportError(VIR_ERR_INTERNAL_ERROR,
87+ "%s", _("cannot get the host uuid"));
88+ goto error;
89+ }
90+
91+ if ((guest = virCapabilitiesAddGuest(caps,
92+ "uml",
93+ utsname.machine,
94+ STREQ(utsname.machine, "x86_64") ? 64 : 32,
95+ NULL,
96+ NULL,
97+ 0,
98+ NULL)) == NULL)
99+ goto error;
100+
101+ if (virCapabilitiesAddGuestDomain(guest,
102+ "uml",
103+ NULL,
104+ NULL,
105+ 0,
106+ NULL) == NULL)
107+ goto error;
108+
109+ caps->defaultConsoleTargetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_UML;
110+
111+ return caps;
112+
113+ error:
114+ virCapabilitiesFree(caps);
115+ return NULL;
116+}
117+
118+
119+static int
120+umlConnectTapDevice(virDomainNetDefPtr net,
121+ const char *bridge)
122+{
123+ brControl *brctl = NULL;
124+ int template_ifname = 0;
125+ int err;
126+ unsigned char tapmac[VIR_MAC_BUFLEN];
127+
128+ if ((err = brInit(&brctl))) {
129+ virReportSystemError(err, "%s",
130+ _("cannot initialize bridge support"));
131+ goto error;
132+ }
133+
134+ if (!net->ifname ||
135+ STRPREFIX(net->ifname, "vnet") ||
136+ strchr(net->ifname, '%')) {
137+ VIR_FREE(net->ifname);
138+ if (!(net->ifname = strdup("vnet%d")))
139+ goto no_memory;
140+ /* avoid exposing vnet%d in dumpxml or error outputs */
141+ template_ifname = 1;
142+ }
143+
144+ memcpy(tapmac, net->mac, VIR_MAC_BUFLEN);
145+ tapmac[0] = 0xFE; /* Discourage bridge from using TAP dev MAC */
146+ if ((err = brAddTap(brctl,
147+ bridge,
148+ &net->ifname,
149+ tapmac,
150+ 0,
151+ NULL))) {
152+ if (errno == ENOTSUP) {
153+ /* In this particular case, give a better diagnostic. */
154+ umlReportError(VIR_ERR_INTERNAL_ERROR,
155+ _("Failed to add tap interface to bridge. "
156+ "%s is not a bridge device"), bridge);
157+ } else if (template_ifname) {
158+ virReportSystemError(err,
159+ _("Failed to add tap interface to bridge '%s'"),
160+ bridge);
161+ } else {
162+ virReportSystemError(err,
163+ _("Failed to add tap interface '%s' to bridge '%s'"),
164+ net->ifname, bridge);
165+ }
166+ if (template_ifname)
167+ VIR_FREE(net->ifname);
168+ goto error;
169+ }
170+
171+ brShutdown(brctl);
172+
173+ return 0;
174+
175+no_memory:
176+ virReportOOMError();
177+error:
178+ brShutdown(brctl);
179+ return -1;
180+}
181+
182+static char *
183+umlBuildCommandLineNet(virConnectPtr conn,
184+ virDomainNetDefPtr def,
185+ int idx)
186+{
187+ virBuffer buf = VIR_BUFFER_INITIALIZER;
188+
189+ /* General format: ethNN=type,options */
190+
191+ virBufferVSprintf(&buf, "eth%d=", idx);
192+
193+ switch (def->type) {
194+ case VIR_DOMAIN_NET_TYPE_USER:
195+ /* ethNNN=slirp,macaddr */
196+ virBufferAddLit(&buf, "slirp");
197+ break;
198+
199+ case VIR_DOMAIN_NET_TYPE_ETHERNET:
200+ /* ethNNN=tuntap,tapname,macaddr,gateway */
201+ virBufferAddLit(&buf, "tuntap");
202+ if (def->data.ethernet.ipaddr) {
203+ umlReportError(VIR_ERR_INTERNAL_ERROR, "%s",
204+ _("IP address not supported for ethernet inteface"));
205+ goto error;
206+ }
207+ if (def->data.ethernet.script) {
208+ umlReportError(VIR_ERR_INTERNAL_ERROR, "%s",
209+ _("script execution not supported for ethernet inteface"));
210+ goto error;
211+ }
212+ break;
213+
214+ case VIR_DOMAIN_NET_TYPE_SERVER:
215+ umlReportError(VIR_ERR_INTERNAL_ERROR, "%s",
216+ _("TCP server networking type not supported"));
217+ goto error;
218+
219+ case VIR_DOMAIN_NET_TYPE_CLIENT:
220+ umlReportError(VIR_ERR_INTERNAL_ERROR, "%s",
221+ _("TCP client networking type not supported"));
222+ goto error;
223+
224+ case VIR_DOMAIN_NET_TYPE_MCAST:
225+ /* ethNNN=tuntap,macaddr,ipaddr,port */
226+ virBufferAddLit(&buf, "mcast");
227+ break;
228+
229+ case VIR_DOMAIN_NET_TYPE_NETWORK:
230+ {
231+ char *bridge;
232+ virNetworkPtr network = virNetworkLookupByName(conn,
233+ def->data.network.name);
234+ if (!network) {
235+ umlReportError(VIR_ERR_INTERNAL_ERROR,
236+ _("Network '%s' not found"),
237+ def->data.network.name);
238+ goto error;
239+ }
240+ bridge = virNetworkGetBridgeName(network);
241+ virNetworkFree(network);
242+ if (bridge == NULL) {
243+ goto error;
244+ }
245+
246+ if (umlConnectTapDevice(def, bridge) < 0) {
247+ VIR_FREE(bridge);
248+ goto error;
249+ }
250+
251+ /* ethNNN=tuntap,tapname,macaddr,gateway */
252+ virBufferVSprintf(&buf, "tuntap,%s", def->ifname);
253+ break;
254+ }
255+
256+ case VIR_DOMAIN_NET_TYPE_BRIDGE:
257+ if (umlConnectTapDevice(def, def->data.bridge.brname) < 0)
258+ goto error;
259+
260+ /* ethNNN=tuntap,tapname,macaddr,gateway */
261+ virBufferVSprintf(&buf, "tuntap,%s", def->ifname);
262+ break;
263+
264+ case VIR_DOMAIN_NET_TYPE_INTERNAL:
265+ umlReportError(VIR_ERR_INTERNAL_ERROR, "%s",
266+ _("internal networking type not supported"));
267+ goto error;
268+
269+ case VIR_DOMAIN_NET_TYPE_DIRECT:
270+ umlReportError(VIR_ERR_INTERNAL_ERROR, "%s",
271+ _("direct networking type not supported"));
272+ goto error;
273+
274+ case VIR_DOMAIN_NET_TYPE_LAST:
275+ break;
276+ }
277+
278+ virBufferVSprintf(&buf, ",%02x:%02x:%02x:%02x:%02x:%02x",
279+ def->mac[0], def->mac[1], def->mac[2],
280+ def->mac[3], def->mac[4], def->mac[5]);
281+
282+ if (def->type == VIR_DOMAIN_NET_TYPE_MCAST) {
283+ virBufferVSprintf(&buf, ",%s,%d",
284+ def->data.socket.address,
285+ def->data.socket.port);
286+ }
287+
288+ if (virBufferError(&buf)) {
289+ virReportOOMError();
290+ return NULL;
291+ }
292+
293+ return virBufferContentAndReset(&buf);
294+
295+error:
296+ virBufferFreeAndReset(&buf);
297+ return NULL;
298+}
299+
300+static char *
301+umlBuildCommandLineChr(virDomainChrDefPtr def,
302+ const char *dev,
303+ fd_set *keepfd)
304+{
305+ char *ret = NULL;
306+
307+ switch (def->type) {
308+ case VIR_DOMAIN_CHR_TYPE_NULL:
309+ if (virAsprintf(&ret, "%s%d=null", dev, def->target.port) < 0) {
310+ virReportOOMError();
311+ return NULL;
312+ }
313+ break;
314+
315+ case VIR_DOMAIN_CHR_TYPE_PTY:
316+ if (virAsprintf(&ret, "%s%d=pts", dev, def->target.port) < 0) {
317+ virReportOOMError();
318+ return NULL;
319+ }
320+ break;
321+
322+ case VIR_DOMAIN_CHR_TYPE_DEV:
323+ if (virAsprintf(&ret, "%s%d=tty:%s", dev, def->target.port,
324+ def->data.file.path) < 0) {
325+ virReportOOMError();
326+ return NULL;
327+ }
328+ break;
329+
330+ case VIR_DOMAIN_CHR_TYPE_STDIO:
331+ if (virAsprintf(&ret, "%s%d=fd:0,fd:1", dev, def->target.port) < 0) {
332+ virReportOOMError();
333+ return NULL;
334+ }
335+ break;
336+
337+ case VIR_DOMAIN_CHR_TYPE_TCP:
338+ if (def->data.tcp.listen != 1) {
339+ umlReportError(VIR_ERR_INTERNAL_ERROR, "%s",
340+ _("only TCP listen is supported for chr device"));
341+ return NULL;
342+ }
343+
344+ if (virAsprintf(&ret, "%s%d=port:%s", dev, def->target.port,
345+ def->data.tcp.service) < 0) {
346+ virReportOOMError();
347+ return NULL;
348+ }
349+ break;
350+
351+ case VIR_DOMAIN_CHR_TYPE_FILE:
352+ {
353+ int fd_out;
354+
355+ if ((fd_out = open(def->data.file.path,
356+ O_WRONLY | O_APPEND | O_CREAT, 0660)) < 0) {
357+ virReportSystemError(errno,
358+ _("failed to open chardev file: %s"),
359+ def->data.file.path);
360+ return NULL;
361+ }
362+ if (virAsprintf(&ret, "%s%d=null,fd:%d", dev, def->target.port, fd_out) < 0) {
363+ virReportOOMError();
364+ close(fd_out);
365+ return NULL;
366+ }
367+ FD_SET(fd_out, keepfd);
368+ }
369+ break;
370+ case VIR_DOMAIN_CHR_TYPE_PIPE:
371+ /* XXX could open the pipe & just pass the FDs. Be wary of
372+ * the effects of blocking I/O, though. */
373+
374+ case VIR_DOMAIN_CHR_TYPE_VC:
375+ case VIR_DOMAIN_CHR_TYPE_UDP:
376+ case VIR_DOMAIN_CHR_TYPE_UNIX:
377+ default:
378+ umlReportError(VIR_ERR_INTERNAL_ERROR,
379+ _("unsupported chr device type %d"), def->type);
380+ break;
381+ }
382+
383+ return ret;
384+}
385+
386+/*
387+ * Null-terminate the current argument and return a pointer to the next.
388+ * This should follow the same rules as the Linux kernel: arguments are
389+ * separated by spaces; arguments can be quoted with double quotes; double
390+ * quotes can't be escaped.
391+ */
392+static char *umlNextArg(char *args)
393+{
394+ int in_quote = 0;
395+
396+ for (; *args; args++) {
397+ if (*args == ' ' && !in_quote) {
398+ *args++ = '\0';
399+ break;
400+ }
401+ if (*args == '"')
402+ in_quote = !in_quote;
403+ }
404+
405+ while (*args == ' ')
406+ args++;
407+
408+ return args;
409+}
410+
411+/*
412+ * Constructs a argv suitable for launching uml with config defined
413+ * for a given virtual machine.
414+ */
415+int umlBuildCommandLine(virConnectPtr conn,
416+ struct uml_driver *driver,
417+ virDomainObjPtr vm,
418+ fd_set *keepfd,
419+ const char ***retargv,
420+ const char ***retenv)
421+{
422+ int i, j;
423+ char memory[50];
424+ struct utsname ut;
425+ int qargc = 0, qarga = 0;
426+ const char **qargv = NULL;
427+ int qenvc = 0, qenva = 0;
428+ const char **qenv = NULL;
429+ char *cmdline = NULL;
430+
431+ uname(&ut);
432+
433+#define ADD_ARG_SPACE \
434+ do { \
435+ if (qargc == qarga) { \
436+ qarga += 10; \
437+ if (VIR_REALLOC_N(qargv, qarga) < 0) \
438+ goto no_memory; \
439+ } \
440+ } while (0)
441+
442+#define ADD_ARG(thisarg) \
443+ do { \
444+ ADD_ARG_SPACE; \
445+ qargv[qargc++] = thisarg; \
446+ } while (0)
447+
448+#define ADD_ARG_LIT(thisarg) \
449+ do { \
450+ ADD_ARG_SPACE; \
451+ if ((qargv[qargc++] = strdup(thisarg)) == NULL) \
452+ goto no_memory; \
453+ } while (0)
454+
455+#define ADD_ARG_PAIR(key,val) \
456+ do { \
457+ char *arg; \
458+ ADD_ARG_SPACE; \
459+ if (virAsprintf(&arg, "%s=%s", key, val) < 0) \
460+ goto no_memory; \
461+ qargv[qargc++] = arg; \
462+ } while (0)
463+
464+
465+#define ADD_ENV_SPACE \
466+ do { \
467+ if (qenvc == qenva) { \
468+ qenva += 10; \
469+ if (VIR_REALLOC_N(qenv, qenva) < 0) \
470+ goto no_memory; \
471+ } \
472+ } while (0)
473+
474+#define ADD_ENV(thisarg) \
475+ do { \
476+ ADD_ENV_SPACE; \
477+ qenv[qenvc++] = thisarg; \
478+ } while (0)
479+
480+#define ADD_ENV_LIT(thisarg) \
481+ do { \
482+ ADD_ENV_SPACE; \
483+ if ((qenv[qenvc++] = strdup(thisarg)) == NULL) \
484+ goto no_memory; \
485+ } while (0)
486+
487+#define ADD_ENV_COPY(envname) \
488+ do { \
489+ char *val = getenv(envname); \
490+ char *envval; \
491+ ADD_ENV_SPACE; \
492+ if (val != NULL) { \
493+ if (virAsprintf(&envval, "%s=%s", envname, val) < 0) \
494+ goto no_memory; \
495+ qenv[qenvc++] = envval; \
496+ } \
497+ } while (0)
498+
499+ snprintf(memory, sizeof(memory), "%luK", vm->def->memory);
500+
501+ ADD_ENV_LIT("LC_ALL=C");
502+
503+ ADD_ENV_COPY("LD_PRELOAD");
504+ ADD_ENV_COPY("LD_LIBRARY_PATH");
505+ ADD_ENV_COPY("PATH");
506+ ADD_ENV_COPY("USER");
507+ ADD_ENV_COPY("LOGNAME");
508+ ADD_ENV_COPY("TMPDIR");
509+
510+ ADD_ARG_LIT(vm->def->os.kernel);
511+ //ADD_ARG_PAIR("con0", "fd:0,fd:1");
512+ ADD_ARG_PAIR("mem", memory);
513+ ADD_ARG_PAIR("umid", vm->def->name);
514+ ADD_ARG_PAIR("uml_dir", driver->monitorDir);
515+
516+ if (vm->def->os.root)
517+ ADD_ARG_PAIR("root", vm->def->os.root);
518+
519+ for (i = 0 ; i < vm->def->ndisks ; i++) {
520+ virDomainDiskDefPtr disk = vm->def->disks[i];
521+
522+ if (!STRPREFIX(disk->dst, "ubd")) {
523+ umlReportError(VIR_ERR_INTERNAL_ERROR,
524+ _("unsupported disk type '%s'"), disk->dst);
525+ goto error;
526+ }
527+
528+ ADD_ARG_PAIR(disk->dst, disk->src);
529+ }
530+
531+ for (i = 0 ; i < vm->def->nnets ; i++) {
532+ char *ret = umlBuildCommandLineNet(conn, vm->def->nets[i], i);
533+ if (!ret)
534+ goto error;
535+ ADD_ARG(ret);
536+ }
537+
538+ for (i = 0 ; i < UML_MAX_CHAR_DEVICE ; i++) {
539+ char *ret = NULL;
540+ if (i == 0 && vm->def->console)
541+ ret = umlBuildCommandLineChr(vm->def->console, "con", keepfd);
542+ if (!ret)
543+ if (virAsprintf(&ret, "con%d=none", i) < 0)
544+ goto no_memory;
545+ ADD_ARG(ret);
546+ }
547+
548+ for (i = 0 ; i < UML_MAX_CHAR_DEVICE ; i++) {
549+ virDomainChrDefPtr chr = NULL;
550+ char *ret = NULL;
551+ for (j = 0 ; j < vm->def->nserials ; j++)
552+ if (vm->def->serials[j]->target.port == i)
553+ chr = vm->def->serials[j];
554+ if (chr)
555+ ret = umlBuildCommandLineChr(chr, "ssl", keepfd);
556+ if (!ret)
557+ if (virAsprintf(&ret, "ssl%d=none", i) < 0)
558+ goto no_memory;
559+ ADD_ARG(ret);
560+ }
561+
562+ if (vm->def->os.cmdline) {
563+ char *args, *next_arg;
564+ if ((cmdline = strdup(vm->def->os.cmdline)) == NULL)
565+ goto no_memory;
566+
567+ args = cmdline;
568+ while (*args == ' ')
569+ args++;
570+
571+ while (*args) {
572+ next_arg = umlNextArg(args);
573+ ADD_ARG_LIT(args);
574+ args = next_arg;
575+ }
576+ }
577+
578+ ADD_ARG(NULL);
579+ ADD_ENV(NULL);
580+
581+ *retargv = qargv;
582+ *retenv = qenv;
583+ return 0;
584+
585+ no_memory:
586+ virReportOOMError();
587+ error:
588+
589+ if (qargv) {
590+ for (i = 0 ; i < qargc ; i++)
591+ VIR_FREE((qargv)[i]);
592+ VIR_FREE(qargv);
593+ }
594+ if (qenv) {
595+ for (i = 0 ; i < qenvc ; i++)
596+ VIR_FREE((qenv)[i]);
597+ VIR_FREE(qenv);
598+ }
599+ VIR_FREE(cmdline);
600+ return -1;
601+
602+#undef ADD_ARG
603+#undef ADD_ARG_LIT
604+#undef ADD_ARG_SPACE
605+#undef ADD_USBDISK
606+#undef ADD_ENV
607+#undef ADD_ENV_COPY
608+#undef ADD_ENV_LIT
609+#undef ADD_ENV_SPACE
610+}
611
612=== added file '.pc/9025-Add-nwfilter-support-to-UML-driver.patch/src/uml/uml_driver.c'
613--- .pc/9025-Add-nwfilter-support-to-UML-driver.patch/src/uml/uml_driver.c 1970-01-01 00:00:00 +0000
614+++ .pc/9025-Add-nwfilter-support-to-UML-driver.patch/src/uml/uml_driver.c 2010-09-14 20:26:05 +0000
615@@ -0,0 +1,2205 @@
616+/*
617+ * uml_driver.c: core driver methods for managing UML guests
618+ *
619+ * Copyright (C) 2006-2010 Red Hat, Inc.
620+ * Copyright (C) 2006-2008 Daniel P. Berrange
621+ *
622+ * This library is free software; you can redistribute it and/or
623+ * modify it under the terms of the GNU Lesser General Public
624+ * License as published by the Free Software Foundation; either
625+ * version 2.1 of the License, or (at your option) any later version.
626+ *
627+ * This library is distributed in the hope that it will be useful,
628+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
629+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
630+ * Lesser General Public License for more details.
631+ *
632+ * You should have received a copy of the GNU Lesser General Public
633+ * License along with this library; if not, write to the Free Software
634+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
635+ *
636+ * Author: Daniel P. Berrange <berrange@redhat.com>
637+ */
638+
639+#include <config.h>
640+
641+#include <sys/types.h>
642+#include <sys/poll.h>
643+#include <dirent.h>
644+#include <limits.h>
645+#include <string.h>
646+#include <stdio.h>
647+#include <stdarg.h>
648+#include <stdlib.h>
649+#include <unistd.h>
650+#include <errno.h>
651+#include <sys/utsname.h>
652+#include <sys/stat.h>
653+#include <fcntl.h>
654+#include <signal.h>
655+#include <paths.h>
656+#include <pwd.h>
657+#include <stdio.h>
658+#include <sys/wait.h>
659+#include <sys/ioctl.h>
660+#include <sys/inotify.h>
661+#include <sys/un.h>
662+
663+#include "uml_driver.h"
664+#include "uml_conf.h"
665+#include "event.h"
666+#include "buf.h"
667+#include "util.h"
668+#include "nodeinfo.h"
669+#include "stats_linux.h"
670+#include "capabilities.h"
671+#include "memory.h"
672+#include "uuid.h"
673+#include "domain_conf.h"
674+#include "datatypes.h"
675+#include "logging.h"
676+
677+#define VIR_FROM_THIS VIR_FROM_UML
678+
679+/* For storing short-lived temporary files. */
680+#define TEMPDIR LOCAL_STATE_DIR "/cache/libvirt"
681+
682+typedef struct _umlDomainObjPrivate umlDomainObjPrivate;
683+typedef umlDomainObjPrivate *umlDomainObjPrivatePtr;
684+struct _umlDomainObjPrivate {
685+ int monitor;
686+ int monitorWatch;
687+};
688+
689+
690+static int umlShutdown(void);
691+
692+static void *umlDomainObjPrivateAlloc(void)
693+{
694+ umlDomainObjPrivatePtr priv;
695+
696+ if (VIR_ALLOC(priv) < 0)
697+ return NULL;
698+
699+ priv->monitor = -1;
700+ priv->monitorWatch = -1;
701+
702+ return priv;
703+}
704+
705+static void umlDomainObjPrivateFree(void *data)
706+{
707+ umlDomainObjPrivatePtr priv = data;
708+
709+ VIR_FREE(priv);
710+}
711+
712+
713+static void umlDriverLock(struct uml_driver *driver)
714+{
715+ virMutexLock(&driver->lock);
716+}
717+static void umlDriverUnlock(struct uml_driver *driver)
718+{
719+ virMutexUnlock(&driver->lock);
720+}
721+
722+
723+static int umlOpenMonitor(struct uml_driver *driver,
724+ virDomainObjPtr vm);
725+static int umlReadPidFile(struct uml_driver *driver,
726+ virDomainObjPtr vm);
727+
728+static int umlSetCloseExec(int fd) {
729+ int flags;
730+ if ((flags = fcntl(fd, F_GETFD)) < 0)
731+ goto error;
732+ flags |= FD_CLOEXEC;
733+ if ((fcntl(fd, F_SETFD, flags)) < 0)
734+ goto error;
735+ return 0;
736+ error:
737+ VIR_ERROR0(_("Failed to set close-on-exec file descriptor flag"));
738+ return -1;
739+}
740+
741+static int umlStartVMDaemon(virConnectPtr conn,
742+ struct uml_driver *driver,
743+ virDomainObjPtr vm);
744+
745+static void umlShutdownVMDaemon(virConnectPtr conn,
746+ struct uml_driver *driver,
747+ virDomainObjPtr vm);
748+
749+
750+static int umlMonitorCommand(const struct uml_driver *driver,
751+ const virDomainObjPtr vm,
752+ const char *cmd,
753+ char **reply);
754+
755+static struct uml_driver *uml_driver = NULL;
756+
757+struct umlAutostartData {
758+ struct uml_driver *driver;
759+ virConnectPtr conn;
760+};
761+
762+static void
763+umlAutostartDomain(void *payload, const char *name ATTRIBUTE_UNUSED, void *opaque)
764+{
765+ virDomainObjPtr vm = payload;
766+ const struct umlAutostartData *data = opaque;
767+
768+ virDomainObjLock(vm);
769+ if (vm->autostart &&
770+ !virDomainObjIsActive(vm)) {
771+ virResetLastError();
772+ if (umlStartVMDaemon(data->conn, data->driver, vm) < 0) {
773+ virErrorPtr err = virGetLastError();
774+ VIR_ERROR(_("Failed to autostart VM '%s': %s"),
775+ vm->def->name, err ? err->message : _("unknown error"));
776+ }
777+ }
778+ virDomainObjUnlock(vm);
779+}
780+
781+static void
782+umlAutostartConfigs(struct uml_driver *driver) {
783+ /* XXX: Figure out a better way todo this. The domain
784+ * startup code needs a connection handle in order
785+ * to lookup the bridge associated with a virtual
786+ * network
787+ */
788+ virConnectPtr conn = virConnectOpen(driver->privileged ?
789+ "uml:///system" :
790+ "uml:///session");
791+ /* Ignoring NULL conn which is mostly harmless here */
792+
793+ struct umlAutostartData data = { driver, conn };
794+
795+ virHashForEach(driver->domains.objs, umlAutostartDomain, &data);
796+
797+ if (conn)
798+ virConnectClose(conn);
799+}
800+
801+
802+static int
803+umlIdentifyOneChrPTY(struct uml_driver *driver,
804+ virDomainObjPtr dom,
805+ virDomainChrDefPtr def,
806+ const char *dev)
807+{
808+ char *cmd;
809+ char *res = NULL;
810+ int retries = 0;
811+ if (virAsprintf(&cmd, "config %s%d", dev, def->target.port) < 0) {
812+ virReportOOMError();
813+ return -1;
814+ }
815+requery:
816+ if (umlMonitorCommand(driver, dom, cmd, &res) < 0)
817+ return -1;
818+
819+ if (res && STRPREFIX(res, "pts:")) {
820+ VIR_FREE(def->data.file.path);
821+ if ((def->data.file.path = strdup(res + 4)) == NULL) {
822+ virReportOOMError();
823+ VIR_FREE(res);
824+ VIR_FREE(cmd);
825+ return -1;
826+ }
827+ } else if (!res || STRPREFIX(res, "pts")) {
828+ /* It can take a while to startup, so retry for
829+ upto 5 seconds */
830+ /* XXX should do this in a better non-blocking
831+ way somehow ...perhaps register a timer */
832+ if (retries++ < 50) {
833+ usleep(1000*10);
834+ goto requery;
835+ }
836+ }
837+
838+ VIR_FREE(cmd);
839+ VIR_FREE(res);
840+ return 0;
841+}
842+
843+static int
844+umlIdentifyChrPTY(struct uml_driver *driver,
845+ virDomainObjPtr dom)
846+{
847+ int i;
848+
849+ if (dom->def->console &&
850+ dom->def->console->type == VIR_DOMAIN_CHR_TYPE_PTY)
851+ if (umlIdentifyOneChrPTY(driver, dom,
852+ dom->def->console, "con") < 0)
853+ return -1;
854+
855+ for (i = 0 ; i < dom->def->nserials; i++)
856+ if (dom->def->serials[i]->type == VIR_DOMAIN_CHR_TYPE_PTY &&
857+ umlIdentifyOneChrPTY(driver, dom,
858+ dom->def->serials[i], "ssl") < 0)
859+ return -1;
860+
861+ return 0;
862+}
863+
864+static void
865+umlInotifyEvent(int watch,
866+ int fd,
867+ int events ATTRIBUTE_UNUSED,
868+ void *data)
869+{
870+ char buf[1024];
871+ struct inotify_event *e;
872+ int got;
873+ char *tmp, *name;
874+ struct uml_driver *driver = data;
875+ virDomainObjPtr dom;
876+
877+ umlDriverLock(driver);
878+ if (watch != driver->inotifyWatch)
879+ goto cleanup;
880+
881+reread:
882+ got = read(fd, buf, sizeof(buf));
883+ if (got == -1) {
884+ if (errno == EINTR)
885+ goto reread;
886+ goto cleanup;
887+ }
888+
889+ tmp = buf;
890+ while (got) {
891+ if (got < sizeof(struct inotify_event))
892+ goto cleanup; /* bad */
893+
894+ e = (struct inotify_event *)tmp;
895+ tmp += sizeof(struct inotify_event);
896+ got -= sizeof(struct inotify_event);
897+
898+ if (got < e->len)
899+ goto cleanup;
900+
901+ tmp += e->len;
902+ got -= e->len;
903+
904+ name = (char *)&(e->name);
905+
906+ dom = virDomainFindByName(&driver->domains, name);
907+
908+ if (!dom) {
909+ continue;
910+ }
911+
912+ if (e->mask & IN_DELETE) {
913+ VIR_DEBUG("Got inotify domain shutdown '%s'", name);
914+ if (!virDomainObjIsActive(dom)) {
915+ virDomainObjUnlock(dom);
916+ continue;
917+ }
918+
919+ umlShutdownVMDaemon(NULL, driver, dom);
920+ } else if (e->mask & (IN_CREATE | IN_MODIFY)) {
921+ VIR_DEBUG("Got inotify domain startup '%s'", name);
922+ if (virDomainObjIsActive(dom)) {
923+ virDomainObjUnlock(dom);
924+ continue;
925+ }
926+
927+ if (umlReadPidFile(driver, dom) < 0) {
928+ virDomainObjUnlock(dom);
929+ continue;
930+ }
931+
932+ dom->def->id = driver->nextvmid++;
933+ dom->state = VIR_DOMAIN_RUNNING;
934+
935+ if (umlOpenMonitor(driver, dom) < 0) {
936+ VIR_WARN0("Could not open monitor for new domain");
937+ umlShutdownVMDaemon(NULL, driver, dom);
938+ } else if (umlIdentifyChrPTY(driver, dom) < 0) {
939+ VIR_WARN0("Could not identify charater devices for new domain");
940+ umlShutdownVMDaemon(NULL, driver, dom);
941+ }
942+ }
943+ virDomainObjUnlock(dom);
944+ }
945+
946+cleanup:
947+ umlDriverUnlock(driver);
948+}
949+
950+/**
951+ * umlStartup:
952+ *
953+ * Initialization function for the Uml daemon
954+ */
955+static int
956+umlStartup(int privileged) {
957+ uid_t uid = geteuid();
958+ char *base = NULL;
959+ char driverConf[PATH_MAX];
960+ char *userdir = NULL;
961+
962+ if (VIR_ALLOC(uml_driver) < 0)
963+ return -1;
964+
965+ uml_driver->privileged = privileged;
966+
967+ if (virMutexInit(&uml_driver->lock) < 0) {
968+ VIR_FREE(uml_driver);
969+ return -1;
970+ }
971+ umlDriverLock(uml_driver);
972+
973+ /* Don't have a dom0 so start from 1 */
974+ uml_driver->nextvmid = 1;
975+ uml_driver->inotifyWatch = -1;
976+
977+ if (virDomainObjListInit(&uml_driver->domains) < 0)
978+ goto error;
979+
980+ userdir = virGetUserDirectory(uid);
981+ if (!userdir)
982+ goto error;
983+
984+ if (privileged) {
985+ if (virAsprintf(&uml_driver->logDir,
986+ "%s/log/libvirt/uml", LOCAL_STATE_DIR) == -1)
987+ goto out_of_memory;
988+
989+ if ((base = strdup (SYSCONF_DIR "/libvirt")) == NULL)
990+ goto out_of_memory;
991+ } else {
992+
993+ if (virAsprintf(&uml_driver->logDir,
994+ "%s/.libvirt/uml/log", userdir) == -1)
995+ goto out_of_memory;
996+
997+ if (virAsprintf(&base, "%s/.libvirt", userdir) == -1)
998+ goto out_of_memory;
999+ }
1000+
1001+ if (virAsprintf(&uml_driver->monitorDir,
1002+ "%s/.uml", userdir) == -1)
1003+ goto out_of_memory;
1004+
1005+ /* Configuration paths are either ~/.libvirt/uml/... (session) or
1006+ * /etc/libvirt/uml/... (system).
1007+ */
1008+ if (snprintf (driverConf, sizeof(driverConf), "%s/uml.conf", base) == -1)
1009+ goto out_of_memory;
1010+ driverConf[sizeof(driverConf)-1] = '\0';
1011+
1012+ if (virAsprintf(&uml_driver->configDir, "%s/uml", base) == -1)
1013+ goto out_of_memory;
1014+
1015+ if (virAsprintf(&uml_driver->autostartDir, "%s/uml/autostart", base) == -1)
1016+ goto out_of_memory;
1017+
1018+ VIR_FREE(base);
1019+
1020+ if ((uml_driver->caps = umlCapsInit()) == NULL)
1021+ goto out_of_memory;
1022+
1023+ uml_driver->caps->privateDataAllocFunc = umlDomainObjPrivateAlloc;
1024+ uml_driver->caps->privateDataFreeFunc = umlDomainObjPrivateFree;
1025+
1026+ if ((uml_driver->inotifyFD = inotify_init()) < 0) {
1027+ VIR_ERROR0(_("cannot initialize inotify"));
1028+ goto error;
1029+ }
1030+
1031+ if (virFileMakePath(uml_driver->monitorDir) != 0) {
1032+ char ebuf[1024];
1033+ VIR_ERROR(_("Failed to create monitor directory %s: %s"),
1034+ uml_driver->monitorDir, virStrerror(errno, ebuf, sizeof ebuf));
1035+ goto error;
1036+ }
1037+
1038+ VIR_INFO("Adding inotify watch on %s", uml_driver->monitorDir);
1039+ if (inotify_add_watch(uml_driver->inotifyFD,
1040+ uml_driver->monitorDir,
1041+ IN_CREATE | IN_MODIFY | IN_DELETE) < 0) {
1042+ goto error;
1043+ }
1044+
1045+ if ((uml_driver->inotifyWatch =
1046+ virEventAddHandle(uml_driver->inotifyFD, POLLIN,
1047+ umlInotifyEvent, uml_driver, NULL)) < 0)
1048+ goto error;
1049+
1050+ if (virDomainLoadAllConfigs(uml_driver->caps,
1051+ &uml_driver->domains,
1052+ uml_driver->configDir,
1053+ uml_driver->autostartDir,
1054+ 0, NULL, NULL) < 0)
1055+ goto error;
1056+
1057+ umlAutostartConfigs(uml_driver);
1058+
1059+ umlDriverUnlock(uml_driver);
1060+ VIR_FREE(userdir);
1061+
1062+ return 0;
1063+
1064+out_of_memory:
1065+ VIR_ERROR0(_("umlStartup: out of memory"));
1066+
1067+error:
1068+ VIR_FREE(userdir);
1069+ VIR_FREE(base);
1070+ umlDriverUnlock(uml_driver);
1071+ umlShutdown();
1072+ return -1;
1073+}
1074+
1075+/**
1076+ * umlReload:
1077+ *
1078+ * Function to restart the Uml daemon, it will recheck the configuration
1079+ * files and update its state and the networking
1080+ */
1081+static int
1082+umlReload(void) {
1083+ if (!uml_driver)
1084+ return 0;
1085+
1086+ umlDriverLock(uml_driver);
1087+ virDomainLoadAllConfigs(uml_driver->caps,
1088+ &uml_driver->domains,
1089+ uml_driver->configDir,
1090+ uml_driver->autostartDir,
1091+ 0, NULL, NULL);
1092+
1093+ umlAutostartConfigs(uml_driver);
1094+ umlDriverUnlock(uml_driver);
1095+
1096+ return 0;
1097+}
1098+
1099+/**
1100+ * umlActive:
1101+ *
1102+ * Checks if the Uml daemon is active, i.e. has an active domain or
1103+ * an active network
1104+ *
1105+ * Returns 1 if active, 0 otherwise
1106+ */
1107+static int
1108+umlActive(void) {
1109+ int active = 0;
1110+
1111+ if (!uml_driver)
1112+ return 0;
1113+
1114+ umlDriverLock(uml_driver);
1115+ active = virDomainObjListNumOfDomains(&uml_driver->domains, 1);
1116+ umlDriverUnlock(uml_driver);
1117+
1118+ return active;
1119+}
1120+
1121+static void
1122+umlShutdownOneVM(void *payload, const char *name ATTRIBUTE_UNUSED, void *opaque)
1123+{
1124+ virDomainObjPtr dom = payload;
1125+ struct uml_driver *driver = opaque;
1126+
1127+ virDomainObjLock(dom);
1128+ if (virDomainObjIsActive(dom))
1129+ umlShutdownVMDaemon(NULL, driver, dom);
1130+ virDomainObjUnlock(dom);
1131+}
1132+
1133+/**
1134+ * umlShutdown:
1135+ *
1136+ * Shutdown the Uml daemon, it will stop all active domains and networks
1137+ */
1138+static int
1139+umlShutdown(void) {
1140+ if (!uml_driver)
1141+ return -1;
1142+
1143+ umlDriverLock(uml_driver);
1144+ if (uml_driver->inotifyWatch != -1)
1145+ virEventRemoveHandle(uml_driver->inotifyWatch);
1146+ close(uml_driver->inotifyFD);
1147+ virCapabilitiesFree(uml_driver->caps);
1148+
1149+ /* shutdown active VMs
1150+ * XXX allow them to stay around & reconnect */
1151+ virHashForEach(uml_driver->domains.objs, umlShutdownOneVM, uml_driver);
1152+
1153+ virDomainObjListDeinit(&uml_driver->domains);
1154+
1155+ VIR_FREE(uml_driver->logDir);
1156+ VIR_FREE(uml_driver->configDir);
1157+ VIR_FREE(uml_driver->autostartDir);
1158+ VIR_FREE(uml_driver->monitorDir);
1159+
1160+ if (uml_driver->brctl)
1161+ brShutdown(uml_driver->brctl);
1162+
1163+ umlDriverUnlock(uml_driver);
1164+ virMutexDestroy(&uml_driver->lock);
1165+ VIR_FREE(uml_driver);
1166+
1167+ return 0;
1168+}
1169+
1170+
1171+static int umlReadPidFile(struct uml_driver *driver,
1172+ virDomainObjPtr vm)
1173+{
1174+ int rc = -1;
1175+ FILE *file;
1176+ char *pidfile = NULL;
1177+ int retries = 0;
1178+
1179+ vm->pid = -1;
1180+ if (virAsprintf(&pidfile, "%s/%s/pid",
1181+ driver->monitorDir, vm->def->name) < 0) {
1182+ virReportOOMError();
1183+ return -1;
1184+ }
1185+
1186+reopen:
1187+ if (!(file = fopen(pidfile, "r"))) {
1188+ if (errno == ENOENT &&
1189+ retries++ < 50) {
1190+ usleep(1000 * 100);
1191+ goto reopen;
1192+ }
1193+ goto cleanup;
1194+ }
1195+
1196+ if (fscanf(file, "%d", &vm->pid) != 1) {
1197+ errno = EINVAL;
1198+ fclose(file);
1199+ goto cleanup;
1200+ }
1201+
1202+ if (fclose(file) < 0)
1203+ goto cleanup;
1204+
1205+ rc = 0;
1206+
1207+ cleanup:
1208+ if (rc != 0)
1209+ virReportSystemError(errno,
1210+ _("failed to read pid: %s"),
1211+ pidfile);
1212+ VIR_FREE(pidfile);
1213+ return rc;
1214+}
1215+
1216+static int umlMonitorAddress(const struct uml_driver *driver,
1217+ virDomainObjPtr vm,
1218+ struct sockaddr_un *addr) {
1219+ char *sockname;
1220+ int retval = 0;
1221+
1222+ if (virAsprintf(&sockname, "%s/%s/mconsole",
1223+ driver->monitorDir, vm->def->name) < 0) {
1224+ virReportOOMError();
1225+ return -1;
1226+ }
1227+
1228+ memset(addr, 0, sizeof *addr);
1229+ addr->sun_family = AF_UNIX;
1230+ if (virStrcpyStatic(addr->sun_path, sockname) == NULL) {
1231+ umlReportError(VIR_ERR_INTERNAL_ERROR,
1232+ _("Unix path %s too long for destination"), sockname);
1233+ retval = -1;
1234+ }
1235+ VIR_FREE(sockname);
1236+ return retval;
1237+}
1238+
1239+static int umlOpenMonitor(struct uml_driver *driver,
1240+ virDomainObjPtr vm) {
1241+ struct sockaddr_un addr;
1242+ struct stat sb;
1243+ int retries = 0;
1244+ umlDomainObjPrivatePtr priv = vm->privateData;
1245+
1246+ if (umlMonitorAddress(driver, vm, &addr) < 0)
1247+ return -1;
1248+
1249+ VIR_DEBUG("Dest address for monitor is '%s'", addr.sun_path);
1250+restat:
1251+ if (stat(addr.sun_path, &sb) < 0) {
1252+ if (errno == ENOENT &&
1253+ retries++ < 50) {
1254+ usleep(1000 * 100);
1255+ goto restat;
1256+ }
1257+ return -1;
1258+ }
1259+
1260+ if ((priv->monitor = socket(PF_UNIX, SOCK_DGRAM, 0)) < 0) {
1261+ virReportSystemError(errno,
1262+ "%s", _("cannot open socket"));
1263+ return -1;
1264+ }
1265+
1266+ memset(addr.sun_path, 0, sizeof addr.sun_path);
1267+ sprintf(addr.sun_path + 1, "libvirt-uml-%u", vm->pid);
1268+ VIR_DEBUG("Reply address for monitor is '%s'", addr.sun_path+1);
1269+ if (bind(priv->monitor, (struct sockaddr *)&addr, sizeof addr) < 0) {
1270+ virReportSystemError(errno,
1271+ "%s", _("cannot bind socket"));
1272+ close(priv->monitor);
1273+ priv->monitor = -1;
1274+ return -1;
1275+ }
1276+
1277+ return 0;
1278+}
1279+
1280+
1281+#define MONITOR_MAGIC 0xcafebabe
1282+#define MONITOR_BUFLEN 512
1283+#define MONITOR_VERSION 2
1284+
1285+struct monitor_request {
1286+ uint32_t magic;
1287+ uint32_t version;
1288+ uint32_t length;
1289+ char data[MONITOR_BUFLEN];
1290+};
1291+
1292+struct monitor_response {
1293+ uint32_t error;
1294+ uint32_t extra;
1295+ uint32_t length;
1296+ char data[MONITOR_BUFLEN];
1297+};
1298+
1299+
1300+static int umlMonitorCommand(const struct uml_driver *driver,
1301+ const virDomainObjPtr vm,
1302+ const char *cmd,
1303+ char **reply)
1304+{
1305+ struct monitor_request req;
1306+ struct monitor_response res;
1307+ char *retdata = NULL;
1308+ int retlen = 0, ret = 0;
1309+ struct sockaddr_un addr;
1310+ unsigned int addrlen;
1311+ umlDomainObjPrivatePtr priv = vm->privateData;
1312+
1313+ VIR_DEBUG("Run command '%s'", cmd);
1314+
1315+ *reply = NULL;
1316+
1317+ if (umlMonitorAddress(driver, vm, &addr) < 0)
1318+ return -1;
1319+
1320+ memset(&req, 0, sizeof(req));
1321+ req.magic = MONITOR_MAGIC;
1322+ req.version = MONITOR_VERSION;
1323+ req.length = strlen(cmd);
1324+ if (req.length > (MONITOR_BUFLEN-1)) {
1325+ virReportSystemError(EINVAL,
1326+ _("cannot send too long command %s (%d bytes)"),
1327+ cmd, req.length);
1328+ return -1;
1329+ }
1330+ if (virStrcpyStatic(req.data, cmd) == NULL) {
1331+ umlReportError(VIR_ERR_INTERNAL_ERROR,
1332+ _("Command %s too long for destination"), cmd);
1333+ return -1;
1334+ }
1335+
1336+ if (sendto(priv->monitor, &req, sizeof req, 0,
1337+ (struct sockaddr *)&addr, sizeof addr) != (sizeof req)) {
1338+ virReportSystemError(errno,
1339+ _("cannot send command %s"),
1340+ cmd);
1341+ return -1;
1342+ }
1343+
1344+ do {
1345+ ssize_t nbytes;
1346+ addrlen = sizeof(addr);
1347+ nbytes = recvfrom(priv->monitor, &res, sizeof res, 0,
1348+ (struct sockaddr *)&addr, &addrlen);
1349+ if (nbytes < 0) {
1350+ if (errno == EAGAIN || errno == EINTR)
1351+ continue;
1352+ virReportSystemError(errno, _("cannot read reply %s"), cmd);
1353+ goto error;
1354+ }
1355+ /* Ensure res.length is safe to read before validating its value. */
1356+ if (nbytes < offsetof(struct monitor_request, data) ||
1357+ nbytes < offsetof(struct monitor_request, data) + res.length) {
1358+ virReportSystemError(0, _("incomplete reply %s"), cmd);
1359+ goto error;
1360+ }
1361+
1362+ if (VIR_REALLOC_N(retdata, retlen + res.length) < 0) {
1363+ virReportOOMError();
1364+ goto error;
1365+ }
1366+ memcpy(retdata + retlen, res.data, res.length);
1367+ retlen += res.length - 1;
1368+ retdata[retlen] = '\0';
1369+
1370+ if (res.error)
1371+ ret = -1;
1372+
1373+ } while (res.extra);
1374+
1375+ VIR_DEBUG("Command reply is '%s'", NULLSTR(retdata));
1376+
1377+ if (ret < 0)
1378+ VIR_FREE(retdata);
1379+ else
1380+ *reply = retdata;
1381+
1382+ return ret;
1383+
1384+error:
1385+ VIR_FREE(retdata);
1386+ return -1;
1387+}
1388+
1389+
1390+static int umlCleanupTapDevices(virConnectPtr conn ATTRIBUTE_UNUSED,
1391+ virDomainObjPtr vm) {
1392+ int i;
1393+ int err;
1394+ int ret = 0;
1395+ brControl *brctl = NULL;
1396+ VIR_ERROR0(_("Cleanup tap"));
1397+ if (brInit(&brctl) < 0)
1398+ return -1;
1399+
1400+ for (i = 0 ; i < vm->def->nnets ; i++) {
1401+ virDomainNetDefPtr def = vm->def->nets[i];
1402+
1403+ if (def->type != VIR_DOMAIN_NET_TYPE_BRIDGE &&
1404+ def->type != VIR_DOMAIN_NET_TYPE_NETWORK)
1405+ continue;
1406+
1407+ VIR_ERROR(_("Cleanup '%s'"), def->ifname);
1408+ err = brDeleteTap(brctl, def->ifname);
1409+ if (err) {
1410+ VIR_ERROR(_("Cleanup failed %d"), err);
1411+ ret = -1;
1412+ }
1413+ }
1414+ VIR_ERROR0(_("Cleanup tap done"));
1415+ brShutdown(brctl);
1416+ return ret;
1417+}
1418+
1419+static int umlStartVMDaemon(virConnectPtr conn,
1420+ struct uml_driver *driver,
1421+ virDomainObjPtr vm) {
1422+ const char **argv = NULL, **tmp;
1423+ const char **progenv = NULL;
1424+ int i, ret;
1425+ pid_t pid;
1426+ char *logfile;
1427+ int logfd = -1;
1428+ struct stat sb;
1429+ fd_set keepfd;
1430+ char ebuf[1024];
1431+ umlDomainObjPrivatePtr priv = vm->privateData;
1432+
1433+ FD_ZERO(&keepfd);
1434+
1435+ if (virDomainObjIsActive(vm)) {
1436+ umlReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1437+ _("VM is already active"));
1438+ return -1;
1439+ }
1440+
1441+ if (!vm->def->os.kernel) {
1442+ umlReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1443+ _("no kernel specified"));
1444+ return -1;
1445+ }
1446+ /* Make sure the binary we are about to try exec'ing exists.
1447+ * Technically we could catch the exec() failure, but that's
1448+ * in a sub-process so its hard to feed back a useful error
1449+ */
1450+ if (stat(vm->def->os.kernel, &sb) < 0) {
1451+ virReportSystemError(errno,
1452+ _("Cannot find UML kernel %s"),
1453+ vm->def->os.kernel);
1454+ return -1;
1455+ }
1456+
1457+ if (virFileMakePath(driver->logDir) != 0) {
1458+ virReportSystemError(errno,
1459+ _("cannot create log directory %s"),
1460+ driver->logDir);
1461+ return -1;
1462+ }
1463+
1464+ if (virAsprintf(&logfile, "%s/%s.log",
1465+ driver->logDir, vm->def->name) < 0) {
1466+ virReportOOMError();
1467+ return -1;
1468+ }
1469+
1470+ if ((logfd = open(logfile, O_CREAT | O_TRUNC | O_WRONLY,
1471+ S_IRUSR | S_IWUSR)) < 0) {
1472+ virReportSystemError(errno,
1473+ _("failed to create logfile %s"),
1474+ logfile);
1475+ VIR_FREE(logfile);
1476+ return -1;
1477+ }
1478+ VIR_FREE(logfile);
1479+
1480+ if (umlSetCloseExec(logfd) < 0) {
1481+ virReportSystemError(errno,
1482+ "%s", _("Unable to set VM logfile close-on-exec flag"));
1483+ close(logfd);
1484+ return -1;
1485+ }
1486+
1487+ if (umlBuildCommandLine(conn, driver, vm, &keepfd,
1488+ &argv, &progenv) < 0) {
1489+ close(logfd);
1490+ umlCleanupTapDevices(conn, vm);
1491+ return -1;
1492+ }
1493+
1494+ tmp = progenv;
1495+ while (*tmp) {
1496+ if (safewrite(logfd, *tmp, strlen(*tmp)) < 0)
1497+ VIR_WARN("Unable to write envv to logfile: %s",
1498+ virStrerror(errno, ebuf, sizeof ebuf));
1499+ if (safewrite(logfd, " ", 1) < 0)
1500+ VIR_WARN("Unable to write envv to logfile: %s",
1501+ virStrerror(errno, ebuf, sizeof ebuf));
1502+ tmp++;
1503+ }
1504+ tmp = argv;
1505+ while (*tmp) {
1506+ if (safewrite(logfd, *tmp, strlen(*tmp)) < 0)
1507+ VIR_WARN("Unable to write argv to logfile: %s",
1508+ virStrerror(errno, ebuf, sizeof ebuf));
1509+ if (safewrite(logfd, " ", 1) < 0)
1510+ VIR_WARN("Unable to write argv to logfile: %s",
1511+ virStrerror(errno, ebuf, sizeof ebuf));
1512+ tmp++;
1513+ }
1514+ if (safewrite(logfd, "\n", 1) < 0)
1515+ VIR_WARN("Unable to write argv to logfile: %s",
1516+ virStrerror(errno, ebuf, sizeof ebuf));
1517+
1518+ priv->monitor = -1;
1519+
1520+ ret = virExecDaemonize(argv, progenv, &keepfd, &pid,
1521+ -1, &logfd, &logfd,
1522+ VIR_EXEC_CLEAR_CAPS,
1523+ NULL, NULL, NULL);
1524+ close(logfd);
1525+
1526+ /*
1527+ * At the moment, the only thing that populates keepfd is
1528+ * umlBuildCommandLineChr. We want to close every fd it opens.
1529+ */
1530+ for (i = 0; i < FD_SETSIZE; i++)
1531+ if (FD_ISSET(i, &keepfd))
1532+ close(i);
1533+
1534+ for (i = 0 ; argv[i] ; i++)
1535+ VIR_FREE(argv[i]);
1536+ VIR_FREE(argv);
1537+
1538+ for (i = 0 ; progenv[i] ; i++)
1539+ VIR_FREE(progenv[i]);
1540+ VIR_FREE(progenv);
1541+
1542+ if (ret < 0)
1543+ umlCleanupTapDevices(conn, vm);
1544+
1545+ /* NB we don't mark it running here - we do that async
1546+ with inotify */
1547+ /* XXX what if someone else tries to start it again
1548+ before we get the inotification ? Sounds like
1549+ trouble.... */
1550+
1551+ return ret;
1552+}
1553+
1554+static void umlShutdownVMDaemon(virConnectPtr conn ATTRIBUTE_UNUSED,
1555+ struct uml_driver *driver ATTRIBUTE_UNUSED,
1556+ virDomainObjPtr vm)
1557+{
1558+ int ret;
1559+ umlDomainObjPrivatePtr priv = vm->privateData;
1560+
1561+ if (!virDomainObjIsActive(vm))
1562+ return;
1563+
1564+ virKillProcess(vm->pid, SIGTERM);
1565+
1566+ if (priv->monitor != -1)
1567+ close(priv->monitor);
1568+ priv->monitor = -1;
1569+
1570+ if ((ret = waitpid(vm->pid, NULL, 0)) != vm->pid) {
1571+ VIR_WARN("Got unexpected pid %d != %d",
1572+ ret, vm->pid);
1573+ }
1574+
1575+ vm->pid = -1;
1576+ vm->def->id = -1;
1577+ vm->state = VIR_DOMAIN_SHUTOFF;
1578+
1579+ umlCleanupTapDevices(conn, vm);
1580+
1581+ if (vm->newDef) {
1582+ virDomainDefFree(vm->def);
1583+ vm->def = vm->newDef;
1584+ vm->def->id = -1;
1585+ vm->newDef = NULL;
1586+ }
1587+}
1588+
1589+
1590+static virDrvOpenStatus umlOpen(virConnectPtr conn,
1591+ virConnectAuthPtr auth ATTRIBUTE_UNUSED,
1592+ int flags ATTRIBUTE_UNUSED) {
1593+ if (conn->uri == NULL) {
1594+ if (uml_driver == NULL)
1595+ return VIR_DRV_OPEN_DECLINED;
1596+
1597+ conn->uri = xmlParseURI(uml_driver->privileged ?
1598+ "uml:///system" :
1599+ "uml:///session");
1600+ if (!conn->uri) {
1601+ virReportOOMError();
1602+ return VIR_DRV_OPEN_ERROR;
1603+ }
1604+ } else {
1605+ if (conn->uri->scheme == NULL ||
1606+ STRNEQ (conn->uri->scheme, "uml"))
1607+ return VIR_DRV_OPEN_DECLINED;
1608+
1609+ /* Allow remote driver to deal with URIs with hostname server */
1610+ if (conn->uri->server != NULL)
1611+ return VIR_DRV_OPEN_DECLINED;
1612+
1613+
1614+ /* Check path and tell them correct path if they made a mistake */
1615+ if (uml_driver->privileged) {
1616+ if (STRNEQ (conn->uri->path, "/system") &&
1617+ STRNEQ (conn->uri->path, "/session")) {
1618+ umlReportError(VIR_ERR_INTERNAL_ERROR,
1619+ _("unexpected UML URI path '%s', try uml:///system"),
1620+ conn->uri->path);
1621+ return VIR_DRV_OPEN_ERROR;
1622+ }
1623+ } else {
1624+ if (STRNEQ (conn->uri->path, "/session")) {
1625+ umlReportError(VIR_ERR_INTERNAL_ERROR,
1626+ _("unexpected UML URI path '%s', try uml:///session"),
1627+ conn->uri->path);
1628+ return VIR_DRV_OPEN_ERROR;
1629+ }
1630+ }
1631+
1632+ /* URI was good, but driver isn't active */
1633+ if (uml_driver == NULL) {
1634+ umlReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1635+ _("uml state driver is not active"));
1636+ return VIR_DRV_OPEN_ERROR;
1637+ }
1638+ }
1639+
1640+ conn->privateData = uml_driver;
1641+
1642+ return VIR_DRV_OPEN_SUCCESS;
1643+}
1644+
1645+static int umlClose(virConnectPtr conn) {
1646+ /*struct uml_driver *driver = conn->privateData;*/
1647+
1648+ conn->privateData = NULL;
1649+
1650+ return 0;
1651+}
1652+
1653+static const char *umlGetType(virConnectPtr conn ATTRIBUTE_UNUSED) {
1654+ return "UML";
1655+}
1656+
1657+
1658+static int umlIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED)
1659+{
1660+ /* Trivially secure, since always inside the daemon */
1661+ return 1;
1662+}
1663+
1664+
1665+static int umlIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED)
1666+{
1667+ /* Not encrypted, but remote driver takes care of that */
1668+ return 0;
1669+}
1670+
1671+
1672+static char *umlGetCapabilities(virConnectPtr conn) {
1673+ struct uml_driver *driver = (struct uml_driver *)conn->privateData;
1674+ char *xml;
1675+
1676+ umlDriverLock(driver);
1677+ if ((xml = virCapabilitiesFormatXML(driver->caps)) == NULL)
1678+ virReportOOMError();
1679+ umlDriverUnlock(driver);
1680+
1681+ return xml;
1682+}
1683+
1684+
1685+
1686+static int umlGetProcessInfo(unsigned long long *cpuTime, int pid) {
1687+ char proc[PATH_MAX];
1688+ FILE *pidinfo;
1689+ unsigned long long usertime, systime;
1690+
1691+ if (snprintf(proc, sizeof(proc), "/proc/%d/stat", pid) >= (int)sizeof(proc)) {
1692+ return -1;
1693+ }
1694+
1695+ if (!(pidinfo = fopen(proc, "r"))) {
1696+ /*printf("cannot read pid info");*/
1697+ /* VM probably shut down, so fake 0 */
1698+ *cpuTime = 0;
1699+ return 0;
1700+ }
1701+
1702+ if (fscanf(pidinfo, "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %llu %llu", &usertime, &systime) != 2) {
1703+ umlDebug("not enough arg");
1704+ fclose(pidinfo);
1705+ return -1;
1706+ }
1707+
1708+ /* We got jiffies
1709+ * We want nanoseconds
1710+ * _SC_CLK_TCK is jiffies per second
1711+ * So calulate thus....
1712+ */
1713+ *cpuTime = 1000ull * 1000ull * 1000ull * (usertime + systime) / (unsigned long long)sysconf(_SC_CLK_TCK);
1714+
1715+ umlDebug("Got %llu %llu %llu", usertime, systime, *cpuTime);
1716+
1717+ fclose(pidinfo);
1718+
1719+ return 0;
1720+}
1721+
1722+
1723+static virDomainPtr umlDomainLookupByID(virConnectPtr conn,
1724+ int id) {
1725+ struct uml_driver *driver = (struct uml_driver *)conn->privateData;
1726+ virDomainObjPtr vm;
1727+ virDomainPtr dom = NULL;
1728+
1729+ umlDriverLock(driver);
1730+ vm = virDomainFindByID(&driver->domains, id);
1731+ umlDriverUnlock(driver);
1732+
1733+ if (!vm) {
1734+ umlReportError(VIR_ERR_NO_DOMAIN, NULL);
1735+ goto cleanup;
1736+ }
1737+
1738+ dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
1739+ if (dom) dom->id = vm->def->id;
1740+
1741+cleanup:
1742+ if (vm)
1743+ virDomainObjUnlock(vm);
1744+ return dom;
1745+}
1746+
1747+static virDomainPtr umlDomainLookupByUUID(virConnectPtr conn,
1748+ const unsigned char *uuid) {
1749+ struct uml_driver *driver = (struct uml_driver *)conn->privateData;
1750+ virDomainObjPtr vm;
1751+ virDomainPtr dom = NULL;
1752+
1753+ umlDriverLock(driver);
1754+ vm = virDomainFindByUUID(&driver->domains, uuid);
1755+ umlDriverUnlock(driver);
1756+
1757+ if (!vm) {
1758+ umlReportError(VIR_ERR_NO_DOMAIN, NULL);
1759+ goto cleanup;
1760+ }
1761+
1762+ dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
1763+ if (dom) dom->id = vm->def->id;
1764+
1765+cleanup:
1766+ if (vm)
1767+ virDomainObjUnlock(vm);
1768+ return dom;
1769+}
1770+
1771+static virDomainPtr umlDomainLookupByName(virConnectPtr conn,
1772+ const char *name) {
1773+ struct uml_driver *driver = (struct uml_driver *)conn->privateData;
1774+ virDomainObjPtr vm;
1775+ virDomainPtr dom = NULL;
1776+
1777+ umlDriverLock(driver);
1778+ vm = virDomainFindByName(&driver->domains, name);
1779+ umlDriverUnlock(driver);
1780+
1781+ if (!vm) {
1782+ umlReportError(VIR_ERR_NO_DOMAIN, NULL);
1783+ goto cleanup;
1784+ }
1785+
1786+ dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
1787+ if (dom) dom->id = vm->def->id;
1788+
1789+cleanup:
1790+ if (vm)
1791+ virDomainObjUnlock(vm);
1792+ return dom;
1793+}
1794+
1795+
1796+static int umlDomainIsActive(virDomainPtr dom)
1797+{
1798+ struct uml_driver *driver = dom->conn->privateData;
1799+ virDomainObjPtr obj;
1800+ int ret = -1;
1801+
1802+ umlDriverLock(driver);
1803+ obj = virDomainFindByUUID(&driver->domains, dom->uuid);
1804+ umlDriverUnlock(driver);
1805+ if (!obj) {
1806+ umlReportError(VIR_ERR_NO_DOMAIN, NULL);
1807+ goto cleanup;
1808+ }
1809+ ret = virDomainObjIsActive(obj);
1810+
1811+cleanup:
1812+ if (obj)
1813+ virDomainObjUnlock(obj);
1814+ return ret;
1815+}
1816+
1817+
1818+static int umlDomainIsPersistent(virDomainPtr dom)
1819+{
1820+ struct uml_driver *driver = dom->conn->privateData;
1821+ virDomainObjPtr obj;
1822+ int ret = -1;
1823+
1824+ umlDriverLock(driver);
1825+ obj = virDomainFindByUUID(&driver->domains, dom->uuid);
1826+ umlDriverUnlock(driver);
1827+ if (!obj) {
1828+ umlReportError(VIR_ERR_NO_DOMAIN, NULL);
1829+ goto cleanup;
1830+ }
1831+ ret = obj->persistent;
1832+
1833+cleanup:
1834+ if (obj)
1835+ virDomainObjUnlock(obj);
1836+ return ret;
1837+}
1838+
1839+
1840+static int umlGetVersion(virConnectPtr conn, unsigned long *version) {
1841+ struct uml_driver *driver = conn->privateData;
1842+ struct utsname ut;
1843+ int ret = -1;
1844+
1845+ umlDriverLock(driver);
1846+
1847+ if (driver->umlVersion == 0) {
1848+ uname(&ut);
1849+
1850+ if (virParseVersionString(ut.release, &driver->umlVersion) < 0) {
1851+ umlReportError(VIR_ERR_INTERNAL_ERROR,
1852+ _("cannot parse version %s"), ut.release);
1853+ goto cleanup;
1854+ }
1855+ }
1856+
1857+ *version = driver->umlVersion;
1858+ ret = 0;
1859+
1860+cleanup:
1861+ umlDriverUnlock(driver);
1862+ return ret;
1863+}
1864+
1865+static int umlListDomains(virConnectPtr conn, int *ids, int nids) {
1866+ struct uml_driver *driver = conn->privateData;
1867+ int n;
1868+
1869+ umlDriverLock(driver);
1870+ n = virDomainObjListGetActiveIDs(&driver->domains, ids, nids);
1871+ umlDriverUnlock(driver);
1872+
1873+ return n;
1874+}
1875+static int umlNumDomains(virConnectPtr conn) {
1876+ struct uml_driver *driver = conn->privateData;
1877+ int n;
1878+
1879+ umlDriverLock(driver);
1880+ n = virDomainObjListNumOfDomains(&driver->domains, 1);
1881+ umlDriverUnlock(driver);
1882+
1883+ return n;
1884+}
1885+static virDomainPtr umlDomainCreate(virConnectPtr conn, const char *xml,
1886+ unsigned int flags) {
1887+ struct uml_driver *driver = conn->privateData;
1888+ virDomainDefPtr def;
1889+ virDomainObjPtr vm = NULL;
1890+ virDomainPtr dom = NULL;
1891+
1892+ virCheckFlags(0, NULL);
1893+
1894+ umlDriverLock(driver);
1895+ if (!(def = virDomainDefParseString(driver->caps, xml,
1896+ VIR_DOMAIN_XML_INACTIVE)))
1897+ goto cleanup;
1898+
1899+ if (virDomainObjIsDuplicate(&driver->domains, def, 1) < 0)
1900+ goto cleanup;
1901+
1902+ if (!(vm = virDomainAssignDef(driver->caps,
1903+ &driver->domains,
1904+ def, false)))
1905+ goto cleanup;
1906+ def = NULL;
1907+
1908+ if (umlStartVMDaemon(conn, driver, vm) < 0) {
1909+ virDomainRemoveInactive(&driver->domains,
1910+ vm);
1911+ vm = NULL;
1912+ goto cleanup;
1913+ }
1914+
1915+ dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
1916+ if (dom) dom->id = vm->def->id;
1917+
1918+cleanup:
1919+ virDomainDefFree(def);
1920+ if (vm)
1921+ virDomainObjUnlock(vm);
1922+ umlDriverUnlock(driver);
1923+ return dom;
1924+}
1925+
1926+
1927+static int umlDomainShutdown(virDomainPtr dom) {
1928+ struct uml_driver *driver = dom->conn->privateData;
1929+ virDomainObjPtr vm;
1930+ char *info = NULL;
1931+ int ret = -1;
1932+
1933+ umlDriverLock(driver);
1934+ vm = virDomainFindByID(&driver->domains, dom->id);
1935+ umlDriverUnlock(driver);
1936+ if (!vm) {
1937+ umlReportError(VIR_ERR_INVALID_DOMAIN,
1938+ _("no domain with matching id %d"), dom->id);
1939+ goto cleanup;
1940+ }
1941+
1942+#if 0
1943+ if (umlMonitorCommand(driver, vm, "system_powerdown", &info) < 0) {
1944+ umlReportError(VIR_ERR_OPERATION_FAILED, "%s",
1945+ _("shutdown operation failed"));
1946+ goto cleanup;
1947+ }
1948+ ret = 0;
1949+#endif
1950+
1951+cleanup:
1952+ VIR_FREE(info);
1953+ if (vm)
1954+ virDomainObjUnlock(vm);
1955+ return ret;
1956+}
1957+
1958+
1959+static int umlDomainDestroy(virDomainPtr dom) {
1960+ struct uml_driver *driver = dom->conn->privateData;
1961+ virDomainObjPtr vm;
1962+ int ret = -1;
1963+
1964+ umlDriverLock(driver);
1965+ vm = virDomainFindByID(&driver->domains, dom->id);
1966+ if (!vm) {
1967+ umlReportError(VIR_ERR_INVALID_DOMAIN,
1968+ _("no domain with matching id %d"), dom->id);
1969+ goto cleanup;
1970+ }
1971+
1972+ umlShutdownVMDaemon(dom->conn, driver, vm);
1973+ if (!vm->persistent) {
1974+ virDomainRemoveInactive(&driver->domains,
1975+ vm);
1976+ vm = NULL;
1977+ }
1978+ ret = 0;
1979+
1980+cleanup:
1981+ if (vm)
1982+ virDomainObjUnlock(vm);
1983+ umlDriverUnlock(driver);
1984+ return ret;
1985+}
1986+
1987+
1988+static char *umlDomainGetOSType(virDomainPtr dom) {
1989+ struct uml_driver *driver = dom->conn->privateData;
1990+ virDomainObjPtr vm;
1991+ char *type = NULL;
1992+
1993+ umlDriverLock(driver);
1994+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1995+ umlDriverUnlock(driver);
1996+ if (!vm) {
1997+ umlReportError(VIR_ERR_INVALID_DOMAIN, "%s",
1998+ _("no domain with matching uuid"));
1999+ goto cleanup;
2000+ }
2001+
2002+ if (!(type = strdup(vm->def->os.type)))
2003+ virReportOOMError();
2004+
2005+cleanup:
2006+ if (vm)
2007+ virDomainObjUnlock(vm);
2008+ return type;
2009+}
2010+
2011+/* Returns max memory in kb, 0 if error */
2012+static unsigned long umlDomainGetMaxMemory(virDomainPtr dom) {
2013+ struct uml_driver *driver = dom->conn->privateData;
2014+ virDomainObjPtr vm;
2015+ unsigned long ret = 0;
2016+
2017+ umlDriverLock(driver);
2018+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
2019+ umlDriverUnlock(driver);
2020+
2021+ if (!vm) {
2022+ char uuidstr[VIR_UUID_STRING_BUFLEN];
2023+
2024+ virUUIDFormat(dom->uuid, uuidstr);
2025+ umlReportError(VIR_ERR_INVALID_DOMAIN,
2026+ _("no domain with matching uuid '%s'"), uuidstr);
2027+ goto cleanup;
2028+ }
2029+ ret = vm->def->maxmem;
2030+
2031+cleanup:
2032+ if (vm)
2033+ virDomainObjUnlock(vm);
2034+ return ret;
2035+}
2036+
2037+static int umlDomainSetMaxMemory(virDomainPtr dom, unsigned long newmax) {
2038+ struct uml_driver *driver = dom->conn->privateData;
2039+ virDomainObjPtr vm;
2040+ int ret = -1;
2041+
2042+ umlDriverLock(driver);
2043+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
2044+ umlDriverUnlock(driver);
2045+
2046+ if (!vm) {
2047+ char uuidstr[VIR_UUID_STRING_BUFLEN];
2048+
2049+ virUUIDFormat(dom->uuid, uuidstr);
2050+ umlReportError(VIR_ERR_INVALID_DOMAIN,
2051+ _("no domain with matching uuid '%s'"), uuidstr);
2052+ goto cleanup;
2053+ }
2054+
2055+ if (newmax < vm->def->memory) {
2056+ umlReportError(VIR_ERR_INVALID_ARG, "%s",
2057+ _("cannot set max memory lower than current memory"));
2058+ goto cleanup;
2059+ }
2060+
2061+ vm->def->maxmem = newmax;
2062+ ret = 0;
2063+
2064+cleanup:
2065+ if (vm)
2066+ virDomainObjUnlock(vm);
2067+ return ret;
2068+}
2069+
2070+static int umlDomainSetMemory(virDomainPtr dom, unsigned long newmem) {
2071+ struct uml_driver *driver = dom->conn->privateData;
2072+ virDomainObjPtr vm;
2073+ int ret = -1;
2074+
2075+ umlDriverLock(driver);
2076+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
2077+ umlDriverUnlock(driver);
2078+
2079+ if (!vm) {
2080+ char uuidstr[VIR_UUID_STRING_BUFLEN];
2081+
2082+ virUUIDFormat(dom->uuid, uuidstr);
2083+ umlReportError(VIR_ERR_INVALID_DOMAIN,
2084+ _("no domain with matching uuid '%s'"), uuidstr);
2085+ goto cleanup;
2086+ }
2087+
2088+ if (virDomainObjIsActive(vm)) {
2089+ umlReportError(VIR_ERR_NO_SUPPORT, "%s",
2090+ _("cannot set memory of an active domain"));
2091+ goto cleanup;
2092+ }
2093+
2094+ if (newmem > vm->def->maxmem) {
2095+ umlReportError(VIR_ERR_INVALID_ARG, "%s",
2096+ _("cannot set memory higher than max memory"));
2097+ goto cleanup;
2098+ }
2099+
2100+ vm->def->memory = newmem;
2101+ ret = 0;
2102+
2103+cleanup:
2104+ if (vm)
2105+ virDomainObjUnlock(vm);
2106+ return ret;
2107+}
2108+
2109+static int umlDomainGetInfo(virDomainPtr dom,
2110+ virDomainInfoPtr info) {
2111+ struct uml_driver *driver = dom->conn->privateData;
2112+ virDomainObjPtr vm;
2113+ int ret = -1;
2114+
2115+ umlDriverLock(driver);
2116+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
2117+ umlDriverUnlock(driver);
2118+
2119+ if (!vm) {
2120+ umlReportError(VIR_ERR_INVALID_DOMAIN, "%s",
2121+ _("no domain with matching uuid"));
2122+ goto cleanup;
2123+ }
2124+
2125+ info->state = vm->state;
2126+
2127+ if (!virDomainObjIsActive(vm)) {
2128+ info->cpuTime = 0;
2129+ } else {
2130+ if (umlGetProcessInfo(&(info->cpuTime), vm->pid) < 0) {
2131+ umlReportError(VIR_ERR_OPERATION_FAILED, "%s",
2132+ _("cannot read cputime for domain"));
2133+ goto cleanup;
2134+ }
2135+ }
2136+
2137+ info->maxMem = vm->def->maxmem;
2138+ info->memory = vm->def->memory;
2139+ info->nrVirtCpu = vm->def->vcpus;
2140+ ret = 0;
2141+
2142+cleanup:
2143+ if (vm)
2144+ virDomainObjUnlock(vm);
2145+ return ret;
2146+}
2147+
2148+
2149+static char *umlDomainDumpXML(virDomainPtr dom,
2150+ int flags ATTRIBUTE_UNUSED) {
2151+ struct uml_driver *driver = dom->conn->privateData;
2152+ virDomainObjPtr vm;
2153+ char *ret = NULL;
2154+
2155+ umlDriverLock(driver);
2156+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
2157+ umlDriverUnlock(driver);
2158+
2159+ if (!vm) {
2160+ umlReportError(VIR_ERR_INVALID_DOMAIN, "%s",
2161+ _("no domain with matching uuid"));
2162+ goto cleanup;
2163+ }
2164+
2165+ ret = virDomainDefFormat((flags & VIR_DOMAIN_XML_INACTIVE) && vm->newDef ?
2166+ vm->newDef : vm->def,
2167+ flags);
2168+
2169+cleanup:
2170+ if (vm)
2171+ virDomainObjUnlock(vm);
2172+ return ret;
2173+}
2174+
2175+
2176+static int umlListDefinedDomains(virConnectPtr conn,
2177+ char **const names, int nnames) {
2178+ struct uml_driver *driver = conn->privateData;
2179+ int n;
2180+
2181+ umlDriverLock(driver);
2182+ n = virDomainObjListGetInactiveNames(&driver->domains, names, nnames);
2183+ umlDriverUnlock(driver);
2184+
2185+ return n;
2186+}
2187+
2188+static int umlNumDefinedDomains(virConnectPtr conn) {
2189+ struct uml_driver *driver = conn->privateData;
2190+ int n;
2191+
2192+ umlDriverLock(driver);
2193+ n = virDomainObjListNumOfDomains(&driver->domains, 0);
2194+ umlDriverUnlock(driver);
2195+
2196+ return n;
2197+}
2198+
2199+
2200+static int umlDomainStartWithFlags(virDomainPtr dom, unsigned int flags) {
2201+ struct uml_driver *driver = dom->conn->privateData;
2202+ virDomainObjPtr vm;
2203+ int ret = -1;
2204+
2205+ virCheckFlags(0, -1);
2206+
2207+ umlDriverLock(driver);
2208+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
2209+
2210+ if (!vm) {
2211+ umlReportError(VIR_ERR_INVALID_DOMAIN, "%s",
2212+ _("no domain with matching uuid"));
2213+ goto cleanup;
2214+ }
2215+
2216+ ret = umlStartVMDaemon(dom->conn, driver, vm);
2217+
2218+cleanup:
2219+ if (vm)
2220+ virDomainObjUnlock(vm);
2221+ umlDriverUnlock(driver);
2222+ return ret;
2223+}
2224+
2225+static int umlDomainStart(virDomainPtr dom) {
2226+ return umlDomainStartWithFlags(dom, 0);
2227+}
2228+
2229+static virDomainPtr umlDomainDefine(virConnectPtr conn, const char *xml) {
2230+ struct uml_driver *driver = conn->privateData;
2231+ virDomainDefPtr def;
2232+ virDomainObjPtr vm = NULL;
2233+ virDomainPtr dom = NULL;
2234+
2235+ umlDriverLock(driver);
2236+ if (!(def = virDomainDefParseString(driver->caps, xml,
2237+ VIR_DOMAIN_XML_INACTIVE)))
2238+ goto cleanup;
2239+
2240+ if (virDomainObjIsDuplicate(&driver->domains, def, 0) < 0)
2241+ goto cleanup;
2242+
2243+ if (!(vm = virDomainAssignDef(driver->caps,
2244+ &driver->domains,
2245+ def, false)))
2246+ goto cleanup;
2247+ def = NULL;
2248+ vm->persistent = 1;
2249+
2250+ if (virDomainSaveConfig(driver->configDir,
2251+ vm->newDef ? vm->newDef : vm->def) < 0) {
2252+ virDomainRemoveInactive(&driver->domains,
2253+ vm);
2254+ vm = NULL;
2255+ goto cleanup;
2256+ }
2257+
2258+ dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
2259+ if (dom) dom->id = vm->def->id;
2260+
2261+cleanup:
2262+ virDomainDefFree(def);
2263+ if (vm)
2264+ virDomainObjUnlock(vm);
2265+ umlDriverUnlock(driver);
2266+ return dom;
2267+}
2268+
2269+static int umlDomainUndefine(virDomainPtr dom) {
2270+ struct uml_driver *driver = dom->conn->privateData;
2271+ virDomainObjPtr vm;
2272+ int ret = -1;
2273+
2274+ umlDriverLock(driver);
2275+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
2276+ if (!vm) {
2277+ umlReportError(VIR_ERR_INVALID_DOMAIN, "%s",
2278+ _("no domain with matching uuid"));
2279+ goto cleanup;
2280+ }
2281+
2282+ if (virDomainObjIsActive(vm)) {
2283+ umlReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2284+ _("cannot delete active domain"));
2285+ goto cleanup;
2286+ }
2287+
2288+ if (!vm->persistent) {
2289+ umlReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2290+ _("cannot undefine transient domain"));
2291+ goto cleanup;
2292+ }
2293+
2294+ if (virDomainDeleteConfig(driver->configDir, driver->autostartDir, vm) < 0)
2295+ goto cleanup;
2296+
2297+ virDomainRemoveInactive(&driver->domains,
2298+ vm);
2299+ vm = NULL;
2300+ ret = 0;
2301+
2302+cleanup:
2303+ if (vm)
2304+ virDomainObjUnlock(vm);
2305+ umlDriverUnlock(driver);
2306+ return ret;
2307+}
2308+
2309+
2310+static int umlDomainAttachUmlDisk(struct uml_driver *driver,
2311+ virDomainObjPtr vm,
2312+ virDomainDiskDefPtr disk)
2313+{
2314+ int i;
2315+ char *cmd = NULL;
2316+ char *reply = NULL;
2317+
2318+ for (i = 0 ; i < vm->def->ndisks ; i++) {
2319+ if (STREQ(vm->def->disks[i]->dst, disk->dst)) {
2320+ umlReportError(VIR_ERR_OPERATION_FAILED,
2321+ _("target %s already exists"), disk->dst);
2322+ return -1;
2323+ }
2324+ }
2325+
2326+ if (!disk->src) {
2327+ umlReportError(VIR_ERR_INTERNAL_ERROR,
2328+ "%s", _("disk source path is missing"));
2329+ goto error;
2330+ }
2331+
2332+ if (virAsprintf(&cmd, "config %s=%s", disk->dst, disk->src) < 0) {
2333+ virReportOOMError();
2334+ return -1;
2335+ }
2336+
2337+ if (umlMonitorCommand(driver, vm, cmd, &reply) < 0)
2338+ goto error;
2339+
2340+ if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0) {
2341+ virReportOOMError();
2342+ goto error;
2343+ }
2344+
2345+ virDomainDiskInsertPreAlloced(vm->def, disk);
2346+
2347+ VIR_FREE(reply);
2348+ VIR_FREE(cmd);
2349+
2350+ return 0;
2351+
2352+error:
2353+
2354+ VIR_FREE(reply);
2355+ VIR_FREE(cmd);
2356+
2357+ return -1;
2358+}
2359+
2360+
2361+static int umlDomainAttachDevice(virDomainPtr dom, const char *xml)
2362+{
2363+ struct uml_driver *driver = dom->conn->privateData;
2364+ virDomainObjPtr vm;
2365+ virDomainDeviceDefPtr dev = NULL;
2366+ int ret = -1;
2367+
2368+ umlDriverLock(driver);
2369+
2370+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
2371+ if (!vm) {
2372+ char uuidstr[VIR_UUID_STRING_BUFLEN];
2373+ virUUIDFormat(dom->uuid, uuidstr);
2374+ umlReportError(VIR_ERR_NO_DOMAIN,
2375+ _("no domain with matching uuid '%s'"), uuidstr);
2376+ goto cleanup;
2377+ }
2378+
2379+ if (!virDomainObjIsActive(vm)) {
2380+ umlReportError(VIR_ERR_OPERATION_INVALID,
2381+ "%s", _("cannot attach device on inactive domain"));
2382+ goto cleanup;
2383+ }
2384+
2385+ dev = virDomainDeviceDefParse(driver->caps, vm->def, xml,
2386+ VIR_DOMAIN_XML_INACTIVE);
2387+
2388+ if (dev == NULL)
2389+ goto cleanup;
2390+
2391+ if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
2392+ if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_UML) {
2393+ ret = umlDomainAttachUmlDisk(driver, vm, dev->data.disk);
2394+ if (ret == 0)
2395+ dev->data.disk = NULL;
2396+ } else {
2397+ umlReportError(VIR_ERR_CONFIG_UNSUPPORTED,
2398+ _("disk bus '%s' cannot be hotplugged."),
2399+ virDomainDiskBusTypeToString(dev->data.disk->bus));
2400+ }
2401+ } else {
2402+ umlReportError(VIR_ERR_CONFIG_UNSUPPORTED,
2403+ _("device type '%s' cannot be attached"),
2404+ virDomainDeviceTypeToString(dev->type));
2405+ goto cleanup;
2406+ }
2407+
2408+cleanup:
2409+
2410+ virDomainDeviceDefFree(dev);
2411+ if (vm)
2412+ virDomainObjUnlock(vm);
2413+ umlDriverUnlock(driver);
2414+ return ret;
2415+}
2416+
2417+
2418+static int umlDomainAttachDeviceFlags(virDomainPtr dom,
2419+ const char *xml,
2420+ unsigned int flags) {
2421+ if (flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG) {
2422+ umlReportError(VIR_ERR_OPERATION_INVALID,
2423+ "%s", _("cannot modify the persistent configuration of a domain"));
2424+ return -1;
2425+ }
2426+
2427+ return umlDomainAttachDevice(dom, xml);
2428+}
2429+
2430+
2431+static int umlDomainDetachUmlDisk(struct uml_driver *driver,
2432+ virDomainObjPtr vm,
2433+ virDomainDeviceDefPtr dev)
2434+{
2435+ int i, ret = -1;
2436+ virDomainDiskDefPtr detach = NULL;
2437+ char *cmd;
2438+ char *reply;
2439+
2440+ for (i = 0 ; i < vm->def->ndisks ; i++) {
2441+ if (STREQ(vm->def->disks[i]->dst, dev->data.disk->dst)) {
2442+ break;
2443+ }
2444+ }
2445+
2446+ if (i == vm->def->ndisks) {
2447+ umlReportError(VIR_ERR_OPERATION_FAILED,
2448+ _("disk %s not found"), dev->data.disk->dst);
2449+ return -1;
2450+ }
2451+
2452+ detach = vm->def->disks[i];
2453+
2454+ if (virAsprintf(&cmd, "remove %s", detach->dst) < 0) {
2455+ virReportOOMError();
2456+ return -1;
2457+ }
2458+
2459+ if (umlMonitorCommand(driver, vm, cmd, &reply) < 0)
2460+ goto cleanup;
2461+
2462+ virDomainDiskRemove(vm->def, i);
2463+
2464+ virDomainDiskDefFree(detach);
2465+
2466+ ret = 0;
2467+
2468+ VIR_FREE(reply);
2469+
2470+cleanup:
2471+ VIR_FREE(cmd);
2472+
2473+ return ret;
2474+}
2475+
2476+
2477+static int umlDomainDetachDevice(virDomainPtr dom, const char *xml) {
2478+ struct uml_driver *driver = dom->conn->privateData;
2479+ virDomainObjPtr vm;
2480+ virDomainDeviceDefPtr dev = NULL;
2481+ int ret = -1;
2482+
2483+ umlDriverLock(driver);
2484+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
2485+ if (!vm) {
2486+ char uuidstr[VIR_UUID_STRING_BUFLEN];
2487+ virUUIDFormat(dom->uuid, uuidstr);
2488+ umlReportError(VIR_ERR_NO_DOMAIN,
2489+ _("no domain with matching uuid '%s'"), uuidstr);
2490+ goto cleanup;
2491+ }
2492+
2493+ if (!virDomainObjIsActive(vm)) {
2494+ umlReportError(VIR_ERR_OPERATION_INVALID,
2495+ "%s", _("cannot detach device on inactive domain"));
2496+ goto cleanup;
2497+ }
2498+
2499+ dev = virDomainDeviceDefParse(driver->caps, vm->def, xml,
2500+ VIR_DOMAIN_XML_INACTIVE);
2501+ if (dev == NULL)
2502+ goto cleanup;
2503+
2504+ if (dev->type == VIR_DOMAIN_DEVICE_DISK &&
2505+ dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
2506+ if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_UML)
2507+ ret = umlDomainDetachUmlDisk(driver, vm, dev);
2508+ else {
2509+ umlReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2510+ _("This type of disk cannot be hot unplugged"));
2511+ }
2512+ } else {
2513+ umlReportError(VIR_ERR_CONFIG_UNSUPPORTED,
2514+ "%s", _("This type of device cannot be hot unplugged"));
2515+ }
2516+
2517+cleanup:
2518+ virDomainDeviceDefFree(dev);
2519+ if (vm)
2520+ virDomainObjUnlock(vm);
2521+ umlDriverUnlock(driver);
2522+ return ret;
2523+}
2524+
2525+
2526+static int umlDomainDetachDeviceFlags(virDomainPtr dom,
2527+ const char *xml,
2528+ unsigned int flags) {
2529+ if (flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG) {
2530+ umlReportError(VIR_ERR_OPERATION_INVALID,
2531+ "%s", _("cannot modify the persistent configuration of a domain"));
2532+ return -1;
2533+ }
2534+
2535+ return umlDomainDetachDevice(dom, xml);
2536+}
2537+
2538+
2539+static int umlDomainGetAutostart(virDomainPtr dom,
2540+ int *autostart) {
2541+ struct uml_driver *driver = dom->conn->privateData;
2542+ virDomainObjPtr vm;
2543+ int ret = -1;
2544+
2545+ umlDriverLock(driver);
2546+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
2547+
2548+ if (!vm) {
2549+ umlReportError(VIR_ERR_INVALID_DOMAIN, "%s",
2550+ _("no domain with matching uuid"));
2551+ goto cleanup;
2552+ }
2553+
2554+ *autostart = vm->autostart;
2555+ ret = 0;
2556+
2557+cleanup:
2558+ if (vm)
2559+ virDomainObjUnlock(vm);
2560+ umlDriverUnlock(driver);
2561+ return ret;
2562+}
2563+
2564+static int umlDomainSetAutostart(virDomainPtr dom,
2565+ int autostart) {
2566+ struct uml_driver *driver = dom->conn->privateData;
2567+ virDomainObjPtr vm;
2568+ char *configFile = NULL, *autostartLink = NULL;
2569+ int ret = -1;
2570+
2571+ umlDriverLock(driver);
2572+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
2573+
2574+ if (!vm) {
2575+ umlReportError(VIR_ERR_INVALID_DOMAIN, "%s",
2576+ _("no domain with matching uuid"));
2577+ goto cleanup;
2578+ }
2579+
2580+ if (!vm->persistent) {
2581+ umlReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2582+ _("cannot set autostart for transient domain"));
2583+ goto cleanup;
2584+ }
2585+
2586+ autostart = (autostart != 0);
2587+
2588+ if (vm->autostart != autostart) {
2589+ if ((configFile = virDomainConfigFile(driver->configDir, vm->def->name)) == NULL)
2590+ goto cleanup;
2591+ if ((autostartLink = virDomainConfigFile(driver->autostartDir, vm->def->name)) == NULL)
2592+ goto cleanup;
2593+
2594+ if (autostart) {
2595+ int err;
2596+
2597+ if ((err = virFileMakePath(driver->autostartDir))) {
2598+ virReportSystemError(err,
2599+ _("cannot create autostart directory %s"),
2600+ driver->autostartDir);
2601+ goto cleanup;
2602+ }
2603+
2604+ if (symlink(configFile, autostartLink) < 0) {
2605+ virReportSystemError(errno,
2606+ _("Failed to create symlink '%s to '%s'"),
2607+ autostartLink, configFile);
2608+ goto cleanup;
2609+ }
2610+ } else {
2611+ if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
2612+ virReportSystemError(errno,
2613+ _("Failed to delete symlink '%s'"),
2614+ autostartLink);
2615+ goto cleanup;
2616+ }
2617+ }
2618+
2619+ vm->autostart = autostart;
2620+ }
2621+ ret = 0;
2622+
2623+cleanup:
2624+ VIR_FREE(configFile);
2625+ VIR_FREE(autostartLink);
2626+ if (vm)
2627+ virDomainObjUnlock(vm);
2628+ umlDriverUnlock(driver);
2629+ return ret;
2630+}
2631+
2632+
2633+static int
2634+umlDomainBlockPeek (virDomainPtr dom,
2635+ const char *path,
2636+ unsigned long long offset, size_t size,
2637+ void *buffer,
2638+ unsigned int flags ATTRIBUTE_UNUSED)
2639+{
2640+ struct uml_driver *driver = dom->conn->privateData;
2641+ virDomainObjPtr vm;
2642+ int fd = -1, ret = -1, i;
2643+
2644+ umlDriverLock(driver);
2645+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
2646+ umlDriverUnlock(driver);
2647+
2648+ if (!vm) {
2649+ umlReportError(VIR_ERR_INVALID_DOMAIN, "%s",
2650+ _("no domain with matching uuid"));
2651+ goto cleanup;
2652+ }
2653+
2654+ if (!path || path[0] == '\0') {
2655+ umlReportError(VIR_ERR_INVALID_ARG, "%s",
2656+ _("NULL or empty path"));
2657+ goto cleanup;
2658+ }
2659+
2660+ /* Check the path belongs to this domain. */
2661+ for (i = 0 ; i < vm->def->ndisks ; i++) {
2662+ if (vm->def->disks[i]->src != NULL &&
2663+ STREQ (vm->def->disks[i]->src, path)) {
2664+ ret = 0;
2665+ break;
2666+ }
2667+ }
2668+
2669+ if (ret == 0) {
2670+ ret = -1;
2671+ /* The path is correct, now try to open it and get its size. */
2672+ fd = open (path, O_RDONLY);
2673+ if (fd == -1) {
2674+ virReportSystemError(errno,
2675+ _("cannot open %s"), path);
2676+ goto cleanup;
2677+ }
2678+
2679+ /* Seek and read. */
2680+ /* NB. Because we configure with AC_SYS_LARGEFILE, off_t should
2681+ * be 64 bits on all platforms.
2682+ */
2683+ if (lseek (fd, offset, SEEK_SET) == (off_t) -1 ||
2684+ saferead (fd, buffer, size) == (ssize_t) -1) {
2685+ virReportSystemError(errno,
2686+ _("cannot read %s"), path);
2687+ goto cleanup;
2688+ }
2689+
2690+ ret = 0;
2691+ } else {
2692+ umlReportError(VIR_ERR_INVALID_ARG, "%s",
2693+ _("invalid path"));
2694+ }
2695+
2696+cleanup:
2697+ if (fd >= 0) close (fd);
2698+ if (vm)
2699+ virDomainObjUnlock(vm);
2700+ return ret;
2701+}
2702+
2703+
2704+
2705+static virDriver umlDriver = {
2706+ VIR_DRV_UML,
2707+ "UML",
2708+ umlOpen, /* open */
2709+ umlClose, /* close */
2710+ NULL, /* supports_feature */
2711+ umlGetType, /* type */
2712+ umlGetVersion, /* version */
2713+ NULL, /* libvirtVersion (impl. in libvirt.c) */
2714+ virGetHostname, /* getHostname */
2715+ NULL, /* getMaxVcpus */
2716+ nodeGetInfo, /* nodeGetInfo */
2717+ umlGetCapabilities, /* getCapabilities */
2718+ umlListDomains, /* listDomains */
2719+ umlNumDomains, /* numOfDomains */
2720+ umlDomainCreate, /* domainCreateXML */
2721+ umlDomainLookupByID, /* domainLookupByID */
2722+ umlDomainLookupByUUID, /* domainLookupByUUID */
2723+ umlDomainLookupByName, /* domainLookupByName */
2724+ NULL, /* domainSuspend */
2725+ NULL, /* domainResume */
2726+ umlDomainShutdown, /* domainShutdown */
2727+ NULL, /* domainReboot */
2728+ umlDomainDestroy, /* domainDestroy */
2729+ umlDomainGetOSType, /* domainGetOSType */
2730+ umlDomainGetMaxMemory, /* domainGetMaxMemory */
2731+ umlDomainSetMaxMemory, /* domainSetMaxMemory */
2732+ umlDomainSetMemory, /* domainSetMemory */
2733+ umlDomainGetInfo, /* domainGetInfo */
2734+ NULL, /* domainSave */
2735+ NULL, /* domainRestore */
2736+ NULL, /* domainCoreDump */
2737+ NULL, /* domainSetVcpus */
2738+ NULL, /* domainPinVcpu */
2739+ NULL, /* domainGetVcpus */
2740+ NULL, /* domainGetMaxVcpus */
2741+ NULL, /* domainGetSecurityLabel */
2742+ NULL, /* nodeGetSecurityModel */
2743+ umlDomainDumpXML, /* domainDumpXML */
2744+ NULL, /* domainXMLFromNative */
2745+ NULL, /* domainXMLToNative */
2746+ umlListDefinedDomains, /* listDefinedDomains */
2747+ umlNumDefinedDomains, /* numOfDefinedDomains */
2748+ umlDomainStart, /* domainCreate */
2749+ umlDomainStartWithFlags, /* domainCreateWithFlags */
2750+ umlDomainDefine, /* domainDefineXML */
2751+ umlDomainUndefine, /* domainUndefine */
2752+ umlDomainAttachDevice, /* domainAttachDevice */
2753+ umlDomainAttachDeviceFlags, /* domainAttachDeviceFlags */
2754+ umlDomainDetachDevice, /* domainDetachDevice */
2755+ umlDomainDetachDeviceFlags, /* domainDetachDeviceFlags */
2756+ NULL, /* domainUpdateDeviceFlags */
2757+ umlDomainGetAutostart, /* domainGetAutostart */
2758+ umlDomainSetAutostart, /* domainSetAutostart */
2759+ NULL, /* domainGetSchedulerType */
2760+ NULL, /* domainGetSchedulerParameters */
2761+ NULL, /* domainSetSchedulerParameters */
2762+ NULL, /* domainMigratePrepare */
2763+ NULL, /* domainMigratePerform */
2764+ NULL, /* domainMigrateFinish */
2765+ NULL, /* domainBlockStats */
2766+ NULL, /* domainInterfaceStats */
2767+ NULL, /* domainMemoryStats */
2768+ umlDomainBlockPeek, /* domainBlockPeek */
2769+ NULL, /* domainMemoryPeek */
2770+ NULL, /* domainGetBlockInfo */
2771+ nodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */
2772+ nodeGetFreeMemory, /* getFreeMemory */
2773+ NULL, /* domainEventRegister */
2774+ NULL, /* domainEventDeregister */
2775+ NULL, /* domainMigratePrepare2 */
2776+ NULL, /* domainMigrateFinish2 */
2777+ NULL, /* nodeDeviceDettach */
2778+ NULL, /* nodeDeviceReAttach */
2779+ NULL, /* nodeDeviceReset */
2780+ NULL, /* domainMigratePrepareTunnel */
2781+ umlIsEncrypted, /* isEncrypted */
2782+ umlIsSecure, /* isSecure */
2783+ umlDomainIsActive, /* domainIsActive */
2784+ umlDomainIsPersistent, /* domainIsPersistent */
2785+ NULL, /* cpuCompare */
2786+ NULL, /* cpuBaseline */
2787+ NULL, /* domainGetJobInfo */
2788+ NULL, /* domainAbortJob */
2789+ NULL, /* domainMigrateSetMaxDowntime */
2790+ NULL, /* domainEventRegisterAny */
2791+ NULL, /* domainEventDeregisterAny */
2792+ NULL, /* domainManagedSave */
2793+ NULL, /* domainHasManagedSaveImage */
2794+ NULL, /* domainManagedSaveRemove */
2795+ NULL, /* domainSnapshotCreateXML */
2796+ NULL, /* domainSnapshotDumpXML */
2797+ NULL, /* domainSnapshotNum */
2798+ NULL, /* domainSnapshotListNames */
2799+ NULL, /* domainSnapshotLookupByName */
2800+ NULL, /* domainHasCurrentSnapshot */
2801+ NULL, /* domainSnapshotCurrent */
2802+ NULL, /* domainRevertToSnapshot */
2803+ NULL, /* domainSnapshotDelete */
2804+ NULL, /* qemuDomainMonitorCommand */
2805+};
2806+
2807+
2808+static virStateDriver umlStateDriver = {
2809+ .name = "UML",
2810+ .initialize = umlStartup,
2811+ .cleanup = umlShutdown,
2812+ .reload = umlReload,
2813+ .active = umlActive,
2814+};
2815+
2816+int umlRegister(void) {
2817+ virRegisterDriver(&umlDriver);
2818+ virRegisterStateDriver(&umlStateDriver);
2819+ return 0;
2820+}
2821
2822=== added file 'debian/patches/9024-Explicitly-pass-uml_dir-argument-to-user-mode-linux.patch'
2823--- debian/patches/9024-Explicitly-pass-uml_dir-argument-to-user-mode-linux.patch 1970-01-01 00:00:00 +0000
2824+++ debian/patches/9024-Explicitly-pass-uml_dir-argument-to-user-mode-linux.patch 2010-09-14 20:26:05 +0000
2825@@ -0,0 +1,58 @@
2826+From bff2985daf724580866b941c88c820894111cc72 Mon Sep 17 00:00:00 2001
2827+From: Soren Hansen <soren@linux2go.dk>
2828+Date: Wed, 25 Aug 2010 10:41:14 +0200
2829+Subject: [PATCH] Explicitly pass uml_dir argument to user-mode-linux
2830+
2831+uml_dir overrides user-mode-linux's default of ~/.uml. This is needed
2832+for a couple of different reasons:
2833+
2834+libvirt expects this to default to virGetUserDirectory(geteuid()) +
2835+'/.uml'. However, user-mode-linux actually uses the HOME environment
2836+variable to determine where to look for the uml sockets, but if running
2837+libvirtd under sudo (which I routinely do during development), $HOME is
2838+pointing at my user's homedir, while my euid is 0, so libvirt looks in
2839+/root.
2840+
2841+Also (and this was my actual motivation for this patch), if HOME isn't
2842+set at all, user-mode-linux utterly fails. Looking at the code, it seems
2843+it's meant to emit a warning, but alas, it doesn't for some reason.
2844+If running libvirtd from upstart, HOME is not set, so any system using
2845+upstart will need this change.
2846+
2847+Signed-off-by: Soren Hansen <soren@linux2go.dk>
2848+---
2849+ src/uml/uml_conf.c | 4 ++--
2850+ 1 files changed, 2 insertions(+), 2 deletions(-)
2851+
2852+diff --git a/src/uml/uml_conf.c b/src/uml/uml_conf.c
2853+index 65b06c5..4906192 100644
2854+--- a/src/uml/uml_conf.c
2855++++ b/src/uml/uml_conf.c
2856+@@ -409,7 +409,7 @@ static char *umlNextArg(char *args)
2857+ * for a given virtual machine.
2858+ */
2859+ int umlBuildCommandLine(virConnectPtr conn,
2860+- struct uml_driver *driver ATTRIBUTE_UNUSED,
2861++ struct uml_driver *driver,
2862+ virDomainObjPtr vm,
2863+ fd_set *keepfd,
2864+ const char ***retargv,
2865+@@ -499,7 +499,6 @@ int umlBuildCommandLine(virConnectPtr conn,
2866+ ADD_ENV_COPY("LD_PRELOAD");
2867+ ADD_ENV_COPY("LD_LIBRARY_PATH");
2868+ ADD_ENV_COPY("PATH");
2869+- ADD_ENV_COPY("HOME");
2870+ ADD_ENV_COPY("USER");
2871+ ADD_ENV_COPY("LOGNAME");
2872+ ADD_ENV_COPY("TMPDIR");
2873+@@ -508,6 +507,7 @@ int umlBuildCommandLine(virConnectPtr conn,
2874+ //ADD_ARG_PAIR("con0", "fd:0,fd:1");
2875+ ADD_ARG_PAIR("mem", memory);
2876+ ADD_ARG_PAIR("umid", vm->def->name);
2877++ ADD_ARG_PAIR("uml_dir", driver->monitorDir);
2878+
2879+ if (vm->def->os.root)
2880+ ADD_ARG_PAIR("root", vm->def->os.root);
2881+--
2882+1.7.0.4
2883+
2884
2885=== removed file 'debian/patches/9024-Explicitly-pass-uml_dir-argument-to-user-mode-linux.patch'
2886--- debian/patches/9024-Explicitly-pass-uml_dir-argument-to-user-mode-linux.patch 2010-08-31 16:05:24 +0000
2887+++ debian/patches/9024-Explicitly-pass-uml_dir-argument-to-user-mode-linux.patch 1970-01-01 00:00:00 +0000
2888@@ -1,58 +0,0 @@
2889-From bff2985daf724580866b941c88c820894111cc72 Mon Sep 17 00:00:00 2001
2890-From: Soren Hansen <soren@linux2go.dk>
2891-Date: Wed, 25 Aug 2010 10:41:14 +0200
2892-Subject: [PATCH] Explicitly pass uml_dir argument to user-mode-linux
2893-
2894-uml_dir overrides user-mode-linux's default of ~/.uml. This is needed
2895-for a couple of different reasons:
2896-
2897-libvirt expects this to default to virGetUserDirectory(geteuid()) +
2898-'/.uml'. However, user-mode-linux actually uses the HOME environment
2899-variable to determine where to look for the uml sockets, but if running
2900-libvirtd under sudo (which I routinely do during development), $HOME is
2901-pointing at my user's homedir, while my euid is 0, so libvirt looks in
2902-/root.
2903-
2904-Also (and this was my actual motivation for this patch), if HOME isn't
2905-set at all, user-mode-linux utterly fails. Looking at the code, it seems
2906-it's meant to emit a warning, but alas, it doesn't for some reason.
2907-If running libvirtd from upstart, HOME is not set, so any system using
2908-upstart will need this change.
2909-
2910-Signed-off-by: Soren Hansen <soren@linux2go.dk>
2911----
2912- src/uml/uml_conf.c | 4 ++--
2913- 1 files changed, 2 insertions(+), 2 deletions(-)
2914-
2915-diff --git a/src/uml/uml_conf.c b/src/uml/uml_conf.c
2916-index 65b06c5..4906192 100644
2917---- a/src/uml/uml_conf.c
2918-+++ b/src/uml/uml_conf.c
2919-@@ -409,7 +409,7 @@ static char *umlNextArg(char *args)
2920- * for a given virtual machine.
2921- */
2922- int umlBuildCommandLine(virConnectPtr conn,
2923-- struct uml_driver *driver ATTRIBUTE_UNUSED,
2924-+ struct uml_driver *driver,
2925- virDomainObjPtr vm,
2926- fd_set *keepfd,
2927- const char ***retargv,
2928-@@ -499,7 +499,6 @@ int umlBuildCommandLine(virConnectPtr conn,
2929- ADD_ENV_COPY("LD_PRELOAD");
2930- ADD_ENV_COPY("LD_LIBRARY_PATH");
2931- ADD_ENV_COPY("PATH");
2932-- ADD_ENV_COPY("HOME");
2933- ADD_ENV_COPY("USER");
2934- ADD_ENV_COPY("LOGNAME");
2935- ADD_ENV_COPY("TMPDIR");
2936-@@ -508,6 +507,7 @@ int umlBuildCommandLine(virConnectPtr conn,
2937- //ADD_ARG_PAIR("con0", "fd:0,fd:1");
2938- ADD_ARG_PAIR("mem", memory);
2939- ADD_ARG_PAIR("umid", vm->def->name);
2940-+ ADD_ARG_PAIR("uml_dir", driver->monitorDir);
2941-
2942- if (vm->def->os.root)
2943- ADD_ARG_PAIR("root", vm->def->os.root);
2944---
2945-1.7.0.4
2946-
2947
2948=== added file 'debian/patches/9025-Add-nwfilter-support-to-UML-driver.patch'
2949--- debian/patches/9025-Add-nwfilter-support-to-UML-driver.patch 1970-01-01 00:00:00 +0000
2950+++ debian/patches/9025-Add-nwfilter-support-to-UML-driver.patch 2010-09-14 20:26:05 +0000
2951@@ -0,0 +1,112 @@
2952+From cdd91f237d8f36e2916a55f01a189fabf826fc26 Mon Sep 17 00:00:00 2001
2953+From: Soren Hansen <soren@linux2go.dk>
2954+Date: Mon, 6 Sep 2010 15:32:30 +0200
2955+Subject: [PATCH] Add nwfilter support to UML driver
2956+
2957+Extend user-mode-linux driver to support nwfilter.
2958+
2959+Signed-off-by: Soren Hansen <soren@linux2go.dk>
2960+---
2961+ src/uml/uml_conf.c | 16 +++++++++++++---
2962+ src/uml/uml_driver.c | 8 +++++++-
2963+ 2 files changed, 20 insertions(+), 4 deletions(-)
2964+
2965+diff --git a/src/uml/uml_conf.c b/src/uml/uml_conf.c
2966+index 4906192..f2eaef5 100644
2967+--- a/src/uml/uml_conf.c
2968++++ b/src/uml/uml_conf.c
2969+@@ -46,6 +46,7 @@
2970+ #include "verify.h"
2971+ #include "bridge.h"
2972+ #include "logging.h"
2973++#include "domain_nwfilter.h"
2974+
2975+ #define VIR_FROM_THIS VIR_FROM_UML
2976+
2977+@@ -108,7 +109,8 @@ virCapsPtr umlCapsInit(void) {
2978+
2979+
2980+ static int
2981+-umlConnectTapDevice(virDomainNetDefPtr net,
2982++umlConnectTapDevice(virConnectPtr conn,
2983++ virDomainNetDefPtr net,
2984+ const char *bridge)
2985+ {
2986+ brControl *brctl = NULL;
2987+@@ -164,6 +166,14 @@ umlConnectTapDevice(virDomainNetDefPtr net,
2988+ goto error;
2989+ }
2990+
2991++ if (net->filter) {
2992++ if (virDomainConfNWFilterInstantiate(conn, net)) {
2993++ if (template_ifname)
2994++ VIR_FREE(net->ifname);
2995++ goto error;
2996++ }
2997++ }
2998++
2999+ brShutdown(brctl);
3000+
3001+ return 0;
3002+@@ -239,7 +249,7 @@ umlBuildCommandLineNet(virConnectPtr conn,
3003+ goto error;
3004+ }
3005+
3006+- if (umlConnectTapDevice(def, bridge) < 0) {
3007++ if (umlConnectTapDevice(conn, def, bridge) < 0) {
3008+ VIR_FREE(bridge);
3009+ goto error;
3010+ }
3011+@@ -250,7 +260,7 @@ umlBuildCommandLineNet(virConnectPtr conn,
3012+ }
3013+
3014+ case VIR_DOMAIN_NET_TYPE_BRIDGE:
3015+- if (umlConnectTapDevice(def, def->data.bridge.brname) < 0)
3016++ if (umlConnectTapDevice(conn, def, def->data.bridge.brname) < 0)
3017+ goto error;
3018+
3019+ /* ethNNN=tuntap,tapname,macaddr,gateway */
3020+diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c
3021+index 0a5c829..40345d5 100644
3022+--- a/src/uml/uml_driver.c
3023++++ b/src/uml/uml_driver.c
3024+@@ -58,6 +58,7 @@
3025+ #include "domain_conf.h"
3026+ #include "datatypes.h"
3027+ #include "logging.h"
3028++#include "domain_nwfilter.h"
3029+
3030+ #define VIR_FROM_THIS VIR_FROM_UML
3031+
3032+@@ -876,6 +877,7 @@ static int umlStartVMDaemon(virConnectPtr conn,
3033+ if (umlBuildCommandLine(conn, driver, vm, &keepfd,
3034+ &argv, &progenv) < 0) {
3035+ close(logfd);
3036++ virDomainConfVMNWFilterTeardown(vm);
3037+ umlCleanupTapDevices(conn, vm);
3038+ return -1;
3039+ }
3040+@@ -928,8 +930,11 @@ static int umlStartVMDaemon(virConnectPtr conn,
3041+ VIR_FREE(progenv[i]);
3042+ VIR_FREE(progenv);
3043+
3044+- if (ret < 0)
3045++ if (ret < 0) {
3046++ virDomainConfVMNWFilterTeardown(vm);
3047+ umlCleanupTapDevices(conn, vm);
3048++ }
3049++
3050+
3051+ /* NB we don't mark it running here - we do that async
3052+ with inotify */
3053+@@ -965,6 +970,7 @@ static void umlShutdownVMDaemon(virConnectPtr conn ATTRIBUTE_UNUSED,
3054+ vm->def->id = -1;
3055+ vm->state = VIR_DOMAIN_SHUTOFF;
3056+
3057++ virDomainConfVMNWFilterTeardown(vm);
3058+ umlCleanupTapDevices(conn, vm);
3059+
3060+ if (vm->newDef) {
3061+--
3062+1.7.1
3063+
3064
3065=== renamed file 'debian/patches/9025-Add-nwfilter-support-to-UML-driver.patch' => 'debian/patches/9025-Add-nwfilter-support-to-UML-driver.patch.moved'

Subscribers

People subscribed via source and target branches