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
=== added directory '.pc/9025-Add-nwfilter-support-to-UML-driver.patch'
=== renamed directory '.pc/9025-Add-nwfilter-support-to-UML-driver.patch' => '.pc/9025-Add-nwfilter-support-to-UML-driver.patch.moved'
=== added file '.pc/9025-Add-nwfilter-support-to-UML-driver.patch/.timestamp'
=== added directory '.pc/9025-Add-nwfilter-support-to-UML-driver.patch/src'
=== added directory '.pc/9025-Add-nwfilter-support-to-UML-driver.patch/src/uml'
=== added file '.pc/9025-Add-nwfilter-support-to-UML-driver.patch/src/uml/uml_conf.c'
--- .pc/9025-Add-nwfilter-support-to-UML-driver.patch/src/uml/uml_conf.c 1970-01-01 00:00:00 +0000
+++ .pc/9025-Add-nwfilter-support-to-UML-driver.patch/src/uml/uml_conf.c 2010-09-14 20:26:05 +0000
@@ -0,0 +1,601 @@
1/*
2 * uml_conf.c: UML driver configuration
3 *
4 * Copyright (C) 2006-2009 Red Hat, Inc.
5 * Copyright (C) 2006 Daniel P. Berrange
6 *
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.
11 *
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.
16 *
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
20 *
21 * Author: Daniel P. Berrange <berrange@redhat.com>
22 */
23
24#include <config.h>
25
26#include <dirent.h>
27#include <string.h>
28#include <limits.h>
29#include <sys/types.h>
30#include <sys/stat.h>
31#include <stdlib.h>
32#include <unistd.h>
33#include <errno.h>
34#include <fcntl.h>
35#include <sys/wait.h>
36#include <arpa/inet.h>
37#include <sys/utsname.h>
38
39#include "uml_conf.h"
40#include "uuid.h"
41#include "buf.h"
42#include "conf.h"
43#include "util.h"
44#include "memory.h"
45#include "nodeinfo.h"
46#include "verify.h"
47#include "bridge.h"
48#include "logging.h"
49
50#define VIR_FROM_THIS VIR_FROM_UML
51
52#define umlLog(level, msg, ...) \
53 virLogMessage(__FILE__, level, 0, msg, __VA_ARGS__)
54
55virCapsPtr umlCapsInit(void) {
56 struct utsname utsname;
57 virCapsPtr caps;
58 virCapsGuestPtr guest;
59
60 /* Really, this never fails - look at the man-page. */
61 uname (&utsname);
62
63 if ((caps = virCapabilitiesNew(utsname.machine,
64 0, 0)) == NULL)
65 goto error;
66
67 /* Some machines have problematic NUMA toplogy causing
68 * unexpected failures. We don't want to break the QEMU
69 * driver in this scenario, so log errors & carry on
70 */
71 if (nodeCapsInitNUMA(caps) < 0) {
72 virCapabilitiesFreeNUMAInfo(caps);
73 VIR_WARN0("Failed to query host NUMA topology, disabling NUMA capabilities");
74 }
75
76 if (virGetHostUUID(caps->host.host_uuid)) {
77 umlReportError(VIR_ERR_INTERNAL_ERROR,
78 "%s", _("cannot get the host uuid"));
79 goto error;
80 }
81
82 if ((guest = virCapabilitiesAddGuest(caps,
83 "uml",
84 utsname.machine,
85 STREQ(utsname.machine, "x86_64") ? 64 : 32,
86 NULL,
87 NULL,
88 0,
89 NULL)) == NULL)
90 goto error;
91
92 if (virCapabilitiesAddGuestDomain(guest,
93 "uml",
94 NULL,
95 NULL,
96 0,
97 NULL) == NULL)
98 goto error;
99
100 caps->defaultConsoleTargetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_UML;
101
102 return caps;
103
104 error:
105 virCapabilitiesFree(caps);
106 return NULL;
107}
108
109
110static int
111umlConnectTapDevice(virDomainNetDefPtr net,
112 const char *bridge)
113{
114 brControl *brctl = NULL;
115 int template_ifname = 0;
116 int err;
117 unsigned char tapmac[VIR_MAC_BUFLEN];
118
119 if ((err = brInit(&brctl))) {
120 virReportSystemError(err, "%s",
121 _("cannot initialize bridge support"));
122 goto error;
123 }
124
125 if (!net->ifname ||
126 STRPREFIX(net->ifname, "vnet") ||
127 strchr(net->ifname, '%')) {
128 VIR_FREE(net->ifname);
129 if (!(net->ifname = strdup("vnet%d")))
130 goto no_memory;
131 /* avoid exposing vnet%d in dumpxml or error outputs */
132 template_ifname = 1;
133 }
134
135 memcpy(tapmac, net->mac, VIR_MAC_BUFLEN);
136 tapmac[0] = 0xFE; /* Discourage bridge from using TAP dev MAC */
137 if ((err = brAddTap(brctl,
138 bridge,
139 &net->ifname,
140 tapmac,
141 0,
142 NULL))) {
143 if (errno == ENOTSUP) {
144 /* In this particular case, give a better diagnostic. */
145 umlReportError(VIR_ERR_INTERNAL_ERROR,
146 _("Failed to add tap interface to bridge. "
147 "%s is not a bridge device"), bridge);
148 } else if (template_ifname) {
149 virReportSystemError(err,
150 _("Failed to add tap interface to bridge '%s'"),
151 bridge);
152 } else {
153 virReportSystemError(err,
154 _("Failed to add tap interface '%s' to bridge '%s'"),
155 net->ifname, bridge);
156 }
157 if (template_ifname)
158 VIR_FREE(net->ifname);
159 goto error;
160 }
161
162 brShutdown(brctl);
163
164 return 0;
165
166no_memory:
167 virReportOOMError();
168error:
169 brShutdown(brctl);
170 return -1;
171}
172
173static char *
174umlBuildCommandLineNet(virConnectPtr conn,
175 virDomainNetDefPtr def,
176 int idx)
177{
178 virBuffer buf = VIR_BUFFER_INITIALIZER;
179
180 /* General format: ethNN=type,options */
181
182 virBufferVSprintf(&buf, "eth%d=", idx);
183
184 switch (def->type) {
185 case VIR_DOMAIN_NET_TYPE_USER:
186 /* ethNNN=slirp,macaddr */
187 virBufferAddLit(&buf, "slirp");
188 break;
189
190 case VIR_DOMAIN_NET_TYPE_ETHERNET:
191 /* ethNNN=tuntap,tapname,macaddr,gateway */
192 virBufferAddLit(&buf, "tuntap");
193 if (def->data.ethernet.ipaddr) {
194 umlReportError(VIR_ERR_INTERNAL_ERROR, "%s",
195 _("IP address not supported for ethernet inteface"));
196 goto error;
197 }
198 if (def->data.ethernet.script) {
199 umlReportError(VIR_ERR_INTERNAL_ERROR, "%s",
200 _("script execution not supported for ethernet inteface"));
201 goto error;
202 }
203 break;
204
205 case VIR_DOMAIN_NET_TYPE_SERVER:
206 umlReportError(VIR_ERR_INTERNAL_ERROR, "%s",
207 _("TCP server networking type not supported"));
208 goto error;
209
210 case VIR_DOMAIN_NET_TYPE_CLIENT:
211 umlReportError(VIR_ERR_INTERNAL_ERROR, "%s",
212 _("TCP client networking type not supported"));
213 goto error;
214
215 case VIR_DOMAIN_NET_TYPE_MCAST:
216 /* ethNNN=tuntap,macaddr,ipaddr,port */
217 virBufferAddLit(&buf, "mcast");
218 break;
219
220 case VIR_DOMAIN_NET_TYPE_NETWORK:
221 {
222 char *bridge;
223 virNetworkPtr network = virNetworkLookupByName(conn,
224 def->data.network.name);
225 if (!network) {
226 umlReportError(VIR_ERR_INTERNAL_ERROR,
227 _("Network '%s' not found"),
228 def->data.network.name);
229 goto error;
230 }
231 bridge = virNetworkGetBridgeName(network);
232 virNetworkFree(network);
233 if (bridge == NULL) {
234 goto error;
235 }
236
237 if (umlConnectTapDevice(def, bridge) < 0) {
238 VIR_FREE(bridge);
239 goto error;
240 }
241
242 /* ethNNN=tuntap,tapname,macaddr,gateway */
243 virBufferVSprintf(&buf, "tuntap,%s", def->ifname);
244 break;
245 }
246
247 case VIR_DOMAIN_NET_TYPE_BRIDGE:
248 if (umlConnectTapDevice(def, def->data.bridge.brname) < 0)
249 goto error;
250
251 /* ethNNN=tuntap,tapname,macaddr,gateway */
252 virBufferVSprintf(&buf, "tuntap,%s", def->ifname);
253 break;
254
255 case VIR_DOMAIN_NET_TYPE_INTERNAL:
256 umlReportError(VIR_ERR_INTERNAL_ERROR, "%s",
257 _("internal networking type not supported"));
258 goto error;
259
260 case VIR_DOMAIN_NET_TYPE_DIRECT:
261 umlReportError(VIR_ERR_INTERNAL_ERROR, "%s",
262 _("direct networking type not supported"));
263 goto error;
264
265 case VIR_DOMAIN_NET_TYPE_LAST:
266 break;
267 }
268
269 virBufferVSprintf(&buf, ",%02x:%02x:%02x:%02x:%02x:%02x",
270 def->mac[0], def->mac[1], def->mac[2],
271 def->mac[3], def->mac[4], def->mac[5]);
272
273 if (def->type == VIR_DOMAIN_NET_TYPE_MCAST) {
274 virBufferVSprintf(&buf, ",%s,%d",
275 def->data.socket.address,
276 def->data.socket.port);
277 }
278
279 if (virBufferError(&buf)) {
280 virReportOOMError();
281 return NULL;
282 }
283
284 return virBufferContentAndReset(&buf);
285
286error:
287 virBufferFreeAndReset(&buf);
288 return NULL;
289}
290
291static char *
292umlBuildCommandLineChr(virDomainChrDefPtr def,
293 const char *dev,
294 fd_set *keepfd)
295{
296 char *ret = NULL;
297
298 switch (def->type) {
299 case VIR_DOMAIN_CHR_TYPE_NULL:
300 if (virAsprintf(&ret, "%s%d=null", dev, def->target.port) < 0) {
301 virReportOOMError();
302 return NULL;
303 }
304 break;
305
306 case VIR_DOMAIN_CHR_TYPE_PTY:
307 if (virAsprintf(&ret, "%s%d=pts", dev, def->target.port) < 0) {
308 virReportOOMError();
309 return NULL;
310 }
311 break;
312
313 case VIR_DOMAIN_CHR_TYPE_DEV:
314 if (virAsprintf(&ret, "%s%d=tty:%s", dev, def->target.port,
315 def->data.file.path) < 0) {
316 virReportOOMError();
317 return NULL;
318 }
319 break;
320
321 case VIR_DOMAIN_CHR_TYPE_STDIO:
322 if (virAsprintf(&ret, "%s%d=fd:0,fd:1", dev, def->target.port) < 0) {
323 virReportOOMError();
324 return NULL;
325 }
326 break;
327
328 case VIR_DOMAIN_CHR_TYPE_TCP:
329 if (def->data.tcp.listen != 1) {
330 umlReportError(VIR_ERR_INTERNAL_ERROR, "%s",
331 _("only TCP listen is supported for chr device"));
332 return NULL;
333 }
334
335 if (virAsprintf(&ret, "%s%d=port:%s", dev, def->target.port,
336 def->data.tcp.service) < 0) {
337 virReportOOMError();
338 return NULL;
339 }
340 break;
341
342 case VIR_DOMAIN_CHR_TYPE_FILE:
343 {
344 int fd_out;
345
346 if ((fd_out = open(def->data.file.path,
347 O_WRONLY | O_APPEND | O_CREAT, 0660)) < 0) {
348 virReportSystemError(errno,
349 _("failed to open chardev file: %s"),
350 def->data.file.path);
351 return NULL;
352 }
353 if (virAsprintf(&ret, "%s%d=null,fd:%d", dev, def->target.port, fd_out) < 0) {
354 virReportOOMError();
355 close(fd_out);
356 return NULL;
357 }
358 FD_SET(fd_out, keepfd);
359 }
360 break;
361 case VIR_DOMAIN_CHR_TYPE_PIPE:
362 /* XXX could open the pipe & just pass the FDs. Be wary of
363 * the effects of blocking I/O, though. */
364
365 case VIR_DOMAIN_CHR_TYPE_VC:
366 case VIR_DOMAIN_CHR_TYPE_UDP:
367 case VIR_DOMAIN_CHR_TYPE_UNIX:
368 default:
369 umlReportError(VIR_ERR_INTERNAL_ERROR,
370 _("unsupported chr device type %d"), def->type);
371 break;
372 }
373
374 return ret;
375}
376
377/*
378 * Null-terminate the current argument and return a pointer to the next.
379 * This should follow the same rules as the Linux kernel: arguments are
380 * separated by spaces; arguments can be quoted with double quotes; double
381 * quotes can't be escaped.
382 */
383static char *umlNextArg(char *args)
384{
385 int in_quote = 0;
386
387 for (; *args; args++) {
388 if (*args == ' ' && !in_quote) {
389 *args++ = '\0';
390 break;
391 }
392 if (*args == '"')
393 in_quote = !in_quote;
394 }
395
396 while (*args == ' ')
397 args++;
398
399 return args;
400}
401
402/*
403 * Constructs a argv suitable for launching uml with config defined
404 * for a given virtual machine.
405 */
406int umlBuildCommandLine(virConnectPtr conn,
407 struct uml_driver *driver,
408 virDomainObjPtr vm,
409 fd_set *keepfd,
410 const char ***retargv,
411 const char ***retenv)
412{
413 int i, j;
414 char memory[50];
415 struct utsname ut;
416 int qargc = 0, qarga = 0;
417 const char **qargv = NULL;
418 int qenvc = 0, qenva = 0;
419 const char **qenv = NULL;
420 char *cmdline = NULL;
421
422 uname(&ut);
423
424#define ADD_ARG_SPACE \
425 do { \
426 if (qargc == qarga) { \
427 qarga += 10; \
428 if (VIR_REALLOC_N(qargv, qarga) < 0) \
429 goto no_memory; \
430 } \
431 } while (0)
432
433#define ADD_ARG(thisarg) \
434 do { \
435 ADD_ARG_SPACE; \
436 qargv[qargc++] = thisarg; \
437 } while (0)
438
439#define ADD_ARG_LIT(thisarg) \
440 do { \
441 ADD_ARG_SPACE; \
442 if ((qargv[qargc++] = strdup(thisarg)) == NULL) \
443 goto no_memory; \
444 } while (0)
445
446#define ADD_ARG_PAIR(key,val) \
447 do { \
448 char *arg; \
449 ADD_ARG_SPACE; \
450 if (virAsprintf(&arg, "%s=%s", key, val) < 0) \
451 goto no_memory; \
452 qargv[qargc++] = arg; \
453 } while (0)
454
455
456#define ADD_ENV_SPACE \
457 do { \
458 if (qenvc == qenva) { \
459 qenva += 10; \
460 if (VIR_REALLOC_N(qenv, qenva) < 0) \
461 goto no_memory; \
462 } \
463 } while (0)
464
465#define ADD_ENV(thisarg) \
466 do { \
467 ADD_ENV_SPACE; \
468 qenv[qenvc++] = thisarg; \
469 } while (0)
470
471#define ADD_ENV_LIT(thisarg) \
472 do { \
473 ADD_ENV_SPACE; \
474 if ((qenv[qenvc++] = strdup(thisarg)) == NULL) \
475 goto no_memory; \
476 } while (0)
477
478#define ADD_ENV_COPY(envname) \
479 do { \
480 char *val = getenv(envname); \
481 char *envval; \
482 ADD_ENV_SPACE; \
483 if (val != NULL) { \
484 if (virAsprintf(&envval, "%s=%s", envname, val) < 0) \
485 goto no_memory; \
486 qenv[qenvc++] = envval; \
487 } \
488 } while (0)
489
490 snprintf(memory, sizeof(memory), "%luK", vm->def->memory);
491
492 ADD_ENV_LIT("LC_ALL=C");
493
494 ADD_ENV_COPY("LD_PRELOAD");
495 ADD_ENV_COPY("LD_LIBRARY_PATH");
496 ADD_ENV_COPY("PATH");
497 ADD_ENV_COPY("USER");
498 ADD_ENV_COPY("LOGNAME");
499 ADD_ENV_COPY("TMPDIR");
500
501 ADD_ARG_LIT(vm->def->os.kernel);
502 //ADD_ARG_PAIR("con0", "fd:0,fd:1");
503 ADD_ARG_PAIR("mem", memory);
504 ADD_ARG_PAIR("umid", vm->def->name);
505 ADD_ARG_PAIR("uml_dir", driver->monitorDir);
506
507 if (vm->def->os.root)
508 ADD_ARG_PAIR("root", vm->def->os.root);
509
510 for (i = 0 ; i < vm->def->ndisks ; i++) {
511 virDomainDiskDefPtr disk = vm->def->disks[i];
512
513 if (!STRPREFIX(disk->dst, "ubd")) {
514 umlReportError(VIR_ERR_INTERNAL_ERROR,
515 _("unsupported disk type '%s'"), disk->dst);
516 goto error;
517 }
518
519 ADD_ARG_PAIR(disk->dst, disk->src);
520 }
521
522 for (i = 0 ; i < vm->def->nnets ; i++) {
523 char *ret = umlBuildCommandLineNet(conn, vm->def->nets[i], i);
524 if (!ret)
525 goto error;
526 ADD_ARG(ret);
527 }
528
529 for (i = 0 ; i < UML_MAX_CHAR_DEVICE ; i++) {
530 char *ret = NULL;
531 if (i == 0 && vm->def->console)
532 ret = umlBuildCommandLineChr(vm->def->console, "con", keepfd);
533 if (!ret)
534 if (virAsprintf(&ret, "con%d=none", i) < 0)
535 goto no_memory;
536 ADD_ARG(ret);
537 }
538
539 for (i = 0 ; i < UML_MAX_CHAR_DEVICE ; i++) {
540 virDomainChrDefPtr chr = NULL;
541 char *ret = NULL;
542 for (j = 0 ; j < vm->def->nserials ; j++)
543 if (vm->def->serials[j]->target.port == i)
544 chr = vm->def->serials[j];
545 if (chr)
546 ret = umlBuildCommandLineChr(chr, "ssl", keepfd);
547 if (!ret)
548 if (virAsprintf(&ret, "ssl%d=none", i) < 0)
549 goto no_memory;
550 ADD_ARG(ret);
551 }
552
553 if (vm->def->os.cmdline) {
554 char *args, *next_arg;
555 if ((cmdline = strdup(vm->def->os.cmdline)) == NULL)
556 goto no_memory;
557
558 args = cmdline;
559 while (*args == ' ')
560 args++;
561
562 while (*args) {
563 next_arg = umlNextArg(args);
564 ADD_ARG_LIT(args);
565 args = next_arg;
566 }
567 }
568
569 ADD_ARG(NULL);
570 ADD_ENV(NULL);
571
572 *retargv = qargv;
573 *retenv = qenv;
574 return 0;
575
576 no_memory:
577 virReportOOMError();
578 error:
579
580 if (qargv) {
581 for (i = 0 ; i < qargc ; i++)
582 VIR_FREE((qargv)[i]);
583 VIR_FREE(qargv);
584 }
585 if (qenv) {
586 for (i = 0 ; i < qenvc ; i++)
587 VIR_FREE((qenv)[i]);
588 VIR_FREE(qenv);
589 }
590 VIR_FREE(cmdline);
591 return -1;
592
593#undef ADD_ARG
594#undef ADD_ARG_LIT
595#undef ADD_ARG_SPACE
596#undef ADD_USBDISK
597#undef ADD_ENV
598#undef ADD_ENV_COPY
599#undef ADD_ENV_LIT
600#undef ADD_ENV_SPACE
601}
0602
=== added file '.pc/9025-Add-nwfilter-support-to-UML-driver.patch/src/uml/uml_driver.c'
--- .pc/9025-Add-nwfilter-support-to-UML-driver.patch/src/uml/uml_driver.c 1970-01-01 00:00:00 +0000
+++ .pc/9025-Add-nwfilter-support-to-UML-driver.patch/src/uml/uml_driver.c 2010-09-14 20:26:05 +0000
@@ -0,0 +1,2205 @@
1/*
2 * uml_driver.c: core driver methods for managing UML guests
3 *
4 * Copyright (C) 2006-2010 Red Hat, Inc.
5 * Copyright (C) 2006-2008 Daniel P. Berrange
6 *
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.
11 *
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.
16 *
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
20 *
21 * Author: Daniel P. Berrange <berrange@redhat.com>
22 */
23
24#include <config.h>
25
26#include <sys/types.h>
27#include <sys/poll.h>
28#include <dirent.h>
29#include <limits.h>
30#include <string.h>
31#include <stdio.h>
32#include <stdarg.h>
33#include <stdlib.h>
34#include <unistd.h>
35#include <errno.h>
36#include <sys/utsname.h>
37#include <sys/stat.h>
38#include <fcntl.h>
39#include <signal.h>
40#include <paths.h>
41#include <pwd.h>
42#include <stdio.h>
43#include <sys/wait.h>
44#include <sys/ioctl.h>
45#include <sys/inotify.h>
46#include <sys/un.h>
47
48#include "uml_driver.h"
49#include "uml_conf.h"
50#include "event.h"
51#include "buf.h"
52#include "util.h"
53#include "nodeinfo.h"
54#include "stats_linux.h"
55#include "capabilities.h"
56#include "memory.h"
57#include "uuid.h"
58#include "domain_conf.h"
59#include "datatypes.h"
60#include "logging.h"
61
62#define VIR_FROM_THIS VIR_FROM_UML
63
64/* For storing short-lived temporary files. */
65#define TEMPDIR LOCAL_STATE_DIR "/cache/libvirt"
66
67typedef struct _umlDomainObjPrivate umlDomainObjPrivate;
68typedef umlDomainObjPrivate *umlDomainObjPrivatePtr;
69struct _umlDomainObjPrivate {
70 int monitor;
71 int monitorWatch;
72};
73
74
75static int umlShutdown(void);
76
77static void *umlDomainObjPrivateAlloc(void)
78{
79 umlDomainObjPrivatePtr priv;
80
81 if (VIR_ALLOC(priv) < 0)
82 return NULL;
83
84 priv->monitor = -1;
85 priv->monitorWatch = -1;
86
87 return priv;
88}
89
90static void umlDomainObjPrivateFree(void *data)
91{
92 umlDomainObjPrivatePtr priv = data;
93
94 VIR_FREE(priv);
95}
96
97
98static void umlDriverLock(struct uml_driver *driver)
99{
100 virMutexLock(&driver->lock);
101}
102static void umlDriverUnlock(struct uml_driver *driver)
103{
104 virMutexUnlock(&driver->lock);
105}
106
107
108static int umlOpenMonitor(struct uml_driver *driver,
109 virDomainObjPtr vm);
110static int umlReadPidFile(struct uml_driver *driver,
111 virDomainObjPtr vm);
112
113static int umlSetCloseExec(int fd) {
114 int flags;
115 if ((flags = fcntl(fd, F_GETFD)) < 0)
116 goto error;
117 flags |= FD_CLOEXEC;
118 if ((fcntl(fd, F_SETFD, flags)) < 0)
119 goto error;
120 return 0;
121 error:
122 VIR_ERROR0(_("Failed to set close-on-exec file descriptor flag"));
123 return -1;
124}
125
126static int umlStartVMDaemon(virConnectPtr conn,
127 struct uml_driver *driver,
128 virDomainObjPtr vm);
129
130static void umlShutdownVMDaemon(virConnectPtr conn,
131 struct uml_driver *driver,
132 virDomainObjPtr vm);
133
134
135static int umlMonitorCommand(const struct uml_driver *driver,
136 const virDomainObjPtr vm,
137 const char *cmd,
138 char **reply);
139
140static struct uml_driver *uml_driver = NULL;
141
142struct umlAutostartData {
143 struct uml_driver *driver;
144 virConnectPtr conn;
145};
146
147static void
148umlAutostartDomain(void *payload, const char *name ATTRIBUTE_UNUSED, void *opaque)
149{
150 virDomainObjPtr vm = payload;
151 const struct umlAutostartData *data = opaque;
152
153 virDomainObjLock(vm);
154 if (vm->autostart &&
155 !virDomainObjIsActive(vm)) {
156 virResetLastError();
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"));
161 }
162 }
163 virDomainObjUnlock(vm);
164}
165
166static void
167umlAutostartConfigs(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
171 * network
172 */
173 virConnectPtr conn = virConnectOpen(driver->privileged ?
174 "uml:///system" :
175 "uml:///session");
176 /* Ignoring NULL conn which is mostly harmless here */
177
178 struct umlAutostartData data = { driver, conn };
179
180 virHashForEach(driver->domains.objs, umlAutostartDomain, &data);
181
182 if (conn)
183 virConnectClose(conn);
184}
185
186
187static int
188umlIdentifyOneChrPTY(struct uml_driver *driver,
189 virDomainObjPtr dom,
190 virDomainChrDefPtr def,
191 const char *dev)
192{
193 char *cmd;
194 char *res = NULL;
195 int retries = 0;
196 if (virAsprintf(&cmd, "config %s%d", dev, def->target.port) < 0) {
197 virReportOOMError();
198 return -1;
199 }
200requery:
201 if (umlMonitorCommand(driver, dom, cmd, &res) < 0)
202 return -1;
203
204 if (res && STRPREFIX(res, "pts:")) {
205 VIR_FREE(def->data.file.path);
206 if ((def->data.file.path = strdup(res + 4)) == NULL) {
207 virReportOOMError();
208 VIR_FREE(res);
209 VIR_FREE(cmd);
210 return -1;
211 }
212 } else if (!res || STRPREFIX(res, "pts")) {
213 /* It can take a while to startup, so retry for
214 upto 5 seconds */
215 /* XXX should do this in a better non-blocking
216 way somehow ...perhaps register a timer */
217 if (retries++ < 50) {
218 usleep(1000*10);
219 goto requery;
220 }
221 }
222
223 VIR_FREE(cmd);
224 VIR_FREE(res);
225 return 0;
226}
227
228static int
229umlIdentifyChrPTY(struct uml_driver *driver,
230 virDomainObjPtr dom)
231{
232 int i;
233
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)
238 return -1;
239
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)
244 return -1;
245
246 return 0;
247}
248
249static void
250umlInotifyEvent(int watch,
251 int fd,
252 int events ATTRIBUTE_UNUSED,
253 void *data)
254{
255 char buf[1024];
256 struct inotify_event *e;
257 int got;
258 char *tmp, *name;
259 struct uml_driver *driver = data;
260 virDomainObjPtr dom;
261
262 umlDriverLock(driver);
263 if (watch != driver->inotifyWatch)
264 goto cleanup;
265
266reread:
267 got = read(fd, buf, sizeof(buf));
268 if (got == -1) {
269 if (errno == EINTR)
270 goto reread;
271 goto cleanup;
272 }
273
274 tmp = buf;
275 while (got) {
276 if (got < sizeof(struct inotify_event))
277 goto cleanup; /* bad */
278
279 e = (struct inotify_event *)tmp;
280 tmp += sizeof(struct inotify_event);
281 got -= sizeof(struct inotify_event);
282
283 if (got < e->len)
284 goto cleanup;
285
286 tmp += e->len;
287 got -= e->len;
288
289 name = (char *)&(e->name);
290
291 dom = virDomainFindByName(&driver->domains, name);
292
293 if (!dom) {
294 continue;
295 }
296
297 if (e->mask & IN_DELETE) {
298 VIR_DEBUG("Got inotify domain shutdown '%s'", name);
299 if (!virDomainObjIsActive(dom)) {
300 virDomainObjUnlock(dom);
301 continue;
302 }
303
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);
309 continue;
310 }
311
312 if (umlReadPidFile(driver, dom) < 0) {
313 virDomainObjUnlock(dom);
314 continue;
315 }
316
317 dom->def->id = driver->nextvmid++;
318 dom->state = VIR_DOMAIN_RUNNING;
319
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);
326 }
327 }
328 virDomainObjUnlock(dom);
329 }
330
331cleanup:
332 umlDriverUnlock(driver);
333}
334
335/**
336 * umlStartup:
337 *
338 * Initialization function for the Uml daemon
339 */
340static int
341umlStartup(int privileged) {
342 uid_t uid = geteuid();
343 char *base = NULL;
344 char driverConf[PATH_MAX];
345 char *userdir = NULL;
346
347 if (VIR_ALLOC(uml_driver) < 0)
348 return -1;
349
350 uml_driver->privileged = privileged;
351
352 if (virMutexInit(&uml_driver->lock) < 0) {
353 VIR_FREE(uml_driver);
354 return -1;
355 }
356 umlDriverLock(uml_driver);
357
358 /* Don't have a dom0 so start from 1 */
359 uml_driver->nextvmid = 1;
360 uml_driver->inotifyWatch = -1;
361
362 if (virDomainObjListInit(&uml_driver->domains) < 0)
363 goto error;
364
365 userdir = virGetUserDirectory(uid);
366 if (!userdir)
367 goto error;
368
369 if (privileged) {
370 if (virAsprintf(&uml_driver->logDir,
371 "%s/log/libvirt/uml", LOCAL_STATE_DIR) == -1)
372 goto out_of_memory;
373
374 if ((base = strdup (SYSCONF_DIR "/libvirt")) == NULL)
375 goto out_of_memory;
376 } else {
377
378 if (virAsprintf(&uml_driver->logDir,
379 "%s/.libvirt/uml/log", userdir) == -1)
380 goto out_of_memory;
381
382 if (virAsprintf(&base, "%s/.libvirt", userdir) == -1)
383 goto out_of_memory;
384 }
385
386 if (virAsprintf(&uml_driver->monitorDir,
387 "%s/.uml", userdir) == -1)
388 goto out_of_memory;
389
390 /* Configuration paths are either ~/.libvirt/uml/... (session) or
391 * /etc/libvirt/uml/... (system).
392 */
393 if (snprintf (driverConf, sizeof(driverConf), "%s/uml.conf", base) == -1)
394 goto out_of_memory;
395 driverConf[sizeof(driverConf)-1] = '\0';
396
397 if (virAsprintf(&uml_driver->configDir, "%s/uml", base) == -1)
398 goto out_of_memory;
399
400 if (virAsprintf(&uml_driver->autostartDir, "%s/uml/autostart", base) == -1)
401 goto out_of_memory;
402
403 VIR_FREE(base);
404
405 if ((uml_driver->caps = umlCapsInit()) == NULL)
406 goto out_of_memory;
407
408 uml_driver->caps->privateDataAllocFunc = umlDomainObjPrivateAlloc;
409 uml_driver->caps->privateDataFreeFunc = umlDomainObjPrivateFree;
410
411 if ((uml_driver->inotifyFD = inotify_init()) < 0) {
412 VIR_ERROR0(_("cannot initialize inotify"));
413 goto error;
414 }
415
416 if (virFileMakePath(uml_driver->monitorDir) != 0) {
417 char ebuf[1024];
418 VIR_ERROR(_("Failed to create monitor directory %s: %s"),
419 uml_driver->monitorDir, virStrerror(errno, ebuf, sizeof ebuf));
420 goto error;
421 }
422
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) {
427 goto error;
428 }
429
430 if ((uml_driver->inotifyWatch =
431 virEventAddHandle(uml_driver->inotifyFD, POLLIN,
432 umlInotifyEvent, uml_driver, NULL)) < 0)
433 goto error;
434
435 if (virDomainLoadAllConfigs(uml_driver->caps,
436 &uml_driver->domains,
437 uml_driver->configDir,
438 uml_driver->autostartDir,
439 0, NULL, NULL) < 0)
440 goto error;
441
442 umlAutostartConfigs(uml_driver);
443
444 umlDriverUnlock(uml_driver);
445 VIR_FREE(userdir);
446
447 return 0;
448
449out_of_memory:
450 VIR_ERROR0(_("umlStartup: out of memory"));
451
452error:
453 VIR_FREE(userdir);
454 VIR_FREE(base);
455 umlDriverUnlock(uml_driver);
456 umlShutdown();
457 return -1;
458}
459
460/**
461 * umlReload:
462 *
463 * Function to restart the Uml daemon, it will recheck the configuration
464 * files and update its state and the networking
465 */
466static int
467umlReload(void) {
468 if (!uml_driver)
469 return 0;
470
471 umlDriverLock(uml_driver);
472 virDomainLoadAllConfigs(uml_driver->caps,
473 &uml_driver->domains,
474 uml_driver->configDir,
475 uml_driver->autostartDir,
476 0, NULL, NULL);
477
478 umlAutostartConfigs(uml_driver);
479 umlDriverUnlock(uml_driver);
480
481 return 0;
482}
483
484/**
485 * umlActive:
486 *
487 * Checks if the Uml daemon is active, i.e. has an active domain or
488 * an active network
489 *
490 * Returns 1 if active, 0 otherwise
491 */
492static int
493umlActive(void) {
494 int active = 0;
495
496 if (!uml_driver)
497 return 0;
498
499 umlDriverLock(uml_driver);
500 active = virDomainObjListNumOfDomains(&uml_driver->domains, 1);
501 umlDriverUnlock(uml_driver);
502
503 return active;
504}
505
506static void
507umlShutdownOneVM(void *payload, const char *name ATTRIBUTE_UNUSED, void *opaque)
508{
509 virDomainObjPtr dom = payload;
510 struct uml_driver *driver = opaque;
511
512 virDomainObjLock(dom);
513 if (virDomainObjIsActive(dom))
514 umlShutdownVMDaemon(NULL, driver, dom);
515 virDomainObjUnlock(dom);
516}
517
518/**
519 * umlShutdown:
520 *
521 * Shutdown the Uml daemon, it will stop all active domains and networks
522 */
523static int
524umlShutdown(void) {
525 if (!uml_driver)
526 return -1;
527
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);
533
534 /* shutdown active VMs
535 * XXX allow them to stay around & reconnect */
536 virHashForEach(uml_driver->domains.objs, umlShutdownOneVM, uml_driver);
537
538 virDomainObjListDeinit(&uml_driver->domains);
539
540 VIR_FREE(uml_driver->logDir);
541 VIR_FREE(uml_driver->configDir);
542 VIR_FREE(uml_driver->autostartDir);
543 VIR_FREE(uml_driver->monitorDir);
544
545 if (uml_driver->brctl)
546 brShutdown(uml_driver->brctl);
547
548 umlDriverUnlock(uml_driver);
549 virMutexDestroy(&uml_driver->lock);
550 VIR_FREE(uml_driver);
551
552 return 0;
553}
554
555
556static int umlReadPidFile(struct uml_driver *driver,
557 virDomainObjPtr vm)
558{
559 int rc = -1;
560 FILE *file;
561 char *pidfile = NULL;
562 int retries = 0;
563
564 vm->pid = -1;
565 if (virAsprintf(&pidfile, "%s/%s/pid",
566 driver->monitorDir, vm->def->name) < 0) {
567 virReportOOMError();
568 return -1;
569 }
570
571reopen:
572 if (!(file = fopen(pidfile, "r"))) {
573 if (errno == ENOENT &&
574 retries++ < 50) {
575 usleep(1000 * 100);
576 goto reopen;
577 }
578 goto cleanup;
579 }
580
581 if (fscanf(file, "%d", &vm->pid) != 1) {
582 errno = EINVAL;
583 fclose(file);
584 goto cleanup;
585 }
586
587 if (fclose(file) < 0)
588 goto cleanup;
589
590 rc = 0;
591
592 cleanup:
593 if (rc != 0)
594 virReportSystemError(errno,
595 _("failed to read pid: %s"),
596 pidfile);
597 VIR_FREE(pidfile);
598 return rc;
599}
600
601static int umlMonitorAddress(const struct uml_driver *driver,
602 virDomainObjPtr vm,
603 struct sockaddr_un *addr) {
604 char *sockname;
605 int retval = 0;
606
607 if (virAsprintf(&sockname, "%s/%s/mconsole",
608 driver->monitorDir, vm->def->name) < 0) {
609 virReportOOMError();
610 return -1;
611 }
612
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);
618 retval = -1;
619 }
620 VIR_FREE(sockname);
621 return retval;
622}
623
624static int umlOpenMonitor(struct uml_driver *driver,
625 virDomainObjPtr vm) {
626 struct sockaddr_un addr;
627 struct stat sb;
628 int retries = 0;
629 umlDomainObjPrivatePtr priv = vm->privateData;
630
631 if (umlMonitorAddress(driver, vm, &addr) < 0)
632 return -1;
633
634 VIR_DEBUG("Dest address for monitor is '%s'", addr.sun_path);
635restat:
636 if (stat(addr.sun_path, &sb) < 0) {
637 if (errno == ENOENT &&
638 retries++ < 50) {
639 usleep(1000 * 100);
640 goto restat;
641 }
642 return -1;
643 }
644
645 if ((priv->monitor = socket(PF_UNIX, SOCK_DGRAM, 0)) < 0) {
646 virReportSystemError(errno,
647 "%s", _("cannot open socket"));
648 return -1;
649 }
650
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);
658 priv->monitor = -1;
659 return -1;
660 }
661
662 return 0;
663}
664
665
666#define MONITOR_MAGIC 0xcafebabe
667#define MONITOR_BUFLEN 512
668#define MONITOR_VERSION 2
669
670struct monitor_request {
671 uint32_t magic;
672 uint32_t version;
673 uint32_t length;
674 char data[MONITOR_BUFLEN];
675};
676
677struct monitor_response {
678 uint32_t error;
679 uint32_t extra;
680 uint32_t length;
681 char data[MONITOR_BUFLEN];
682};
683
684
685static int umlMonitorCommand(const struct uml_driver *driver,
686 const virDomainObjPtr vm,
687 const char *cmd,
688 char **reply)
689{
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;
697
698 VIR_DEBUG("Run command '%s'", cmd);
699
700 *reply = NULL;
701
702 if (umlMonitorAddress(driver, vm, &addr) < 0)
703 return -1;
704
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)"),
712 cmd, req.length);
713 return -1;
714 }
715 if (virStrcpyStatic(req.data, cmd) == NULL) {
716 umlReportError(VIR_ERR_INTERNAL_ERROR,
717 _("Command %s too long for destination"), cmd);
718 return -1;
719 }
720
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"),
725 cmd);
726 return -1;
727 }
728
729 do {
730 ssize_t nbytes;
731 addrlen = sizeof(addr);
732 nbytes = recvfrom(priv->monitor, &res, sizeof res, 0,
733 (struct sockaddr *)&addr, &addrlen);
734 if (nbytes < 0) {
735 if (errno == EAGAIN || errno == EINTR)
736 continue;
737 virReportSystemError(errno, _("cannot read reply %s"), cmd);
738 goto error;
739 }
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);
744 goto error;
745 }
746
747 if (VIR_REALLOC_N(retdata, retlen + res.length) < 0) {
748 virReportOOMError();
749 goto error;
750 }
751 memcpy(retdata + retlen, res.data, res.length);
752 retlen += res.length - 1;
753 retdata[retlen] = '\0';
754
755 if (res.error)
756 ret = -1;
757
758 } while (res.extra);
759
760 VIR_DEBUG("Command reply is '%s'", NULLSTR(retdata));
761
762 if (ret < 0)
763 VIR_FREE(retdata);
764 else
765 *reply = retdata;
766
767 return ret;
768
769error:
770 VIR_FREE(retdata);
771 return -1;
772}
773
774
775static int umlCleanupTapDevices(virConnectPtr conn ATTRIBUTE_UNUSED,
776 virDomainObjPtr vm) {
777 int i;
778 int err;
779 int ret = 0;
780 brControl *brctl = NULL;
781 VIR_ERROR0(_("Cleanup tap"));
782 if (brInit(&brctl) < 0)
783 return -1;
784
785 for (i = 0 ; i < vm->def->nnets ; i++) {
786 virDomainNetDefPtr def = vm->def->nets[i];
787
788 if (def->type != VIR_DOMAIN_NET_TYPE_BRIDGE &&
789 def->type != VIR_DOMAIN_NET_TYPE_NETWORK)
790 continue;
791
792 VIR_ERROR(_("Cleanup '%s'"), def->ifname);
793 err = brDeleteTap(brctl, def->ifname);
794 if (err) {
795 VIR_ERROR(_("Cleanup failed %d"), err);
796 ret = -1;
797 }
798 }
799 VIR_ERROR0(_("Cleanup tap done"));
800 brShutdown(brctl);
801 return ret;
802}
803
804static int umlStartVMDaemon(virConnectPtr conn,
805 struct uml_driver *driver,
806 virDomainObjPtr vm) {
807 const char **argv = NULL, **tmp;
808 const char **progenv = NULL;
809 int i, ret;
810 pid_t pid;
811 char *logfile;
812 int logfd = -1;
813 struct stat sb;
814 fd_set keepfd;
815 char ebuf[1024];
816 umlDomainObjPrivatePtr priv = vm->privateData;
817
818 FD_ZERO(&keepfd);
819
820 if (virDomainObjIsActive(vm)) {
821 umlReportError(VIR_ERR_INTERNAL_ERROR, "%s",
822 _("VM is already active"));
823 return -1;
824 }
825
826 if (!vm->def->os.kernel) {
827 umlReportError(VIR_ERR_INTERNAL_ERROR, "%s",
828 _("no kernel specified"));
829 return -1;
830 }
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
834 */
835 if (stat(vm->def->os.kernel, &sb) < 0) {
836 virReportSystemError(errno,
837 _("Cannot find UML kernel %s"),
838 vm->def->os.kernel);
839 return -1;
840 }
841
842 if (virFileMakePath(driver->logDir) != 0) {
843 virReportSystemError(errno,
844 _("cannot create log directory %s"),
845 driver->logDir);
846 return -1;
847 }
848
849 if (virAsprintf(&logfile, "%s/%s.log",
850 driver->logDir, vm->def->name) < 0) {
851 virReportOOMError();
852 return -1;
853 }
854
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"),
859 logfile);
860 VIR_FREE(logfile);
861 return -1;
862 }
863 VIR_FREE(logfile);
864
865 if (umlSetCloseExec(logfd) < 0) {
866 virReportSystemError(errno,
867 "%s", _("Unable to set VM logfile close-on-exec flag"));
868 close(logfd);
869 return -1;
870 }
871
872 if (umlBuildCommandLine(conn, driver, vm, &keepfd,
873 &argv, &progenv) < 0) {
874 close(logfd);
875 umlCleanupTapDevices(conn, vm);
876 return -1;
877 }
878
879 tmp = progenv;
880 while (*tmp) {
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));
887 tmp++;
888 }
889 tmp = argv;
890 while (*tmp) {
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));
897 tmp++;
898 }
899 if (safewrite(logfd, "\n", 1) < 0)
900 VIR_WARN("Unable to write argv to logfile: %s",
901 virStrerror(errno, ebuf, sizeof ebuf));
902
903 priv->monitor = -1;
904
905 ret = virExecDaemonize(argv, progenv, &keepfd, &pid,
906 -1, &logfd, &logfd,
907 VIR_EXEC_CLEAR_CAPS,
908 NULL, NULL, NULL);
909 close(logfd);
910
911 /*
912 * At the moment, the only thing that populates keepfd is
913 * umlBuildCommandLineChr. We want to close every fd it opens.
914 */
915 for (i = 0; i < FD_SETSIZE; i++)
916 if (FD_ISSET(i, &keepfd))
917 close(i);
918
919 for (i = 0 ; argv[i] ; i++)
920 VIR_FREE(argv[i]);
921 VIR_FREE(argv);
922
923 for (i = 0 ; progenv[i] ; i++)
924 VIR_FREE(progenv[i]);
925 VIR_FREE(progenv);
926
927 if (ret < 0)
928 umlCleanupTapDevices(conn, vm);
929
930 /* NB we don't mark it running here - we do that async
931 with inotify */
932 /* XXX what if someone else tries to start it again
933 before we get the inotification ? Sounds like
934 trouble.... */
935
936 return ret;
937}
938
939static void umlShutdownVMDaemon(virConnectPtr conn ATTRIBUTE_UNUSED,
940 struct uml_driver *driver ATTRIBUTE_UNUSED,
941 virDomainObjPtr vm)
942{
943 int ret;
944 umlDomainObjPrivatePtr priv = vm->privateData;
945
946 if (!virDomainObjIsActive(vm))
947 return;
948
949 virKillProcess(vm->pid, SIGTERM);
950
951 if (priv->monitor != -1)
952 close(priv->monitor);
953 priv->monitor = -1;
954
955 if ((ret = waitpid(vm->pid, NULL, 0)) != vm->pid) {
956 VIR_WARN("Got unexpected pid %d != %d",
957 ret, vm->pid);
958 }
959
960 vm->pid = -1;
961 vm->def->id = -1;
962 vm->state = VIR_DOMAIN_SHUTOFF;
963
964 umlCleanupTapDevices(conn, vm);
965
966 if (vm->newDef) {
967 virDomainDefFree(vm->def);
968 vm->def = vm->newDef;
969 vm->def->id = -1;
970 vm->newDef = NULL;
971 }
972}
973
974
975static virDrvOpenStatus umlOpen(virConnectPtr conn,
976 virConnectAuthPtr auth ATTRIBUTE_UNUSED,
977 int flags ATTRIBUTE_UNUSED) {
978 if (conn->uri == NULL) {
979 if (uml_driver == NULL)
980 return VIR_DRV_OPEN_DECLINED;
981
982 conn->uri = xmlParseURI(uml_driver->privileged ?
983 "uml:///system" :
984 "uml:///session");
985 if (!conn->uri) {
986 virReportOOMError();
987 return VIR_DRV_OPEN_ERROR;
988 }
989 } else {
990 if (conn->uri->scheme == NULL ||
991 STRNEQ (conn->uri->scheme, "uml"))
992 return VIR_DRV_OPEN_DECLINED;
993
994 /* Allow remote driver to deal with URIs with hostname server */
995 if (conn->uri->server != NULL)
996 return VIR_DRV_OPEN_DECLINED;
997
998
999 /* Check path and tell them correct path if they made a mistake */
1000 if (uml_driver->privileged) {
1001 if (STRNEQ (conn->uri->path, "/system") &&
1002 STRNEQ (conn->uri->path, "/session")) {
1003 umlReportError(VIR_ERR_INTERNAL_ERROR,
1004 _("unexpected UML URI path '%s', try uml:///system"),
1005 conn->uri->path);
1006 return VIR_DRV_OPEN_ERROR;
1007 }
1008 } else {
1009 if (STRNEQ (conn->uri->path, "/session")) {
1010 umlReportError(VIR_ERR_INTERNAL_ERROR,
1011 _("unexpected UML URI path '%s', try uml:///session"),
1012 conn->uri->path);
1013 return VIR_DRV_OPEN_ERROR;
1014 }
1015 }
1016
1017 /* URI was good, but driver isn't active */
1018 if (uml_driver == NULL) {
1019 umlReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1020 _("uml state driver is not active"));
1021 return VIR_DRV_OPEN_ERROR;
1022 }
1023 }
1024
1025 conn->privateData = uml_driver;
1026
1027 return VIR_DRV_OPEN_SUCCESS;
1028}
1029
1030static int umlClose(virConnectPtr conn) {
1031 /*struct uml_driver *driver = conn->privateData;*/
1032
1033 conn->privateData = NULL;
1034
1035 return 0;
1036}
1037
1038static const char *umlGetType(virConnectPtr conn ATTRIBUTE_UNUSED) {
1039 return "UML";
1040}
1041
1042
1043static int umlIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED)
1044{
1045 /* Trivially secure, since always inside the daemon */
1046 return 1;
1047}
1048
1049
1050static int umlIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED)
1051{
1052 /* Not encrypted, but remote driver takes care of that */
1053 return 0;
1054}
1055
1056
1057static char *umlGetCapabilities(virConnectPtr conn) {
1058 struct uml_driver *driver = (struct uml_driver *)conn->privateData;
1059 char *xml;
1060
1061 umlDriverLock(driver);
1062 if ((xml = virCapabilitiesFormatXML(driver->caps)) == NULL)
1063 virReportOOMError();
1064 umlDriverUnlock(driver);
1065
1066 return xml;
1067}
1068
1069
1070
1071static int umlGetProcessInfo(unsigned long long *cpuTime, int pid) {
1072 char proc[PATH_MAX];
1073 FILE *pidinfo;
1074 unsigned long long usertime, systime;
1075
1076 if (snprintf(proc, sizeof(proc), "/proc/%d/stat", pid) >= (int)sizeof(proc)) {
1077 return -1;
1078 }
1079
1080 if (!(pidinfo = fopen(proc, "r"))) {
1081 /*printf("cannot read pid info");*/
1082 /* VM probably shut down, so fake 0 */
1083 *cpuTime = 0;
1084 return 0;
1085 }
1086
1087 if (fscanf(pidinfo, "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %llu %llu", &usertime, &systime) != 2) {
1088 umlDebug("not enough arg");
1089 fclose(pidinfo);
1090 return -1;
1091 }
1092
1093 /* We got jiffies
1094 * We want nanoseconds
1095 * _SC_CLK_TCK is jiffies per second
1096 * So calulate thus....
1097 */
1098 *cpuTime = 1000ull * 1000ull * 1000ull * (usertime + systime) / (unsigned long long)sysconf(_SC_CLK_TCK);
1099
1100 umlDebug("Got %llu %llu %llu", usertime, systime, *cpuTime);
1101
1102 fclose(pidinfo);
1103
1104 return 0;
1105}
1106
1107
1108static virDomainPtr umlDomainLookupByID(virConnectPtr conn,
1109 int id) {
1110 struct uml_driver *driver = (struct uml_driver *)conn->privateData;
1111 virDomainObjPtr vm;
1112 virDomainPtr dom = NULL;
1113
1114 umlDriverLock(driver);
1115 vm = virDomainFindByID(&driver->domains, id);
1116 umlDriverUnlock(driver);
1117
1118 if (!vm) {
1119 umlReportError(VIR_ERR_NO_DOMAIN, NULL);
1120 goto cleanup;
1121 }
1122
1123 dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
1124 if (dom) dom->id = vm->def->id;
1125
1126cleanup:
1127 if (vm)
1128 virDomainObjUnlock(vm);
1129 return dom;
1130}
1131
1132static virDomainPtr umlDomainLookupByUUID(virConnectPtr conn,
1133 const unsigned char *uuid) {
1134 struct uml_driver *driver = (struct uml_driver *)conn->privateData;
1135 virDomainObjPtr vm;
1136 virDomainPtr dom = NULL;
1137
1138 umlDriverLock(driver);
1139 vm = virDomainFindByUUID(&driver->domains, uuid);
1140 umlDriverUnlock(driver);
1141
1142 if (!vm) {
1143 umlReportError(VIR_ERR_NO_DOMAIN, NULL);
1144 goto cleanup;
1145 }
1146
1147 dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
1148 if (dom) dom->id = vm->def->id;
1149
1150cleanup:
1151 if (vm)
1152 virDomainObjUnlock(vm);
1153 return dom;
1154}
1155
1156static virDomainPtr umlDomainLookupByName(virConnectPtr conn,
1157 const char *name) {
1158 struct uml_driver *driver = (struct uml_driver *)conn->privateData;
1159 virDomainObjPtr vm;
1160 virDomainPtr dom = NULL;
1161
1162 umlDriverLock(driver);
1163 vm = virDomainFindByName(&driver->domains, name);
1164 umlDriverUnlock(driver);
1165
1166 if (!vm) {
1167 umlReportError(VIR_ERR_NO_DOMAIN, NULL);
1168 goto cleanup;
1169 }
1170
1171 dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
1172 if (dom) dom->id = vm->def->id;
1173
1174cleanup:
1175 if (vm)
1176 virDomainObjUnlock(vm);
1177 return dom;
1178}
1179
1180
1181static int umlDomainIsActive(virDomainPtr dom)
1182{
1183 struct uml_driver *driver = dom->conn->privateData;
1184 virDomainObjPtr obj;
1185 int ret = -1;
1186
1187 umlDriverLock(driver);
1188 obj = virDomainFindByUUID(&driver->domains, dom->uuid);
1189 umlDriverUnlock(driver);
1190 if (!obj) {
1191 umlReportError(VIR_ERR_NO_DOMAIN, NULL);
1192 goto cleanup;
1193 }
1194 ret = virDomainObjIsActive(obj);
1195
1196cleanup:
1197 if (obj)
1198 virDomainObjUnlock(obj);
1199 return ret;
1200}
1201
1202
1203static int umlDomainIsPersistent(virDomainPtr dom)
1204{
1205 struct uml_driver *driver = dom->conn->privateData;
1206 virDomainObjPtr obj;
1207 int ret = -1;
1208
1209 umlDriverLock(driver);
1210 obj = virDomainFindByUUID(&driver->domains, dom->uuid);
1211 umlDriverUnlock(driver);
1212 if (!obj) {
1213 umlReportError(VIR_ERR_NO_DOMAIN, NULL);
1214 goto cleanup;
1215 }
1216 ret = obj->persistent;
1217
1218cleanup:
1219 if (obj)
1220 virDomainObjUnlock(obj);
1221 return ret;
1222}
1223
1224
1225static int umlGetVersion(virConnectPtr conn, unsigned long *version) {
1226 struct uml_driver *driver = conn->privateData;
1227 struct utsname ut;
1228 int ret = -1;
1229
1230 umlDriverLock(driver);
1231
1232 if (driver->umlVersion == 0) {
1233 uname(&ut);
1234
1235 if (virParseVersionString(ut.release, &driver->umlVersion) < 0) {
1236 umlReportError(VIR_ERR_INTERNAL_ERROR,
1237 _("cannot parse version %s"), ut.release);
1238 goto cleanup;
1239 }
1240 }
1241
1242 *version = driver->umlVersion;
1243 ret = 0;
1244
1245cleanup:
1246 umlDriverUnlock(driver);
1247 return ret;
1248}
1249
1250static int umlListDomains(virConnectPtr conn, int *ids, int nids) {
1251 struct uml_driver *driver = conn->privateData;
1252 int n;
1253
1254 umlDriverLock(driver);
1255 n = virDomainObjListGetActiveIDs(&driver->domains, ids, nids);
1256 umlDriverUnlock(driver);
1257
1258 return n;
1259}
1260static int umlNumDomains(virConnectPtr conn) {
1261 struct uml_driver *driver = conn->privateData;
1262 int n;
1263
1264 umlDriverLock(driver);
1265 n = virDomainObjListNumOfDomains(&driver->domains, 1);
1266 umlDriverUnlock(driver);
1267
1268 return n;
1269}
1270static virDomainPtr umlDomainCreate(virConnectPtr conn, const char *xml,
1271 unsigned int flags) {
1272 struct uml_driver *driver = conn->privateData;
1273 virDomainDefPtr def;
1274 virDomainObjPtr vm = NULL;
1275 virDomainPtr dom = NULL;
1276
1277 virCheckFlags(0, NULL);
1278
1279 umlDriverLock(driver);
1280 if (!(def = virDomainDefParseString(driver->caps, xml,
1281 VIR_DOMAIN_XML_INACTIVE)))
1282 goto cleanup;
1283
1284 if (virDomainObjIsDuplicate(&driver->domains, def, 1) < 0)
1285 goto cleanup;
1286
1287 if (!(vm = virDomainAssignDef(driver->caps,
1288 &driver->domains,
1289 def, false)))
1290 goto cleanup;
1291 def = NULL;
1292
1293 if (umlStartVMDaemon(conn, driver, vm) < 0) {
1294 virDomainRemoveInactive(&driver->domains,
1295 vm);
1296 vm = NULL;
1297 goto cleanup;
1298 }
1299
1300 dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
1301 if (dom) dom->id = vm->def->id;
1302
1303cleanup:
1304 virDomainDefFree(def);
1305 if (vm)
1306 virDomainObjUnlock(vm);
1307 umlDriverUnlock(driver);
1308 return dom;
1309}
1310
1311
1312static int umlDomainShutdown(virDomainPtr dom) {
1313 struct uml_driver *driver = dom->conn->privateData;
1314 virDomainObjPtr vm;
1315 char *info = NULL;
1316 int ret = -1;
1317
1318 umlDriverLock(driver);
1319 vm = virDomainFindByID(&driver->domains, dom->id);
1320 umlDriverUnlock(driver);
1321 if (!vm) {
1322 umlReportError(VIR_ERR_INVALID_DOMAIN,
1323 _("no domain with matching id %d"), dom->id);
1324 goto cleanup;
1325 }
1326
1327#if 0
1328 if (umlMonitorCommand(driver, vm, "system_powerdown", &info) < 0) {
1329 umlReportError(VIR_ERR_OPERATION_FAILED, "%s",
1330 _("shutdown operation failed"));
1331 goto cleanup;
1332 }
1333 ret = 0;
1334#endif
1335
1336cleanup:
1337 VIR_FREE(info);
1338 if (vm)
1339 virDomainObjUnlock(vm);
1340 return ret;
1341}
1342
1343
1344static int umlDomainDestroy(virDomainPtr dom) {
1345 struct uml_driver *driver = dom->conn->privateData;
1346 virDomainObjPtr vm;
1347 int ret = -1;
1348
1349 umlDriverLock(driver);
1350 vm = virDomainFindByID(&driver->domains, dom->id);
1351 if (!vm) {
1352 umlReportError(VIR_ERR_INVALID_DOMAIN,
1353 _("no domain with matching id %d"), dom->id);
1354 goto cleanup;
1355 }
1356
1357 umlShutdownVMDaemon(dom->conn, driver, vm);
1358 if (!vm->persistent) {
1359 virDomainRemoveInactive(&driver->domains,
1360 vm);
1361 vm = NULL;
1362 }
1363 ret = 0;
1364
1365cleanup:
1366 if (vm)
1367 virDomainObjUnlock(vm);
1368 umlDriverUnlock(driver);
1369 return ret;
1370}
1371
1372
1373static char *umlDomainGetOSType(virDomainPtr dom) {
1374 struct uml_driver *driver = dom->conn->privateData;
1375 virDomainObjPtr vm;
1376 char *type = NULL;
1377
1378 umlDriverLock(driver);
1379 vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1380 umlDriverUnlock(driver);
1381 if (!vm) {
1382 umlReportError(VIR_ERR_INVALID_DOMAIN, "%s",
1383 _("no domain with matching uuid"));
1384 goto cleanup;
1385 }
1386
1387 if (!(type = strdup(vm->def->os.type)))
1388 virReportOOMError();
1389
1390cleanup:
1391 if (vm)
1392 virDomainObjUnlock(vm);
1393 return type;
1394}
1395
1396/* Returns max memory in kb, 0 if error */
1397static unsigned long umlDomainGetMaxMemory(virDomainPtr dom) {
1398 struct uml_driver *driver = dom->conn->privateData;
1399 virDomainObjPtr vm;
1400 unsigned long ret = 0;
1401
1402 umlDriverLock(driver);
1403 vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1404 umlDriverUnlock(driver);
1405
1406 if (!vm) {
1407 char uuidstr[VIR_UUID_STRING_BUFLEN];
1408
1409 virUUIDFormat(dom->uuid, uuidstr);
1410 umlReportError(VIR_ERR_INVALID_DOMAIN,
1411 _("no domain with matching uuid '%s'"), uuidstr);
1412 goto cleanup;
1413 }
1414 ret = vm->def->maxmem;
1415
1416cleanup:
1417 if (vm)
1418 virDomainObjUnlock(vm);
1419 return ret;
1420}
1421
1422static int umlDomainSetMaxMemory(virDomainPtr dom, unsigned long newmax) {
1423 struct uml_driver *driver = dom->conn->privateData;
1424 virDomainObjPtr vm;
1425 int ret = -1;
1426
1427 umlDriverLock(driver);
1428 vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1429 umlDriverUnlock(driver);
1430
1431 if (!vm) {
1432 char uuidstr[VIR_UUID_STRING_BUFLEN];
1433
1434 virUUIDFormat(dom->uuid, uuidstr);
1435 umlReportError(VIR_ERR_INVALID_DOMAIN,
1436 _("no domain with matching uuid '%s'"), uuidstr);
1437 goto cleanup;
1438 }
1439
1440 if (newmax < vm->def->memory) {
1441 umlReportError(VIR_ERR_INVALID_ARG, "%s",
1442 _("cannot set max memory lower than current memory"));
1443 goto cleanup;
1444 }
1445
1446 vm->def->maxmem = newmax;
1447 ret = 0;
1448
1449cleanup:
1450 if (vm)
1451 virDomainObjUnlock(vm);
1452 return ret;
1453}
1454
1455static int umlDomainSetMemory(virDomainPtr dom, unsigned long newmem) {
1456 struct uml_driver *driver = dom->conn->privateData;
1457 virDomainObjPtr vm;
1458 int ret = -1;
1459
1460 umlDriverLock(driver);
1461 vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1462 umlDriverUnlock(driver);
1463
1464 if (!vm) {
1465 char uuidstr[VIR_UUID_STRING_BUFLEN];
1466
1467 virUUIDFormat(dom->uuid, uuidstr);
1468 umlReportError(VIR_ERR_INVALID_DOMAIN,
1469 _("no domain with matching uuid '%s'"), uuidstr);
1470 goto cleanup;
1471 }
1472
1473 if (virDomainObjIsActive(vm)) {
1474 umlReportError(VIR_ERR_NO_SUPPORT, "%s",
1475 _("cannot set memory of an active domain"));
1476 goto cleanup;
1477 }
1478
1479 if (newmem > vm->def->maxmem) {
1480 umlReportError(VIR_ERR_INVALID_ARG, "%s",
1481 _("cannot set memory higher than max memory"));
1482 goto cleanup;
1483 }
1484
1485 vm->def->memory = newmem;
1486 ret = 0;
1487
1488cleanup:
1489 if (vm)
1490 virDomainObjUnlock(vm);
1491 return ret;
1492}
1493
1494static int umlDomainGetInfo(virDomainPtr dom,
1495 virDomainInfoPtr info) {
1496 struct uml_driver *driver = dom->conn->privateData;
1497 virDomainObjPtr vm;
1498 int ret = -1;
1499
1500 umlDriverLock(driver);
1501 vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1502 umlDriverUnlock(driver);
1503
1504 if (!vm) {
1505 umlReportError(VIR_ERR_INVALID_DOMAIN, "%s",
1506 _("no domain with matching uuid"));
1507 goto cleanup;
1508 }
1509
1510 info->state = vm->state;
1511
1512 if (!virDomainObjIsActive(vm)) {
1513 info->cpuTime = 0;
1514 } else {
1515 if (umlGetProcessInfo(&(info->cpuTime), vm->pid) < 0) {
1516 umlReportError(VIR_ERR_OPERATION_FAILED, "%s",
1517 _("cannot read cputime for domain"));
1518 goto cleanup;
1519 }
1520 }
1521
1522 info->maxMem = vm->def->maxmem;
1523 info->memory = vm->def->memory;
1524 info->nrVirtCpu = vm->def->vcpus;
1525 ret = 0;
1526
1527cleanup:
1528 if (vm)
1529 virDomainObjUnlock(vm);
1530 return ret;
1531}
1532
1533
1534static char *umlDomainDumpXML(virDomainPtr dom,
1535 int flags ATTRIBUTE_UNUSED) {
1536 struct uml_driver *driver = dom->conn->privateData;
1537 virDomainObjPtr vm;
1538 char *ret = NULL;
1539
1540 umlDriverLock(driver);
1541 vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1542 umlDriverUnlock(driver);
1543
1544 if (!vm) {
1545 umlReportError(VIR_ERR_INVALID_DOMAIN, "%s",
1546 _("no domain with matching uuid"));
1547 goto cleanup;
1548 }
1549
1550 ret = virDomainDefFormat((flags & VIR_DOMAIN_XML_INACTIVE) && vm->newDef ?
1551 vm->newDef : vm->def,
1552 flags);
1553
1554cleanup:
1555 if (vm)
1556 virDomainObjUnlock(vm);
1557 return ret;
1558}
1559
1560
1561static int umlListDefinedDomains(virConnectPtr conn,
1562 char **const names, int nnames) {
1563 struct uml_driver *driver = conn->privateData;
1564 int n;
1565
1566 umlDriverLock(driver);
1567 n = virDomainObjListGetInactiveNames(&driver->domains, names, nnames);
1568 umlDriverUnlock(driver);
1569
1570 return n;
1571}
1572
1573static int umlNumDefinedDomains(virConnectPtr conn) {
1574 struct uml_driver *driver = conn->privateData;
1575 int n;
1576
1577 umlDriverLock(driver);
1578 n = virDomainObjListNumOfDomains(&driver->domains, 0);
1579 umlDriverUnlock(driver);
1580
1581 return n;
1582}
1583
1584
1585static int umlDomainStartWithFlags(virDomainPtr dom, unsigned int flags) {
1586 struct uml_driver *driver = dom->conn->privateData;
1587 virDomainObjPtr vm;
1588 int ret = -1;
1589
1590 virCheckFlags(0, -1);
1591
1592 umlDriverLock(driver);
1593 vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1594
1595 if (!vm) {
1596 umlReportError(VIR_ERR_INVALID_DOMAIN, "%s",
1597 _("no domain with matching uuid"));
1598 goto cleanup;
1599 }
1600
1601 ret = umlStartVMDaemon(dom->conn, driver, vm);
1602
1603cleanup:
1604 if (vm)
1605 virDomainObjUnlock(vm);
1606 umlDriverUnlock(driver);
1607 return ret;
1608}
1609
1610static int umlDomainStart(virDomainPtr dom) {
1611 return umlDomainStartWithFlags(dom, 0);
1612}
1613
1614static virDomainPtr umlDomainDefine(virConnectPtr conn, const char *xml) {
1615 struct uml_driver *driver = conn->privateData;
1616 virDomainDefPtr def;
1617 virDomainObjPtr vm = NULL;
1618 virDomainPtr dom = NULL;
1619
1620 umlDriverLock(driver);
1621 if (!(def = virDomainDefParseString(driver->caps, xml,
1622 VIR_DOMAIN_XML_INACTIVE)))
1623 goto cleanup;
1624
1625 if (virDomainObjIsDuplicate(&driver->domains, def, 0) < 0)
1626 goto cleanup;
1627
1628 if (!(vm = virDomainAssignDef(driver->caps,
1629 &driver->domains,
1630 def, false)))
1631 goto cleanup;
1632 def = NULL;
1633 vm->persistent = 1;
1634
1635 if (virDomainSaveConfig(driver->configDir,
1636 vm->newDef ? vm->newDef : vm->def) < 0) {
1637 virDomainRemoveInactive(&driver->domains,
1638 vm);
1639 vm = NULL;
1640 goto cleanup;
1641 }
1642
1643 dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
1644 if (dom) dom->id = vm->def->id;
1645
1646cleanup:
1647 virDomainDefFree(def);
1648 if (vm)
1649 virDomainObjUnlock(vm);
1650 umlDriverUnlock(driver);
1651 return dom;
1652}
1653
1654static int umlDomainUndefine(virDomainPtr dom) {
1655 struct uml_driver *driver = dom->conn->privateData;
1656 virDomainObjPtr vm;
1657 int ret = -1;
1658
1659 umlDriverLock(driver);
1660 vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1661 if (!vm) {
1662 umlReportError(VIR_ERR_INVALID_DOMAIN, "%s",
1663 _("no domain with matching uuid"));
1664 goto cleanup;
1665 }
1666
1667 if (virDomainObjIsActive(vm)) {
1668 umlReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1669 _("cannot delete active domain"));
1670 goto cleanup;
1671 }
1672
1673 if (!vm->persistent) {
1674 umlReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1675 _("cannot undefine transient domain"));
1676 goto cleanup;
1677 }
1678
1679 if (virDomainDeleteConfig(driver->configDir, driver->autostartDir, vm) < 0)
1680 goto cleanup;
1681
1682 virDomainRemoveInactive(&driver->domains,
1683 vm);
1684 vm = NULL;
1685 ret = 0;
1686
1687cleanup:
1688 if (vm)
1689 virDomainObjUnlock(vm);
1690 umlDriverUnlock(driver);
1691 return ret;
1692}
1693
1694
1695static int umlDomainAttachUmlDisk(struct uml_driver *driver,
1696 virDomainObjPtr vm,
1697 virDomainDiskDefPtr disk)
1698{
1699 int i;
1700 char *cmd = NULL;
1701 char *reply = NULL;
1702
1703 for (i = 0 ; i < vm->def->ndisks ; i++) {
1704 if (STREQ(vm->def->disks[i]->dst, disk->dst)) {
1705 umlReportError(VIR_ERR_OPERATION_FAILED,
1706 _("target %s already exists"), disk->dst);
1707 return -1;
1708 }
1709 }
1710
1711 if (!disk->src) {
1712 umlReportError(VIR_ERR_INTERNAL_ERROR,
1713 "%s", _("disk source path is missing"));
1714 goto error;
1715 }
1716
1717 if (virAsprintf(&cmd, "config %s=%s", disk->dst, disk->src) < 0) {
1718 virReportOOMError();
1719 return -1;
1720 }
1721
1722 if (umlMonitorCommand(driver, vm, cmd, &reply) < 0)
1723 goto error;
1724
1725 if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0) {
1726 virReportOOMError();
1727 goto error;
1728 }
1729
1730 virDomainDiskInsertPreAlloced(vm->def, disk);
1731
1732 VIR_FREE(reply);
1733 VIR_FREE(cmd);
1734
1735 return 0;
1736
1737error:
1738
1739 VIR_FREE(reply);
1740 VIR_FREE(cmd);
1741
1742 return -1;
1743}
1744
1745
1746static int umlDomainAttachDevice(virDomainPtr dom, const char *xml)
1747{
1748 struct uml_driver *driver = dom->conn->privateData;
1749 virDomainObjPtr vm;
1750 virDomainDeviceDefPtr dev = NULL;
1751 int ret = -1;
1752
1753 umlDriverLock(driver);
1754
1755 vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1756 if (!vm) {
1757 char uuidstr[VIR_UUID_STRING_BUFLEN];
1758 virUUIDFormat(dom->uuid, uuidstr);
1759 umlReportError(VIR_ERR_NO_DOMAIN,
1760 _("no domain with matching uuid '%s'"), uuidstr);
1761 goto cleanup;
1762 }
1763
1764 if (!virDomainObjIsActive(vm)) {
1765 umlReportError(VIR_ERR_OPERATION_INVALID,
1766 "%s", _("cannot attach device on inactive domain"));
1767 goto cleanup;
1768 }
1769
1770 dev = virDomainDeviceDefParse(driver->caps, vm->def, xml,
1771 VIR_DOMAIN_XML_INACTIVE);
1772
1773 if (dev == NULL)
1774 goto cleanup;
1775
1776 if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
1777 if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_UML) {
1778 ret = umlDomainAttachUmlDisk(driver, vm, dev->data.disk);
1779 if (ret == 0)
1780 dev->data.disk = NULL;
1781 } else {
1782 umlReportError(VIR_ERR_CONFIG_UNSUPPORTED,
1783 _("disk bus '%s' cannot be hotplugged."),
1784 virDomainDiskBusTypeToString(dev->data.disk->bus));
1785 }
1786 } else {
1787 umlReportError(VIR_ERR_CONFIG_UNSUPPORTED,
1788 _("device type '%s' cannot be attached"),
1789 virDomainDeviceTypeToString(dev->type));
1790 goto cleanup;
1791 }
1792
1793cleanup:
1794
1795 virDomainDeviceDefFree(dev);
1796 if (vm)
1797 virDomainObjUnlock(vm);
1798 umlDriverUnlock(driver);
1799 return ret;
1800}
1801
1802
1803static int umlDomainAttachDeviceFlags(virDomainPtr dom,
1804 const char *xml,
1805 unsigned int flags) {
1806 if (flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG) {
1807 umlReportError(VIR_ERR_OPERATION_INVALID,
1808 "%s", _("cannot modify the persistent configuration of a domain"));
1809 return -1;
1810 }
1811
1812 return umlDomainAttachDevice(dom, xml);
1813}
1814
1815
1816static int umlDomainDetachUmlDisk(struct uml_driver *driver,
1817 virDomainObjPtr vm,
1818 virDomainDeviceDefPtr dev)
1819{
1820 int i, ret = -1;
1821 virDomainDiskDefPtr detach = NULL;
1822 char *cmd;
1823 char *reply;
1824
1825 for (i = 0 ; i < vm->def->ndisks ; i++) {
1826 if (STREQ(vm->def->disks[i]->dst, dev->data.disk->dst)) {
1827 break;
1828 }
1829 }
1830
1831 if (i == vm->def->ndisks) {
1832 umlReportError(VIR_ERR_OPERATION_FAILED,
1833 _("disk %s not found"), dev->data.disk->dst);
1834 return -1;
1835 }
1836
1837 detach = vm->def->disks[i];
1838
1839 if (virAsprintf(&cmd, "remove %s", detach->dst) < 0) {
1840 virReportOOMError();
1841 return -1;
1842 }
1843
1844 if (umlMonitorCommand(driver, vm, cmd, &reply) < 0)
1845 goto cleanup;
1846
1847 virDomainDiskRemove(vm->def, i);
1848
1849 virDomainDiskDefFree(detach);
1850
1851 ret = 0;
1852
1853 VIR_FREE(reply);
1854
1855cleanup:
1856 VIR_FREE(cmd);
1857
1858 return ret;
1859}
1860
1861
1862static int umlDomainDetachDevice(virDomainPtr dom, const char *xml) {
1863 struct uml_driver *driver = dom->conn->privateData;
1864 virDomainObjPtr vm;
1865 virDomainDeviceDefPtr dev = NULL;
1866 int ret = -1;
1867
1868 umlDriverLock(driver);
1869 vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1870 if (!vm) {
1871 char uuidstr[VIR_UUID_STRING_BUFLEN];
1872 virUUIDFormat(dom->uuid, uuidstr);
1873 umlReportError(VIR_ERR_NO_DOMAIN,
1874 _("no domain with matching uuid '%s'"), uuidstr);
1875 goto cleanup;
1876 }
1877
1878 if (!virDomainObjIsActive(vm)) {
1879 umlReportError(VIR_ERR_OPERATION_INVALID,
1880 "%s", _("cannot detach device on inactive domain"));
1881 goto cleanup;
1882 }
1883
1884 dev = virDomainDeviceDefParse(driver->caps, vm->def, xml,
1885 VIR_DOMAIN_XML_INACTIVE);
1886 if (dev == NULL)
1887 goto cleanup;
1888
1889 if (dev->type == VIR_DOMAIN_DEVICE_DISK &&
1890 dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
1891 if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_UML)
1892 ret = umlDomainDetachUmlDisk(driver, vm, dev);
1893 else {
1894 umlReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
1895 _("This type of disk cannot be hot unplugged"));
1896 }
1897 } else {
1898 umlReportError(VIR_ERR_CONFIG_UNSUPPORTED,
1899 "%s", _("This type of device cannot be hot unplugged"));
1900 }
1901
1902cleanup:
1903 virDomainDeviceDefFree(dev);
1904 if (vm)
1905 virDomainObjUnlock(vm);
1906 umlDriverUnlock(driver);
1907 return ret;
1908}
1909
1910
1911static int umlDomainDetachDeviceFlags(virDomainPtr dom,
1912 const char *xml,
1913 unsigned int flags) {
1914 if (flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG) {
1915 umlReportError(VIR_ERR_OPERATION_INVALID,
1916 "%s", _("cannot modify the persistent configuration of a domain"));
1917 return -1;
1918 }
1919
1920 return umlDomainDetachDevice(dom, xml);
1921}
1922
1923
1924static int umlDomainGetAutostart(virDomainPtr dom,
1925 int *autostart) {
1926 struct uml_driver *driver = dom->conn->privateData;
1927 virDomainObjPtr vm;
1928 int ret = -1;
1929
1930 umlDriverLock(driver);
1931 vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1932
1933 if (!vm) {
1934 umlReportError(VIR_ERR_INVALID_DOMAIN, "%s",
1935 _("no domain with matching uuid"));
1936 goto cleanup;
1937 }
1938
1939 *autostart = vm->autostart;
1940 ret = 0;
1941
1942cleanup:
1943 if (vm)
1944 virDomainObjUnlock(vm);
1945 umlDriverUnlock(driver);
1946 return ret;
1947}
1948
1949static int umlDomainSetAutostart(virDomainPtr dom,
1950 int autostart) {
1951 struct uml_driver *driver = dom->conn->privateData;
1952 virDomainObjPtr vm;
1953 char *configFile = NULL, *autostartLink = NULL;
1954 int ret = -1;
1955
1956 umlDriverLock(driver);
1957 vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1958
1959 if (!vm) {
1960 umlReportError(VIR_ERR_INVALID_DOMAIN, "%s",
1961 _("no domain with matching uuid"));
1962 goto cleanup;
1963 }
1964
1965 if (!vm->persistent) {
1966 umlReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1967 _("cannot set autostart for transient domain"));
1968 goto cleanup;
1969 }
1970
1971 autostart = (autostart != 0);
1972
1973 if (vm->autostart != autostart) {
1974 if ((configFile = virDomainConfigFile(driver->configDir, vm->def->name)) == NULL)
1975 goto cleanup;
1976 if ((autostartLink = virDomainConfigFile(driver->autostartDir, vm->def->name)) == NULL)
1977 goto cleanup;
1978
1979 if (autostart) {
1980 int err;
1981
1982 if ((err = virFileMakePath(driver->autostartDir))) {
1983 virReportSystemError(err,
1984 _("cannot create autostart directory %s"),
1985 driver->autostartDir);
1986 goto cleanup;
1987 }
1988
1989 if (symlink(configFile, autostartLink) < 0) {
1990 virReportSystemError(errno,
1991 _("Failed to create symlink '%s to '%s'"),
1992 autostartLink, configFile);
1993 goto cleanup;
1994 }
1995 } else {
1996 if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
1997 virReportSystemError(errno,
1998 _("Failed to delete symlink '%s'"),
1999 autostartLink);
2000 goto cleanup;
2001 }
2002 }
2003
2004 vm->autostart = autostart;
2005 }
2006 ret = 0;
2007
2008cleanup:
2009 VIR_FREE(configFile);
2010 VIR_FREE(autostartLink);
2011 if (vm)
2012 virDomainObjUnlock(vm);
2013 umlDriverUnlock(driver);
2014 return ret;
2015}
2016
2017
2018static int
2019umlDomainBlockPeek (virDomainPtr dom,
2020 const char *path,
2021 unsigned long long offset, size_t size,
2022 void *buffer,
2023 unsigned int flags ATTRIBUTE_UNUSED)
2024{
2025 struct uml_driver *driver = dom->conn->privateData;
2026 virDomainObjPtr vm;
2027 int fd = -1, ret = -1, i;
2028
2029 umlDriverLock(driver);
2030 vm = virDomainFindByUUID(&driver->domains, dom->uuid);
2031 umlDriverUnlock(driver);
2032
2033 if (!vm) {
2034 umlReportError(VIR_ERR_INVALID_DOMAIN, "%s",
2035 _("no domain with matching uuid"));
2036 goto cleanup;
2037 }
2038
2039 if (!path || path[0] == '\0') {
2040 umlReportError(VIR_ERR_INVALID_ARG, "%s",
2041 _("NULL or empty path"));
2042 goto cleanup;
2043 }
2044
2045 /* Check the path belongs to this domain. */
2046 for (i = 0 ; i < vm->def->ndisks ; i++) {
2047 if (vm->def->disks[i]->src != NULL &&
2048 STREQ (vm->def->disks[i]->src, path)) {
2049 ret = 0;
2050 break;
2051 }
2052 }
2053
2054 if (ret == 0) {
2055 ret = -1;
2056 /* The path is correct, now try to open it and get its size. */
2057 fd = open (path, O_RDONLY);
2058 if (fd == -1) {
2059 virReportSystemError(errno,
2060 _("cannot open %s"), path);
2061 goto cleanup;
2062 }
2063
2064 /* Seek and read. */
2065 /* NB. Because we configure with AC_SYS_LARGEFILE, off_t should
2066 * be 64 bits on all platforms.
2067 */
2068 if (lseek (fd, offset, SEEK_SET) == (off_t) -1 ||
2069 saferead (fd, buffer, size) == (ssize_t) -1) {
2070 virReportSystemError(errno,
2071 _("cannot read %s"), path);
2072 goto cleanup;
2073 }
2074
2075 ret = 0;
2076 } else {
2077 umlReportError(VIR_ERR_INVALID_ARG, "%s",
2078 _("invalid path"));
2079 }
2080
2081cleanup:
2082 if (fd >= 0) close (fd);
2083 if (vm)
2084 virDomainObjUnlock(vm);
2085 return ret;
2086}
2087
2088
2089
2090static virDriver umlDriver = {
2091 VIR_DRV_UML,
2092 "UML",
2093 umlOpen, /* open */
2094 umlClose, /* close */
2095 NULL, /* supports_feature */
2096 umlGetType, /* type */
2097 umlGetVersion, /* version */
2098 NULL, /* libvirtVersion (impl. in libvirt.c) */
2099 virGetHostname, /* getHostname */
2100 NULL, /* getMaxVcpus */
2101 nodeGetInfo, /* nodeGetInfo */
2102 umlGetCapabilities, /* getCapabilities */
2103 umlListDomains, /* listDomains */
2104 umlNumDomains, /* numOfDomains */
2105 umlDomainCreate, /* domainCreateXML */
2106 umlDomainLookupByID, /* domainLookupByID */
2107 umlDomainLookupByUUID, /* domainLookupByUUID */
2108 umlDomainLookupByName, /* domainLookupByName */
2109 NULL, /* domainSuspend */
2110 NULL, /* domainResume */
2111 umlDomainShutdown, /* domainShutdown */
2112 NULL, /* domainReboot */
2113 umlDomainDestroy, /* domainDestroy */
2114 umlDomainGetOSType, /* domainGetOSType */
2115 umlDomainGetMaxMemory, /* domainGetMaxMemory */
2116 umlDomainSetMaxMemory, /* domainSetMaxMemory */
2117 umlDomainSetMemory, /* domainSetMemory */
2118 umlDomainGetInfo, /* domainGetInfo */
2119 NULL, /* domainSave */
2120 NULL, /* domainRestore */
2121 NULL, /* domainCoreDump */
2122 NULL, /* domainSetVcpus */
2123 NULL, /* domainPinVcpu */
2124 NULL, /* domainGetVcpus */
2125 NULL, /* domainGetMaxVcpus */
2126 NULL, /* domainGetSecurityLabel */
2127 NULL, /* nodeGetSecurityModel */
2128 umlDomainDumpXML, /* domainDumpXML */
2129 NULL, /* domainXMLFromNative */
2130 NULL, /* domainXMLToNative */
2131 umlListDefinedDomains, /* listDefinedDomains */
2132 umlNumDefinedDomains, /* numOfDefinedDomains */
2133 umlDomainStart, /* domainCreate */
2134 umlDomainStartWithFlags, /* domainCreateWithFlags */
2135 umlDomainDefine, /* domainDefineXML */
2136 umlDomainUndefine, /* domainUndefine */
2137 umlDomainAttachDevice, /* domainAttachDevice */
2138 umlDomainAttachDeviceFlags, /* domainAttachDeviceFlags */
2139 umlDomainDetachDevice, /* domainDetachDevice */
2140 umlDomainDetachDeviceFlags, /* domainDetachDeviceFlags */
2141 NULL, /* domainUpdateDeviceFlags */
2142 umlDomainGetAutostart, /* domainGetAutostart */
2143 umlDomainSetAutostart, /* domainSetAutostart */
2144 NULL, /* domainGetSchedulerType */
2145 NULL, /* domainGetSchedulerParameters */
2146 NULL, /* domainSetSchedulerParameters */
2147 NULL, /* domainMigratePrepare */
2148 NULL, /* domainMigratePerform */
2149 NULL, /* domainMigrateFinish */
2150 NULL, /* domainBlockStats */
2151 NULL, /* domainInterfaceStats */
2152 NULL, /* domainMemoryStats */
2153 umlDomainBlockPeek, /* domainBlockPeek */
2154 NULL, /* domainMemoryPeek */
2155 NULL, /* domainGetBlockInfo */
2156 nodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */
2157 nodeGetFreeMemory, /* getFreeMemory */
2158 NULL, /* domainEventRegister */
2159 NULL, /* domainEventDeregister */
2160 NULL, /* domainMigratePrepare2 */
2161 NULL, /* domainMigrateFinish2 */
2162 NULL, /* nodeDeviceDettach */
2163 NULL, /* nodeDeviceReAttach */
2164 NULL, /* nodeDeviceReset */
2165 NULL, /* domainMigratePrepareTunnel */
2166 umlIsEncrypted, /* isEncrypted */
2167 umlIsSecure, /* isSecure */
2168 umlDomainIsActive, /* domainIsActive */
2169 umlDomainIsPersistent, /* domainIsPersistent */
2170 NULL, /* cpuCompare */
2171 NULL, /* cpuBaseline */
2172 NULL, /* domainGetJobInfo */
2173 NULL, /* domainAbortJob */
2174 NULL, /* domainMigrateSetMaxDowntime */
2175 NULL, /* domainEventRegisterAny */
2176 NULL, /* domainEventDeregisterAny */
2177 NULL, /* domainManagedSave */
2178 NULL, /* domainHasManagedSaveImage */
2179 NULL, /* domainManagedSaveRemove */
2180 NULL, /* domainSnapshotCreateXML */
2181 NULL, /* domainSnapshotDumpXML */
2182 NULL, /* domainSnapshotNum */
2183 NULL, /* domainSnapshotListNames */
2184 NULL, /* domainSnapshotLookupByName */
2185 NULL, /* domainHasCurrentSnapshot */
2186 NULL, /* domainSnapshotCurrent */
2187 NULL, /* domainRevertToSnapshot */
2188 NULL, /* domainSnapshotDelete */
2189 NULL, /* qemuDomainMonitorCommand */
2190};
2191
2192
2193static virStateDriver umlStateDriver = {
2194 .name = "UML",
2195 .initialize = umlStartup,
2196 .cleanup = umlShutdown,
2197 .reload = umlReload,
2198 .active = umlActive,
2199};
2200
2201int umlRegister(void) {
2202 virRegisterDriver(&umlDriver);
2203 virRegisterStateDriver(&umlStateDriver);
2204 return 0;
2205}
02206
=== added file 'debian/patches/9024-Explicitly-pass-uml_dir-argument-to-user-mode-linux.patch'
--- debian/patches/9024-Explicitly-pass-uml_dir-argument-to-user-mode-linux.patch 1970-01-01 00:00:00 +0000
+++ debian/patches/9024-Explicitly-pass-uml_dir-argument-to-user-mode-linux.patch 2010-09-14 20:26:05 +0000
@@ -0,0 +1,58 @@
1From bff2985daf724580866b941c88c820894111cc72 Mon Sep 17 00:00:00 2001
2From: Soren Hansen <soren@linux2go.dk>
3Date: Wed, 25 Aug 2010 10:41:14 +0200
4Subject: [PATCH] Explicitly pass uml_dir argument to user-mode-linux
5
6uml_dir overrides user-mode-linux's default of ~/.uml. This is needed
7for a couple of different reasons:
8
9libvirt expects this to default to virGetUserDirectory(geteuid()) +
10'/.uml'. However, user-mode-linux actually uses the HOME environment
11variable to determine where to look for the uml sockets, but if running
12libvirtd under sudo (which I routinely do during development), $HOME is
13pointing at my user's homedir, while my euid is 0, so libvirt looks in
14/root.
15
16Also (and this was my actual motivation for this patch), if HOME isn't
17set at all, user-mode-linux utterly fails. Looking at the code, it seems
18it's meant to emit a warning, but alas, it doesn't for some reason.
19If running libvirtd from upstart, HOME is not set, so any system using
20upstart will need this change.
21
22Signed-off-by: Soren Hansen <soren@linux2go.dk>
23---
24 src/uml/uml_conf.c | 4 ++--
25 1 files changed, 2 insertions(+), 2 deletions(-)
26
27diff --git a/src/uml/uml_conf.c b/src/uml/uml_conf.c
28index 65b06c5..4906192 100644
29--- a/src/uml/uml_conf.c
30+++ b/src/uml/uml_conf.c
31@@ -409,7 +409,7 @@ static char *umlNextArg(char *args)
32 * for a given virtual machine.
33 */
34 int umlBuildCommandLine(virConnectPtr conn,
35- struct uml_driver *driver ATTRIBUTE_UNUSED,
36+ struct uml_driver *driver,
37 virDomainObjPtr vm,
38 fd_set *keepfd,
39 const char ***retargv,
40@@ -499,7 +499,6 @@ int umlBuildCommandLine(virConnectPtr conn,
41 ADD_ENV_COPY("LD_PRELOAD");
42 ADD_ENV_COPY("LD_LIBRARY_PATH");
43 ADD_ENV_COPY("PATH");
44- ADD_ENV_COPY("HOME");
45 ADD_ENV_COPY("USER");
46 ADD_ENV_COPY("LOGNAME");
47 ADD_ENV_COPY("TMPDIR");
48@@ -508,6 +507,7 @@ int umlBuildCommandLine(virConnectPtr conn,
49 //ADD_ARG_PAIR("con0", "fd:0,fd:1");
50 ADD_ARG_PAIR("mem", memory);
51 ADD_ARG_PAIR("umid", vm->def->name);
52+ ADD_ARG_PAIR("uml_dir", driver->monitorDir);
53
54 if (vm->def->os.root)
55 ADD_ARG_PAIR("root", vm->def->os.root);
56--
571.7.0.4
58
059
=== removed file 'debian/patches/9024-Explicitly-pass-uml_dir-argument-to-user-mode-linux.patch'
--- debian/patches/9024-Explicitly-pass-uml_dir-argument-to-user-mode-linux.patch 2010-08-31 16:05:24 +0000
+++ debian/patches/9024-Explicitly-pass-uml_dir-argument-to-user-mode-linux.patch 1970-01-01 00:00:00 +0000
@@ -1,58 +0,0 @@
1From bff2985daf724580866b941c88c820894111cc72 Mon Sep 17 00:00:00 2001
2From: Soren Hansen <soren@linux2go.dk>
3Date: Wed, 25 Aug 2010 10:41:14 +0200
4Subject: [PATCH] Explicitly pass uml_dir argument to user-mode-linux
5
6uml_dir overrides user-mode-linux's default of ~/.uml. This is needed
7for a couple of different reasons:
8
9libvirt expects this to default to virGetUserDirectory(geteuid()) +
10'/.uml'. However, user-mode-linux actually uses the HOME environment
11variable to determine where to look for the uml sockets, but if running
12libvirtd under sudo (which I routinely do during development), $HOME is
13pointing at my user's homedir, while my euid is 0, so libvirt looks in
14/root.
15
16Also (and this was my actual motivation for this patch), if HOME isn't
17set at all, user-mode-linux utterly fails. Looking at the code, it seems
18it's meant to emit a warning, but alas, it doesn't for some reason.
19If running libvirtd from upstart, HOME is not set, so any system using
20upstart will need this change.
21
22Signed-off-by: Soren Hansen <soren@linux2go.dk>
23---
24 src/uml/uml_conf.c | 4 ++--
25 1 files changed, 2 insertions(+), 2 deletions(-)
26
27diff --git a/src/uml/uml_conf.c b/src/uml/uml_conf.c
28index 65b06c5..4906192 100644
29--- a/src/uml/uml_conf.c
30+++ b/src/uml/uml_conf.c
31@@ -409,7 +409,7 @@ static char *umlNextArg(char *args)
32 * for a given virtual machine.
33 */
34 int umlBuildCommandLine(virConnectPtr conn,
35- struct uml_driver *driver ATTRIBUTE_UNUSED,
36+ struct uml_driver *driver,
37 virDomainObjPtr vm,
38 fd_set *keepfd,
39 const char ***retargv,
40@@ -499,7 +499,6 @@ int umlBuildCommandLine(virConnectPtr conn,
41 ADD_ENV_COPY("LD_PRELOAD");
42 ADD_ENV_COPY("LD_LIBRARY_PATH");
43 ADD_ENV_COPY("PATH");
44- ADD_ENV_COPY("HOME");
45 ADD_ENV_COPY("USER");
46 ADD_ENV_COPY("LOGNAME");
47 ADD_ENV_COPY("TMPDIR");
48@@ -508,6 +507,7 @@ int umlBuildCommandLine(virConnectPtr conn,
49 //ADD_ARG_PAIR("con0", "fd:0,fd:1");
50 ADD_ARG_PAIR("mem", memory);
51 ADD_ARG_PAIR("umid", vm->def->name);
52+ ADD_ARG_PAIR("uml_dir", driver->monitorDir);
53
54 if (vm->def->os.root)
55 ADD_ARG_PAIR("root", vm->def->os.root);
56--
571.7.0.4
58
590
=== added file 'debian/patches/9025-Add-nwfilter-support-to-UML-driver.patch'
--- debian/patches/9025-Add-nwfilter-support-to-UML-driver.patch 1970-01-01 00:00:00 +0000
+++ debian/patches/9025-Add-nwfilter-support-to-UML-driver.patch 2010-09-14 20:26:05 +0000
@@ -0,0 +1,112 @@
1From cdd91f237d8f36e2916a55f01a189fabf826fc26 Mon Sep 17 00:00:00 2001
2From: Soren Hansen <soren@linux2go.dk>
3Date: Mon, 6 Sep 2010 15:32:30 +0200
4Subject: [PATCH] Add nwfilter support to UML driver
5
6Extend user-mode-linux driver to support nwfilter.
7
8Signed-off-by: Soren Hansen <soren@linux2go.dk>
9---
10 src/uml/uml_conf.c | 16 +++++++++++++---
11 src/uml/uml_driver.c | 8 +++++++-
12 2 files changed, 20 insertions(+), 4 deletions(-)
13
14diff --git a/src/uml/uml_conf.c b/src/uml/uml_conf.c
15index 4906192..f2eaef5 100644
16--- a/src/uml/uml_conf.c
17+++ b/src/uml/uml_conf.c
18@@ -46,6 +46,7 @@
19 #include "verify.h"
20 #include "bridge.h"
21 #include "logging.h"
22+#include "domain_nwfilter.h"
23
24 #define VIR_FROM_THIS VIR_FROM_UML
25
26@@ -108,7 +109,8 @@ virCapsPtr umlCapsInit(void) {
27
28
29 static int
30-umlConnectTapDevice(virDomainNetDefPtr net,
31+umlConnectTapDevice(virConnectPtr conn,
32+ virDomainNetDefPtr net,
33 const char *bridge)
34 {
35 brControl *brctl = NULL;
36@@ -164,6 +166,14 @@ umlConnectTapDevice(virDomainNetDefPtr net,
37 goto error;
38 }
39
40+ if (net->filter) {
41+ if (virDomainConfNWFilterInstantiate(conn, net)) {
42+ if (template_ifname)
43+ VIR_FREE(net->ifname);
44+ goto error;
45+ }
46+ }
47+
48 brShutdown(brctl);
49
50 return 0;
51@@ -239,7 +249,7 @@ umlBuildCommandLineNet(virConnectPtr conn,
52 goto error;
53 }
54
55- if (umlConnectTapDevice(def, bridge) < 0) {
56+ if (umlConnectTapDevice(conn, def, bridge) < 0) {
57 VIR_FREE(bridge);
58 goto error;
59 }
60@@ -250,7 +260,7 @@ umlBuildCommandLineNet(virConnectPtr conn,
61 }
62
63 case VIR_DOMAIN_NET_TYPE_BRIDGE:
64- if (umlConnectTapDevice(def, def->data.bridge.brname) < 0)
65+ if (umlConnectTapDevice(conn, def, def->data.bridge.brname) < 0)
66 goto error;
67
68 /* ethNNN=tuntap,tapname,macaddr,gateway */
69diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c
70index 0a5c829..40345d5 100644
71--- a/src/uml/uml_driver.c
72+++ b/src/uml/uml_driver.c
73@@ -58,6 +58,7 @@
74 #include "domain_conf.h"
75 #include "datatypes.h"
76 #include "logging.h"
77+#include "domain_nwfilter.h"
78
79 #define VIR_FROM_THIS VIR_FROM_UML
80
81@@ -876,6 +877,7 @@ static int umlStartVMDaemon(virConnectPtr conn,
82 if (umlBuildCommandLine(conn, driver, vm, &keepfd,
83 &argv, &progenv) < 0) {
84 close(logfd);
85+ virDomainConfVMNWFilterTeardown(vm);
86 umlCleanupTapDevices(conn, vm);
87 return -1;
88 }
89@@ -928,8 +930,11 @@ static int umlStartVMDaemon(virConnectPtr conn,
90 VIR_FREE(progenv[i]);
91 VIR_FREE(progenv);
92
93- if (ret < 0)
94+ if (ret < 0) {
95+ virDomainConfVMNWFilterTeardown(vm);
96 umlCleanupTapDevices(conn, vm);
97+ }
98+
99
100 /* NB we don't mark it running here - we do that async
101 with inotify */
102@@ -965,6 +970,7 @@ static void umlShutdownVMDaemon(virConnectPtr conn ATTRIBUTE_UNUSED,
103 vm->def->id = -1;
104 vm->state = VIR_DOMAIN_SHUTOFF;
105
106+ virDomainConfVMNWFilterTeardown(vm);
107 umlCleanupTapDevices(conn, vm);
108
109 if (vm->newDef) {
110--
1111.7.1
112
0113
=== 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