uml_driver.c 72.3 KB
Newer Older
1 2 3
/*
 * uml_driver.c: core driver methods for managing UML guests
 *
4
 * Copyright (C) 2006-2012 Red Hat, Inc.
5 6 7 8 9 10 11 12 13 14 15 16 17
 * 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
18
 * License along with this library.  If not, see
O
Osier Yang 已提交
19
 * <http://www.gnu.org/licenses/>.
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
 *
 * Author: Daniel P. Berrange <berrange@redhat.com>
 */

#include <config.h>

#include <sys/types.h>
#include <sys/poll.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>
45
#include <sys/un.h>
46 47 48

#include "uml_driver.h"
#include "uml_conf.h"
49
#include "virbuffer.h"
50
#include "virutil.h"
51
#include "nodeinfo.h"
52
#include "virstatslinux.h"
53
#include "capabilities.h"
54
#include "viralloc.h"
55
#include "viruuid.h"
56
#include "domain_conf.h"
57
#include "domain_audit.h"
58
#include "datatypes.h"
59
#include "virlog.h"
60
#include "domain_nwfilter.h"
E
Eric Blake 已提交
61
#include "virfile.h"
62
#include "fdstream.h"
63
#include "configmake.h"
64
#include "virnetdevtap.h"
65
#include "virnodesuspend.h"
66
#include "virprocess.h"
M
Martin Kletzander 已提交
67
#include "viruri.h"
68

69 70
#define VIR_FROM_THIS VIR_FROM_UML

71
/* For storing short-lived temporary files. */
72
#define TEMPDIR LOCALSTATEDIR "/cache/libvirt"
73

74 75 76 77 78 79 80
typedef struct _umlDomainObjPrivate umlDomainObjPrivate;
typedef umlDomainObjPrivate *umlDomainObjPrivatePtr;
struct _umlDomainObjPrivate {
    int monitor;
    int monitorWatch;
};

81 82 83 84 85 86 87 88 89 90
static int umlProcessAutoDestroyInit(struct uml_driver *driver);
static void umlProcessAutoDestroyRun(struct uml_driver *driver,
                                     virConnectPtr conn);
static void umlProcessAutoDestroyShutdown(struct uml_driver *driver);
static int umlProcessAutoDestroyAdd(struct uml_driver *driver,
                                    virDomainObjPtr vm,
                                    virConnectPtr conn);
static int umlProcessAutoDestroyRemove(struct uml_driver *driver,
                                       virDomainObjPtr vm);

91

92 93
static int umlShutdown(void);

94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
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);
}


115 116
static void umlDriverLock(struct uml_driver *driver)
{
117
    virMutexLock(&driver->lock);
118 119 120
}
static void umlDriverUnlock(struct uml_driver *driver)
{
121
    virMutexUnlock(&driver->lock);
122 123
}

124

125
static int umlOpenMonitor(struct uml_driver *driver,
126
                          virDomainObjPtr vm);
127
static int umlReadPidFile(struct uml_driver *driver,
128
                          virDomainObjPtr vm);
129 130
static void umlDomainEventQueue(struct uml_driver *driver,
                                virDomainEventPtr event);
131 132 133

static int umlStartVMDaemon(virConnectPtr conn,
                            struct uml_driver *driver,
134 135
                            virDomainObjPtr vm,
                            bool autoDestroy);
136

137
static void umlShutdownVMDaemon(struct uml_driver *driver,
J
Jiri Denemark 已提交
138 139
                                virDomainObjPtr vm,
                                virDomainShutoffReason reason);
140 141


142 143 144 145
static int umlMonitorCommand(const struct uml_driver *driver,
                             const virDomainObjPtr vm,
                             const char *cmd,
                             char **reply);
146 147 148

static struct uml_driver *uml_driver = NULL;

149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
static int
umlVMFilterRebuild(virConnectPtr conn ATTRIBUTE_UNUSED,
                   virHashIterator iter, void *data)
{
    virHashForEach(uml_driver->domains.objs, iter, data);

    return 0;
}

static void
umlVMDriverLock(void)
{
    umlDriverLock(uml_driver);
}

static void
umlVMDriverUnlock(void)
{
    umlDriverUnlock(uml_driver);
}

static virNWFilterCallbackDriver umlCallbackDriver = {
    .name = "UML",
    .vmFilterRebuild = umlVMFilterRebuild,
    .vmDriverLock = umlVMDriverLock,
    .vmDriverUnlock = umlVMDriverUnlock,
};

177 178 179 180 181 182
struct umlAutostartData {
    struct uml_driver *driver;
    virConnectPtr conn;
};

static void
183
umlAutostartDomain(void *payload, const void *name ATTRIBUTE_UNUSED, void *opaque)
184 185 186 187
{
    virDomainObjPtr vm = payload;
    const struct umlAutostartData *data = opaque;

188
    virObjectLock(vm);
189
    if (vm->autostart &&
D
Daniel P. Berrange 已提交
190
        !virDomainObjIsActive(vm)) {
191
        int ret;
192
        virResetLastError();
193
        ret = umlStartVMDaemon(data->conn, data->driver, vm, false);
194 195
        virDomainAuditStart(vm, "booted", ret >= 0);
        if (ret < 0) {
196 197
            virErrorPtr err = virGetLastError();
            VIR_ERROR(_("Failed to autostart VM '%s': %s"),
198
                      vm->def->name, err ? err->message : _("unknown error"));
199 200 201 202 203 204 205
        } else {
            virDomainEventPtr event =
                virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_STARTED,
                                         VIR_DOMAIN_EVENT_STARTED_BOOTED);
            if (event)
                umlDomainEventQueue(data->driver, event);
206 207
        }
    }
208
    virObjectUnlock(vm);
209
}
210 211 212

static void
umlAutostartConfigs(struct uml_driver *driver) {
213 214 215 216 217
    /* 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
     */
218 219 220
    virConnectPtr conn = virConnectOpen(driver->privileged ?
                                        "uml:///system" :
                                        "uml:///session");
221
    /* Ignoring NULL conn which is mostly harmless here */
222

223 224
    struct umlAutostartData data = { driver, conn };

225
    umlDriverLock(driver);
226
    virHashForEach(driver->domains.objs, umlAutostartDomain, &data);
227
    umlDriverUnlock(driver);
228

229 230
    if (conn)
        virConnectClose(conn);
231 232 233 234
}


static int
235
umlIdentifyOneChrPTY(struct uml_driver *driver,
236 237 238 239 240 241 242
                     virDomainObjPtr dom,
                     virDomainChrDefPtr def,
                     const char *dev)
{
    char *cmd;
    char *res = NULL;
    int retries = 0;
243
    if (virAsprintf(&cmd, "config %s%d", dev, def->target.port) < 0) {
244
        virReportOOMError();
245 246 247
        return -1;
    }
requery:
248
    if (umlMonitorCommand(driver, dom, cmd, &res) < 0)
249
        return -1;
250

251
    if (res && STRPREFIX(res, "pts:")) {
252 253
        VIR_FREE(def->source.data.file.path);
        if ((def->source.data.file.path = strdup(res + 4)) == NULL) {
254
            virReportOOMError();
255 256 257 258
            VIR_FREE(res);
            VIR_FREE(cmd);
            return -1;
        }
259
    } else if (!res || STRPREFIX(res, "pts")) {
260
        /* It can take a while to startup, so retry for
J
Ján Tomko 已提交
261
           up to 5 seconds */
262 263 264 265 266 267 268 269 270 271 272 273 274 275
        /* 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
276
umlIdentifyChrPTY(struct uml_driver *driver,
277 278 279 280
                  virDomainObjPtr dom)
{
    int i;

281
    for (i = 0 ; i < dom->def->nconsoles; i++)
282
        if (dom->def->consoles[i]->source.type == VIR_DOMAIN_CHR_TYPE_PTY)
283
        if (umlIdentifyOneChrPTY(driver, dom,
284
                                 dom->def->consoles[i], "con") < 0)
285 286 287
            return -1;

    for (i = 0 ; i < dom->def->nserials; i++)
288
        if (dom->def->serials[i]->source.type == VIR_DOMAIN_CHR_TYPE_PTY &&
289
            umlIdentifyOneChrPTY(driver, dom,
290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307
                                 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;
308
    virDomainEventPtr event = NULL;
309

310
    umlDriverLock(driver);
311
    if (watch != driver->inotifyWatch)
312
        goto cleanup;
313 314 315 316 317 318

reread:
    got = read(fd, buf, sizeof(buf));
    if (got == -1) {
        if (errno == EINTR)
            goto reread;
319
        goto cleanup;
320 321 322 323 324
    }

    tmp = buf;
    while (got) {
        if (got < sizeof(struct inotify_event))
325
            goto cleanup; /* bad */
326 327 328 329 330 331

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

        if (got < e->len)
332
            goto cleanup;
333 334 335 336 337 338 339 340 341 342 343 344 345

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

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

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

        if (!dom) {
            continue;
        }

        if (e->mask & IN_DELETE) {
346
            VIR_DEBUG("Got inotify domain shutdown '%s'", name);
D
Daniel P. Berrange 已提交
347
            if (!virDomainObjIsActive(dom)) {
348
                virObjectUnlock(dom);
349 350 351
                continue;
            }

352
            umlShutdownVMDaemon(driver, dom, VIR_DOMAIN_SHUTOFF_SHUTDOWN);
353
            virDomainAuditStop(dom, "shutdown");
354 355 356
            event = virDomainEventNewFromObj(dom,
                                             VIR_DOMAIN_EVENT_STOPPED,
                                             VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN);
357 358 359 360 361
            if (!dom->persistent) {
                virDomainRemoveInactive(&driver->domains,
                                        dom);
                dom = NULL;
            }
362
        } else if (e->mask & (IN_CREATE | IN_MODIFY)) {
363
            VIR_DEBUG("Got inotify domain startup '%s'", name);
D
Daniel P. Berrange 已提交
364
            if (virDomainObjIsActive(dom)) {
365
                virObjectUnlock(dom);
366 367 368
                continue;
            }

369
            if (umlReadPidFile(driver, dom) < 0) {
370
                virObjectUnlock(dom);
371 372 373 374
                continue;
            }

            dom->def->id = driver->nextvmid++;
375 376 377 378 379

            if (!driver->nactive && driver->inhibitCallback)
                driver->inhibitCallback(true, driver->inhibitOpaque);
            driver->nactive++;

J
Jiri Denemark 已提交
380 381
            virDomainObjSetState(dom, VIR_DOMAIN_RUNNING,
                                 VIR_DOMAIN_RUNNING_BOOTED);
382

383
            if (umlOpenMonitor(driver, dom) < 0) {
384
                VIR_WARN("Could not open monitor for new domain");
385
                umlShutdownVMDaemon(driver, dom,
J
Jiri Denemark 已提交
386
                                    VIR_DOMAIN_SHUTOFF_FAILED);
387
                virDomainAuditStop(dom, "failed");
388 389 390
                event = virDomainEventNewFromObj(dom,
                                                 VIR_DOMAIN_EVENT_STOPPED,
                                                 VIR_DOMAIN_EVENT_STOPPED_FAILED);
391 392 393 394 395
                if (!dom->persistent) {
                    virDomainRemoveInactive(&driver->domains,
                                            dom);
                    dom = NULL;
                }
396
            } else if (umlIdentifyChrPTY(driver, dom) < 0) {
397
                VIR_WARN("Could not identify character devices for new domain");
398
                umlShutdownVMDaemon(driver, dom,
J
Jiri Denemark 已提交
399
                                    VIR_DOMAIN_SHUTOFF_FAILED);
400
                virDomainAuditStop(dom, "failed");
401 402 403
                event = virDomainEventNewFromObj(dom,
                                                 VIR_DOMAIN_EVENT_STOPPED,
                                                 VIR_DOMAIN_EVENT_STOPPED_FAILED);
404 405 406 407 408
                if (!dom->persistent) {
                    virDomainRemoveInactive(&driver->domains,
                                            dom);
                    dom = NULL;
                }
409
            }
410
        }
411
        if (dom)
412
            virObjectUnlock(dom);
413
    }
414 415

cleanup:
416 417
    if (event)
        umlDomainEventQueue(driver, event);
418
    umlDriverUnlock(driver);
419 420 421 422 423 424 425 426
}

/**
 * umlStartup:
 *
 * Initialization function for the Uml daemon
 */
static int
427 428 429
umlStartup(bool privileged,
           virStateInhibitCallback callback,
           void *opaque)
430
{
431
    char *base = NULL;
432
    char *userdir = NULL;
433 434 435 436

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

437
    uml_driver->privileged = privileged;
438 439
    uml_driver->inhibitCallback = callback;
    uml_driver->inhibitOpaque = opaque;
440

441 442 443 444
    if (virMutexInit(&uml_driver->lock) < 0) {
        VIR_FREE(uml_driver);
        return -1;
    }
445 446
    umlDriverLock(uml_driver);

447 448
    /* Don't have a dom0 so start from 1 */
    uml_driver->nextvmid = 1;
449
    uml_driver->inotifyWatch = -1;
450

451 452 453
    if (virDomainObjListInit(&uml_driver->domains) < 0)
        goto error;

454
    uml_driver->domainEventState = virDomainEventStateNew();
455 456 457
    if (!uml_driver->domainEventState)
        goto error;

458
    userdir = virGetUserDirectory();
459
    if (!userdir)
460
        goto error;
461

462
    if (privileged) {
463
        if (virAsprintf(&uml_driver->logDir,
464
                        "%s/log/libvirt/uml", LOCALSTATEDIR) == -1)
465 466
            goto out_of_memory;

467
        if ((base = strdup(SYSCONFDIR "/libvirt")) == NULL)
468
            goto out_of_memory;
469 470

        if (virAsprintf(&uml_driver->monitorDir,
471
                        "%s/run/libvirt/uml-guest", LOCALSTATEDIR) == -1)
472
            goto out_of_memory;
473
    } else {
474
        base = virGetUserConfigDirectory();
475 476
        if (!base)
            goto error;
477

478
        if (virAsprintf(&uml_driver->logDir,
479
                        "%s/uml/log", base) == -1)
480 481
            goto out_of_memory;

482 483 484 485
        if (virAsprintf(&uml_driver->monitorDir,
                        "%s/.uml", userdir) == -1)
            goto out_of_memory;
    }
486

487
    /* Configuration paths are either $XDG_CONFIG_HOME/libvirt/uml/... (session) or
488 489
     * /etc/libvirt/uml/... (system).
     */
490
    if (virAsprintf(&uml_driver->configDir, "%s/uml", base) == -1)
491 492
        goto out_of_memory;

493
    if (virAsprintf(&uml_driver->autostartDir, "%s/uml/autostart", base) == -1)
494 495 496 497 498 499 500
        goto out_of_memory;

    VIR_FREE(base);

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

501 502
    uml_driver->caps->privateDataAllocFunc = umlDomainObjPrivateAlloc;
    uml_driver->caps->privateDataFreeFunc = umlDomainObjPrivateFree;
503 504

    if ((uml_driver->inotifyFD = inotify_init()) < 0) {
505
        VIR_ERROR(_("cannot initialize inotify"));
506
        goto error;
507 508
    }

509
    if (virFileMakePath(uml_driver->monitorDir) < 0) {
510
        char ebuf[1024];
D
Daniel Veillard 已提交
511
        VIR_ERROR(_("Failed to create monitor directory %s: %s"),
512 513
                  uml_driver->monitorDir,
                  virStrerror(errno, ebuf, sizeof(ebuf)));
514
        goto error;
515 516
    }

517
    VIR_INFO("Adding inotify watch on %s", uml_driver->monitorDir);
518 519 520
    if (inotify_add_watch(uml_driver->inotifyFD,
                          uml_driver->monitorDir,
                          IN_CREATE | IN_MODIFY | IN_DELETE) < 0) {
521 522 523 524
        char ebuf[1024];
        VIR_ERROR(_("Failed to create inotify watch on %s: %s"),
                  uml_driver->monitorDir,
                  virStrerror(errno, ebuf, sizeof(ebuf)));
525
        goto error;
526 527
    }

528 529
    if ((uml_driver->inotifyWatch =
         virEventAddHandle(uml_driver->inotifyFD, POLLIN,
530 531
                           umlInotifyEvent, uml_driver, NULL)) < 0)
        goto error;
532

533 534 535
    if (umlProcessAutoDestroyInit(uml_driver) < 0)
        goto error;

536
    if (virDomainLoadAllConfigs(uml_driver->caps,
537 538 539
                                &uml_driver->domains,
                                uml_driver->configDir,
                                uml_driver->autostartDir,
M
Matthias Bolte 已提交
540 541
                                0, 1 << VIR_DOMAIN_VIRT_UML,
                                NULL, NULL) < 0)
542 543
        goto error;

544 545
    umlDriverUnlock(uml_driver);

546 547
    umlAutostartConfigs(uml_driver);

548 549
    VIR_FREE(userdir);

550
    virNWFilterRegisterCallbackDriver(&umlCallbackDriver);
551 552
    return 0;

553
out_of_memory:
554
    VIR_ERROR(_("umlStartup: out of memory"));
555 556

error:
557
    VIR_FREE(userdir);
558
    VIR_FREE(base);
559 560
    umlDriverUnlock(uml_driver);
    umlShutdown();
561 562 563
    return -1;
}

564 565 566 567 568 569 570 571 572 573 574 575 576 577 578
static void umlNotifyLoadDomain(virDomainObjPtr vm, int newVM, void *opaque)
{
    struct uml_driver *driver = opaque;

    if (newVM) {
        virDomainEventPtr event =
            virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_DEFINED,
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED);
        if (event)
            umlDomainEventQueue(driver, event);
    }
}


579 580 581 582 583 584 585 586 587 588 589
/**
 * 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;

590
    umlDriverLock(uml_driver);
591
    virDomainLoadAllConfigs(uml_driver->caps,
592 593 594
                            &uml_driver->domains,
                            uml_driver->configDir,
                            uml_driver->autostartDir,
M
Matthias Bolte 已提交
595
                            0, 1 << VIR_DOMAIN_VIRT_UML,
596 597
                            umlNotifyLoadDomain, uml_driver);
    umlDriverUnlock(uml_driver);
598 599 600 601 602

    return 0;
}


603
static void
604
umlShutdownOneVM(void *payload, const void *name ATTRIBUTE_UNUSED, void *opaque)
605 606 607 608
{
    virDomainObjPtr dom = payload;
    struct uml_driver *driver = opaque;

609
    virObjectLock(dom);
610
    if (virDomainObjIsActive(dom)) {
611
        umlShutdownVMDaemon(driver, dom, VIR_DOMAIN_SHUTOFF_SHUTDOWN);
612 613
        virDomainAuditStop(dom, "shutdown");
    }
614
    virObjectUnlock(dom);
615 616
}

617 618 619 620 621 622 623 624 625 626
/**
 * umlShutdown:
 *
 * Shutdown the Uml daemon, it will stop all active domains and networks
 */
static int
umlShutdown(void) {
    if (!uml_driver)
        return -1;

627
    umlDriverLock(uml_driver);
628
    virNWFilterRegisterCallbackDriver(&umlCallbackDriver);
629 630
    if (uml_driver->inotifyWatch != -1)
        virEventRemoveHandle(uml_driver->inotifyWatch);
631
    VIR_FORCE_CLOSE(uml_driver->inotifyFD);
632 633
    virCapabilitiesFree(uml_driver->caps);

634 635 636
    /* shutdown active VMs
     * XXX allow them to stay around & reconnect */
    virHashForEach(uml_driver->domains.objs, umlShutdownOneVM, uml_driver);
637

638
    virDomainObjListDeinit(&uml_driver->domains);
639

640 641
    virDomainEventStateFree(uml_driver->domainEventState);

642 643 644 645 646
    VIR_FREE(uml_driver->logDir);
    VIR_FREE(uml_driver->configDir);
    VIR_FREE(uml_driver->autostartDir);
    VIR_FREE(uml_driver->monitorDir);

647 648
    umlProcessAutoDestroyShutdown(uml_driver);

649
    umlDriverUnlock(uml_driver);
650
    virMutexDestroy(&uml_driver->lock);
651 652 653 654 655 656
    VIR_FREE(uml_driver);

    return 0;
}


657 658 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 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707
static int umlProcessAutoDestroyInit(struct uml_driver *driver)
{
    if (!(driver->autodestroy = virHashCreate(5, NULL)))
        return -1;

    return 0;
}

struct umlProcessAutoDestroyData {
    struct uml_driver *driver;
    virConnectPtr conn;
};

static void umlProcessAutoDestroyDom(void *payload,
                                     const void *name,
                                     void *opaque)
{
    struct umlProcessAutoDestroyData *data = opaque;
    virConnectPtr conn = payload;
    const char *uuidstr = name;
    unsigned char uuid[VIR_UUID_BUFLEN];
    virDomainObjPtr dom;
    virDomainEventPtr event = NULL;

    VIR_DEBUG("conn=%p uuidstr=%s thisconn=%p", conn, uuidstr, data->conn);

    if (data->conn != conn)
        return;

    if (virUUIDParse(uuidstr, uuid) < 0) {
        VIR_WARN("Failed to parse %s", uuidstr);
        return;
    }

    if (!(dom = virDomainFindByUUID(&data->driver->domains,
                                    uuid))) {
        VIR_DEBUG("No domain object to kill");
        return;
    }

    VIR_DEBUG("Killing domain");
    umlShutdownVMDaemon(data->driver, dom, VIR_DOMAIN_SHUTOFF_DESTROYED);
    virDomainAuditStop(dom, "destroyed");
    event = virDomainEventNewFromObj(dom,
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_DESTROYED);

    if (dom && !dom->persistent)
        virDomainRemoveInactive(&data->driver->domains, dom);

    if (dom)
708
        virObjectUnlock(dom);
709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754
    if (event)
        umlDomainEventQueue(data->driver, event);
    virHashRemoveEntry(data->driver->autodestroy, uuidstr);
}

/*
 * Precondition: driver is locked
 */
static void umlProcessAutoDestroyRun(struct uml_driver *driver, virConnectPtr conn)
{
    struct umlProcessAutoDestroyData data = {
        driver, conn
    };
    VIR_DEBUG("conn=%p", conn);
    virHashForEach(driver->autodestroy, umlProcessAutoDestroyDom, &data);
}

static void umlProcessAutoDestroyShutdown(struct uml_driver *driver)
{
    virHashFree(driver->autodestroy);
}

static int umlProcessAutoDestroyAdd(struct uml_driver *driver,
                                    virDomainObjPtr vm,
                                    virConnectPtr conn)
{
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    virUUIDFormat(vm->def->uuid, uuidstr);
    VIR_DEBUG("vm=%s uuid=%s conn=%p", vm->def->name, uuidstr, conn);
    if (virHashAddEntry(driver->autodestroy, uuidstr, conn) < 0)
        return -1;
    return 0;
}

static int umlProcessAutoDestroyRemove(struct uml_driver *driver,
                                       virDomainObjPtr vm)
{
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    virUUIDFormat(vm->def->uuid, uuidstr);
    VIR_DEBUG("vm=%s uuid=%s", vm->def->name, uuidstr);
    if (virHashRemoveEntry(driver->autodestroy, uuidstr) < 0)
        return -1;
    return 0;
}


755
static int umlReadPidFile(struct uml_driver *driver,
756 757 758 759 760 761 762 763
                          virDomainObjPtr vm)
{
    int rc = -1;
    FILE *file;
    char *pidfile = NULL;
    int retries = 0;

    vm->pid = -1;
764 765
    if (virAsprintf(&pidfile, "%s/%s/pid",
                    driver->monitorDir, vm->def->name) < 0) {
766
        virReportOOMError();
767 768 769 770 771 772 773 774 775 776 777 778 779 780 781
        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;
782
        VIR_FORCE_FCLOSE(file);
783 784 785
        goto cleanup;
    }

786
    if (VIR_FCLOSE(file) < 0)
787 788 789 790 791 792
        goto cleanup;

    rc = 0;

 cleanup:
    if (rc != 0)
793
        virReportSystemError(errno,
794 795
                             _("failed to read pid: %s"),
                             pidfile);
796 797 798 799
    VIR_FREE(pidfile);
    return rc;
}

800
static int umlMonitorAddress(const struct uml_driver *driver,
801 802 803
                             virDomainObjPtr vm,
                             struct sockaddr_un *addr) {
    char *sockname;
C
Chris Lalancette 已提交
804
    int retval = 0;
805

806 807
    if (virAsprintf(&sockname, "%s/%s/mconsole",
                    driver->monitorDir, vm->def->name) < 0) {
808
        virReportOOMError();
809 810 811
        return -1;
    }

812
    memset(addr, 0, sizeof(*addr));
813
    addr->sun_family = AF_UNIX;
C
Chris Lalancette 已提交
814
    if (virStrcpyStatic(addr->sun_path, sockname) == NULL) {
815
        virReportError(VIR_ERR_INTERNAL_ERROR,
C
Chris Lalancette 已提交
816 817 818
                       _("Unix path %s too long for destination"), sockname);
        retval = -1;
    }
819
    VIR_FREE(sockname);
C
Chris Lalancette 已提交
820
    return retval;
821 822
}

823
static int umlOpenMonitor(struct uml_driver *driver,
824 825 826 827
                          virDomainObjPtr vm) {
    struct sockaddr_un addr;
    struct stat sb;
    int retries = 0;
828
    umlDomainObjPrivatePtr priv = vm->privateData;
829

830
    if (umlMonitorAddress(driver, vm, &addr) < 0)
831 832
        return -1;

833
    VIR_DEBUG("Dest address for monitor is '%s'", addr.sun_path);
834 835 836
restat:
    if (stat(addr.sun_path, &sb) < 0) {
        if (errno == ENOENT &&
837
            retries++ < 50) {
838 839 840 841 842 843
            usleep(1000 * 100);
            goto restat;
        }
        return -1;
    }

844
    if ((priv->monitor = socket(PF_UNIX, SOCK_DGRAM, 0)) < 0) {
845
        virReportSystemError(errno,
846
                             "%s", _("cannot open socket"));
847 848 849
        return -1;
    }

850
    memset(addr.sun_path, 0, sizeof(addr.sun_path));
E
Eric Blake 已提交
851 852
    snprintf(addr.sun_path + 1, sizeof(addr.sun_path) - 1,
             "libvirt-uml-%u", vm->pid);
853
    VIR_DEBUG("Reply address for monitor is '%s'", addr.sun_path+1);
854
    if (bind(priv->monitor, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
855
        virReportSystemError(errno,
856
                             "%s", _("cannot bind socket"));
857
        VIR_FORCE_CLOSE(priv->monitor);
858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883
        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];
};


884
static int umlMonitorCommand(const struct uml_driver *driver,
885 886 887 888 889 890 891 892 893 894
                             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;
895
    umlDomainObjPrivatePtr priv = vm->privateData;
896

897 898
    VIR_DEBUG("Run command '%s'", cmd);

899 900
    *reply = NULL;

901
    if (umlMonitorAddress(driver, vm, &addr) < 0)
902 903 904 905 906 907 908
        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)) {
909
        virReportSystemError(EINVAL,
910 911
                             _("cannot send too long command %s (%d bytes)"),
                             cmd, req.length);
912 913
        return -1;
    }
C
Chris Lalancette 已提交
914
    if (virStrcpyStatic(req.data, cmd) == NULL) {
915
        virReportError(VIR_ERR_INTERNAL_ERROR,
C
Chris Lalancette 已提交
916 917 918
                       _("Command %s too long for destination"), cmd);
        return -1;
    }
919

920 921
    if (sendto(priv->monitor, &req, sizeof(req), 0,
               (struct sockaddr *)&addr, sizeof(addr)) != sizeof(req)) {
922
        virReportSystemError(errno,
923 924
                             _("cannot send command %s"),
                             cmd);
925 926 927 928
        return -1;
    }

    do {
E
Eric Blake 已提交
929
        ssize_t nbytes;
930
        addrlen = sizeof(addr);
931
        nbytes = recvfrom(priv->monitor, &res, sizeof(res), 0,
932
                          (struct sockaddr *)&addr, &addrlen);
E
Eric Blake 已提交
933 934 935
        if (nbytes < 0) {
            if (errno == EAGAIN || errno == EINTR)
                continue;
936
            virReportSystemError(errno, _("cannot read reply %s"), cmd);
937 938
            goto error;
        }
939 940 941
        /* 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) {
942 943 944
            virReportSystemError(0, _("incomplete reply %s"), cmd);
            goto error;
        }
945 946

        if (VIR_REALLOC_N(retdata, retlen + res.length) < 0) {
947
            virReportOOMError();
948 949 950 951 952 953 954 955 956 957 958
            goto error;
        }
        memcpy(retdata + retlen, res.data, res.length);
        retlen += res.length - 1;
        retdata[retlen] = '\0';

        if (res.error)
            ret = -1;

    } while (res.extra);

959 960
    VIR_DEBUG("Command reply is '%s'", NULLSTR(retdata));

961 962 963 964
    if (ret < 0)
        VIR_FREE(retdata);
    else
        *reply = retdata;
965 966 967 968 969 970 971 972 973

    return ret;

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


974
static void umlCleanupTapDevices(virDomainObjPtr vm) {
975 976 977 978 979 980 981 982 983
    int i;

    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;

984
        ignore_value(virNetDevTapDelete(def->ifname));
985 986 987
    }
}

988 989
static int umlStartVMDaemon(virConnectPtr conn,
                            struct uml_driver *driver,
990 991
                            virDomainObjPtr vm,
                            bool autoDestroy) {
992
    int ret = -1;
993 994
    char *logfile;
    int logfd = -1;
995
    umlDomainObjPrivatePtr priv = vm->privateData;
D
Daniel P. Berrange 已提交
996
    virCommandPtr cmd = NULL;
997
    size_t i;
998

D
Daniel P. Berrange 已提交
999
    if (virDomainObjIsActive(vm)) {
1000
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
1001
                       _("VM is already active"));
1002 1003 1004 1005
        return -1;
    }

    if (!vm->def->os.kernel) {
1006
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1007
                       _("no kernel specified"));
1008 1009 1010 1011 1012 1013
        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
     */
E
Eric Blake 已提交
1014
    if (!virFileIsExecutable(vm->def->os.kernel)) {
1015
        virReportSystemError(errno,
1016 1017
                             _("Cannot find UML kernel %s"),
                             vm->def->os.kernel);
1018 1019 1020
        return -1;
    }

1021
    if (virFileMakePath(driver->logDir) < 0) {
1022
        virReportSystemError(errno,
1023 1024
                             _("cannot create log directory %s"),
                             driver->logDir);
1025 1026 1027
        return -1;
    }

1028 1029
    if (virAsprintf(&logfile, "%s/%s.log",
                    driver->logDir, vm->def->name) < 0) {
1030
        virReportOOMError();
1031 1032 1033 1034 1035
        return -1;
    }

    if ((logfd = open(logfile, O_CREAT | O_TRUNC | O_WRONLY,
                      S_IRUSR | S_IWUSR)) < 0) {
1036
        virReportSystemError(errno,
1037 1038
                             _("failed to create logfile %s"),
                             logfile);
1039 1040 1041 1042 1043
        VIR_FREE(logfile);
        return -1;
    }
    VIR_FREE(logfile);

E
Eric Blake 已提交
1044 1045 1046
    if (virSetCloseExec(logfd) < 0) {
        virReportSystemError(errno, "%s",
                             _("Unable to set VM logfile close-on-exec flag"));
1047
        VIR_FORCE_CLOSE(logfd);
1048 1049 1050
        return -1;
    }

1051 1052 1053 1054 1055 1056 1057 1058 1059 1060
    /* Do this upfront, so any part of the startup process can add
     * runtime state to vm->def that won't be persisted. This let's us
     * report implicit runtime defaults in the XML, like vnc listen/socket
     */
    VIR_DEBUG("Setting current domain def as transient");
    if (virDomainObjSetDefTransient(driver->caps, vm, true) < 0) {
        VIR_FORCE_CLOSE(logfd);
        return -1;
    }

1061 1062
    if (!(cmd = umlBuildCommandLine(conn, driver, vm)))
        goto cleanup;
1063

1064 1065 1066 1067 1068 1069 1070 1071
    for (i = 0 ; i < vm->def->nconsoles ; i++) {
        VIR_FREE(vm->def->consoles[i]->info.alias);
        if (virAsprintf(&vm->def->consoles[i]->info.alias, "console%zu", i) < 0) {
            virReportOOMError();
            goto cleanup;
        }
    }

D
Daniel P. Berrange 已提交
1072
    virCommandWriteArgLog(cmd, logfd);
1073

1074
    priv->monitor = -1;
1075

D
Daniel P. Berrange 已提交
1076 1077 1078 1079 1080 1081
    virCommandClearCaps(cmd);
    virCommandSetOutputFD(cmd, &logfd);
    virCommandSetErrorFD(cmd, &logfd);
    virCommandDaemonize(cmd);

    ret = virCommandRun(cmd, NULL);
1082 1083
    if (ret < 0)
        goto cleanup;
1084

1085
    if (autoDestroy &&
1086
        (ret = umlProcessAutoDestroyAdd(driver, vm, conn)) < 0)
1087 1088
        goto cleanup;

1089
    ret = virDomainObjSetDefTransient(driver->caps, vm, false);
1090
cleanup:
1091
    VIR_FORCE_CLOSE(logfd);
D
Daniel P. Berrange 已提交
1092
    virCommandFree(cmd);
1093

1094 1095
    if (ret < 0) {
        virDomainConfVMNWFilterTeardown(vm);
1096
        umlCleanupTapDevices(vm);
1097 1098 1099 1100 1101 1102
        if (vm->newDef) {
            virDomainDefFree(vm->def);
            vm->def = vm->newDef;
            vm->def->id = -1;
            vm->newDef = NULL;
        }
1103 1104
    }

1105 1106
    /* NB we don't mark it running here - we do that async
       with inotify */
1107 1108 1109
    /* XXX what if someone else tries to start it again
       before we get the inotification ? Sounds like
       trouble.... */
1110
    /* XXX this is bad for events too. must fix this better */
1111 1112 1113 1114

    return ret;
}

1115
static void umlShutdownVMDaemon(struct uml_driver *driver,
J
Jiri Denemark 已提交
1116 1117
                                virDomainObjPtr vm,
                                virDomainShutoffReason reason)
1118 1119
{
    int ret;
1120 1121
    umlDomainObjPrivatePtr priv = vm->privateData;

D
Daniel P. Berrange 已提交
1122
    if (!virDomainObjIsActive(vm))
1123 1124
        return;

1125
    virProcessKill(vm->pid, SIGTERM);
1126

1127
    VIR_FORCE_CLOSE(priv->monitor);
1128 1129

    if ((ret = waitpid(vm->pid, NULL, 0)) != vm->pid) {
1130
        VIR_WARN("Got unexpected pid %d != %d",
1131 1132 1133 1134 1135
               ret, vm->pid);
    }

    vm->pid = -1;
    vm->def->id = -1;
J
Jiri Denemark 已提交
1136
    virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF, reason);
1137

1138
    virDomainConfVMNWFilterTeardown(vm);
1139 1140 1141 1142
    umlCleanupTapDevices(vm);

    /* Stop autodestroy in case guest is restarted */
    umlProcessAutoDestroyRemove(driver, vm);
1143

1144 1145 1146 1147 1148 1149
    if (vm->newDef) {
        virDomainDefFree(vm->def);
        vm->def = vm->newDef;
        vm->def->id = -1;
        vm->newDef = NULL;
    }
1150 1151 1152 1153

    driver->nactive--;
    if (!driver->nactive && driver->inhibitCallback)
        driver->inhibitCallback(false, driver->inhibitOpaque);
1154 1155 1156 1157 1158
}


static virDrvOpenStatus umlOpen(virConnectPtr conn,
                                virConnectAuthPtr auth ATTRIBUTE_UNUSED,
E
Eric Blake 已提交
1159 1160 1161 1162
                                unsigned int flags)
{
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

1163 1164 1165
    if (conn->uri == NULL) {
        if (uml_driver == NULL)
            return VIR_DRV_OPEN_DECLINED;
1166

1167 1168 1169
        if (!(conn->uri = virURIParse(uml_driver->privileged ?
                                      "uml:///system" :
                                      "uml:///session")))
1170 1171 1172
            return VIR_DRV_OPEN_ERROR;
    } else {
        if (conn->uri->scheme == NULL ||
1173
            STRNEQ(conn->uri->scheme, "uml"))
1174 1175 1176 1177 1178
            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;
1179 1180


1181
        /* Check path and tell them correct path if they made a mistake */
1182
        if (uml_driver->privileged) {
1183 1184
            if (STRNEQ(conn->uri->path, "/system") &&
                STRNEQ(conn->uri->path, "/session")) {
1185
                virReportError(VIR_ERR_INTERNAL_ERROR,
1186 1187 1188 1189 1190
                               _("unexpected UML URI path '%s', try uml:///system"),
                               conn->uri->path);
                return VIR_DRV_OPEN_ERROR;
            }
        } else {
1191
            if (STRNEQ(conn->uri->path, "/session")) {
1192
                virReportError(VIR_ERR_INTERNAL_ERROR,
1193 1194 1195 1196
                               _("unexpected UML URI path '%s', try uml:///session"),
                               conn->uri->path);
                return VIR_DRV_OPEN_ERROR;
            }
1197
        }
1198 1199 1200

        /* URI was good, but driver isn't active */
        if (uml_driver == NULL) {
1201
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1202
                           _("uml state driver is not active"));
1203 1204 1205 1206 1207 1208 1209 1210 1211 1212
            return VIR_DRV_OPEN_ERROR;
        }
    }

    conn->privateData = uml_driver;

    return VIR_DRV_OPEN_SUCCESS;
}

static int umlClose(virConnectPtr conn) {
1213 1214 1215
    struct uml_driver *driver = conn->privateData;

    umlDriverLock(driver);
1216
    umlProcessAutoDestroyRun(driver, conn);
1217
    umlDriverUnlock(driver);
1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228

    conn->privateData = NULL;

    return 0;
}

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


1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242
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;
}


1243 1244 1245 1246 1247 1248
static int umlIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED)
{
    return 1;
}


1249 1250 1251 1252
static char *umlGetCapabilities(virConnectPtr conn) {
    struct uml_driver *driver = (struct uml_driver *)conn->privateData;
    char *xml;

1253
    umlDriverLock(driver);
1254
    if ((xml = virCapabilitiesFormatXML(driver->caps)) == NULL)
1255
        virReportOOMError();
1256
    umlDriverUnlock(driver);
1257 1258 1259 1260 1261 1262

    return xml;
}



1263
static int umlGetProcessInfo(unsigned long long *cpuTime, pid_t pid)
1264 1265
{
    char *proc;
1266 1267 1268
    FILE *pidinfo;
    unsigned long long usertime, systime;

1269
    if (virAsprintf(&proc, "/proc/%lld/stat", (long long) pid) < 0) {
1270 1271 1272 1273 1274 1275
        return -1;
    }

    if (!(pidinfo = fopen(proc, "r"))) {
        /* VM probably shut down, so fake 0 */
        *cpuTime = 0;
1276
        VIR_FREE(proc);
1277 1278 1279
        return 0;
    }

1280 1281
    VIR_FREE(proc);

1282 1283
    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");
1284
        VIR_FORCE_FCLOSE(pidinfo);
1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296
        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);

1297
    VIR_FORCE_FCLOSE(pidinfo);
1298 1299 1300 1301 1302 1303 1304 1305

    return 0;
}


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

1309
    umlDriverLock(driver);
1310
    vm = virDomainFindByID(&driver->domains, id);
1311 1312
    umlDriverUnlock(driver);

1313
    if (!vm) {
1314
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
1315
        goto cleanup;
1316 1317 1318 1319
    }

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

cleanup:
1322
    if (vm)
1323
        virObjectUnlock(vm);
1324 1325
    return dom;
}
1326

1327 1328 1329
static virDomainPtr umlDomainLookupByUUID(virConnectPtr conn,
                                            const unsigned char *uuid) {
    struct uml_driver *driver = (struct uml_driver *)conn->privateData;
1330 1331
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
1332

1333
    umlDriverLock(driver);
1334
    vm = virDomainFindByUUID(&driver->domains, uuid);
1335 1336
    umlDriverUnlock(driver);

1337
    if (!vm) {
1338
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
1339
        goto cleanup;
1340 1341 1342 1343
    }

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

cleanup:
1346
    if (vm)
1347
        virObjectUnlock(vm);
1348 1349
    return dom;
}
1350

1351 1352 1353
static virDomainPtr umlDomainLookupByName(virConnectPtr conn,
                                            const char *name) {
    struct uml_driver *driver = (struct uml_driver *)conn->privateData;
1354 1355
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
1356

1357
    umlDriverLock(driver);
1358
    vm = virDomainFindByName(&driver->domains, name);
1359 1360
    umlDriverUnlock(driver);

1361
    if (!vm) {
1362
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
1363
        goto cleanup;
1364 1365 1366 1367
    }

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

cleanup:
1370
    if (vm)
1371
        virObjectUnlock(vm);
1372 1373 1374
    return dom;
}

1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385

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) {
1386
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
1387 1388 1389 1390 1391 1392
        goto cleanup;
    }
    ret = virDomainObjIsActive(obj);

cleanup:
    if (obj)
1393
        virObjectUnlock(obj);
1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407
    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) {
1408
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
1409 1410 1411 1412 1413 1414
        goto cleanup;
    }
    ret = obj->persistent;

cleanup:
    if (obj)
1415
        virObjectUnlock(obj);
1416 1417 1418
    return ret;
}

1419 1420 1421 1422 1423 1424 1425 1426 1427 1428
static int umlDomainIsUpdated(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) {
1429
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
1430 1431 1432 1433 1434 1435
        goto cleanup;
    }
    ret = obj->updated;

cleanup:
    if (obj)
1436
        virObjectUnlock(obj);
1437 1438
    return ret;
}
1439

1440
static int umlGetVersion(virConnectPtr conn, unsigned long *version) {
1441
    struct uml_driver *driver = conn->privateData;
1442
    struct utsname ut;
1443
    int ret = -1;
1444

1445
    umlDriverLock(driver);
1446 1447 1448 1449

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

1450
        if (virParseVersionString(ut.release, &driver->umlVersion, true) < 0) {
1451
            virReportError(VIR_ERR_INTERNAL_ERROR,
1452 1453 1454
                           _("cannot parse version %s"), ut.release);
            goto cleanup;
        }
1455 1456
    }

1457 1458 1459 1460 1461 1462
    *version = driver->umlVersion;
    ret = 0;

cleanup:
    umlDriverUnlock(driver);
    return ret;
1463 1464 1465
}

static int umlListDomains(virConnectPtr conn, int *ids, int nids) {
1466
    struct uml_driver *driver = conn->privateData;
1467
    int n;
1468

1469
    umlDriverLock(driver);
1470
    n = virDomainObjListGetActiveIDs(&driver->domains, ids, nids);
1471
    umlDriverUnlock(driver);
1472

1473
    return n;
1474 1475
}
static int umlNumDomains(virConnectPtr conn) {
1476
    struct uml_driver *driver = conn->privateData;
1477
    int n;
1478

1479
    umlDriverLock(driver);
1480
    n = virDomainObjListNumOfDomains(&driver->domains, 1);
1481
    umlDriverUnlock(driver);
1482 1483 1484 1485

    return n;
}
static virDomainPtr umlDomainCreate(virConnectPtr conn, const char *xml,
1486
                                      unsigned int flags) {
1487
    struct uml_driver *driver = conn->privateData;
1488
    virDomainDefPtr def;
1489
    virDomainObjPtr vm = NULL;
1490
    virDomainPtr dom = NULL;
1491
    virDomainEventPtr event = NULL;
1492

1493
    virCheckFlags(VIR_DOMAIN_START_AUTODESTROY, NULL);
1494

1495
    umlDriverLock(driver);
1496
    if (!(def = virDomainDefParseString(driver->caps, xml,
M
Matthias Bolte 已提交
1497
                                        1 << VIR_DOMAIN_VIRT_UML,
1498
                                        VIR_DOMAIN_XML_INACTIVE)))
1499
        goto cleanup;
1500

1501
    if (virDomainObjIsDuplicate(&driver->domains, def, 1) < 0)
1502
        goto cleanup;
1503

1504
    if (!(vm = virDomainAssignDef(driver->caps,
1505
                                  &driver->domains,
1506
                                  def, false)))
1507 1508
        goto cleanup;
    def = NULL;
1509

1510 1511
    if (umlStartVMDaemon(conn, driver, vm,
                         (flags & VIR_DOMAIN_START_AUTODESTROY)) < 0) {
1512
        virDomainAuditStart(vm, "booted", false);
1513 1514
        virDomainRemoveInactive(&driver->domains,
                                vm);
1515 1516
        vm = NULL;
        goto cleanup;
1517
    }
1518
    virDomainAuditStart(vm, "booted", true);
1519 1520 1521
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_BOOTED);
1522 1523 1524

    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
    if (dom) dom->id = vm->def->id;
1525 1526 1527

cleanup:
    virDomainDefFree(def);
1528
    if (vm)
1529
        virObjectUnlock(vm);
1530 1531
    if (event)
        umlDomainEventQueue(driver, event);
1532
    umlDriverUnlock(driver);
1533 1534 1535 1536
    return dom;
}


1537 1538
static int umlDomainShutdownFlags(virDomainPtr dom,
                                  unsigned int flags) {
1539 1540
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
1541
    char *info = NULL;
1542
    int ret = -1;
1543

1544 1545
    virCheckFlags(0, -1);

1546
    umlDriverLock(driver);
1547
    vm = virDomainFindByID(&driver->domains, dom->id);
1548
    umlDriverUnlock(driver);
1549
    if (!vm) {
1550
        virReportError(VIR_ERR_NO_DOMAIN,
1551
                       _("no domain with matching id %d"), dom->id);
1552
        goto cleanup;
1553 1554 1555 1556
    }

#if 0
    if (umlMonitorCommand(driver, vm, "system_powerdown", &info) < 0) {
1557
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
1558
                       _("shutdown operation failed"));
1559
        goto cleanup;
1560
    }
1561
    ret = 0;
1562 1563
#endif

1564 1565
cleanup:
    VIR_FREE(info);
1566
    if (vm)
1567
        virObjectUnlock(vm);
1568
    return ret;
1569 1570
}

1571 1572 1573 1574 1575
static int
umlDomainShutdown(virDomainPtr dom)
{
    return umlDomainShutdownFlags(dom, 0);
}
1576

1577 1578 1579 1580
static int
umlDomainDestroyFlags(virDomainPtr dom,
                      unsigned int flags)
{
1581 1582
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
1583
    virDomainEventPtr event = NULL;
1584
    int ret = -1;
1585

1586 1587
    virCheckFlags(0, -1);

1588
    umlDriverLock(driver);
1589
    vm = virDomainFindByID(&driver->domains, dom->id);
1590
    if (!vm) {
1591
        virReportError(VIR_ERR_NO_DOMAIN,
1592
                       _("no domain with matching id %d"), dom->id);
1593
        goto cleanup;
1594 1595
    }

1596
    umlShutdownVMDaemon(driver, vm, VIR_DOMAIN_SHUTOFF_DESTROYED);
1597
    virDomainAuditStop(vm, "destroyed");
1598 1599 1600
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
1601
    if (!vm->persistent) {
1602 1603
        virDomainRemoveInactive(&driver->domains,
                                vm);
1604 1605 1606
        vm = NULL;
    }
    ret = 0;
1607

1608
cleanup:
1609
    if (vm)
1610
        virObjectUnlock(vm);
1611 1612
    if (event)
        umlDomainEventQueue(driver, event);
1613
    umlDriverUnlock(driver);
1614
    return ret;
1615 1616 1617
}


1618 1619 1620 1621 1622 1623
static int umlDomainDestroy(virDomainPtr dom)
{
    return umlDomainDestroyFlags(dom, 0);
}


1624
static char *umlDomainGetOSType(virDomainPtr dom) {
1625 1626 1627
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *type = NULL;
1628

1629
    umlDriverLock(driver);
1630
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1631
    umlDriverUnlock(driver);
1632
    if (!vm) {
1633
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
1634
                       _("no domain with matching uuid"));
1635
        goto cleanup;
1636 1637
    }

1638
    if (!(type = strdup(vm->def->os.type)))
1639
        virReportOOMError();
1640 1641

cleanup:
1642
    if (vm)
1643
        virObjectUnlock(vm);
1644 1645 1646 1647
    return type;
}

/* Returns max memory in kb, 0 if error */
1648 1649 1650
static unsigned long long
umlDomainGetMaxMemory(virDomainPtr dom)
{
1651 1652
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
1653
    unsigned long long ret = 0;
1654

1655
    umlDriverLock(driver);
1656
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1657 1658
    umlDriverUnlock(driver);

1659 1660 1661 1662
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];

        virUUIDFormat(dom->uuid, uuidstr);
1663
        virReportError(VIR_ERR_NO_DOMAIN,
1664 1665
                       _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
1666
    }
1667
    ret = vm->def->mem.max_balloon;
1668

1669
cleanup:
1670
    if (vm)
1671
        virObjectUnlock(vm);
1672
    return ret;
1673 1674 1675
}

static int umlDomainSetMaxMemory(virDomainPtr dom, unsigned long newmax) {
1676 1677 1678
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
1679

1680
    umlDriverLock(driver);
1681
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1682 1683
    umlDriverUnlock(driver);

1684 1685 1686 1687
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];

        virUUIDFormat(dom->uuid, uuidstr);
1688
        virReportError(VIR_ERR_NO_DOMAIN,
1689
                       _("no domain with matching uuid '%s'"), uuidstr);
1690
        goto cleanup;
1691 1692
    }

1693
    if (newmax < vm->def->mem.cur_balloon) {
1694
        virReportError(VIR_ERR_INVALID_ARG, "%s",
1695
                       _("cannot set max memory lower than current memory"));
1696
        goto cleanup;
1697 1698
    }

1699
    vm->def->mem.max_balloon = newmax;
1700 1701 1702
    ret = 0;

cleanup:
1703
    if (vm)
1704
        virObjectUnlock(vm);
1705
    return ret;
1706 1707 1708
}

static int umlDomainSetMemory(virDomainPtr dom, unsigned long newmem) {
1709 1710 1711
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
1712

1713
    umlDriverLock(driver);
1714
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1715 1716
    umlDriverUnlock(driver);

1717 1718 1719 1720
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];

        virUUIDFormat(dom->uuid, uuidstr);
1721
        virReportError(VIR_ERR_NO_DOMAIN,
1722
                       _("no domain with matching uuid '%s'"), uuidstr);
1723
        goto cleanup;
1724 1725
    }

D
Daniel P. Berrange 已提交
1726
    if (virDomainObjIsActive(vm)) {
1727
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
1728
                       _("cannot set memory of an active domain"));
1729
        goto cleanup;
1730 1731
    }

1732
    if (newmem > vm->def->mem.max_balloon) {
1733
        virReportError(VIR_ERR_INVALID_ARG, "%s",
1734
                       _("cannot set memory higher than max memory"));
1735
        goto cleanup;
1736 1737
    }

1738
    vm->def->mem.cur_balloon = newmem;
1739 1740 1741
    ret = 0;

cleanup:
1742
    if (vm)
1743
        virObjectUnlock(vm);
1744
    return ret;
1745 1746 1747 1748
}

static int umlDomainGetInfo(virDomainPtr dom,
                              virDomainInfoPtr info) {
1749 1750 1751 1752
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;

1753
    umlDriverLock(driver);
1754
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1755 1756
    umlDriverUnlock(driver);

1757
    if (!vm) {
1758
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
1759
                       _("no domain with matching uuid"));
1760
        goto cleanup;
1761 1762
    }

J
Jiri Denemark 已提交
1763
    info->state = virDomainObjGetState(vm, NULL);
1764

D
Daniel P. Berrange 已提交
1765
    if (!virDomainObjIsActive(vm)) {
1766 1767 1768
        info->cpuTime = 0;
    } else {
        if (umlGetProcessInfo(&(info->cpuTime), vm->pid) < 0) {
1769
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
1770
                           _("cannot read cputime for domain"));
1771
            goto cleanup;
1772 1773 1774
        }
    }

1775 1776
    info->maxMem = vm->def->mem.max_balloon;
    info->memory = vm->def->mem.cur_balloon;
1777
    info->nrVirtCpu = vm->def->vcpus;
1778 1779 1780
    ret = 0;

cleanup:
1781
    if (vm)
1782
        virObjectUnlock(vm);
1783
    return ret;
1784 1785 1786
}


1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803
static int
umlDomainGetState(virDomainPtr dom,
                  int *state,
                  int *reason,
                  unsigned int flags)
{
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;

    virCheckFlags(0, -1);

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

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

J
Jiri Denemark 已提交
1809
    *state = virDomainObjGetState(vm, reason);
1810 1811 1812 1813
    ret = 0;

cleanup:
    if (vm)
1814
        virObjectUnlock(vm);
1815 1816 1817 1818
    return ret;
}


1819
static char *umlDomainGetXMLDesc(virDomainPtr dom,
E
Eric Blake 已提交
1820 1821
                                 unsigned int flags)
{
1822 1823 1824 1825
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *ret = NULL;

1826
    /* Flags checked by virDomainDefFormat */
E
Eric Blake 已提交
1827

1828
    umlDriverLock(driver);
1829
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1830 1831
    umlDriverUnlock(driver);

1832
    if (!vm) {
1833
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
1834
                       _("no domain with matching uuid"));
1835
        goto cleanup;
1836 1837
    }

1838
    ret = virDomainDefFormat((flags & VIR_DOMAIN_XML_INACTIVE) && vm->newDef ?
1839 1840 1841 1842
                             vm->newDef : vm->def,
                             flags);

cleanup:
1843
    if (vm)
1844
        virObjectUnlock(vm);
1845
    return ret;
1846 1847 1848 1849 1850
}


static int umlListDefinedDomains(virConnectPtr conn,
                            char **const names, int nnames) {
1851
    struct uml_driver *driver = conn->privateData;
1852
    int n;
1853

1854
    umlDriverLock(driver);
1855
    n = virDomainObjListGetInactiveNames(&driver->domains, names, nnames);
1856
    umlDriverUnlock(driver);
1857

1858
    return n;
1859 1860 1861
}

static int umlNumDefinedDomains(virConnectPtr conn) {
1862
    struct uml_driver *driver = conn->privateData;
1863
    int n;
1864

1865
    umlDriverLock(driver);
1866
    n = virDomainObjListNumOfDomains(&driver->domains, 0);
1867
    umlDriverUnlock(driver);
1868 1869 1870 1871 1872

    return n;
}


1873
static int umlDomainStartWithFlags(virDomainPtr dom, unsigned int flags) {
1874 1875
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
1876
    virDomainEventPtr event = NULL;
1877
    int ret = -1;
1878

1879
    virCheckFlags(VIR_DOMAIN_START_AUTODESTROY, -1);
1880

1881
    umlDriverLock(driver);
1882
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1883

1884
    if (!vm) {
1885
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
1886
                       _("no domain with matching uuid"));
1887
        goto cleanup;
1888 1889
    }

1890 1891
    ret = umlStartVMDaemon(dom->conn, driver, vm,
                           (flags & VIR_DOMAIN_START_AUTODESTROY));
1892
    virDomainAuditStart(vm, "booted", ret >= 0);
1893 1894 1895 1896
    if (ret == 0)
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_STARTED,
                                         VIR_DOMAIN_EVENT_STARTED_BOOTED);
1897 1898

cleanup:
1899
    if (vm)
1900
        virObjectUnlock(vm);
1901 1902
    if (event)
        umlDomainEventQueue(driver, event);
1903
    umlDriverUnlock(driver);
1904
    return ret;
1905 1906
}

1907 1908 1909
static int umlDomainStart(virDomainPtr dom) {
    return umlDomainStartWithFlags(dom, 0);
}
1910 1911

static virDomainPtr umlDomainDefine(virConnectPtr conn, const char *xml) {
1912
    struct uml_driver *driver = conn->privateData;
1913
    virDomainDefPtr def;
1914
    virDomainObjPtr vm = NULL;
1915
    virDomainPtr dom = NULL;
1916

1917
    umlDriverLock(driver);
1918
    if (!(def = virDomainDefParseString(driver->caps, xml,
M
Matthias Bolte 已提交
1919
                                        1 << VIR_DOMAIN_VIRT_UML,
1920
                                        VIR_DOMAIN_XML_INACTIVE)))
1921
        goto cleanup;
1922

1923 1924 1925
    if (virDomainObjIsDuplicate(&driver->domains, def, 0) < 0)
        goto cleanup;

1926
    if (!(vm = virDomainAssignDef(driver->caps,
1927
                                  &driver->domains,
1928
                                  def, false)))
1929 1930
        goto cleanup;
    def = NULL;
1931 1932
    vm->persistent = 1;

1933
    if (virDomainSaveConfig(driver->configDir,
1934 1935 1936
                            vm->newDef ? vm->newDef : vm->def) < 0) {
        virDomainRemoveInactive(&driver->domains,
                                vm);
1937
        vm = NULL;
1938
        goto cleanup;
1939 1940 1941 1942
    }

    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
    if (dom) dom->id = vm->def->id;
1943 1944 1945

cleanup:
    virDomainDefFree(def);
1946
    if (vm)
1947
        virObjectUnlock(vm);
1948
    umlDriverUnlock(driver);
1949 1950 1951
    return dom;
}

1952 1953 1954
static int umlDomainUndefineFlags(virDomainPtr dom,
                                  unsigned int flags)
{
1955 1956 1957
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
1958

1959 1960
    virCheckFlags(0, -1);

1961
    umlDriverLock(driver);
1962
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1963
    if (!vm) {
1964
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
1965
                       _("no domain with matching uuid"));
1966
        goto cleanup;
1967 1968 1969
    }

    if (!vm->persistent) {
1970
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
1971
                       _("cannot undefine transient domain"));
1972
        goto cleanup;
1973 1974
    }

1975
    if (virDomainDeleteConfig(driver->configDir, driver->autostartDir, vm) < 0)
1976
        goto cleanup;
1977

1978 1979 1980 1981 1982 1983 1984
    if (virDomainObjIsActive(vm)) {
        vm->persistent = 0;
    } else {
        virDomainRemoveInactive(&driver->domains, vm);
        vm = NULL;
    }

1985
    ret = 0;
1986

1987
cleanup:
1988
    if (vm)
1989
        virObjectUnlock(vm);
1990
    umlDriverUnlock(driver);
1991
    return ret;
1992 1993 1994
}


1995 1996 1997 1998 1999
static int umlDomainUndefine(virDomainPtr dom)
{
    return umlDomainUndefineFlags(dom, 0);
}

2000 2001 2002 2003 2004 2005 2006 2007 2008 2009
static int umlDomainAttachUmlDisk(struct uml_driver *driver,
                                  virDomainObjPtr vm,
                                  virDomainDiskDefPtr disk)
{
    int i;
    char *cmd = NULL;
    char *reply = NULL;

    for (i = 0 ; i < vm->def->ndisks ; i++) {
        if (STREQ(vm->def->disks[i]->dst, disk->dst)) {
2010
            virReportError(VIR_ERR_OPERATION_FAILED,
2011 2012 2013 2014 2015 2016
                           _("target %s already exists"), disk->dst);
            return -1;
        }
    }

    if (!disk->src) {
2017
        virReportError(VIR_ERR_INTERNAL_ERROR,
2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063
                       "%s", _("disk source path is missing"));
        goto error;
    }

    if (virAsprintf(&cmd, "config %s=%s", disk->dst, disk->src) < 0) {
        virReportOOMError();
        return -1;
    }

    if (umlMonitorCommand(driver, vm, cmd, &reply) < 0)
        goto error;

    if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0) {
        virReportOOMError();
        goto error;
    }

    virDomainDiskInsertPreAlloced(vm->def, disk);

    VIR_FREE(reply);
    VIR_FREE(cmd);

    return 0;

error:

    VIR_FREE(reply);
    VIR_FREE(cmd);

    return -1;
}


static int umlDomainAttachDevice(virDomainPtr dom, const char *xml)
{
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    virDomainDeviceDefPtr dev = NULL;
    int ret = -1;

    umlDriverLock(driver);

    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
2064
        virReportError(VIR_ERR_NO_DOMAIN,
2065 2066 2067 2068 2069
                       _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

    if (!virDomainObjIsActive(vm)) {
2070
        virReportError(VIR_ERR_OPERATION_INVALID,
2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086
                       "%s", _("cannot attach device on inactive domain"));
        goto cleanup;
    }

    dev = virDomainDeviceDefParse(driver->caps, vm->def, xml,
                                  VIR_DOMAIN_XML_INACTIVE);

    if (dev == NULL)
        goto cleanup;

    if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
        if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_UML) {
            ret = umlDomainAttachUmlDisk(driver, vm, dev->data.disk);
            if (ret == 0)
                dev->data.disk = NULL;
        } else {
2087
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
2088 2089 2090 2091
                           _("disk bus '%s' cannot be hotplugged."),
                           virDomainDiskBusTypeToString(dev->data.disk->bus));
        }
    } else {
2092
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
2093 2094 2095 2096 2097 2098 2099 2100 2101
                       _("device type '%s' cannot be attached"),
                       virDomainDeviceTypeToString(dev->type));
        goto cleanup;
    }

cleanup:

    virDomainDeviceDefFree(dev);
    if (vm)
2102
        virObjectUnlock(vm);
2103 2104 2105 2106 2107
    umlDriverUnlock(driver);
    return ret;
}


2108 2109 2110 2111 2112 2113 2114
static int
umlDomainAttachDeviceFlags(virDomainPtr dom,
                           const char *xml,
                           unsigned int flags)
{
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG, -1);

2115
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
2116
        virReportError(VIR_ERR_OPERATION_INVALID,
2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140
                       "%s", _("cannot modify the persistent configuration of a domain"));
        return -1;
    }

    return umlDomainAttachDevice(dom, xml);
}


static int umlDomainDetachUmlDisk(struct uml_driver *driver,
                                  virDomainObjPtr vm,
                                  virDomainDeviceDefPtr dev)
{
    int i, ret = -1;
    virDomainDiskDefPtr detach = NULL;
    char *cmd;
    char *reply;

    for (i = 0 ; i < vm->def->ndisks ; i++) {
        if (STREQ(vm->def->disks[i]->dst, dev->data.disk->dst)) {
            break;
        }
    }

    if (i == vm->def->ndisks) {
2141
        virReportError(VIR_ERR_OPERATION_FAILED,
2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181
                       _("disk %s not found"), dev->data.disk->dst);
        return -1;
    }

    detach = vm->def->disks[i];

    if (virAsprintf(&cmd, "remove %s", detach->dst) < 0) {
        virReportOOMError();
        return -1;
    }

    if (umlMonitorCommand(driver, vm, cmd, &reply) < 0)
        goto cleanup;

    virDomainDiskRemove(vm->def, i);

    virDomainDiskDefFree(detach);

    ret = 0;

    VIR_FREE(reply);

cleanup:
    VIR_FREE(cmd);

    return ret;
}


static int umlDomainDetachDevice(virDomainPtr dom, const char *xml) {
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    virDomainDeviceDefPtr dev = NULL;
    int ret = -1;

    umlDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
2182
        virReportError(VIR_ERR_NO_DOMAIN,
2183 2184 2185 2186 2187
                       _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

    if (!virDomainObjIsActive(vm)) {
2188
        virReportError(VIR_ERR_OPERATION_INVALID,
2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202
                       "%s", _("cannot detach device on inactive domain"));
        goto cleanup;
    }

    dev = virDomainDeviceDefParse(driver->caps, vm->def, xml,
                                  VIR_DOMAIN_XML_INACTIVE);
    if (dev == NULL)
        goto cleanup;

    if (dev->type == VIR_DOMAIN_DEVICE_DISK &&
        dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
        if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_UML)
            ret = umlDomainDetachUmlDisk(driver, vm, dev);
        else {
2203
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2204 2205 2206
                           _("This type of disk cannot be hot unplugged"));
        }
    } else {
2207
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
2208 2209 2210 2211 2212 2213
                       "%s", _("This type of device cannot be hot unplugged"));
    }

cleanup:
    virDomainDeviceDefFree(dev);
    if (vm)
2214
        virObjectUnlock(vm);
2215 2216 2217 2218 2219
    umlDriverUnlock(driver);
    return ret;
}


2220 2221 2222 2223 2224 2225 2226
static int
umlDomainDetachDeviceFlags(virDomainPtr dom,
                           const char *xml,
                           unsigned int flags)
{
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG, -1);

2227
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
2228
        virReportError(VIR_ERR_OPERATION_INVALID,
2229 2230 2231 2232 2233 2234 2235
                       "%s", _("cannot modify the persistent configuration of a domain"));
        return -1;
    }

    return umlDomainDetachDevice(dom, xml);
}

2236 2237 2238

static int umlDomainGetAutostart(virDomainPtr dom,
                            int *autostart) {
2239 2240 2241
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
2242

2243
    umlDriverLock(driver);
2244
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
2245

2246
    if (!vm) {
2247
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
2248
                       _("no domain with matching uuid"));
2249
        goto cleanup;
2250 2251 2252
    }

    *autostart = vm->autostart;
2253
    ret = 0;
2254

2255
cleanup:
2256
    if (vm)
2257
        virObjectUnlock(vm);
2258
    umlDriverUnlock(driver);
2259
    return ret;
2260 2261 2262 2263
}

static int umlDomainSetAutostart(virDomainPtr dom,
                                   int autostart) {
2264
    struct uml_driver *driver = dom->conn->privateData;
2265
    virDomainObjPtr vm;
2266 2267 2268
    char *configFile = NULL, *autostartLink = NULL;
    int ret = -1;

2269 2270 2271
    umlDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

2272
    if (!vm) {
2273
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
2274
                       _("no domain with matching uuid"));
2275
        goto cleanup;
2276 2277 2278
    }

    if (!vm->persistent) {
2279
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
2280
                       _("cannot set autostart for transient domain"));
2281
        goto cleanup;
2282 2283 2284 2285
    }

    autostart = (autostart != 0);

2286
    if (vm->autostart != autostart) {
2287
        if ((configFile = virDomainConfigFile(driver->configDir, vm->def->name)) == NULL)
2288
            goto cleanup;
2289
        if ((autostartLink = virDomainConfigFile(driver->autostartDir, vm->def->name)) == NULL)
2290
            goto cleanup;
2291

2292
        if (autostart) {
2293 2294
            if (virFileMakePath(driver->autostartDir) < 0) {
                virReportSystemError(errno,
2295 2296
                                     _("cannot create autostart directory %s"),
                                     driver->autostartDir);
2297 2298
                goto cleanup;
            }
2299

2300
            if (symlink(configFile, autostartLink) < 0) {
2301
                virReportSystemError(errno,
2302 2303
                                     _("Failed to create symlink '%s to '%s'"),
                                     autostartLink, configFile);
2304 2305 2306 2307
                goto cleanup;
            }
        } else {
            if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
2308
                virReportSystemError(errno,
2309 2310
                                     _("Failed to delete symlink '%s'"),
                                     autostartLink);
2311 2312
                goto cleanup;
            }
2313 2314
        }

2315
        vm->autostart = autostart;
2316 2317 2318 2319 2320 2321
    }
    ret = 0;

cleanup:
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
2322
    if (vm)
2323
        virObjectUnlock(vm);
2324
    umlDriverUnlock(driver);
2325 2326 2327 2328 2329
    return ret;
}


static int
2330 2331 2332 2333
umlDomainBlockPeek(virDomainPtr dom,
                   const char *path,
                   unsigned long long offset, size_t size,
                   void *buffer,
E
Eric Blake 已提交
2334
                   unsigned int flags)
2335
{
2336 2337
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
2338 2339
    int fd = -1, ret = -1;
    const char *actual;
2340

E
Eric Blake 已提交
2341 2342
    virCheckFlags(0, -1);

2343
    umlDriverLock(driver);
2344
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
2345 2346
    umlDriverUnlock(driver);

2347
    if (!vm) {
2348
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
2349
                       _("no domain with matching uuid"));
2350
        goto cleanup;
2351 2352 2353
    }

    if (!path || path[0] == '\0') {
2354
        virReportError(VIR_ERR_INVALID_ARG, "%s",
2355
                       _("NULL or empty path"));
2356
        goto cleanup;
2357 2358 2359
    }

    /* Check the path belongs to this domain. */
2360
    if (!(actual = virDomainDiskPathByName(vm->def, path))) {
2361
        virReportError(VIR_ERR_INVALID_ARG,
2362 2363
                       _("invalid path '%s'"), path);
        goto cleanup;
2364
    }
2365
    path = actual;
2366

2367 2368 2369 2370 2371 2372 2373
    /* The path is correct, now try to open it and get its size. */
    fd = open(path, O_RDONLY);
    if (fd == -1) {
        virReportSystemError(errno,
                             _("cannot open %s"), path);
        goto cleanup;
    }
2374

2375 2376 2377 2378 2379 2380 2381 2382 2383
    /* 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) {
        virReportSystemError(errno,
                             _("cannot read %s"), path);
        goto cleanup;
2384 2385
    }

2386 2387
    ret = 0;

2388
cleanup:
2389
    VIR_FORCE_CLOSE(fd);
2390
    if (vm)
2391
        virObjectUnlock(vm);
2392 2393 2394 2395
    return ret;
}


2396 2397
static int
umlDomainOpenConsole(virDomainPtr dom,
2398
                     const char *dev_name,
2399 2400 2401 2402 2403 2404 2405 2406
                     virStreamPtr st,
                     unsigned int flags)
{
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm = NULL;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    int ret = -1;
    virDomainChrDefPtr chr = NULL;
2407
    size_t i;
2408 2409 2410 2411 2412 2413 2414

    virCheckFlags(0, -1);

    umlDriverLock(driver);
    virUUIDFormat(dom->uuid, uuidstr);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    if (!vm) {
2415
        virReportError(VIR_ERR_NO_DOMAIN,
2416 2417 2418 2419 2420
                       _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

    if (!virDomainObjIsActive(vm)) {
2421
        virReportError(VIR_ERR_OPERATION_INVALID,
2422 2423 2424 2425
                        "%s", _("domain is not running"));
        goto cleanup;
    }

2426
    if (dev_name) {
2427 2428 2429 2430 2431 2432 2433
        for (i = 0 ; i < vm->def->nconsoles ; i++) {
            if (vm->def->consoles[i]->info.alias &&
                STREQ(vm->def->consoles[i]->info.alias, dev_name)) {
                chr = vm->def->consoles[i];
                break;
            }
        }
2434
    } else {
2435 2436
        if (vm->def->nconsoles)
            chr = vm->def->consoles[0];
2437 2438 2439 2440 2441
        else if (vm->def->nserials)
            chr = vm->def->serials[0];
    }

    if (!chr) {
2442
        virReportError(VIR_ERR_INTERNAL_ERROR,
2443 2444
                       _("cannot find console device '%s'"),
                       dev_name ? dev_name : _("default"));
2445 2446 2447
        goto cleanup;
    }

2448
    if (chr->source.type != VIR_DOMAIN_CHR_TYPE_PTY) {
2449
        virReportError(VIR_ERR_INTERNAL_ERROR,
2450
                        _("character device %s is not using a PTY"), dev_name);
2451 2452 2453
        goto cleanup;
    }

2454
    if (virFDStreamOpenFile(st, chr->source.data.file.path,
E
Eric Blake 已提交
2455
                            0, 0, O_RDWR) < 0)
2456 2457 2458 2459 2460
        goto cleanup;

    ret = 0;
cleanup:
    if (vm)
2461
        virObjectUnlock(vm);
2462 2463 2464 2465
    umlDriverUnlock(driver);
    return ret;
}

2466

2467 2468 2469 2470 2471 2472 2473 2474 2475 2476
static int
umlDomainEventRegister(virConnectPtr conn,
                       virConnectDomainEventCallback callback,
                       void *opaque,
                       virFreeCallback freecb)
{
    struct uml_driver *driver = conn->privateData;
    int ret;

    umlDriverLock(driver);
2477 2478 2479
    ret = virDomainEventStateRegister(conn,
                                      driver->domainEventState,
                                      callback, opaque, freecb);
2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512
    umlDriverUnlock(driver);

    return ret;
}

static int
umlDomainEventDeregister(virConnectPtr conn,
                         virConnectDomainEventCallback callback)
{
    struct uml_driver *driver = conn->privateData;
    int ret;

    umlDriverLock(driver);
    ret = virDomainEventStateDeregister(conn,
                                        driver->domainEventState,
                                        callback);
    umlDriverUnlock(driver);

    return ret;
}

static int
umlDomainEventRegisterAny(virConnectPtr conn,
                          virDomainPtr dom,
                          int eventID,
                          virConnectDomainEventGenericCallback callback,
                          void *opaque,
                          virFreeCallback freecb)
{
    struct uml_driver *driver = conn->privateData;
    int ret;

    umlDriverLock(driver);
2513 2514 2515 2516
    if (virDomainEventStateRegisterID(conn,
                                      driver->domainEventState,
                                      dom, eventID,
                                      callback, opaque, freecb, &ret) < 0)
2517
        ret = -1;
2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531
    umlDriverUnlock(driver);

    return ret;
}


static int
umlDomainEventDeregisterAny(virConnectPtr conn,
                            int callbackID)
{
    struct uml_driver *driver = conn->privateData;
    int ret;

    umlDriverLock(driver);
2532 2533 2534
    ret = virDomainEventStateDeregisterID(conn,
                                          driver->domainEventState,
                                          callbackID);
2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547
    umlDriverUnlock(driver);

    return ret;
}


/* driver must be locked before calling */
static void umlDomainEventQueue(struct uml_driver *driver,
                                virDomainEventPtr event)
{
    virDomainEventStateQueue(driver->domainEventState, event);
}

2548 2549 2550 2551 2552 2553 2554
static int umlListAllDomains(virConnectPtr conn,
                             virDomainPtr **domains,
                             unsigned int flags)
{
    struct uml_driver *driver = conn->privateData;
    int ret = -1;

O
Osier Yang 已提交
2555
    virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
2556 2557 2558 2559 2560 2561 2562 2563

    umlDriverLock(driver);
    ret = virDomainList(conn, driver->domains.objs, domains, flags);
    umlDriverUnlock(driver);

    return ret;
}

2564 2565


2566
static virDriver umlDriver = {
2567 2568
    .no = VIR_DRV_UML,
    .name = "UML",
2569 2570 2571 2572 2573 2574 2575 2576 2577
    .open = umlOpen, /* 0.5.0 */
    .close = umlClose, /* 0.5.0 */
    .type = umlGetType, /* 0.5.0 */
    .version = umlGetVersion, /* 0.5.0 */
    .getHostname = virGetHostname, /* 0.5.0 */
    .nodeGetInfo = nodeGetInfo, /* 0.5.0 */
    .getCapabilities = umlGetCapabilities, /* 0.5.0 */
    .listDomains = umlListDomains, /* 0.5.0 */
    .numOfDomains = umlNumDomains, /* 0.5.0 */
2578
    .listAllDomains = umlListAllDomains, /* 0.9.13 */
2579 2580 2581 2582 2583
    .domainCreateXML = umlDomainCreate, /* 0.5.0 */
    .domainLookupByID = umlDomainLookupByID, /* 0.5.0 */
    .domainLookupByUUID = umlDomainLookupByUUID, /* 0.5.0 */
    .domainLookupByName = umlDomainLookupByName, /* 0.5.0 */
    .domainShutdown = umlDomainShutdown, /* 0.5.0 */
2584
    .domainShutdownFlags = umlDomainShutdownFlags, /* 0.9.10 */
2585
    .domainDestroy = umlDomainDestroy, /* 0.5.0 */
2586
    .domainDestroyFlags = umlDomainDestroyFlags, /* 0.9.4 */
2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599
    .domainGetOSType = umlDomainGetOSType, /* 0.5.0 */
    .domainGetMaxMemory = umlDomainGetMaxMemory, /* 0.5.0 */
    .domainSetMaxMemory = umlDomainSetMaxMemory, /* 0.5.0 */
    .domainSetMemory = umlDomainSetMemory, /* 0.5.0 */
    .domainGetInfo = umlDomainGetInfo, /* 0.5.0 */
    .domainGetState = umlDomainGetState, /* 0.9.2 */
    .domainGetXMLDesc = umlDomainGetXMLDesc, /* 0.5.0 */
    .listDefinedDomains = umlListDefinedDomains, /* 0.5.0 */
    .numOfDefinedDomains = umlNumDefinedDomains, /* 0.5.0 */
    .domainCreate = umlDomainStart, /* 0.5.0 */
    .domainCreateWithFlags = umlDomainStartWithFlags, /* 0.8.2 */
    .domainDefineXML = umlDomainDefine, /* 0.5.0 */
    .domainUndefine = umlDomainUndefine, /* 0.5.0 */
2600
    .domainUndefineFlags = umlDomainUndefineFlags, /* 0.9.4 */
2601 2602 2603 2604 2605 2606 2607
    .domainAttachDevice = umlDomainAttachDevice, /* 0.8.4 */
    .domainAttachDeviceFlags = umlDomainAttachDeviceFlags, /* 0.8.4 */
    .domainDetachDevice = umlDomainDetachDevice, /* 0.8.4 */
    .domainDetachDeviceFlags = umlDomainDetachDeviceFlags, /* 0.8.4 */
    .domainGetAutostart = umlDomainGetAutostart, /* 0.5.0 */
    .domainSetAutostart = umlDomainSetAutostart, /* 0.5.0 */
    .domainBlockPeek = umlDomainBlockPeek, /* 0.5.0 */
2608
    .nodeGetCPUStats = nodeGetCPUStats, /* 0.9.3 */
2609
    .nodeGetMemoryStats = nodeGetMemoryStats, /* 0.9.3 */
2610 2611
    .nodeGetCellsFreeMemory = nodeGetCellsFreeMemory, /* 0.5.0 */
    .nodeGetFreeMemory = nodeGetFreeMemory, /* 0.5.0 */
2612
    .nodeGetCPUMap = nodeGetCPUMap, /* 1.0.0 */
2613 2614
    .domainEventRegister = umlDomainEventRegister, /* 0.9.4 */
    .domainEventDeregister = umlDomainEventDeregister, /* 0.9.4 */
2615 2616 2617 2618 2619
    .isEncrypted = umlIsEncrypted, /* 0.7.3 */
    .isSecure = umlIsSecure, /* 0.7.3 */
    .domainIsActive = umlDomainIsActive, /* 0.7.3 */
    .domainIsPersistent = umlDomainIsPersistent, /* 0.7.3 */
    .domainIsUpdated = umlDomainIsUpdated, /* 0.8.6 */
2620 2621
    .domainEventRegisterAny = umlDomainEventRegisterAny, /* 0.9.4 */
    .domainEventDeregisterAny = umlDomainEventDeregisterAny, /* 0.9.4 */
2622
    .domainOpenConsole = umlDomainOpenConsole, /* 0.8.6 */
2623
    .isAlive = umlIsAlive, /* 0.9.8 */
2624
    .nodeSuspendForDuration = nodeSuspendForDuration, /* 0.9.8 */
2625 2626
    .nodeGetMemoryParameters = nodeGetMemoryParameters, /* 0.10.2 */
    .nodeSetMemoryParameters = nodeSetMemoryParameters, /* 0.10.2 */
2627 2628 2629
};

static virStateDriver umlStateDriver = {
2630
    .name = "UML",
2631 2632 2633 2634 2635 2636 2637 2638 2639 2640
    .initialize = umlStartup,
    .cleanup = umlShutdown,
    .reload = umlReload,
};

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