uml_driver.c 52.5 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
 * 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 <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>
46
#include <sys/un.h>
47 48 49 50 51 52 53 54 55 56 57 58 59

#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"
60
#include "logging.h"
61

62 63
#define VIR_FROM_THIS VIR_FROM_UML

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

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


75 76
static int umlShutdown(void);

77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
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);
}


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

107

108
static int umlOpenMonitor(struct uml_driver *driver,
109
                          virDomainObjPtr vm);
110
static int umlReadPidFile(struct uml_driver *driver,
111 112 113 114 115 116 117 118 119 120 121
                          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 已提交
122
    VIR_ERROR0(_("Failed to set close-on-exec file descriptor flag"));
123 124 125 126 127 128 129 130 131 132 133 134
    return -1;
}

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

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


135 136 137 138
static int umlMonitorCommand(const struct uml_driver *driver,
                             const virDomainObjPtr vm,
                             const char *cmd,
                             char **reply);
139 140 141

static struct uml_driver *uml_driver = NULL;

142 143 144 145 146 147 148 149 150 151 152 153 154
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 已提交
155
        !virDomainObjIsActive(vm)) {
156 157 158 159
        virResetLastError();
        if (umlStartVMDaemon(data->conn, data->driver, vm) < 0) {
            virErrorPtr err = virGetLastError();
            VIR_ERROR(_("Failed to autostart VM '%s': %s"),
160
                      vm->def->name, err ? err->message : _("unknown error"));
161 162 163 164
        }
    }
    virDomainObjUnlock(vm);
}
165 166 167

static void
umlAutostartConfigs(struct uml_driver *driver) {
168 169 170 171 172
    /* 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
     */
173 174 175
    virConnectPtr conn = virConnectOpen(driver->privileged ?
                                        "uml:///system" :
                                        "uml:///session");
176
    /* Ignoring NULL conn which is mostly harmless here */
177

178 179 180
    struct umlAutostartData data = { driver, conn };

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

182 183
    if (conn)
        virConnectClose(conn);
184 185 186 187
}


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

204
    if (res && STRPREFIX(res, "pts:")) {
205 206
        VIR_FREE(def->data.file.path);
        if ((def->data.file.path = strdup(res + 4)) == NULL) {
207
            virReportOOMError();
208 209 210 211
            VIR_FREE(res);
            VIR_FREE(cmd);
            return -1;
        }
212
    } else if (!res || STRPREFIX(res, "pts")) {
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
        /* 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
229
umlIdentifyChrPTY(struct uml_driver *driver,
230 231 232 233 234 235
                  virDomainObjPtr dom)
{
    int i;

    if (dom->def->console &&
        dom->def->console->type == VIR_DOMAIN_CHR_TYPE_PTY)
236
        if (umlIdentifyOneChrPTY(driver, dom,
237 238 239 240 241
                                 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 &&
242
            umlIdentifyOneChrPTY(driver, dom,
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
                                 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;

262
    umlDriverLock(driver);
263
    if (watch != driver->inotifyWatch)
264
        goto cleanup;
265 266 267 268 269 270

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

    tmp = buf;
    while (got) {
        if (got < sizeof(struct inotify_event))
277
            goto cleanup; /* bad */
278 279 280 281 282 283

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

        if (got < e->len)
284
            goto cleanup;
285 286 287 288 289 290 291 292 293 294 295 296 297

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

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

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

        if (!dom) {
            continue;
        }

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

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

312
            if (umlReadPidFile(driver, dom) < 0) {
313
                virDomainObjUnlock(dom);
314 315 316 317 318 319
                continue;
            }

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

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

cleanup:
    umlDriverUnlock(driver);
333 334 335 336 337 338 339 340
}

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

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

350 351
    uml_driver->privileged = privileged;

352 353 354 355
    if (virMutexInit(&uml_driver->lock) < 0) {
        VIR_FREE(uml_driver);
        return -1;
    }
356 357
    umlDriverLock(uml_driver);

358 359
    /* Don't have a dom0 so start from 1 */
    uml_driver->nextvmid = 1;
360
    uml_driver->inotifyWatch = -1;
361

362 363 364
    if (virDomainObjListInit(&uml_driver->domains) < 0)
        goto error;

365
    userdir = virGetUserDirectory(uid);
366
    if (!userdir)
367
        goto error;
368

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

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

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

382
        if (virAsprintf(&base, "%s/.libvirt", userdir) == -1)
383 384 385
            goto out_of_memory;
    }

386
    if (virAsprintf(&uml_driver->monitorDir,
387
                    "%s/.uml", userdir) == -1)
388 389 390 391 392 393 394 395 396
        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';

397
    if (virAsprintf(&uml_driver->configDir, "%s/uml", base) == -1)
398 399
        goto out_of_memory;

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

    VIR_FREE(base);

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

408 409
    uml_driver->caps->privateDataAllocFunc = umlDomainObjPrivateAlloc;
    uml_driver->caps->privateDataFreeFunc = umlDomainObjPrivateFree;
410 411

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

L
Laine Stump 已提交
416
    if (virFileMakePath(uml_driver->monitorDir) != 0) {
417
        char ebuf[1024];
D
Daniel Veillard 已提交
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 425 426
    if (inotify_add_watch(uml_driver->inotifyFD,
                          uml_driver->monitorDir,
                          IN_CREATE | IN_MODIFY | IN_DELETE) < 0) {
427
        goto error;
428 429
    }

430 431
    if ((uml_driver->inotifyWatch =
         virEventAddHandle(uml_driver->inotifyFD, POLLIN,
432 433
                           umlInotifyEvent, uml_driver, NULL)) < 0)
        goto error;
434

435
    if (virDomainLoadAllConfigs(uml_driver->caps,
436 437 438
                                &uml_driver->domains,
                                uml_driver->configDir,
                                uml_driver->autostartDir,
439
                                0, NULL, NULL) < 0)
440 441
        goto error;

442 443
    umlAutostartConfigs(uml_driver);

444
    umlDriverUnlock(uml_driver);
445 446
    VIR_FREE(userdir);

447 448
    return 0;

449
out_of_memory:
D
Daniel Veillard 已提交
450
    VIR_ERROR0(_("umlStartup: out of memory"));
451 452

error:
453
    VIR_FREE(userdir);
454
    VIR_FREE(base);
455 456
    umlDriverUnlock(uml_driver);
    umlShutdown();
457 458 459 460 461 462 463 464 465 466 467 468 469 470
    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;

471
    umlDriverLock(uml_driver);
472
    virDomainLoadAllConfigs(uml_driver->caps,
473 474 475
                            &uml_driver->domains,
                            uml_driver->configDir,
                            uml_driver->autostartDir,
476
                            0, NULL, NULL);
477 478

    umlAutostartConfigs(uml_driver);
479
    umlDriverUnlock(uml_driver);
480 481 482 483 484 485 486 487 488 489 490 491 492 493

    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) {
494
    int active = 0;
495 496 497 498

    if (!uml_driver)
        return 0;

499
    umlDriverLock(uml_driver);
500
    active = virDomainObjListNumOfDomains(&uml_driver->domains, 1);
501
    umlDriverUnlock(uml_driver);
502

503
    return active;
504 505
}

506 507 508 509 510 511 512
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 已提交
513
    if (virDomainObjIsActive(dom))
514 515 516 517
        umlShutdownVMDaemon(NULL, driver, dom);
    virDomainObjUnlock(dom);
}

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

528
    umlDriverLock(uml_driver);
529 530
    if (uml_driver->inotifyWatch != -1)
        virEventRemoveHandle(uml_driver->inotifyWatch);
531 532 533
    close(uml_driver->inotifyFD);
    virCapabilitiesFree(uml_driver->caps);

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

538
    virDomainObjListDeinit(&uml_driver->domains);
539 540 541 542 543 544 545 546 547

    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);

548
    umlDriverUnlock(uml_driver);
549
    virMutexDestroy(&uml_driver->lock);
550 551 552 553 554 555
    VIR_FREE(uml_driver);

    return 0;
}


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

    vm->pid = -1;
565 566
    if (virAsprintf(&pidfile, "%s/%s/pid",
                    driver->monitorDir, vm->def->name) < 0) {
567
        virReportOOMError();
568 569 570 571 572 573 574 575 576 577 578 579 580 581 582
        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;
583
        fclose(file);
584 585 586 587 588 589 590 591 592 593
        goto cleanup;
    }

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

    rc = 0;

 cleanup:
    if (rc != 0)
594
        virReportSystemError(errno,
595 596
                             _("failed to read pid: %s"),
                             pidfile);
597 598 599 600
    VIR_FREE(pidfile);
    return rc;
}

601
static int umlMonitorAddress(const struct uml_driver *driver,
602 603 604
                             virDomainObjPtr vm,
                             struct sockaddr_un *addr) {
    char *sockname;
C
Chris Lalancette 已提交
605
    int retval = 0;
606

607 608
    if (virAsprintf(&sockname, "%s/%s/mconsole",
                    driver->monitorDir, vm->def->name) < 0) {
609
        virReportOOMError();
610 611 612 613 614
        return -1;
    }

    memset(addr, 0, sizeof *addr);
    addr->sun_family = AF_UNIX;
C
Chris Lalancette 已提交
615
    if (virStrcpyStatic(addr->sun_path, sockname) == NULL) {
616
        umlReportError(VIR_ERR_INTERNAL_ERROR,
C
Chris Lalancette 已提交
617 618 619
                       _("Unix path %s too long for destination"), sockname);
        retval = -1;
    }
620
    VIR_FREE(sockname);
C
Chris Lalancette 已提交
621
    return retval;
622 623
}

624
static int umlOpenMonitor(struct uml_driver *driver,
625 626 627 628
                          virDomainObjPtr vm) {
    struct sockaddr_un addr;
    struct stat sb;
    int retries = 0;
629
    umlDomainObjPrivatePtr priv = vm->privateData;
630

631
    if (umlMonitorAddress(driver, vm, &addr) < 0)
632 633
        return -1;

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

645
    if ((priv->monitor = socket(PF_UNIX, SOCK_DGRAM, 0)) < 0) {
646
        virReportSystemError(errno,
647
                             "%s", _("cannot open socket"));
648 649 650 651
        return -1;
    }

    memset(addr.sun_path, 0, sizeof addr.sun_path);
652 653
    sprintf(addr.sun_path + 1, "libvirt-uml-%u", vm->pid);
    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 658
        close(priv->monitor);
        priv->monitor = -1;
659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684
        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];
};


685
static int umlMonitorCommand(const struct uml_driver *driver,
686 687 688 689 690 691 692 693 694 695
                             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;
696
    umlDomainObjPrivatePtr priv = vm->privateData;
697

698 699
    VIR_DEBUG("Run command '%s'", cmd);

700 701
    *reply = NULL;

702
    if (umlMonitorAddress(driver, vm, &addr) < 0)
703 704 705 706 707 708 709
        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)) {
710
        virReportSystemError(EINVAL,
711 712
                             _("cannot send too long command %s (%d bytes)"),
                             cmd, req.length);
713 714
        return -1;
    }
C
Chris Lalancette 已提交
715
    if (virStrcpyStatic(req.data, cmd) == NULL) {
716
        umlReportError(VIR_ERR_INTERNAL_ERROR,
C
Chris Lalancette 已提交
717 718 719
                       _("Command %s too long for destination"), cmd);
        return -1;
    }
720

721
    if (sendto(priv->monitor, &req, sizeof req, 0,
722
               (struct sockaddr *)&addr, sizeof addr) != (sizeof req)) {
723
        virReportSystemError(errno,
724 725
                             _("cannot send command %s"),
                             cmd);
726 727 728 729
        return -1;
    }

    do {
E
Eric Blake 已提交
730
        ssize_t nbytes;
731
        addrlen = sizeof(addr);
E
Eric Blake 已提交
732
        nbytes = recvfrom(priv->monitor, &res, sizeof res, 0,
733
                          (struct sockaddr *)&addr, &addrlen);
E
Eric Blake 已提交
734 735 736
        if (nbytes < 0) {
            if (errno == EAGAIN || errno == EINTR)
                continue;
737
            virReportSystemError(errno, _("cannot read reply %s"), cmd);
738 739
            goto error;
        }
740 741 742
        /* Ensure res.length is safe to read before validating its value.  */
        if (nbytes < offsetof(struct monitor_request, data) ||
            nbytes < offsetof(struct monitor_request, data) + res.length) {
743 744 745
            virReportSystemError(0, _("incomplete reply %s"), cmd);
            goto error;
        }
746 747

        if (VIR_REALLOC_N(retdata, retlen + res.length) < 0) {
748
            virReportOOMError();
749 750 751 752 753 754 755 756 757 758 759
            goto error;
        }
        memcpy(retdata + retlen, res.data, res.length);
        retlen += res.length - 1;
        retdata[retlen] = '\0';

        if (res.error)
            ret = -1;

    } while (res.extra);

760 761
    VIR_DEBUG("Command reply is '%s'", NULLSTR(retdata));

762 763 764 765
    if (ret < 0)
        VIR_FREE(retdata);
    else
        *reply = retdata;
766 767 768 769 770 771 772 773 774

    return ret;

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


775 776 777 778 779 780
static int umlCleanupTapDevices(virConnectPtr conn ATTRIBUTE_UNUSED,
                                virDomainObjPtr vm) {
    int i;
    int err;
    int ret = 0;
    brControl *brctl = NULL;
781
    VIR_ERROR0(_("Cleanup tap"));
782 783 784 785 786 787 788 789 790 791
    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;

792
        VIR_ERROR(_("Cleanup '%s'"), def->ifname);
793 794
        err = brDeleteTap(brctl, def->ifname);
        if (err) {
795
            VIR_ERROR(_("Cleanup failed %d"), err);
796 797 798
            ret = -1;
        }
    }
799
    VIR_ERROR0(_("Cleanup tap done"));
800 801 802 803
    brShutdown(brctl);
    return ret;
}

804 805 806 807 808
static int umlStartVMDaemon(virConnectPtr conn,
                            struct uml_driver *driver,
                            virDomainObjPtr vm) {
    const char **argv = NULL, **tmp;
    const char **progenv = NULL;
809 810
    int i, ret;
    pid_t pid;
811 812 813 814
    char *logfile;
    int logfd = -1;
    struct stat sb;
    fd_set keepfd;
815
    char ebuf[1024];
816
    umlDomainObjPrivatePtr priv = vm->privateData;
817 818 819

    FD_ZERO(&keepfd);

D
Daniel P. Berrange 已提交
820
    if (virDomainObjIsActive(vm)) {
821 822
        umlReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("VM is already active"));
823 824 825 826
        return -1;
    }

    if (!vm->def->os.kernel) {
827 828
        umlReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("no kernel specified"));
829 830 831 832 833 834 835
        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) {
836
        virReportSystemError(errno,
837 838
                             _("Cannot find UML kernel %s"),
                             vm->def->os.kernel);
839 840 841
        return -1;
    }

L
Laine Stump 已提交
842
    if (virFileMakePath(driver->logDir) != 0) {
843
        virReportSystemError(errno,
844 845
                             _("cannot create log directory %s"),
                             driver->logDir);
846 847 848
        return -1;
    }

849 850
    if (virAsprintf(&logfile, "%s/%s.log",
                    driver->logDir, vm->def->name) < 0) {
851
        virReportOOMError();
852 853 854 855 856
        return -1;
    }

    if ((logfd = open(logfile, O_CREAT | O_TRUNC | O_WRONLY,
                      S_IRUSR | S_IWUSR)) < 0) {
857
        virReportSystemError(errno,
858 859
                             _("failed to create logfile %s"),
                             logfile);
860 861 862 863 864 865
        VIR_FREE(logfile);
        return -1;
    }
    VIR_FREE(logfile);

    if (umlSetCloseExec(logfd) < 0) {
866
        virReportSystemError(errno,
867
                             "%s", _("Unable to set VM logfile close-on-exec flag"));
868 869 870 871
        close(logfd);
        return -1;
    }

872
    if (umlBuildCommandLine(conn, driver, vm, &keepfd,
873
                            &argv, &progenv) < 0) {
874
        close(logfd);
875
        umlCleanupTapDevices(conn, vm);
876 877 878 879 880 881
        return -1;
    }

    tmp = progenv;
    while (*tmp) {
        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 888 889 890 891
        tmp++;
    }
    tmp = argv;
    while (*tmp) {
        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 898 899
        tmp++;
    }
    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 908
                           VIR_EXEC_CLEAR_CAPS,
                           NULL, NULL, NULL);
909 910
    close(logfd);

911 912 913 914 915 916 917 918
    /*
     * At the moment, the only thing that populates keepfd is
     * umlBuildCommandLineChr. We want to close every fd it opens.
     */
    for (i = 0; i < FD_SETSIZE; i++)
        if (FD_ISSET(i, &keepfd))
            close(i);

919 920 921 922 923 924 925 926
    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) {
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
                STRNEQ (conn->uri->path, "/session")) {
1003
                umlReportError(VIR_ERR_INTERNAL_ERROR,
1004 1005 1006 1007 1008 1009
                               _("unexpected UML URI path '%s', try uml:///system"),
                               conn->uri->path);
                return VIR_DRV_OPEN_ERROR;
            }
        } else {
            if (STRNEQ (conn->uri->path, "/session")) {
1010
                umlReportError(VIR_ERR_INTERNAL_ERROR,
1011 1012 1013 1014
                               _("unexpected UML URI path '%s', try uml:///session"),
                               conn->uri->path);
                return VIR_DRV_OPEN_ERROR;
            }
1015
        }
1016 1017 1018

        /* URI was good, but driver isn't active */
        if (uml_driver == NULL) {
1019
            umlReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1020
                           _("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

    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"))) {
        /* 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");
1088
        fclose(pidinfo);
1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109
        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;
1110 1111
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
1112

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189

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) {
1190
        umlReportError(VIR_ERR_NO_DOMAIN, NULL);
1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211
        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) {
1212
        umlReportError(VIR_ERR_NO_DOMAIN, NULL);
1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223
        goto cleanup;
    }
    ret = obj->persistent;

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


1224
static int umlGetVersion(virConnectPtr conn, unsigned long *version) {
1225
    struct uml_driver *driver = conn->privateData;
1226
    struct utsname ut;
1227
    int ret = -1;
1228

1229
    umlDriverLock(driver);
1230 1231 1232 1233 1234

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

        if (virParseVersionString(ut.release, &driver->umlVersion) < 0) {
1235
            umlReportError(VIR_ERR_INTERNAL_ERROR,
1236 1237 1238
                           _("cannot parse version %s"), ut.release);
            goto cleanup;
        }
1239 1240
    }

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

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

static int umlListDomains(virConnectPtr conn, int *ids, int nids) {
1250
    struct uml_driver *driver = conn->privateData;
1251
    int n;
1252

1253
    umlDriverLock(driver);
1254
    n = virDomainObjListGetActiveIDs(&driver->domains, ids, nids);
1255
    umlDriverUnlock(driver);
1256

1257
    return n;
1258 1259
}
static int umlNumDomains(virConnectPtr conn) {
1260
    struct uml_driver *driver = conn->privateData;
1261
    int n;
1262

1263
    umlDriverLock(driver);
1264
    n = virDomainObjListNumOfDomains(&driver->domains, 1);
1265
    umlDriverUnlock(driver);
1266 1267 1268 1269

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

1276 1277
    virCheckFlags(0, NULL);

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

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

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

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

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

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


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

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

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

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


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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    info->state = vm->state;

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

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

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


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

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

1543
    if (!vm) {
1544 1545
        umlReportError(VIR_ERR_INVALID_DOMAIN, "%s",
                       _("no domain with matching uuid"));
1546
        goto cleanup;
1547 1548
    }

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

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


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

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

1569
    return n;
1570 1571 1572
}

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

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

    return n;
}


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

1589 1590
    virCheckFlags(0, -1);

1591
    umlDriverLock(driver);
1592
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1593

1594
    if (!vm) {
1595 1596
        umlReportError(VIR_ERR_INVALID_DOMAIN, "%s",
                       _("no domain with matching uuid"));
1597
        goto cleanup;
1598 1599
    }

1600 1601 1602
    ret = umlStartVMDaemon(dom->conn, driver, vm);

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

1609 1610 1611
static int umlDomainStart(virDomainPtr dom) {
    return umlDomainStartWithFlags(dom, 0);
}
1612 1613

static virDomainPtr umlDomainDefine(virConnectPtr conn, const char *xml) {
1614
    struct uml_driver *driver = conn->privateData;
1615
    virDomainDefPtr def;
1616
    virDomainObjPtr vm = NULL;
1617
    virDomainPtr dom = NULL;
1618

1619
    umlDriverLock(driver);
1620
    if (!(def = virDomainDefParseString(driver->caps, xml,
1621
                                        VIR_DOMAIN_XML_INACTIVE)))
1622
        goto cleanup;
1623

1624 1625 1626
    if (virDomainObjIsDuplicate(&driver->domains, def, 0) < 0)
        goto cleanup;

1627
    if (!(vm = virDomainAssignDef(driver->caps,
1628
                                  &driver->domains,
1629
                                  def, false)))
1630 1631
        goto cleanup;
    def = NULL;
1632 1633
    vm->persistent = 1;

1634
    if (virDomainSaveConfig(driver->configDir,
1635 1636 1637
                            vm->newDef ? vm->newDef : vm->def) < 0) {
        virDomainRemoveInactive(&driver->domains,
                                vm);
1638
        vm = NULL;
1639
        goto cleanup;
1640 1641 1642 1643
    }

    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
    if (dom) dom->id = vm->def->id;
1644 1645 1646

cleanup:
    virDomainDefFree(def);
1647 1648 1649
    if (vm)
        virDomainObjUnlock(vm);
    umlDriverUnlock(driver);
1650 1651 1652 1653
    return dom;
}

static int umlDomainUndefine(virDomainPtr dom) {
1654 1655 1656
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
1657

1658
    umlDriverLock(driver);
1659
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1660
    if (!vm) {
1661 1662
        umlReportError(VIR_ERR_INVALID_DOMAIN, "%s",
                       _("no domain with matching uuid"));
1663
        goto cleanup;
1664 1665
    }

D
Daniel P. Berrange 已提交
1666
    if (virDomainObjIsActive(vm)) {
1667 1668
        umlReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("cannot delete active domain"));
1669
        goto cleanup;
1670 1671 1672
    }

    if (!vm->persistent) {
1673 1674
        umlReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("cannot undefine transient domain"));
1675
        goto cleanup;
1676 1677
    }

1678
    if (virDomainDeleteConfig(driver->configDir, driver->autostartDir, vm) < 0)
1679
        goto cleanup;
1680 1681 1682

    virDomainRemoveInactive(&driver->domains,
                            vm);
1683
    vm = NULL;
1684
    ret = 0;
1685

1686
cleanup:
1687 1688 1689
    if (vm)
        virDomainObjUnlock(vm);
    umlDriverUnlock(driver);
1690
    return ret;
1691 1692 1693 1694 1695 1696
}



static int umlDomainGetAutostart(virDomainPtr dom,
                            int *autostart) {
1697 1698 1699
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
1700

1701
    umlDriverLock(driver);
1702
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1703

1704
    if (!vm) {
1705 1706
        umlReportError(VIR_ERR_INVALID_DOMAIN, "%s",
                       _("no domain with matching uuid"));
1707
        goto cleanup;
1708 1709 1710
    }

    *autostart = vm->autostart;
1711
    ret = 0;
1712

1713
cleanup:
1714 1715
    if (vm)
        virDomainObjUnlock(vm);
1716
    umlDriverUnlock(driver);
1717
    return ret;
1718 1719 1720 1721
}

static int umlDomainSetAutostart(virDomainPtr dom,
                                   int autostart) {
1722
    struct uml_driver *driver = dom->conn->privateData;
1723
    virDomainObjPtr vm;
1724 1725 1726
    char *configFile = NULL, *autostartLink = NULL;
    int ret = -1;

1727 1728 1729
    umlDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

1730
    if (!vm) {
1731 1732
        umlReportError(VIR_ERR_INVALID_DOMAIN, "%s",
                       _("no domain with matching uuid"));
1733
        goto cleanup;
1734 1735 1736
    }

    if (!vm->persistent) {
1737 1738
        umlReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("cannot set autostart for transient domain"));
1739
        goto cleanup;
1740 1741 1742 1743
    }

    autostart = (autostart != 0);

1744
    if (vm->autostart != autostart) {
1745
        if ((configFile = virDomainConfigFile(driver->configDir, vm->def->name)) == NULL)
1746
            goto cleanup;
1747
        if ((autostartLink = virDomainConfigFile(driver->autostartDir, vm->def->name)) == NULL)
1748
            goto cleanup;
1749

1750 1751
        if (autostart) {
            int err;
1752

1753
            if ((err = virFileMakePath(driver->autostartDir))) {
1754
                virReportSystemError(err,
1755 1756
                                     _("cannot create autostart directory %s"),
                                     driver->autostartDir);
1757 1758
                goto cleanup;
            }
1759

1760
            if (symlink(configFile, autostartLink) < 0) {
1761
                virReportSystemError(errno,
1762 1763
                                     _("Failed to create symlink '%s to '%s'"),
                                     autostartLink, configFile);
1764 1765 1766 1767
                goto cleanup;
            }
        } else {
            if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
1768
                virReportSystemError(errno,
1769 1770
                                     _("Failed to delete symlink '%s'"),
                                     autostartLink);
1771 1772
                goto cleanup;
            }
1773 1774
        }

1775
        vm->autostart = autostart;
1776 1777 1778 1779 1780 1781
    }
    ret = 0;

cleanup:
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
1782 1783
    if (vm)
        virDomainObjUnlock(vm);
1784
    umlDriverUnlock(driver);
1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795
    return ret;
}


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

1800
    umlDriverLock(driver);
1801
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1802 1803
    umlDriverUnlock(driver);

1804
    if (!vm) {
1805 1806
        umlReportError(VIR_ERR_INVALID_DOMAIN, "%s",
                       _("no domain with matching uuid"));
1807
        goto cleanup;
1808 1809 1810
    }

    if (!path || path[0] == '\0') {
1811 1812
        umlReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("NULL or empty path"));
1813
        goto cleanup;
1814 1815 1816 1817 1818
    }

    /* Check the path belongs to this domain. */
    for (i = 0 ; i < vm->def->ndisks ; i++) {
        if (vm->def->disks[i]->src != NULL &&
1819 1820 1821 1822
            STREQ (vm->def->disks[i]->src, path)) {
            ret = 0;
            break;
        }
1823 1824
    }

1825 1826 1827 1828 1829
    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) {
1830
            virReportSystemError(errno,
1831
                                 _("cannot open %s"), path);
1832 1833
            goto cleanup;
        }
1834

1835 1836 1837 1838 1839 1840
        /* 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) {
1841
            virReportSystemError(errno,
1842
                                 _("cannot read %s"), path);
1843 1844 1845 1846 1847
            goto cleanup;
        }

        ret = 0;
    } else {
1848 1849
        umlReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("invalid path"));
1850 1851
    }

1852
cleanup:
1853
    if (fd >= 0) close (fd);
1854 1855
    if (vm)
        virDomainObjUnlock(vm);
1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868
    return ret;
}



static virDriver umlDriver = {
    VIR_DRV_UML,
    "UML",
    umlOpen, /* open */
    umlClose, /* close */
    NULL, /* supports_feature */
    umlGetType, /* type */
    umlGetVersion, /* version */
1869
    NULL, /* libvirtVersion (impl. in libvirt.c) */
1870
    virGetHostname, /* getHostname */
1871
    NULL, /* getMaxVcpus */
1872
    nodeGetInfo, /* nodeGetInfo */
1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896
    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 */
1897 1898
    NULL, /* domainGetSecurityLabel */
    NULL, /* nodeGetSecurityModel */
1899
    umlDomainDumpXML, /* domainDumpXML */
1900 1901
    NULL, /* domainXMLFromNative */
    NULL, /* domainXMLToNative */
1902 1903
    umlListDefinedDomains, /* listDefinedDomains */
    umlNumDefinedDomains, /* numOfDefinedDomains */
1904
    umlDomainStart, /* domainCreate */
1905
    umlDomainStartWithFlags, /* domainCreateWithFlags */
1906 1907 1908
    umlDomainDefine, /* domainDefineXML */
    umlDomainUndefine, /* domainUndefine */
    NULL, /* domainAttachDevice */
1909
    NULL, /* domainAttachDeviceFlags */
1910
    NULL, /* domainDetachDevice */
1911
    NULL, /* domainDetachDeviceFlags */
1912
    NULL, /* domainUpdateDeviceFlags */
1913 1914 1915 1916 1917 1918 1919 1920 1921 1922
    umlDomainGetAutostart, /* domainGetAutostart */
    umlDomainSetAutostart, /* domainSetAutostart */
    NULL, /* domainGetSchedulerType */
    NULL, /* domainGetSchedulerParameters */
    NULL, /* domainSetSchedulerParameters */
    NULL, /* domainMigratePrepare */
    NULL, /* domainMigratePerform */
    NULL, /* domainMigrateFinish */
    NULL, /* domainBlockStats */
    NULL, /* domainInterfaceStats */
1923
    NULL, /* domainMemoryStats */
1924 1925
    umlDomainBlockPeek, /* domainBlockPeek */
    NULL, /* domainMemoryPeek */
1926
    NULL, /* domainGetBlockInfo */
1927 1928
    nodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */
    nodeGetFreeMemory,  /* getFreeMemory */
1929
    NULL, /* domainEventRegister */
1930
    NULL, /* domainEventDeregister */
1931 1932
    NULL, /* domainMigratePrepare2 */
    NULL, /* domainMigrateFinish2 */
1933
    NULL, /* nodeDeviceDettach */
1934 1935
    NULL, /* nodeDeviceReAttach */
    NULL, /* nodeDeviceReset */
C
Chris Lalancette 已提交
1936
    NULL, /* domainMigratePrepareTunnel */
1937 1938 1939 1940
    umlIsEncrypted, /* isEncrypted */
    umlIsSecure, /* isSecure */
    umlDomainIsActive, /* domainIsActive */
    umlDomainIsPersistent, /* domainIsPersistent */
J
Jiri Denemark 已提交
1941
    NULL, /* cpuCompare */
1942
    NULL, /* cpuBaseline */
1943
    NULL, /* domainGetJobInfo */
1944
    NULL, /* domainAbortJob */
1945
    NULL, /* domainMigrateSetMaxDowntime */
1946 1947
    NULL, /* domainEventRegisterAny */
    NULL, /* domainEventDeregisterAny */
1948 1949 1950
    NULL, /* domainManagedSave */
    NULL, /* domainHasManagedSaveImage */
    NULL, /* domainManagedSaveRemove */
C
Chris Lalancette 已提交
1951 1952 1953 1954 1955 1956 1957 1958 1959
    NULL, /* domainSnapshotCreateXML */
    NULL, /* domainSnapshotDumpXML */
    NULL, /* domainSnapshotNum */
    NULL, /* domainSnapshotListNames */
    NULL, /* domainSnapshotLookupByName */
    NULL, /* domainHasCurrentSnapshot */
    NULL, /* domainSnapshotCurrent */
    NULL, /* domainRevertToSnapshot */
    NULL, /* domainSnapshotDelete */
C
Chris Lalancette 已提交
1960
    NULL, /* qemuDomainMonitorCommand */
1961 1962 1963 1964
};


static virStateDriver umlStateDriver = {
1965
    .name = "UML",
1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976
    .initialize = umlStartup,
    .cleanup = umlShutdown,
    .reload = umlReload,
    .active = umlActive,
};

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