uml_driver.c 53.0 KB
Newer Older
1 2 3
/*
 * uml_driver.c: core driver methods for managing UML guests
 *
4
 * Copyright (C) 2006-2010 Red Hat, Inc.
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
 * Copyright (C) 2006-2008 Daniel P. Berrange
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
 *
 * Author: Daniel P. Berrange <berrange@redhat.com>
 */

#include <config.h>

#include <sys/types.h>
#include <sys/poll.h>
#include <dirent.h>
#include <limits.h>
#include <string.h>
#include <stdio.h>
#include <strings.h>
#include <stdarg.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/utsname.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <paths.h>
#include <pwd.h>
#include <stdio.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <sys/inotify.h>
47
#include <sys/un.h>
48 49 50 51 52 53 54 55 56 57 58 59 60

#include "uml_driver.h"
#include "uml_conf.h"
#include "event.h"
#include "buf.h"
#include "util.h"
#include "nodeinfo.h"
#include "stats_linux.h"
#include "capabilities.h"
#include "memory.h"
#include "uuid.h"
#include "domain_conf.h"
#include "datatypes.h"
61
#include "logging.h"
62

63 64
#define VIR_FROM_THIS VIR_FROM_UML

65 66 67
/* For storing short-lived temporary files. */
#define TEMPDIR LOCAL_STATE_DIR "/cache/libvirt"

68 69 70 71 72 73 74 75
typedef struct _umlDomainObjPrivate umlDomainObjPrivate;
typedef umlDomainObjPrivate *umlDomainObjPrivatePtr;
struct _umlDomainObjPrivate {
    int monitor;
    int monitorWatch;
};


76 77
static int umlShutdown(void);

78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
static void *umlDomainObjPrivateAlloc(void)
{
    umlDomainObjPrivatePtr priv;

    if (VIR_ALLOC(priv) < 0)
        return NULL;

    priv->monitor = -1;
    priv->monitorWatch = -1;

    return priv;
}

static void umlDomainObjPrivateFree(void *data)
{
    umlDomainObjPrivatePtr priv = data;

    VIR_FREE(priv);
}


99 100
static void umlDriverLock(struct uml_driver *driver)
{
101
    virMutexLock(&driver->lock);
102 103 104
}
static void umlDriverUnlock(struct uml_driver *driver)
{
105
    virMutexUnlock(&driver->lock);
106 107
}

108 109 110 111

static int umlOpenMonitor(virConnectPtr conn,
                          struct uml_driver *driver,
                          virDomainObjPtr vm);
112
static int umlReadPidFile(struct uml_driver *driver,
113 114 115 116 117 118 119 120 121 122 123
                          virDomainObjPtr vm);

static int umlSetCloseExec(int fd) {
    int flags;
    if ((flags = fcntl(fd, F_GETFD)) < 0)
        goto error;
    flags |= FD_CLOEXEC;
    if ((fcntl(fd, F_SETFD, flags)) < 0)
        goto error;
    return 0;
 error:
D
Daniel Veillard 已提交
124
    VIR_ERROR0(_("Failed to set close-on-exec file descriptor flag"));
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
    return -1;
}

static int umlStartVMDaemon(virConnectPtr conn,
                            struct uml_driver *driver,
                            virDomainObjPtr vm);

static void umlShutdownVMDaemon(virConnectPtr conn,
                                struct uml_driver *driver,
                                virDomainObjPtr vm);


static int umlMonitorCommand (virConnectPtr conn,
                              const struct uml_driver *driver,
                              const virDomainObjPtr vm,
                              const char *cmd,
                              char **reply);

static struct uml_driver *uml_driver = NULL;

145 146 147 148 149 150 151 152 153 154 155 156 157
struct umlAutostartData {
    struct uml_driver *driver;
    virConnectPtr conn;
};

static void
umlAutostartDomain(void *payload, const char *name ATTRIBUTE_UNUSED, void *opaque)
{
    virDomainObjPtr vm = payload;
    const struct umlAutostartData *data = opaque;

    virDomainObjLock(vm);
    if (vm->autostart &&
D
Daniel P. Berrange 已提交
158
        !virDomainObjIsActive(vm)) {
159 160 161 162 163 164 165 166 167
        virResetLastError();
        if (umlStartVMDaemon(data->conn, data->driver, vm) < 0) {
            virErrorPtr err = virGetLastError();
            VIR_ERROR(_("Failed to autostart VM '%s': %s"),
                      vm->def->name, err->message);
        }
    }
    virDomainObjUnlock(vm);
}
168 169 170

static void
umlAutostartConfigs(struct uml_driver *driver) {
171 172 173 174 175
    /* XXX: Figure out a better way todo this. The domain
     * startup code needs a connection handle in order
     * to lookup the bridge associated with a virtual
     * network
     */
176 177 178
    virConnectPtr conn = virConnectOpen(driver->privileged ?
                                        "uml:///system" :
                                        "uml:///session");
179
    /* Ignoring NULL conn which is mostly harmless here */
180

181 182 183
    struct umlAutostartData data = { driver, conn };

    virHashForEach(driver->domains.objs, umlAutostartDomain, &data);
184

185 186
    if (conn)
        virConnectClose(conn);
187 188 189 190
}


static int
191
umlIdentifyOneChrPTY(struct uml_driver *driver,
192 193 194 195 196 197 198
                     virDomainObjPtr dom,
                     virDomainChrDefPtr def,
                     const char *dev)
{
    char *cmd;
    char *res = NULL;
    int retries = 0;
199
    if (virAsprintf(&cmd, "config %s%d", dev, def->target.port) < 0) {
200
        virReportOOMError();
201 202 203
        return -1;
    }
requery:
204 205
    if (umlMonitorCommand(NULL, driver, dom, cmd, &res) < 0)
        return -1;
206

207
    if (res && STRPREFIX(res, "pts:")) {
208 209
        VIR_FREE(def->data.file.path);
        if ((def->data.file.path = strdup(res + 4)) == NULL) {
210
            virReportOOMError();
211 212 213 214
            VIR_FREE(res);
            VIR_FREE(cmd);
            return -1;
        }
215
    } else if (!res || STRPREFIX(res, "pts")) {
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
        /* It can take a while to startup, so retry for
           upto 5 seconds */
        /* XXX should do this in a better non-blocking
           way somehow ...perhaps register a timer */
        if (retries++ < 50) {
            usleep(1000*10);
            goto requery;
        }
    }

    VIR_FREE(cmd);
    VIR_FREE(res);
    return 0;
}

static int
232
umlIdentifyChrPTY(struct uml_driver *driver,
233 234 235 236 237 238
                  virDomainObjPtr dom)
{
    int i;

    if (dom->def->console &&
        dom->def->console->type == VIR_DOMAIN_CHR_TYPE_PTY)
239
        if (umlIdentifyOneChrPTY(driver, dom,
240 241 242 243 244
                                 dom->def->console, "con") < 0)
            return -1;

    for (i = 0 ; i < dom->def->nserials; i++)
        if (dom->def->serials[i]->type == VIR_DOMAIN_CHR_TYPE_PTY &&
245
            umlIdentifyOneChrPTY(driver, dom,
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264
                                 dom->def->serials[i], "ssl") < 0)
            return -1;

    return 0;
}

static void
umlInotifyEvent(int watch,
                int fd,
                int events ATTRIBUTE_UNUSED,
                void *data)
{
    char buf[1024];
    struct inotify_event *e;
    int got;
    char *tmp, *name;
    struct uml_driver *driver = data;
    virDomainObjPtr dom;

265
    umlDriverLock(driver);
266
    if (watch != driver->inotifyWatch)
267
        goto cleanup;
268 269 270 271 272 273

reread:
    got = read(fd, buf, sizeof(buf));
    if (got == -1) {
        if (errno == EINTR)
            goto reread;
274
        goto cleanup;
275 276 277 278 279
    }

    tmp = buf;
    while (got) {
        if (got < sizeof(struct inotify_event))
280
            goto cleanup; /* bad */
281 282 283 284 285 286

        e = (struct inotify_event *)tmp;
        tmp += sizeof(struct inotify_event);
        got -= sizeof(struct inotify_event);

        if (got < e->len)
287
            goto cleanup;
288 289 290 291 292 293 294 295 296 297 298 299 300

        tmp += e->len;
        got -= e->len;

        name = (char *)&(e->name);

        dom = virDomainFindByName(&driver->domains, name);

        if (!dom) {
            continue;
        }

        if (e->mask & IN_DELETE) {
301
            VIR_DEBUG("Got inotify domain shutdown '%s'", name);
D
Daniel P. Berrange 已提交
302
            if (!virDomainObjIsActive(dom)) {
303
                virDomainObjUnlock(dom);
304 305 306
                continue;
            }

307
            umlShutdownVMDaemon(NULL, driver, dom);
308
        } else if (e->mask & (IN_CREATE | IN_MODIFY)) {
309
            VIR_DEBUG("Got inotify domain startup '%s'", name);
D
Daniel P. Berrange 已提交
310
            if (virDomainObjIsActive(dom)) {
311
                virDomainObjUnlock(dom);
312 313 314
                continue;
            }

315
            if (umlReadPidFile(driver, dom) < 0) {
316
                virDomainObjUnlock(dom);
317 318 319 320 321 322
                continue;
            }

            dom->def->id = driver->nextvmid++;
            dom->state = VIR_DOMAIN_RUNNING;

323 324
            if (umlOpenMonitor(NULL, driver, dom) < 0) {
                VIR_WARN0("Could not open monitor for new domain");
325
                umlShutdownVMDaemon(NULL, driver, dom);
326
            } else if (umlIdentifyChrPTY(driver, dom) < 0) {
327
                VIR_WARN0("Could not identify charater devices for new domain");
328
                umlShutdownVMDaemon(NULL, driver, dom);
329
            }
330
        }
331
        virDomainObjUnlock(dom);
332
    }
333 334 335

cleanup:
    umlDriverUnlock(driver);
336 337 338 339 340 341 342 343
}

/**
 * umlStartup:
 *
 * Initialization function for the Uml daemon
 */
static int
344
umlStartup(int privileged) {
345 346 347
    uid_t uid = geteuid();
    char *base = NULL;
    char driverConf[PATH_MAX];
348
    char *userdir = NULL;
349 350 351 352

    if (VIR_ALLOC(uml_driver) < 0)
        return -1;

353 354
    uml_driver->privileged = privileged;

355 356 357 358
    if (virMutexInit(&uml_driver->lock) < 0) {
        VIR_FREE(uml_driver);
        return -1;
    }
359 360
    umlDriverLock(uml_driver);

361 362
    /* Don't have a dom0 so start from 1 */
    uml_driver->nextvmid = 1;
363
    uml_driver->inotifyWatch = -1;
364

365 366 367
    if (virDomainObjListInit(&uml_driver->domains) < 0)
        goto error;

368
    userdir = virGetUserDirectory(uid);
369
    if (!userdir)
370
        goto error;
371

372
    if (privileged) {
373 374
        if (virAsprintf(&uml_driver->logDir,
                        "%s/log/libvirt/uml", LOCAL_STATE_DIR) == -1)
375 376 377 378 379
            goto out_of_memory;

        if ((base = strdup (SYSCONF_DIR "/libvirt")) == NULL)
            goto out_of_memory;
    } else {
380

381
        if (virAsprintf(&uml_driver->logDir,
382
                        "%s/.libvirt/uml/log", userdir) == -1)
383 384
            goto out_of_memory;

385
        if (virAsprintf(&base, "%s/.libvirt", userdir) == -1)
386 387 388
            goto out_of_memory;
    }

389
    if (virAsprintf(&uml_driver->monitorDir,
390
                    "%s/.uml", userdir) == -1)
391 392 393 394 395 396 397 398 399
        goto out_of_memory;

    /* Configuration paths are either ~/.libvirt/uml/... (session) or
     * /etc/libvirt/uml/... (system).
     */
    if (snprintf (driverConf, sizeof(driverConf), "%s/uml.conf", base) == -1)
        goto out_of_memory;
    driverConf[sizeof(driverConf)-1] = '\0';

400
    if (virAsprintf(&uml_driver->configDir, "%s/uml", base) == -1)
401 402
        goto out_of_memory;

403
    if (virAsprintf(&uml_driver->autostartDir, "%s/uml/autostart", base) == -1)
404 405 406 407 408 409 410
        goto out_of_memory;

    VIR_FREE(base);

    if ((uml_driver->caps = umlCapsInit()) == NULL)
        goto out_of_memory;

411 412
    uml_driver->caps->privateDataAllocFunc = umlDomainObjPrivateAlloc;
    uml_driver->caps->privateDataFreeFunc = umlDomainObjPrivateFree;
413 414

    if ((uml_driver->inotifyFD = inotify_init()) < 0) {
D
Daniel Veillard 已提交
415
        VIR_ERROR0(_("cannot initialize inotify"));
416
        goto error;
417 418
    }

L
Laine Stump 已提交
419
    if (virFileMakePath(uml_driver->monitorDir) != 0) {
420
        char ebuf[1024];
D
Daniel Veillard 已提交
421
        VIR_ERROR(_("Failed to create monitor directory %s: %s"),
422
               uml_driver->monitorDir, virStrerror(errno, ebuf, sizeof ebuf));
423
        goto error;
424 425
    }

426
    VIR_INFO("Adding inotify watch on %s", uml_driver->monitorDir);
427 428 429
    if (inotify_add_watch(uml_driver->inotifyFD,
                          uml_driver->monitorDir,
                          IN_CREATE | IN_MODIFY | IN_DELETE) < 0) {
430
        goto error;
431 432
    }

433 434
    if ((uml_driver->inotifyWatch =
         virEventAddHandle(uml_driver->inotifyFD, POLLIN,
435 436
                           umlInotifyEvent, uml_driver, NULL)) < 0)
        goto error;
437

438
    if (virDomainLoadAllConfigs(uml_driver->caps,
439 440 441
                                &uml_driver->domains,
                                uml_driver->configDir,
                                uml_driver->autostartDir,
442
                                0, NULL, NULL) < 0)
443 444
        goto error;

445 446
    umlAutostartConfigs(uml_driver);

447
    umlDriverUnlock(uml_driver);
448 449
    VIR_FREE(userdir);

450 451
    return 0;

452
out_of_memory:
D
Daniel Veillard 已提交
453
    VIR_ERROR0(_("umlStartup: out of memory"));
454 455

error:
456
    VIR_FREE(userdir);
457
    VIR_FREE(base);
458 459
    umlDriverUnlock(uml_driver);
    umlShutdown();
460 461 462 463 464 465 466 467 468 469 470 471 472 473
    return -1;
}

/**
 * umlReload:
 *
 * Function to restart the Uml daemon, it will recheck the configuration
 * files and update its state and the networking
 */
static int
umlReload(void) {
    if (!uml_driver)
        return 0;

474
    umlDriverLock(uml_driver);
475
    virDomainLoadAllConfigs(uml_driver->caps,
476 477 478
                            &uml_driver->domains,
                            uml_driver->configDir,
                            uml_driver->autostartDir,
479
                            0, NULL, NULL);
480 481

    umlAutostartConfigs(uml_driver);
482
    umlDriverUnlock(uml_driver);
483 484 485 486 487 488 489 490 491 492 493 494 495 496

    return 0;
}

/**
 * umlActive:
 *
 * Checks if the Uml daemon is active, i.e. has an active domain or
 * an active network
 *
 * Returns 1 if active, 0 otherwise
 */
static int
umlActive(void) {
497
    int active = 0;
498 499 500 501

    if (!uml_driver)
        return 0;

502
    umlDriverLock(uml_driver);
503
    active = virDomainObjListNumOfDomains(&uml_driver->domains, 1);
504
    umlDriverUnlock(uml_driver);
505

506
    return active;
507 508
}

509 510 511 512 513 514 515
static void
umlShutdownOneVM(void *payload, const char *name ATTRIBUTE_UNUSED, void *opaque)
{
    virDomainObjPtr dom = payload;
    struct uml_driver *driver = opaque;

    virDomainObjLock(dom);
D
Daniel P. Berrange 已提交
516
    if (virDomainObjIsActive(dom))
517 518 519 520
        umlShutdownVMDaemon(NULL, driver, dom);
    virDomainObjUnlock(dom);
}

521 522 523 524 525 526 527 528 529 530
/**
 * umlShutdown:
 *
 * Shutdown the Uml daemon, it will stop all active domains and networks
 */
static int
umlShutdown(void) {
    if (!uml_driver)
        return -1;

531
    umlDriverLock(uml_driver);
532 533
    if (uml_driver->inotifyWatch != -1)
        virEventRemoveHandle(uml_driver->inotifyWatch);
534 535 536
    close(uml_driver->inotifyFD);
    virCapabilitiesFree(uml_driver->caps);

537 538 539
    /* shutdown active VMs
     * XXX allow them to stay around & reconnect */
    virHashForEach(uml_driver->domains.objs, umlShutdownOneVM, uml_driver);
540

541
    virDomainObjListDeinit(&uml_driver->domains);
542 543 544 545 546 547 548 549 550

    VIR_FREE(uml_driver->logDir);
    VIR_FREE(uml_driver->configDir);
    VIR_FREE(uml_driver->autostartDir);
    VIR_FREE(uml_driver->monitorDir);

    if (uml_driver->brctl)
        brShutdown(uml_driver->brctl);

551
    umlDriverUnlock(uml_driver);
552
    virMutexDestroy(&uml_driver->lock);
553 554 555 556 557 558
    VIR_FREE(uml_driver);

    return 0;
}


559
static int umlReadPidFile(struct uml_driver *driver,
560 561 562 563 564 565 566 567
                          virDomainObjPtr vm)
{
    int rc = -1;
    FILE *file;
    char *pidfile = NULL;
    int retries = 0;

    vm->pid = -1;
568 569
    if (virAsprintf(&pidfile, "%s/%s/pid",
                    driver->monitorDir, vm->def->name) < 0) {
570
        virReportOOMError();
571 572 573 574 575 576 577 578 579 580 581 582 583 584 585
        return -1;
    }

reopen:
    if (!(file = fopen(pidfile, "r"))) {
        if (errno == ENOENT &&
            retries++ < 50) {
            usleep(1000 * 100);
            goto reopen;
        }
        goto cleanup;
    }

    if (fscanf(file, "%d", &vm->pid) != 1) {
        errno = EINVAL;
586
        fclose(file);
587 588 589 590 591 592 593 594 595 596
        goto cleanup;
    }

    if (fclose(file) < 0)
        goto cleanup;

    rc = 0;

 cleanup:
    if (rc != 0)
597
        virReportSystemError(errno,
598 599
                             _("failed to read pid: %s"),
                             pidfile);
600 601 602 603 604 605 606 607 608
    VIR_FREE(pidfile);
    return rc;
}

static int umlMonitorAddress(virConnectPtr conn,
                             const struct uml_driver *driver,
                             virDomainObjPtr vm,
                             struct sockaddr_un *addr) {
    char *sockname;
C
Chris Lalancette 已提交
609
    int retval = 0;
610

611 612
    if (virAsprintf(&sockname, "%s/%s/mconsole",
                    driver->monitorDir, vm->def->name) < 0) {
613
        virReportOOMError();
614 615 616 617 618
        return -1;
    }

    memset(addr, 0, sizeof *addr);
    addr->sun_family = AF_UNIX;
C
Chris Lalancette 已提交
619 620 621 622 623
    if (virStrcpyStatic(addr->sun_path, sockname) == NULL) {
        umlReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                       _("Unix path %s too long for destination"), sockname);
        retval = -1;
    }
624
    VIR_FREE(sockname);
C
Chris Lalancette 已提交
625
    return retval;
626 627 628 629 630 631 632 633
}

static int umlOpenMonitor(virConnectPtr conn,
                          struct uml_driver *driver,
                          virDomainObjPtr vm) {
    struct sockaddr_un addr;
    struct stat sb;
    int retries = 0;
634
    umlDomainObjPrivatePtr priv = vm->privateData;
635 636 637 638

    if (umlMonitorAddress(conn, driver, vm, &addr) < 0)
        return -1;

639
    VIR_DEBUG("Dest address for monitor is '%s'", addr.sun_path);
640 641 642
restat:
    if (stat(addr.sun_path, &sb) < 0) {
        if (errno == ENOENT &&
643
            retries++ < 50) {
644 645 646 647 648 649
            usleep(1000 * 100);
            goto restat;
        }
        return -1;
    }

650
    if ((priv->monitor = socket(PF_UNIX, SOCK_DGRAM, 0)) < 0) {
651
        virReportSystemError(errno,
652
                             "%s", _("cannot open socket"));
653 654 655 656
        return -1;
    }

    memset(addr.sun_path, 0, sizeof addr.sun_path);
657 658
    sprintf(addr.sun_path + 1, "libvirt-uml-%u", vm->pid);
    VIR_DEBUG("Reply address for monitor is '%s'", addr.sun_path+1);
659
    if (bind(priv->monitor, (struct sockaddr *)&addr, sizeof addr) < 0) {
660
        virReportSystemError(errno,
661
                             "%s", _("cannot bind socket"));
662 663
        close(priv->monitor);
        priv->monitor = -1;
664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701
        return -1;
    }

    return 0;
}


#define MONITOR_MAGIC 0xcafebabe
#define MONITOR_BUFLEN 512
#define MONITOR_VERSION 2

struct monitor_request {
    uint32_t magic;
    uint32_t version;
    uint32_t length;
    char data[MONITOR_BUFLEN];
};

struct monitor_response {
    uint32_t error;
    uint32_t extra;
    uint32_t length;
    char data[MONITOR_BUFLEN];
};


static int umlMonitorCommand(virConnectPtr conn,
                             const struct uml_driver *driver,
                             const virDomainObjPtr vm,
                             const char *cmd,
                             char **reply)
{
    struct monitor_request req;
    struct monitor_response res;
    char *retdata = NULL;
    int retlen = 0, ret = 0;
    struct sockaddr_un addr;
    unsigned int addrlen;
702
    umlDomainObjPrivatePtr priv = vm->privateData;
703

704 705
    VIR_DEBUG("Run command '%s'", cmd);

706 707 708 709 710 711 712 713 714 715
    *reply = NULL;

    if (umlMonitorAddress(conn, driver, vm, &addr) < 0)
        return -1;

    memset(&req, 0, sizeof(req));
    req.magic = MONITOR_MAGIC;
    req.version = MONITOR_VERSION;
    req.length = strlen(cmd);
    if (req.length > (MONITOR_BUFLEN-1)) {
716
        virReportSystemError(EINVAL,
717 718
                             _("cannot send too long command %s (%d bytes)"),
                             cmd, req.length);
719 720
        return -1;
    }
C
Chris Lalancette 已提交
721 722 723 724 725
    if (virStrcpyStatic(req.data, cmd) == NULL) {
        umlReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                       _("Command %s too long for destination"), cmd);
        return -1;
    }
726

727
    if (sendto(priv->monitor, &req, sizeof req, 0,
728
               (struct sockaddr *)&addr, sizeof addr) != (sizeof req)) {
729
        virReportSystemError(errno,
730 731
                             _("cannot send command %s"),
                             cmd);
732 733 734 735
        return -1;
    }

    do {
E
Eric Blake 已提交
736
        ssize_t nbytes;
737
        addrlen = sizeof(addr);
E
Eric Blake 已提交
738 739 740 741 742
        nbytes = recvfrom(priv->monitor, &res, sizeof res, 0,
                          (struct sockaddr *)&addr, &addrlen) < 0;
        if (nbytes < 0) {
            if (errno == EAGAIN || errno == EINTR)
                continue;
743
            virReportSystemError(errno,
744 745
                                 _("cannot read reply %s"),
                                 cmd);
746 747
            goto error;
        }
E
Eric Blake 已提交
748 749 750 751 752 753
        if (nbytes < sizeof res) {
            virReportSystemError(errno,
                                 _("incomplete reply %s"),
                                 cmd);
            goto error;
        }
754 755

        if (VIR_REALLOC_N(retdata, retlen + res.length) < 0) {
756
            virReportOOMError();
757 758 759 760 761 762 763 764 765 766 767
            goto error;
        }
        memcpy(retdata + retlen, res.data, res.length);
        retlen += res.length - 1;
        retdata[retlen] = '\0';

        if (res.error)
            ret = -1;

    } while (res.extra);

768 769
    VIR_DEBUG("Command reply is '%s'", NULLSTR(retdata));

770 771 772 773
    if (ret < 0)
        VIR_FREE(retdata);
    else
        *reply = retdata;
774 775 776 777 778 779 780 781 782

    return ret;

error:
    VIR_FREE(retdata);
    return -1;
}


783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811
static int umlCleanupTapDevices(virConnectPtr conn ATTRIBUTE_UNUSED,
                                virDomainObjPtr vm) {
    int i;
    int err;
    int ret = 0;
    brControl *brctl = NULL;
    VIR_ERROR0("Cleanup tap");
    if (brInit(&brctl) < 0)
        return -1;

    for (i = 0 ; i < vm->def->nnets ; i++) {
        virDomainNetDefPtr def = vm->def->nets[i];

        if (def->type != VIR_DOMAIN_NET_TYPE_BRIDGE &&
            def->type != VIR_DOMAIN_NET_TYPE_NETWORK)
            continue;

        VIR_ERROR("Cleanup '%s'", def->ifname);
        err = brDeleteTap(brctl, def->ifname);
        if (err) {
            VIR_ERROR("Cleanup failed %d", err);
            ret = -1;
        }
    }
    VIR_ERROR0("Cleanup tap done");
    brShutdown(brctl);
    return ret;
}

812 813 814 815 816
static int umlStartVMDaemon(virConnectPtr conn,
                            struct uml_driver *driver,
                            virDomainObjPtr vm) {
    const char **argv = NULL, **tmp;
    const char **progenv = NULL;
817 818
    int i, ret;
    pid_t pid;
819 820 821 822
    char *logfile;
    int logfd = -1;
    struct stat sb;
    fd_set keepfd;
823
    char ebuf[1024];
824
    umlDomainObjPrivatePtr priv = vm->privateData;
825 826 827

    FD_ZERO(&keepfd);

D
Daniel P. Berrange 已提交
828
    if (virDomainObjIsActive(vm)) {
829 830 831 832 833 834 835 836 837 838 839 840 841 842 843
        umlReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                         "%s", _("VM is already active"));
        return -1;
    }

    if (!vm->def->os.kernel) {
        umlReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                       "%s", _("no kernel specified"));
        return -1;
    }
    /* Make sure the binary we are about to try exec'ing exists.
     * Technically we could catch the exec() failure, but that's
     * in a sub-process so its hard to feed back a useful error
     */
    if (stat(vm->def->os.kernel, &sb) < 0) {
844
        virReportSystemError(errno,
845 846
                             _("Cannot find UML kernel %s"),
                             vm->def->os.kernel);
847 848 849
        return -1;
    }

L
Laine Stump 已提交
850
    if (virFileMakePath(driver->logDir) != 0) {
851
        virReportSystemError(errno,
852 853
                             _("cannot create log directory %s"),
                             driver->logDir);
854 855 856
        return -1;
    }

857 858
    if (virAsprintf(&logfile, "%s/%s.log",
                    driver->logDir, vm->def->name) < 0) {
859
        virReportOOMError();
860 861 862 863 864
        return -1;
    }

    if ((logfd = open(logfile, O_CREAT | O_TRUNC | O_WRONLY,
                      S_IRUSR | S_IWUSR)) < 0) {
865
        virReportSystemError(errno,
866 867
                             _("failed to create logfile %s"),
                             logfile);
868 869 870 871 872 873
        VIR_FREE(logfile);
        return -1;
    }
    VIR_FREE(logfile);

    if (umlSetCloseExec(logfd) < 0) {
874
        virReportSystemError(errno,
875
                             "%s", _("Unable to set VM logfile close-on-exec flag"));
876 877 878 879 880
        close(logfd);
        return -1;
    }

    if (umlBuildCommandLine(conn, driver, vm,
881
                            &argv, &progenv) < 0) {
882
        close(logfd);
883
        umlCleanupTapDevices(conn, vm);
884 885 886 887 888 889
        return -1;
    }

    tmp = progenv;
    while (*tmp) {
        if (safewrite(logfd, *tmp, strlen(*tmp)) < 0)
D
Daniel Veillard 已提交
890
            VIR_WARN(_("Unable to write envv to logfile: %s"),
891
                   virStrerror(errno, ebuf, sizeof ebuf));
892
        if (safewrite(logfd, " ", 1) < 0)
D
Daniel Veillard 已提交
893
            VIR_WARN(_("Unable to write envv to logfile: %s"),
894
                   virStrerror(errno, ebuf, sizeof ebuf));
895 896 897 898 899
        tmp++;
    }
    tmp = argv;
    while (*tmp) {
        if (safewrite(logfd, *tmp, strlen(*tmp)) < 0)
D
Daniel Veillard 已提交
900
            VIR_WARN(_("Unable to write argv to logfile: %s"),
901
                   virStrerror(errno, ebuf, sizeof ebuf));
902
        if (safewrite(logfd, " ", 1) < 0)
D
Daniel Veillard 已提交
903
            VIR_WARN(_("Unable to write argv to logfile: %s"),
904
                   virStrerror(errno, ebuf, sizeof ebuf));
905 906 907
        tmp++;
    }
    if (safewrite(logfd, "\n", 1) < 0)
D
Daniel Veillard 已提交
908
        VIR_WARN(_("Unable to write argv to logfile: %s"),
909
                 virStrerror(errno, ebuf, sizeof ebuf));
910

911
    priv->monitor = -1;
912

913
    ret = virExecDaemonize(argv, progenv, &keepfd, &pid,
914
                           -1, &logfd, &logfd,
915 916
                           VIR_EXEC_CLEAR_CAPS,
                           NULL, NULL, NULL);
917 918 919 920 921 922 923 924 925 926
    close(logfd);

    for (i = 0 ; argv[i] ; i++)
        VIR_FREE(argv[i]);
    VIR_FREE(argv);

    for (i = 0 ; progenv[i] ; i++)
        VIR_FREE(progenv[i]);
    VIR_FREE(progenv);

927 928
    if (ret < 0)
        umlCleanupTapDevices(conn, vm);
929 930 931

    /* NB we don't mark it running here - we do that async
       with inotify */
932 933 934
    /* XXX what if someone else tries to start it again
       before we get the inotification ? Sounds like
       trouble.... */
935 936 937 938 939 940 941 942 943

    return ret;
}

static void umlShutdownVMDaemon(virConnectPtr conn ATTRIBUTE_UNUSED,
                                struct uml_driver *driver ATTRIBUTE_UNUSED,
                                virDomainObjPtr vm)
{
    int ret;
944 945
    umlDomainObjPrivatePtr priv = vm->privateData;

D
Daniel P. Berrange 已提交
946
    if (!virDomainObjIsActive(vm))
947 948
        return;

949
    virKillProcess(vm->pid, SIGTERM);
950

951 952 953
    if (priv->monitor != -1)
        close(priv->monitor);
    priv->monitor = -1;
954 955

    if ((ret = waitpid(vm->pid, NULL, 0)) != vm->pid) {
D
Daniel Veillard 已提交
956
        VIR_WARN(_("Got unexpected pid %d != %d"),
957 958 959 960 961 962 963
               ret, vm->pid);
    }

    vm->pid = -1;
    vm->def->id = -1;
    vm->state = VIR_DOMAIN_SHUTOFF;

964 965
    umlCleanupTapDevices(conn, vm);

966 967 968 969 970 971 972 973 974 975 976 977
    if (vm->newDef) {
        virDomainDefFree(vm->def);
        vm->def = vm->newDef;
        vm->def->id = -1;
        vm->newDef = NULL;
    }
}


static virDrvOpenStatus umlOpen(virConnectPtr conn,
                                virConnectAuthPtr auth ATTRIBUTE_UNUSED,
                                int flags ATTRIBUTE_UNUSED) {
978 979 980
    if (conn->uri == NULL) {
        if (uml_driver == NULL)
            return VIR_DRV_OPEN_DECLINED;
981

982
        conn->uri = xmlParseURI(uml_driver->privileged ?
983 984 985
                                "uml:///system" :
                                "uml:///session");
        if (!conn->uri) {
986
            virReportOOMError();
987 988 989 990 991 992 993 994 995 996
            return VIR_DRV_OPEN_ERROR;
        }
    } else {
        if (conn->uri->scheme == NULL ||
            STRNEQ (conn->uri->scheme, "uml"))
            return VIR_DRV_OPEN_DECLINED;

        /* Allow remote driver to deal with URIs with hostname server */
        if (conn->uri->server != NULL)
            return VIR_DRV_OPEN_DECLINED;
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 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014
                STRNEQ (conn->uri->path, "/session")) {
                umlReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                               _("unexpected UML URI path '%s', try uml:///system"),
                               conn->uri->path);
                return VIR_DRV_OPEN_ERROR;
            }
        } else {
            if (STRNEQ (conn->uri->path, "/session")) {
                umlReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                               _("unexpected UML URI path '%s', try uml:///session"),
                               conn->uri->path);
                return VIR_DRV_OPEN_ERROR;
            }
1015
        }
1016 1017 1018 1019 1020

        /* URI was good, but driver isn't active */
        if (uml_driver == NULL) {
            umlReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s",
                           _("uml state driver is not active"));
1021 1022 1023 1024 1025 1026 1027 1028 1029 1030
            return VIR_DRV_OPEN_ERROR;
        }
    }

    conn->privateData = uml_driver;

    return VIR_DRV_OPEN_SUCCESS;
}

static int umlClose(virConnectPtr conn) {
1031
    /*struct uml_driver *driver = conn->privateData;*/
1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042

    conn->privateData = NULL;

    return 0;
}

static const char *umlGetType(virConnectPtr conn ATTRIBUTE_UNUSED) {
    return "UML";
}


1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056
static int umlIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED)
{
    /* Trivially secure, since always inside the daemon */
    return 1;
}


static int umlIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED)
{
    /* Not encrypted, but remote driver takes care of that */
    return 0;
}


1057 1058 1059 1060
static char *umlGetCapabilities(virConnectPtr conn) {
    struct uml_driver *driver = (struct uml_driver *)conn->privateData;
    char *xml;

1061
    umlDriverLock(driver);
1062
    if ((xml = virCapabilitiesFormatXML(driver->caps)) == NULL)
1063
        virReportOOMError();
1064
    umlDriverUnlock(driver);
1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088

    return xml;
}



static int umlGetProcessInfo(unsigned long long *cpuTime, int pid) {
    char proc[PATH_MAX];
    FILE *pidinfo;
    unsigned long long usertime, systime;

    if (snprintf(proc, sizeof(proc), "/proc/%d/stat", pid) >= (int)sizeof(proc)) {
        return -1;
    }

    if (!(pidinfo = fopen(proc, "r"))) {
        /*printf("cannot read pid info");*/
        /* VM probably shut down, so fake 0 */
        *cpuTime = 0;
        return 0;
    }

    if (fscanf(pidinfo, "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %llu %llu", &usertime, &systime) != 2) {
        umlDebug("not enough arg");
1089
        fclose(pidinfo);
1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110
        return -1;
    }

    /* We got jiffies
     * We want nanoseconds
     * _SC_CLK_TCK is jiffies per second
     * So calulate thus....
     */
    *cpuTime = 1000ull * 1000ull * 1000ull * (usertime + systime) / (unsigned long long)sysconf(_SC_CLK_TCK);

    umlDebug("Got %llu %llu %llu", usertime, systime, *cpuTime);

    fclose(pidinfo);

    return 0;
}


static virDomainPtr umlDomainLookupByID(virConnectPtr conn,
                                          int id) {
    struct uml_driver *driver = (struct uml_driver *)conn->privateData;
1111 1112
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
1113

1114
    umlDriverLock(driver);
1115
    vm = virDomainFindByID(&driver->domains, id);
1116 1117
    umlDriverUnlock(driver);

1118 1119
    if (!vm) {
        umlReportError(conn, NULL, NULL, VIR_ERR_NO_DOMAIN, NULL);
1120
        goto cleanup;
1121 1122 1123 1124
    }

    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
    if (dom) dom->id = vm->def->id;
1125 1126

cleanup:
1127 1128
    if (vm)
        virDomainObjUnlock(vm);
1129 1130
    return dom;
}
1131

1132 1133 1134
static virDomainPtr umlDomainLookupByUUID(virConnectPtr conn,
                                            const unsigned char *uuid) {
    struct uml_driver *driver = (struct uml_driver *)conn->privateData;
1135 1136
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
1137

1138
    umlDriverLock(driver);
1139
    vm = virDomainFindByUUID(&driver->domains, uuid);
1140 1141
    umlDriverUnlock(driver);

1142 1143
    if (!vm) {
        umlReportError(conn, NULL, NULL, VIR_ERR_NO_DOMAIN, NULL);
1144
        goto cleanup;
1145 1146 1147 1148
    }

    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
    if (dom) dom->id = vm->def->id;
1149 1150

cleanup:
1151 1152
    if (vm)
        virDomainObjUnlock(vm);
1153 1154
    return dom;
}
1155

1156 1157 1158
static virDomainPtr umlDomainLookupByName(virConnectPtr conn,
                                            const char *name) {
    struct uml_driver *driver = (struct uml_driver *)conn->privateData;
1159 1160
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
1161

1162
    umlDriverLock(driver);
1163
    vm = virDomainFindByName(&driver->domains, name);
1164 1165
    umlDriverUnlock(driver);

1166 1167
    if (!vm) {
        umlReportError(conn, NULL, NULL, VIR_ERR_NO_DOMAIN, NULL);
1168
        goto cleanup;
1169 1170 1171 1172
    }

    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
    if (dom) dom->id = vm->def->id;
1173 1174

cleanup:
1175 1176
    if (vm)
        virDomainObjUnlock(vm);
1177 1178 1179
    return dom;
}

1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224

static int umlDomainIsActive(virDomainPtr dom)
{
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr obj;
    int ret = -1;

    umlDriverLock(driver);
    obj = virDomainFindByUUID(&driver->domains, dom->uuid);
    umlDriverUnlock(driver);
    if (!obj) {
        umlReportError(dom->conn, NULL, NULL, VIR_ERR_NO_DOMAIN, NULL);
        goto cleanup;
    }
    ret = virDomainObjIsActive(obj);

cleanup:
    if (obj)
        virDomainObjUnlock(obj);
    return ret;
}


static int umlDomainIsPersistent(virDomainPtr dom)
{
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr obj;
    int ret = -1;

    umlDriverLock(driver);
    obj = virDomainFindByUUID(&driver->domains, dom->uuid);
    umlDriverUnlock(driver);
    if (!obj) {
        umlReportError(dom->conn, NULL, NULL, VIR_ERR_NO_DOMAIN, NULL);
        goto cleanup;
    }
    ret = obj->persistent;

cleanup:
    if (obj)
        virDomainObjUnlock(obj);
    return ret;
}


1225
static 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 1233 1234 1235 1236 1237 1238 1239

    if (driver->umlVersion == 0) {
        uname(&ut);

        if (virParseVersionString(ut.release, &driver->umlVersion) < 0) {
            umlReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                           _("cannot parse version %s"), ut.release);
            goto cleanup;
        }
1240 1241
    }

1242 1243 1244 1245 1246 1247
    *version = driver->umlVersion;
    ret = 0;

cleanup:
    umlDriverUnlock(driver);
    return ret;
1248 1249 1250
}

static 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 1260
}
static 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 1269 1270 1271

    return n;
}
static virDomainPtr umlDomainCreate(virConnectPtr conn, const char *xml,
                                      unsigned int flags ATTRIBUTE_UNUSED) {
1272
    struct uml_driver *driver = conn->privateData;
1273
    virDomainDefPtr def;
1274
    virDomainObjPtr vm = NULL;
1275
    virDomainPtr dom = NULL;
1276

1277
    umlDriverLock(driver);
1278
    if (!(def = virDomainDefParseString(driver->caps, xml,
1279
                                        VIR_DOMAIN_XML_INACTIVE)))
1280
        goto cleanup;
1281

1282
    if (virDomainObjIsDuplicate(&driver->domains, def, 1) < 0)
1283
        goto cleanup;
1284

1285
    if (!(vm = virDomainAssignDef(driver->caps,
1286
                                  &driver->domains,
1287
                                  def, false)))
1288 1289
        goto cleanup;
    def = NULL;
1290 1291 1292 1293

    if (umlStartVMDaemon(conn, driver, vm) < 0) {
        virDomainRemoveInactive(&driver->domains,
                                vm);
1294 1295
        vm = NULL;
        goto cleanup;
1296 1297 1298 1299
    }

    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
    if (dom) dom->id = vm->def->id;
1300 1301 1302

cleanup:
    virDomainDefFree(def);
1303 1304 1305
    if (vm)
        virDomainObjUnlock(vm);
    umlDriverUnlock(driver);
1306 1307 1308 1309 1310
    return dom;
}


static int umlDomainShutdown(virDomainPtr dom) {
1311 1312
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
1313
    char *info = NULL;
1314
    int ret = -1;
1315

1316
    umlDriverLock(driver);
1317
    vm = virDomainFindByID(&driver->domains, dom->id);
1318
    umlDriverUnlock(driver);
1319 1320 1321
    if (!vm) {
        umlReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN,
                         _("no domain with matching id %d"), dom->id);
1322
        goto cleanup;
1323 1324 1325 1326 1327 1328
    }

#if 0
    if (umlMonitorCommand(driver, vm, "system_powerdown", &info) < 0) {
        umlReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
                         "%s", _("shutdown operation failed"));
1329
        goto cleanup;
1330
    }
1331
    ret = 0;
1332 1333
#endif

1334 1335
cleanup:
    VIR_FREE(info);
1336 1337
    if (vm)
        virDomainObjUnlock(vm);
1338
    return ret;
1339 1340 1341 1342
}


static int umlDomainDestroy(virDomainPtr dom) {
1343 1344 1345
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
1346

1347
    umlDriverLock(driver);
1348
    vm = virDomainFindByID(&driver->domains, dom->id);
1349 1350 1351
    if (!vm) {
        umlReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN,
                         _("no domain with matching id %d"), dom->id);
1352
        goto cleanup;
1353 1354 1355
    }

    umlShutdownVMDaemon(dom->conn, driver, vm);
1356
    if (!vm->persistent) {
1357 1358
        virDomainRemoveInactive(&driver->domains,
                                vm);
1359 1360 1361
        vm = NULL;
    }
    ret = 0;
1362

1363
cleanup:
1364 1365 1366
    if (vm)
        virDomainObjUnlock(vm);
    umlDriverUnlock(driver);
1367
    return ret;
1368 1369 1370 1371
}


static char *umlDomainGetOSType(virDomainPtr dom) {
1372 1373 1374
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *type = NULL;
1375

1376
    umlDriverLock(driver);
1377
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1378
    umlDriverUnlock(driver);
1379 1380 1381
    if (!vm) {
        umlReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN,
                         "%s", _("no domain with matching uuid"));
1382
        goto cleanup;
1383 1384
    }

1385
    if (!(type = strdup(vm->def->os.type)))
1386
        virReportOOMError();
1387 1388

cleanup:
1389 1390
    if (vm)
        virDomainObjUnlock(vm);
1391 1392 1393 1394 1395
    return type;
}

/* Returns max memory in kb, 0 if error */
static unsigned long umlDomainGetMaxMemory(virDomainPtr dom) {
1396 1397 1398
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    unsigned long ret = 0;
1399

1400
    umlDriverLock(driver);
1401
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1402 1403
    umlDriverUnlock(driver);

1404 1405 1406 1407 1408
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];

        virUUIDFormat(dom->uuid, uuidstr);
        umlReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN,
1409 1410
                       _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
1411
    }
1412
    ret = vm->def->maxmem;
1413

1414
cleanup:
1415 1416
    if (vm)
        virDomainObjUnlock(vm);
1417
    return ret;
1418 1419 1420
}

static int umlDomainSetMaxMemory(virDomainPtr dom, unsigned long newmax) {
1421 1422 1423
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
1424

1425
    umlDriverLock(driver);
1426
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1427 1428
    umlDriverUnlock(driver);

1429 1430 1431 1432 1433 1434
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];

        virUUIDFormat(dom->uuid, uuidstr);
        umlReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN,
                         _("no domain with matching uuid '%s'"), uuidstr);
1435
        goto cleanup;
1436 1437 1438 1439 1440
    }

    if (newmax < vm->def->memory) {
        umlReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_ARG,
                         "%s", _("cannot set max memory lower than current memory"));
1441
        goto cleanup;
1442 1443 1444
    }

    vm->def->maxmem = newmax;
1445 1446 1447
    ret = 0;

cleanup:
1448 1449
    if (vm)
        virDomainObjUnlock(vm);
1450
    return ret;
1451 1452 1453
}

static int umlDomainSetMemory(virDomainPtr dom, unsigned long newmem) {
1454 1455 1456
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
1457

1458
    umlDriverLock(driver);
1459
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1460 1461
    umlDriverUnlock(driver);

1462 1463 1464 1465 1466 1467
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];

        virUUIDFormat(dom->uuid, uuidstr);
        umlReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN,
                         _("no domain with matching uuid '%s'"), uuidstr);
1468
        goto cleanup;
1469 1470
    }

D
Daniel P. Berrange 已提交
1471
    if (virDomainObjIsActive(vm)) {
1472 1473
        umlReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
                         "%s", _("cannot set memory of an active domain"));
1474
        goto cleanup;
1475 1476 1477 1478 1479
    }

    if (newmem > vm->def->maxmem) {
        umlReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_ARG,
                         "%s", _("cannot set memory higher than max memory"));
1480
        goto cleanup;
1481 1482 1483
    }

    vm->def->memory = newmem;
1484 1485 1486
    ret = 0;

cleanup:
1487 1488
    if (vm)
        virDomainObjUnlock(vm);
1489
    return ret;
1490 1491 1492 1493
}

static int umlDomainGetInfo(virDomainPtr dom,
                              virDomainInfoPtr info) {
1494 1495 1496 1497
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;

1498
    umlDriverLock(driver);
1499
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1500 1501
    umlDriverUnlock(driver);

1502 1503
    if (!vm) {
        umlReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN,
1504 1505
                       "%s", _("no domain with matching uuid"));
        goto cleanup;
1506 1507 1508 1509
    }

    info->state = vm->state;

D
Daniel P. Berrange 已提交
1510
    if (!virDomainObjIsActive(vm)) {
1511 1512 1513
        info->cpuTime = 0;
    } else {
        if (umlGetProcessInfo(&(info->cpuTime), vm->pid) < 0) {
1514 1515 1516
            umlReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
                           "%s", _("cannot read cputime for domain"));
            goto cleanup;
1517 1518 1519 1520 1521 1522
        }
    }

    info->maxMem = vm->def->maxmem;
    info->memory = vm->def->memory;
    info->nrVirtCpu = vm->def->vcpus;
1523 1524 1525
    ret = 0;

cleanup:
1526 1527
    if (vm)
        virDomainObjUnlock(vm);
1528
    return ret;
1529 1530 1531 1532 1533
}


static char *umlDomainDumpXML(virDomainPtr dom,
                                int flags ATTRIBUTE_UNUSED) {
1534 1535 1536 1537
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *ret = NULL;

1538
    umlDriverLock(driver);
1539
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1540 1541
    umlDriverUnlock(driver);

1542 1543 1544
    if (!vm) {
        umlReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN,
                         "%s", _("no domain with matching uuid"));
1545
        goto cleanup;
1546 1547
    }

1548
    ret = virDomainDefFormat((flags & VIR_DOMAIN_XML_INACTIVE) && vm->newDef ?
1549 1550 1551 1552
                             vm->newDef : vm->def,
                             flags);

cleanup:
1553 1554
    if (vm)
        virDomainObjUnlock(vm);
1555
    return ret;
1556 1557 1558 1559 1560
}


static int umlListDefinedDomains(virConnectPtr conn,
                            char **const names, int nnames) {
1561
    struct uml_driver *driver = conn->privateData;
1562
    int n;
1563

1564
    umlDriverLock(driver);
1565
    n = virDomainObjListGetInactiveNames(&driver->domains, names, nnames);
1566
    umlDriverUnlock(driver);
1567

1568
    return n;
1569 1570 1571
}

static int umlNumDefinedDomains(virConnectPtr conn) {
1572
    struct uml_driver *driver = conn->privateData;
1573
    int n;
1574

1575
    umlDriverLock(driver);
1576
    n = virDomainObjListNumOfDomains(&driver->domains, 0);
1577
    umlDriverUnlock(driver);
1578 1579 1580 1581 1582 1583

    return n;
}


static int umlDomainStart(virDomainPtr dom) {
1584 1585 1586
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
1587

1588
    umlDriverLock(driver);
1589
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1590

1591 1592 1593
    if (!vm) {
        umlReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN,
                         "%s", _("no domain with matching uuid"));
1594
        goto cleanup;
1595 1596
    }

1597 1598 1599
    ret = umlStartVMDaemon(dom->conn, driver, vm);

cleanup:
1600 1601 1602
    if (vm)
        virDomainObjUnlock(vm);
    umlDriverUnlock(driver);
1603
    return ret;
1604 1605 1606 1607
}


static virDomainPtr umlDomainDefine(virConnectPtr conn, const char *xml) {
1608
    struct uml_driver *driver = conn->privateData;
1609
    virDomainDefPtr def;
1610
    virDomainObjPtr vm = NULL;
1611
    virDomainPtr dom = NULL;
1612

1613
    umlDriverLock(driver);
1614
    if (!(def = virDomainDefParseString(driver->caps, xml,
1615
                                        VIR_DOMAIN_XML_INACTIVE)))
1616
        goto cleanup;
1617

1618 1619 1620
    if (virDomainObjIsDuplicate(&driver->domains, def, 0) < 0)
        goto cleanup;

1621
    if (!(vm = virDomainAssignDef(driver->caps,
1622
                                  &driver->domains,
1623
                                  def, false)))
1624 1625
        goto cleanup;
    def = NULL;
1626 1627
    vm->persistent = 1;

1628
    if (virDomainSaveConfig(driver->configDir,
1629 1630 1631
                            vm->newDef ? vm->newDef : vm->def) < 0) {
        virDomainRemoveInactive(&driver->domains,
                                vm);
1632
        vm = NULL;
1633
        goto cleanup;
1634 1635 1636 1637
    }

    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
    if (dom) dom->id = vm->def->id;
1638 1639 1640

cleanup:
    virDomainDefFree(def);
1641 1642 1643
    if (vm)
        virDomainObjUnlock(vm);
    umlDriverUnlock(driver);
1644 1645 1646 1647
    return dom;
}

static int umlDomainUndefine(virDomainPtr dom) {
1648 1649 1650
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
1651

1652
    umlDriverLock(driver);
1653
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1654 1655 1656
    if (!vm) {
        umlReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN,
                         "%s", _("no domain with matching uuid"));
1657
        goto cleanup;
1658 1659
    }

D
Daniel P. Berrange 已提交
1660
    if (virDomainObjIsActive(vm)) {
1661 1662
        umlReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR,
                         "%s", _("cannot delete active domain"));
1663
        goto cleanup;
1664 1665 1666 1667 1668
    }

    if (!vm->persistent) {
        umlReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR,
                         "%s", _("cannot undefine transient domain"));
1669
        goto cleanup;
1670 1671
    }

1672
    if (virDomainDeleteConfig(driver->configDir, driver->autostartDir, vm) < 0)
1673
        goto cleanup;
1674 1675 1676

    virDomainRemoveInactive(&driver->domains,
                            vm);
1677
    vm = NULL;
1678
    ret = 0;
1679

1680
cleanup:
1681 1682 1683
    if (vm)
        virDomainObjUnlock(vm);
    umlDriverUnlock(driver);
1684
    return ret;
1685 1686 1687 1688 1689 1690
}



static int umlDomainGetAutostart(virDomainPtr dom,
                            int *autostart) {
1691 1692 1693
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
1694

1695
    umlDriverLock(driver);
1696
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1697

1698 1699 1700
    if (!vm) {
        umlReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN,
                         "%s", _("no domain with matching uuid"));
1701
        goto cleanup;
1702 1703 1704
    }

    *autostart = vm->autostart;
1705
    ret = 0;
1706

1707
cleanup:
1708 1709
    if (vm)
        virDomainObjUnlock(vm);
1710
    umlDriverUnlock(driver);
1711
    return ret;
1712 1713 1714 1715
}

static int umlDomainSetAutostart(virDomainPtr dom,
                                   int autostart) {
1716
    struct uml_driver *driver = dom->conn->privateData;
1717
    virDomainObjPtr vm;
1718 1719 1720
    char *configFile = NULL, *autostartLink = NULL;
    int ret = -1;

1721 1722 1723
    umlDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

1724 1725 1726
    if (!vm) {
        umlReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN,
                         "%s", _("no domain with matching uuid"));
1727
        goto cleanup;
1728 1729 1730 1731 1732
    }

    if (!vm->persistent) {
        umlReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR,
                         "%s", _("cannot set autostart for transient domain"));
1733
        goto cleanup;
1734 1735 1736 1737
    }

    autostart = (autostart != 0);

1738
    if (vm->autostart != autostart) {
1739
        if ((configFile = virDomainConfigFile(driver->configDir, vm->def->name)) == NULL)
1740
            goto cleanup;
1741
        if ((autostartLink = virDomainConfigFile(driver->autostartDir, vm->def->name)) == NULL)
1742
            goto cleanup;
1743

1744 1745
        if (autostart) {
            int err;
1746

1747
            if ((err = virFileMakePath(driver->autostartDir))) {
1748
                virReportSystemError(err,
1749 1750
                                     _("cannot create autostart directory %s"),
                                     driver->autostartDir);
1751 1752
                goto cleanup;
            }
1753

1754
            if (symlink(configFile, autostartLink) < 0) {
1755
                virReportSystemError(errno,
1756 1757
                                     _("Failed to create symlink '%s to '%s'"),
                                     autostartLink, configFile);
1758 1759 1760 1761
                goto cleanup;
            }
        } else {
            if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
1762
                virReportSystemError(errno,
1763 1764
                                     _("Failed to delete symlink '%s'"),
                                     autostartLink);
1765 1766
                goto cleanup;
            }
1767 1768
        }

1769
        vm->autostart = autostart;
1770 1771 1772 1773 1774 1775
    }
    ret = 0;

cleanup:
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
1776 1777
    if (vm)
        virDomainObjUnlock(vm);
1778
    umlDriverUnlock(driver);
1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789
    return ret;
}


static int
umlDomainBlockPeek (virDomainPtr dom,
                      const char *path,
                      unsigned long long offset, size_t size,
                      void *buffer,
                      unsigned int flags ATTRIBUTE_UNUSED)
{
1790 1791 1792
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int fd = -1, ret = -1, i;
1793

1794
    umlDriverLock(driver);
1795
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1796 1797
    umlDriverUnlock(driver);

1798 1799
    if (!vm) {
        umlReportError (dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN,
J
Jim Meyering 已提交
1800
                        "%s", _("no domain with matching uuid"));
1801
        goto cleanup;
1802 1803 1804 1805
    }

    if (!path || path[0] == '\0') {
        umlReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_ARG,
J
Jim Meyering 已提交
1806
                       "%s", _("NULL or empty path"));
1807
        goto cleanup;
1808 1809 1810 1811 1812
    }

    /* Check the path belongs to this domain. */
    for (i = 0 ; i < vm->def->ndisks ; i++) {
        if (vm->def->disks[i]->src != NULL &&
1813 1814 1815 1816
            STREQ (vm->def->disks[i]->src, path)) {
            ret = 0;
            break;
        }
1817 1818
    }

1819 1820 1821 1822 1823
    if (ret == 0) {
        ret = -1;
        /* The path is correct, now try to open it and get its size. */
        fd = open (path, O_RDONLY);
        if (fd == -1) {
1824
            virReportSystemError(errno,
1825
                                 _("cannot open %s"), path);
1826 1827
            goto cleanup;
        }
1828

1829 1830 1831 1832 1833 1834
        /* Seek and read. */
        /* NB. Because we configure with AC_SYS_LARGEFILE, off_t should
         * be 64 bits on all platforms.
         */
        if (lseek (fd, offset, SEEK_SET) == (off_t) -1 ||
            saferead (fd, buffer, size) == (ssize_t) -1) {
1835
            virReportSystemError(errno,
1836
                                 _("cannot read %s"), path);
1837 1838 1839 1840 1841 1842
            goto cleanup;
        }

        ret = 0;
    } else {
        umlReportError (dom->conn, dom, NULL, VIR_ERR_INVALID_ARG,
J
Jim Meyering 已提交
1843
                        "%s", _("invalid path"));
1844 1845
    }

1846
cleanup:
1847
    if (fd >= 0) close (fd);
1848 1849
    if (vm)
        virDomainObjUnlock(vm);
1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862
    return ret;
}



static virDriver umlDriver = {
    VIR_DRV_UML,
    "UML",
    umlOpen, /* open */
    umlClose, /* close */
    NULL, /* supports_feature */
    umlGetType, /* type */
    umlGetVersion, /* version */
1863
    NULL, /* libvirtVersion (impl. in libvirt.c) */
1864
    virGetHostname, /* getHostname */
1865
    NULL, /* getMaxVcpus */
1866
    nodeGetInfo, /* nodeGetInfo */
1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890
    umlGetCapabilities, /* getCapabilities */
    umlListDomains, /* listDomains */
    umlNumDomains, /* numOfDomains */
    umlDomainCreate, /* domainCreateXML */
    umlDomainLookupByID, /* domainLookupByID */
    umlDomainLookupByUUID, /* domainLookupByUUID */
    umlDomainLookupByName, /* domainLookupByName */
    NULL, /* domainSuspend */
    NULL, /* domainResume */
    umlDomainShutdown, /* domainShutdown */
    NULL, /* domainReboot */
    umlDomainDestroy, /* domainDestroy */
    umlDomainGetOSType, /* domainGetOSType */
    umlDomainGetMaxMemory, /* domainGetMaxMemory */
    umlDomainSetMaxMemory, /* domainSetMaxMemory */
    umlDomainSetMemory, /* domainSetMemory */
    umlDomainGetInfo, /* domainGetInfo */
    NULL, /* domainSave */
    NULL, /* domainRestore */
    NULL, /* domainCoreDump */
    NULL, /* domainSetVcpus */
    NULL, /* domainPinVcpu */
    NULL, /* domainGetVcpus */
    NULL, /* domainGetMaxVcpus */
1891 1892
    NULL, /* domainGetSecurityLabel */
    NULL, /* nodeGetSecurityModel */
1893
    umlDomainDumpXML, /* domainDumpXML */
1894 1895
    NULL, /* domainXMLFromNative */
    NULL, /* domainXMLToNative */
1896 1897
    umlListDefinedDomains, /* listDefinedDomains */
    umlNumDefinedDomains, /* numOfDefinedDomains */
1898 1899 1900 1901
    umlDomainStart, /* domainCreate */
    umlDomainDefine, /* domainDefineXML */
    umlDomainUndefine, /* domainUndefine */
    NULL, /* domainAttachDevice */
1902
    NULL, /* domainAttachDeviceFlags */
1903
    NULL, /* domainDetachDevice */
1904
    NULL, /* domainDetachDeviceFlags */
1905
    NULL, /* domainUpdateDeviceFlags */
1906 1907 1908 1909 1910 1911 1912 1913 1914 1915
    umlDomainGetAutostart, /* domainGetAutostart */
    umlDomainSetAutostart, /* domainSetAutostart */
    NULL, /* domainGetSchedulerType */
    NULL, /* domainGetSchedulerParameters */
    NULL, /* domainSetSchedulerParameters */
    NULL, /* domainMigratePrepare */
    NULL, /* domainMigratePerform */
    NULL, /* domainMigrateFinish */
    NULL, /* domainBlockStats */
    NULL, /* domainInterfaceStats */
1916
    NULL, /* domainMemoryStats */
1917 1918
    umlDomainBlockPeek, /* domainBlockPeek */
    NULL, /* domainMemoryPeek */
1919 1920
    nodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */
    nodeGetFreeMemory,  /* getFreeMemory */
1921
    NULL, /* domainEventRegister */
1922
    NULL, /* domainEventDeregister */
1923 1924
    NULL, /* domainMigratePrepare2 */
    NULL, /* domainMigrateFinish2 */
1925
    NULL, /* nodeDeviceDettach */
1926 1927
    NULL, /* nodeDeviceReAttach */
    NULL, /* nodeDeviceReset */
C
Chris Lalancette 已提交
1928
    NULL, /* domainMigratePrepareTunnel */
1929 1930 1931 1932
    umlIsEncrypted,
    umlIsSecure,
    umlDomainIsActive,
    umlDomainIsPersistent,
J
Jiri Denemark 已提交
1933
    NULL, /* cpuCompare */
1934
    NULL, /* cpuBaseline */
1935
    NULL, /* domainGetJobInfo */
1936
    NULL, /* domainAbortJob */
1937
    NULL, /* domainMigrateSetMaxDowntime */
1938 1939
    NULL, /* domainEventRegisterAny */
    NULL, /* domainEventDeregisterAny */
1940 1941 1942
    NULL, /* domainManagedSave */
    NULL, /* domainHasManagedSaveImage */
    NULL, /* domainManagedSaveRemove */
C
Chris Lalancette 已提交
1943 1944 1945 1946 1947 1948 1949 1950 1951
    NULL, /* domainSnapshotCreateXML */
    NULL, /* domainSnapshotDumpXML */
    NULL, /* domainSnapshotNum */
    NULL, /* domainSnapshotListNames */
    NULL, /* domainSnapshotLookupByName */
    NULL, /* domainHasCurrentSnapshot */
    NULL, /* domainSnapshotCurrent */
    NULL, /* domainRevertToSnapshot */
    NULL, /* domainSnapshotDelete */
1952 1953 1954 1955
};


static virStateDriver umlStateDriver = {
1956
    .name = "UML",
1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967
    .initialize = umlStartup,
    .cleanup = umlShutdown,
    .reload = umlReload,
    .active = umlActive,
};

int umlRegister(void) {
    virRegisterDriver(&umlDriver);
    virRegisterStateDriver(&umlStateDriver);
    return 0;
}