uml_driver.c 52.1 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 733 734 735 736
        nbytes = recvfrom(priv->monitor, &res, sizeof res, 0,
                          (struct sockaddr *)&addr, &addrlen) < 0;
        if (nbytes < 0) {
            if (errno == EAGAIN || errno == EINTR)
                continue;
737
            virReportSystemError(errno,
738 739
                                 _("cannot read reply %s"),
                                 cmd);
740 741
            goto error;
        }
E
Eric Blake 已提交
742 743 744 745 746 747
        if (nbytes < sizeof res) {
            virReportSystemError(errno,
                                 _("incomplete reply %s"),
                                 cmd);
            goto error;
        }
748 749

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

        if (res.error)
            ret = -1;

    } while (res.extra);

762 763
    VIR_DEBUG("Command reply is '%s'", NULLSTR(retdata));

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

    return ret;

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


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

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

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

    FD_ZERO(&keepfd);

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

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

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

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

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

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

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

    tmp = progenv;
    while (*tmp) {
        if (safewrite(logfd, *tmp, strlen(*tmp)) < 0)
884
            VIR_WARN("Unable to write envv to logfile: %s",
885
                   virStrerror(errno, ebuf, sizeof ebuf));
886
        if (safewrite(logfd, " ", 1) < 0)
887
            VIR_WARN("Unable to write envv to logfile: %s",
888
                   virStrerror(errno, ebuf, sizeof ebuf));
889 890 891 892 893
        tmp++;
    }
    tmp = argv;
    while (*tmp) {
        if (safewrite(logfd, *tmp, strlen(*tmp)) < 0)
894
            VIR_WARN("Unable to write argv to logfile: %s",
895
                   virStrerror(errno, ebuf, sizeof ebuf));
896
        if (safewrite(logfd, " ", 1) < 0)
897
            VIR_WARN("Unable to write argv to logfile: %s",
898
                   virStrerror(errno, ebuf, sizeof ebuf));
899 900 901
        tmp++;
    }
    if (safewrite(logfd, "\n", 1) < 0)
902
        VIR_WARN("Unable to write argv to logfile: %s",
903
                 virStrerror(errno, ebuf, sizeof ebuf));
904

905
    priv->monitor = -1;
906

907
    ret = virExecDaemonize(argv, progenv, &keepfd, &pid,
908
                           -1, &logfd, &logfd,
909 910
                           VIR_EXEC_CLEAR_CAPS,
                           NULL, NULL, NULL);
911 912 913 914 915 916 917 918 919 920
    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);

921 922
    if (ret < 0)
        umlCleanupTapDevices(conn, vm);
923 924 925

    /* NB we don't mark it running here - we do that async
       with inotify */
926 927 928
    /* XXX what if someone else tries to start it again
       before we get the inotification ? Sounds like
       trouble.... */
929 930 931 932 933 934 935 936 937

    return ret;
}

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

D
Daniel P. Berrange 已提交
940
    if (!virDomainObjIsActive(vm))
941 942
        return;

943
    virKillProcess(vm->pid, SIGTERM);
944

945 946 947
    if (priv->monitor != -1)
        close(priv->monitor);
    priv->monitor = -1;
948 949

    if ((ret = waitpid(vm->pid, NULL, 0)) != vm->pid) {
950
        VIR_WARN("Got unexpected pid %d != %d",
951 952 953 954 955 956 957
               ret, vm->pid);
    }

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

958 959
    umlCleanupTapDevices(conn, vm);

960 961 962 963 964 965 966 967 968 969 970 971
    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) {
972 973 974
    if (conn->uri == NULL) {
        if (uml_driver == NULL)
            return VIR_DRV_OPEN_DECLINED;
975

976
        conn->uri = xmlParseURI(uml_driver->privileged ?
977 978 979
                                "uml:///system" :
                                "uml:///session");
        if (!conn->uri) {
980
            virReportOOMError();
981 982 983 984 985 986 987 988 989 990
            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;
991 992


993
        /* Check path and tell them correct path if they made a mistake */
994
        if (uml_driver->privileged) {
995
            if (STRNEQ (conn->uri->path, "/system") &&
996
                STRNEQ (conn->uri->path, "/session")) {
997
                umlReportError(VIR_ERR_INTERNAL_ERROR,
998 999 1000 1001 1002 1003
                               _("unexpected UML URI path '%s', try uml:///system"),
                               conn->uri->path);
                return VIR_DRV_OPEN_ERROR;
            }
        } else {
            if (STRNEQ (conn->uri->path, "/session")) {
1004
                umlReportError(VIR_ERR_INTERNAL_ERROR,
1005 1006 1007 1008
                               _("unexpected UML URI path '%s', try uml:///session"),
                               conn->uri->path);
                return VIR_DRV_OPEN_ERROR;
            }
1009
        }
1010 1011 1012

        /* URI was good, but driver isn't active */
        if (uml_driver == NULL) {
1013
            umlReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1014
                           _("uml state driver is not active"));
1015 1016 1017 1018 1019 1020 1021 1022 1023 1024
            return VIR_DRV_OPEN_ERROR;
        }
    }

    conn->privateData = uml_driver;

    return VIR_DRV_OPEN_SUCCESS;
}

static int umlClose(virConnectPtr conn) {
1025
    /*struct uml_driver *driver = conn->privateData;*/
1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036

    conn->privateData = NULL;

    return 0;
}

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


1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050
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;
}


1051 1052 1053 1054
static char *umlGetCapabilities(virConnectPtr conn) {
    struct uml_driver *driver = (struct uml_driver *)conn->privateData;
    char *xml;

1055
    umlDriverLock(driver);
1056
    if ((xml = virCapabilitiesFormatXML(driver->caps)) == NULL)
1057
        virReportOOMError();
1058
    umlDriverUnlock(driver);
1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082

    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");
1083
        fclose(pidinfo);
1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104
        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;
1105 1106
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
1107

1108
    umlDriverLock(driver);
1109
    vm = virDomainFindByID(&driver->domains, id);
1110 1111
    umlDriverUnlock(driver);

1112
    if (!vm) {
1113
        umlReportError(VIR_ERR_NO_DOMAIN, NULL);
1114
        goto cleanup;
1115 1116 1117 1118
    }

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

cleanup:
1121 1122
    if (vm)
        virDomainObjUnlock(vm);
1123 1124
    return dom;
}
1125

1126 1127 1128
static virDomainPtr umlDomainLookupByUUID(virConnectPtr conn,
                                            const unsigned char *uuid) {
    struct uml_driver *driver = (struct uml_driver *)conn->privateData;
1129 1130
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
1131

1132
    umlDriverLock(driver);
1133
    vm = virDomainFindByUUID(&driver->domains, uuid);
1134 1135
    umlDriverUnlock(driver);

1136
    if (!vm) {
1137
        umlReportError(VIR_ERR_NO_DOMAIN, NULL);
1138
        goto cleanup;
1139 1140 1141 1142
    }

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

cleanup:
1145 1146
    if (vm)
        virDomainObjUnlock(vm);
1147 1148
    return dom;
}
1149

1150 1151 1152
static virDomainPtr umlDomainLookupByName(virConnectPtr conn,
                                            const char *name) {
    struct uml_driver *driver = (struct uml_driver *)conn->privateData;
1153 1154
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
1155

1156
    umlDriverLock(driver);
1157
    vm = virDomainFindByName(&driver->domains, name);
1158 1159
    umlDriverUnlock(driver);

1160
    if (!vm) {
1161
        umlReportError(VIR_ERR_NO_DOMAIN, NULL);
1162
        goto cleanup;
1163 1164 1165 1166
    }

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

cleanup:
1169 1170
    if (vm)
        virDomainObjUnlock(vm);
1171 1172 1173
    return dom;
}

1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184

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

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


1219
static int umlGetVersion(virConnectPtr conn, unsigned long *version) {
1220
    struct uml_driver *driver = conn->privateData;
1221
    struct utsname ut;
1222
    int ret = -1;
1223

1224
    umlDriverLock(driver);
1225 1226 1227 1228 1229

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

        if (virParseVersionString(ut.release, &driver->umlVersion) < 0) {
1230
            umlReportError(VIR_ERR_INTERNAL_ERROR,
1231 1232 1233
                           _("cannot parse version %s"), ut.release);
            goto cleanup;
        }
1234 1235
    }

1236 1237 1238 1239 1240 1241
    *version = driver->umlVersion;
    ret = 0;

cleanup:
    umlDriverUnlock(driver);
    return ret;
1242 1243 1244
}

static int umlListDomains(virConnectPtr conn, int *ids, int nids) {
1245
    struct uml_driver *driver = conn->privateData;
1246
    int n;
1247

1248
    umlDriverLock(driver);
1249
    n = virDomainObjListGetActiveIDs(&driver->domains, ids, nids);
1250
    umlDriverUnlock(driver);
1251

1252
    return n;
1253 1254
}
static int umlNumDomains(virConnectPtr conn) {
1255
    struct uml_driver *driver = conn->privateData;
1256
    int n;
1257

1258
    umlDriverLock(driver);
1259
    n = virDomainObjListNumOfDomains(&driver->domains, 1);
1260
    umlDriverUnlock(driver);
1261 1262 1263 1264

    return n;
}
static virDomainPtr umlDomainCreate(virConnectPtr conn, const char *xml,
1265
                                      unsigned int flags) {
1266
    struct uml_driver *driver = conn->privateData;
1267
    virDomainDefPtr def;
1268
    virDomainObjPtr vm = NULL;
1269
    virDomainPtr dom = NULL;
1270

1271 1272
    virCheckFlags(0, NULL);

1273
    umlDriverLock(driver);
1274
    if (!(def = virDomainDefParseString(driver->caps, xml,
1275
                                        VIR_DOMAIN_XML_INACTIVE)))
1276
        goto cleanup;
1277

1278
    if (virDomainObjIsDuplicate(&driver->domains, def, 1) < 0)
1279
        goto cleanup;
1280

1281
    if (!(vm = virDomainAssignDef(driver->caps,
1282
                                  &driver->domains,
1283
                                  def, false)))
1284 1285
        goto cleanup;
    def = NULL;
1286 1287 1288 1289

    if (umlStartVMDaemon(conn, driver, vm) < 0) {
        virDomainRemoveInactive(&driver->domains,
                                vm);
1290 1291
        vm = NULL;
        goto cleanup;
1292 1293 1294 1295
    }

    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
    if (dom) dom->id = vm->def->id;
1296 1297 1298

cleanup:
    virDomainDefFree(def);
1299 1300 1301
    if (vm)
        virDomainObjUnlock(vm);
    umlDriverUnlock(driver);
1302 1303 1304 1305 1306
    return dom;
}


static int umlDomainShutdown(virDomainPtr dom) {
1307 1308
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
1309
    char *info = NULL;
1310
    int ret = -1;
1311

1312
    umlDriverLock(driver);
1313
    vm = virDomainFindByID(&driver->domains, dom->id);
1314
    umlDriverUnlock(driver);
1315
    if (!vm) {
1316 1317
        umlReportError(VIR_ERR_INVALID_DOMAIN,
                       _("no domain with matching id %d"), dom->id);
1318
        goto cleanup;
1319 1320 1321 1322
    }

#if 0
    if (umlMonitorCommand(driver, vm, "system_powerdown", &info) < 0) {
1323 1324
        umlReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("shutdown operation failed"));
1325
        goto cleanup;
1326
    }
1327
    ret = 0;
1328 1329
#endif

1330 1331
cleanup:
    VIR_FREE(info);
1332 1333
    if (vm)
        virDomainObjUnlock(vm);
1334
    return ret;
1335 1336 1337 1338
}


static int umlDomainDestroy(virDomainPtr dom) {
1339 1340 1341
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
1342

1343
    umlDriverLock(driver);
1344
    vm = virDomainFindByID(&driver->domains, dom->id);
1345
    if (!vm) {
1346 1347
        umlReportError(VIR_ERR_INVALID_DOMAIN,
                       _("no domain with matching id %d"), dom->id);
1348
        goto cleanup;
1349 1350 1351
    }

    umlShutdownVMDaemon(dom->conn, driver, vm);
1352
    if (!vm->persistent) {
1353 1354
        virDomainRemoveInactive(&driver->domains,
                                vm);
1355 1356 1357
        vm = NULL;
    }
    ret = 0;
1358

1359
cleanup:
1360 1361 1362
    if (vm)
        virDomainObjUnlock(vm);
    umlDriverUnlock(driver);
1363
    return ret;
1364 1365 1366 1367
}


static char *umlDomainGetOSType(virDomainPtr dom) {
1368 1369 1370
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *type = NULL;
1371

1372
    umlDriverLock(driver);
1373
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1374
    umlDriverUnlock(driver);
1375
    if (!vm) {
1376 1377
        umlReportError(VIR_ERR_INVALID_DOMAIN, "%s",
                       _("no domain with matching uuid"));
1378
        goto cleanup;
1379 1380
    }

1381
    if (!(type = strdup(vm->def->os.type)))
1382
        virReportOOMError();
1383 1384

cleanup:
1385 1386
    if (vm)
        virDomainObjUnlock(vm);
1387 1388 1389 1390 1391
    return type;
}

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

1396
    umlDriverLock(driver);
1397
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1398 1399
    umlDriverUnlock(driver);

1400 1401 1402 1403
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];

        virUUIDFormat(dom->uuid, uuidstr);
1404
        umlReportError(VIR_ERR_INVALID_DOMAIN,
1405 1406
                       _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
1407
    }
1408
    ret = vm->def->maxmem;
1409

1410
cleanup:
1411 1412
    if (vm)
        virDomainObjUnlock(vm);
1413
    return ret;
1414 1415 1416
}

static int umlDomainSetMaxMemory(virDomainPtr dom, unsigned long newmax) {
1417 1418 1419
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
1420

1421
    umlDriverLock(driver);
1422
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1423 1424
    umlDriverUnlock(driver);

1425 1426 1427 1428
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];

        virUUIDFormat(dom->uuid, uuidstr);
1429 1430
        umlReportError(VIR_ERR_INVALID_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
1431
        goto cleanup;
1432 1433 1434
    }

    if (newmax < vm->def->memory) {
1435 1436
        umlReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("cannot set max memory lower than current memory"));
1437
        goto cleanup;
1438 1439 1440
    }

    vm->def->maxmem = newmax;
1441 1442 1443
    ret = 0;

cleanup:
1444 1445
    if (vm)
        virDomainObjUnlock(vm);
1446
    return ret;
1447 1448 1449
}

static int umlDomainSetMemory(virDomainPtr dom, unsigned long newmem) {
1450 1451 1452
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
1453

1454
    umlDriverLock(driver);
1455
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1456 1457
    umlDriverUnlock(driver);

1458 1459 1460 1461
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];

        virUUIDFormat(dom->uuid, uuidstr);
1462 1463
        umlReportError(VIR_ERR_INVALID_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
1464
        goto cleanup;
1465 1466
    }

D
Daniel P. Berrange 已提交
1467
    if (virDomainObjIsActive(vm)) {
1468 1469
        umlReportError(VIR_ERR_NO_SUPPORT, "%s",
                       _("cannot set memory of an active domain"));
1470
        goto cleanup;
1471 1472 1473
    }

    if (newmem > vm->def->maxmem) {
1474 1475
        umlReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("cannot set memory higher than max memory"));
1476
        goto cleanup;
1477 1478 1479
    }

    vm->def->memory = newmem;
1480 1481 1482
    ret = 0;

cleanup:
1483 1484
    if (vm)
        virDomainObjUnlock(vm);
1485
    return ret;
1486 1487 1488 1489
}

static int umlDomainGetInfo(virDomainPtr dom,
                              virDomainInfoPtr info) {
1490 1491 1492 1493
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;

1494
    umlDriverLock(driver);
1495
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1496 1497
    umlDriverUnlock(driver);

1498
    if (!vm) {
1499 1500
        umlReportError(VIR_ERR_INVALID_DOMAIN, "%s",
                       _("no domain with matching uuid"));
1501
        goto cleanup;
1502 1503 1504 1505
    }

    info->state = vm->state;

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

    info->maxMem = vm->def->maxmem;
    info->memory = vm->def->memory;
    info->nrVirtCpu = vm->def->vcpus;
1519 1520 1521
    ret = 0;

cleanup:
1522 1523
    if (vm)
        virDomainObjUnlock(vm);
1524
    return ret;
1525 1526 1527 1528 1529
}


static char *umlDomainDumpXML(virDomainPtr dom,
                                int flags ATTRIBUTE_UNUSED) {
1530 1531 1532 1533
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *ret = NULL;

1534
    umlDriverLock(driver);
1535
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1536 1537
    umlDriverUnlock(driver);

1538
    if (!vm) {
1539 1540
        umlReportError(VIR_ERR_INVALID_DOMAIN, "%s",
                       _("no domain with matching uuid"));
1541
        goto cleanup;
1542 1543
    }

1544
    ret = virDomainDefFormat((flags & VIR_DOMAIN_XML_INACTIVE) && vm->newDef ?
1545 1546 1547 1548
                             vm->newDef : vm->def,
                             flags);

cleanup:
1549 1550
    if (vm)
        virDomainObjUnlock(vm);
1551
    return ret;
1552 1553 1554 1555 1556
}


static int umlListDefinedDomains(virConnectPtr conn,
                            char **const names, int nnames) {
1557
    struct uml_driver *driver = conn->privateData;
1558
    int n;
1559

1560
    umlDriverLock(driver);
1561
    n = virDomainObjListGetInactiveNames(&driver->domains, names, nnames);
1562
    umlDriverUnlock(driver);
1563

1564
    return n;
1565 1566 1567
}

static int umlNumDefinedDomains(virConnectPtr conn) {
1568
    struct uml_driver *driver = conn->privateData;
1569
    int n;
1570

1571
    umlDriverLock(driver);
1572
    n = virDomainObjListNumOfDomains(&driver->domains, 0);
1573
    umlDriverUnlock(driver);
1574 1575 1576 1577 1578 1579

    return n;
}


static int umlDomainStart(virDomainPtr dom) {
1580 1581 1582
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
1583

1584
    umlDriverLock(driver);
1585
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1586

1587
    if (!vm) {
1588 1589
        umlReportError(VIR_ERR_INVALID_DOMAIN, "%s",
                       _("no domain with matching uuid"));
1590
        goto cleanup;
1591 1592
    }

1593 1594 1595
    ret = umlStartVMDaemon(dom->conn, driver, vm);

cleanup:
1596 1597 1598
    if (vm)
        virDomainObjUnlock(vm);
    umlDriverUnlock(driver);
1599
    return ret;
1600 1601 1602 1603
}


static virDomainPtr umlDomainDefine(virConnectPtr conn, const char *xml) {
1604
    struct uml_driver *driver = conn->privateData;
1605
    virDomainDefPtr def;
1606
    virDomainObjPtr vm = NULL;
1607
    virDomainPtr dom = NULL;
1608

1609
    umlDriverLock(driver);
1610
    if (!(def = virDomainDefParseString(driver->caps, xml,
1611
                                        VIR_DOMAIN_XML_INACTIVE)))
1612
        goto cleanup;
1613

1614 1615 1616
    if (virDomainObjIsDuplicate(&driver->domains, def, 0) < 0)
        goto cleanup;

1617
    if (!(vm = virDomainAssignDef(driver->caps,
1618
                                  &driver->domains,
1619
                                  def, false)))
1620 1621
        goto cleanup;
    def = NULL;
1622 1623
    vm->persistent = 1;

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

    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
    if (dom) dom->id = vm->def->id;
1634 1635 1636

cleanup:
    virDomainDefFree(def);
1637 1638 1639
    if (vm)
        virDomainObjUnlock(vm);
    umlDriverUnlock(driver);
1640 1641 1642 1643
    return dom;
}

static int umlDomainUndefine(virDomainPtr dom) {
1644 1645 1646
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
1647

1648
    umlDriverLock(driver);
1649
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1650
    if (!vm) {
1651 1652
        umlReportError(VIR_ERR_INVALID_DOMAIN, "%s",
                       _("no domain with matching uuid"));
1653
        goto cleanup;
1654 1655
    }

D
Daniel P. Berrange 已提交
1656
    if (virDomainObjIsActive(vm)) {
1657 1658
        umlReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("cannot delete active domain"));
1659
        goto cleanup;
1660 1661 1662
    }

    if (!vm->persistent) {
1663 1664
        umlReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("cannot undefine transient domain"));
1665
        goto cleanup;
1666 1667
    }

1668
    if (virDomainDeleteConfig(driver->configDir, driver->autostartDir, vm) < 0)
1669
        goto cleanup;
1670 1671 1672

    virDomainRemoveInactive(&driver->domains,
                            vm);
1673
    vm = NULL;
1674
    ret = 0;
1675

1676
cleanup:
1677 1678 1679
    if (vm)
        virDomainObjUnlock(vm);
    umlDriverUnlock(driver);
1680
    return ret;
1681 1682 1683 1684 1685 1686
}



static int umlDomainGetAutostart(virDomainPtr dom,
                            int *autostart) {
1687 1688 1689
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
1690

1691
    umlDriverLock(driver);
1692
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1693

1694
    if (!vm) {
1695 1696
        umlReportError(VIR_ERR_INVALID_DOMAIN, "%s",
                       _("no domain with matching uuid"));
1697
        goto cleanup;
1698 1699 1700
    }

    *autostart = vm->autostart;
1701
    ret = 0;
1702

1703
cleanup:
1704 1705
    if (vm)
        virDomainObjUnlock(vm);
1706
    umlDriverUnlock(driver);
1707
    return ret;
1708 1709 1710 1711
}

static int umlDomainSetAutostart(virDomainPtr dom,
                                   int autostart) {
1712
    struct uml_driver *driver = dom->conn->privateData;
1713
    virDomainObjPtr vm;
1714 1715 1716
    char *configFile = NULL, *autostartLink = NULL;
    int ret = -1;

1717 1718 1719
    umlDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

1720
    if (!vm) {
1721 1722
        umlReportError(VIR_ERR_INVALID_DOMAIN, "%s",
                       _("no domain with matching uuid"));
1723
        goto cleanup;
1724 1725 1726
    }

    if (!vm->persistent) {
1727 1728
        umlReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("cannot set autostart for transient domain"));
1729
        goto cleanup;
1730 1731 1732 1733
    }

    autostart = (autostart != 0);

1734
    if (vm->autostart != autostart) {
1735
        if ((configFile = virDomainConfigFile(driver->configDir, vm->def->name)) == NULL)
1736
            goto cleanup;
1737
        if ((autostartLink = virDomainConfigFile(driver->autostartDir, vm->def->name)) == NULL)
1738
            goto cleanup;
1739

1740 1741
        if (autostart) {
            int err;
1742

1743
            if ((err = virFileMakePath(driver->autostartDir))) {
1744
                virReportSystemError(err,
1745 1746
                                     _("cannot create autostart directory %s"),
                                     driver->autostartDir);
1747 1748
                goto cleanup;
            }
1749

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

1765
        vm->autostart = autostart;
1766 1767 1768 1769 1770 1771
    }
    ret = 0;

cleanup:
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
1772 1773
    if (vm)
        virDomainObjUnlock(vm);
1774
    umlDriverUnlock(driver);
1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785
    return ret;
}


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

1790
    umlDriverLock(driver);
1791
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1792 1793
    umlDriverUnlock(driver);

1794
    if (!vm) {
1795 1796
        umlReportError(VIR_ERR_INVALID_DOMAIN, "%s",
                       _("no domain with matching uuid"));
1797
        goto cleanup;
1798 1799 1800
    }

    if (!path || path[0] == '\0') {
1801 1802
        umlReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("NULL or empty path"));
1803
        goto cleanup;
1804 1805 1806 1807 1808
    }

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

1815 1816 1817 1818 1819
    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) {
1820
            virReportSystemError(errno,
1821
                                 _("cannot open %s"), path);
1822 1823
            goto cleanup;
        }
1824

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

        ret = 0;
    } else {
1838 1839
        umlReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("invalid path"));
1840 1841
    }

1842
cleanup:
1843
    if (fd >= 0) close (fd);
1844 1845
    if (vm)
        virDomainObjUnlock(vm);
1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858
    return ret;
}



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


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

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