uml_driver.c 80.0 KB
Newer Older
1 2 3
/*
 * uml_driver.c: core driver methods for managing UML guests
 *
4
 * Copyright (C) 2006-2013 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
 *
 * 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 <sys/wait.h>
#include <sys/ioctl.h>
#include <sys/inotify.h>
44
#include <sys/un.h>
45 46 47

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

70 71
#define VIR_FROM_THIS VIR_FROM_UML

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

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

82 83 84 85 86 87 88 89 90 91
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);

92

93
static int umlStateCleanup(void);
94

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


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

125

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

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

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


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

static struct uml_driver *uml_driver = NULL;

150
static int
151
umlVMFilterRebuild(virDomainObjListIterator iter, void *data)
152
{
153
    return virDomainObjListForEach(uml_driver->domains, iter, data);
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
}

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,
};

175 176 177 178 179
struct umlAutostartData {
    struct uml_driver *driver;
    virConnectPtr conn;
};

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

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

221 222
    struct umlAutostartData data = { driver, conn };

223
    umlDriverLock(driver);
224
    virDomainObjListForEach(driver->domains, umlAutostartDomain, &data);
225
    umlDriverUnlock(driver);
226

227 228
    if (conn)
        virConnectClose(conn);
229 230 231 232
}


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

247
    if (res && STRPREFIX(res, "pts:")) {
248
        VIR_FREE(def->source.data.file.path);
249
        if (VIR_STRDUP(def->source.data.file.path, res + 4) < 0) {
250 251 252 253
            VIR_FREE(res);
            VIR_FREE(cmd);
            return -1;
        }
254
    } else if (!res || STRPREFIX(res, "pts")) {
255
        /* It can take a while to startup, so retry for
J
Ján Tomko 已提交
256
           up to 5 seconds */
257 258 259
        /* XXX should do this in a better non-blocking
           way somehow ...perhaps register a timer */
        if (retries++ < 50) {
260
            VIR_FREE(res);
261 262 263 264 265 266 267 268 269 270 271
            usleep(1000*10);
            goto requery;
        }
    }

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

static int
272
umlIdentifyChrPTY(struct uml_driver *driver,
273 274
                  virDomainObjPtr dom)
{
275
    size_t i;
276

277
    for (i = 0; i < dom->def->nconsoles; i++)
278
        if (dom->def->consoles[i]->source.type == VIR_DOMAIN_CHR_TYPE_PTY)
279
        if (umlIdentifyOneChrPTY(driver, dom,
280
                                 dom->def->consoles[i], "con") < 0)
281 282
            return -1;

283
    for (i = 0; i < dom->def->nserials; i++)
284
        if (dom->def->serials[i]->source.type == VIR_DOMAIN_CHR_TYPE_PTY &&
285
            umlIdentifyOneChrPTY(driver, dom,
286 287 288 289 290 291 292 293 294 295 296 297 298
                                 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];
299
    struct inotify_event e;
300 301 302 303
    int got;
    char *tmp, *name;
    struct uml_driver *driver = data;
    virDomainObjPtr dom;
304
    virDomainEventPtr event = NULL;
305

306
    umlDriverLock(driver);
307
    if (watch != driver->inotifyWatch)
308
        goto cleanup;
309 310 311 312 313 314

reread:
    got = read(fd, buf, sizeof(buf));
    if (got == -1) {
        if (errno == EINTR)
            goto reread;
315
        goto cleanup;
316 317 318 319
    }

    tmp = buf;
    while (got) {
320
        if (got < sizeof(e))
321
            goto cleanup; /* bad */
322

323 324 325
        memcpy(&e, tmp, sizeof(e));
        tmp += sizeof(e);
        got -= sizeof(e);
326

327
        if (got < e.len)
328
            goto cleanup;
329

330 331
        tmp += e.len;
        got -= e.len;
332

333
        name = (char *)&(e.name);
334

335
        dom = virDomainObjListFindByName(driver->domains, name);
336 337 338 339 340

        if (!dom) {
            continue;
        }

341
        if (e.mask & IN_DELETE) {
342
            VIR_DEBUG("Got inotify domain shutdown '%s'", name);
D
Daniel P. Berrange 已提交
343
            if (!virDomainObjIsActive(dom)) {
344
                virObjectUnlock(dom);
345 346 347
                continue;
            }

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

365
            if (umlReadPidFile(driver, dom) < 0) {
366
                virObjectUnlock(dom);
367 368 369 370
                continue;
            }

            dom->def->id = driver->nextvmid++;
371 372 373 374 375

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

J
Jiri Denemark 已提交
376 377
            virDomainObjSetState(dom, VIR_DOMAIN_RUNNING,
                                 VIR_DOMAIN_RUNNING_BOOTED);
378

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

cleanup:
    umlDriverUnlock(driver);
417 418
}

419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439

static int
umlDomainDeviceDefPostParse(virDomainDeviceDefPtr dev,
                             virDomainDefPtr def ATTRIBUTE_UNUSED,
                             virCapsPtr caps ATTRIBUTE_UNUSED,
                             void *opaque ATTRIBUTE_UNUSED)
{
    if (dev->type == VIR_DOMAIN_DEVICE_CHR &&
        dev->data.chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE &&
        dev->data.chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_NONE)
        dev->data.chr->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_UML;

    return 0;
}


virDomainDefParserConfig umlDriverDomainDefParserConfig = {
    .devicesPostParseCallback = umlDomainDeviceDefPostParse,
};


440 441 442 443 444 445
/**
 * umlStartup:
 *
 * Initialization function for the Uml daemon
 */
static int
446 447 448
umlStateInitialize(bool privileged,
                   virStateInhibitCallback callback,
                   void *opaque)
449
{
450
    char *base = NULL;
451
    char *userdir = NULL;
452

453 454 455 456 457
    virDomainXMLPrivateDataCallbacks privcb = {
        .alloc = umlDomainObjPrivateAlloc,
        .free = umlDomainObjPrivateFree,
    };

458 459 460
    if (VIR_ALLOC(uml_driver) < 0)
        return -1;

461
    uml_driver->privileged = privileged;
462 463
    uml_driver->inhibitCallback = callback;
    uml_driver->inhibitOpaque = opaque;
464

465 466 467 468
    if (virMutexInit(&uml_driver->lock) < 0) {
        VIR_FREE(uml_driver);
        return -1;
    }
469 470
    umlDriverLock(uml_driver);

471 472
    /* Don't have a dom0 so start from 1 */
    uml_driver->nextvmid = 1;
473
    uml_driver->inotifyWatch = -1;
474

475
    if (!(uml_driver->domains = virDomainObjListNew()))
476 477
        goto error;

478
    uml_driver->domainEventState = virDomainEventStateNew();
479 480 481
    if (!uml_driver->domainEventState)
        goto error;

482
    userdir = virGetUserDirectory();
483
    if (!userdir)
484
        goto error;
485

486
    if (privileged) {
487
        if (virAsprintf(&uml_driver->logDir,
488
                        "%s/log/libvirt/uml", LOCALSTATEDIR) == -1)
489 490
            goto out_of_memory;

491 492
        if (VIR_STRDUP(base, SYSCONFDIR "/libvirt") < 0)
            goto error;
493 494

        if (virAsprintf(&uml_driver->monitorDir,
495
                        "%s/run/libvirt/uml-guest", LOCALSTATEDIR) == -1)
496
            goto out_of_memory;
497
    } else {
498
        base = virGetUserConfigDirectory();
499 500
        if (!base)
            goto error;
501

502
        if (virAsprintf(&uml_driver->logDir,
503
                        "%s/uml/log", base) == -1)
504 505
            goto out_of_memory;

506 507 508 509
        if (virAsprintf(&uml_driver->monitorDir,
                        "%s/.uml", userdir) == -1)
            goto out_of_memory;
    }
510

511
    /* Configuration paths are either $XDG_CONFIG_HOME/libvirt/uml/... (session) or
512 513
     * /etc/libvirt/uml/... (system).
     */
514
    if (virAsprintf(&uml_driver->configDir, "%s/uml", base) == -1)
515 516
        goto out_of_memory;

517
    if (virAsprintf(&uml_driver->autostartDir, "%s/uml/autostart", base) == -1)
518 519 520 521 522 523 524
        goto out_of_memory;

    VIR_FREE(base);

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

525 526
    if (!(uml_driver->xmlopt = virDomainXMLOptionNew(&umlDriverDomainDefParserConfig,
                                                     &privcb, NULL)))
527
        goto error;
528 529

    if ((uml_driver->inotifyFD = inotify_init()) < 0) {
530
        VIR_ERROR(_("cannot initialize inotify"));
531
        goto error;
532 533
    }

534
    if (virFileMakePath(uml_driver->monitorDir) < 0) {
535
        char ebuf[1024];
D
Daniel Veillard 已提交
536
        VIR_ERROR(_("Failed to create monitor directory %s: %s"),
537 538
                  uml_driver->monitorDir,
                  virStrerror(errno, ebuf, sizeof(ebuf)));
539
        goto error;
540 541
    }

542
    VIR_INFO("Adding inotify watch on %s", uml_driver->monitorDir);
543 544 545
    if (inotify_add_watch(uml_driver->inotifyFD,
                          uml_driver->monitorDir,
                          IN_CREATE | IN_MODIFY | IN_DELETE) < 0) {
546 547 548 549
        char ebuf[1024];
        VIR_ERROR(_("Failed to create inotify watch on %s: %s"),
                  uml_driver->monitorDir,
                  virStrerror(errno, ebuf, sizeof(ebuf)));
550
        goto error;
551 552
    }

553 554
    if ((uml_driver->inotifyWatch =
         virEventAddHandle(uml_driver->inotifyFD, POLLIN,
555 556
                           umlInotifyEvent, uml_driver, NULL)) < 0)
        goto error;
557

558 559 560
    if (umlProcessAutoDestroyInit(uml_driver) < 0)
        goto error;

561
    if (virDomainObjListLoadAllConfigs(uml_driver->domains,
562 563
                                       uml_driver->configDir,
                                       uml_driver->autostartDir, 0,
564
                                       uml_driver->caps,
565
                                       uml_driver->xmlopt,
566
                                       1 << VIR_DOMAIN_VIRT_UML,
567
                                       NULL, NULL) < 0)
568 569
        goto error;

570 571
    umlDriverUnlock(uml_driver);

572 573
    VIR_FREE(userdir);

574
    virNWFilterRegisterCallbackDriver(&umlCallbackDriver);
575 576
    return 0;

577
out_of_memory:
578
    VIR_ERROR(_("umlStartup: out of memory"));
579 580

error:
581
    VIR_FREE(userdir);
582
    VIR_FREE(base);
583
    umlDriverUnlock(uml_driver);
584
    umlStateCleanup();
585 586 587
    return -1;
}

588 589 590 591 592 593 594 595 596 597 598 599 600 601
/**
 * umlStateAutoStart:
 *
 * Function to autostart the Uml daemons
 */
static void
umlStateAutoStart(void)
{
    if (!uml_driver)
        return;

    umlAutostartConfigs(uml_driver);
}

602 603 604 605 606 607 608 609 610 611 612 613 614 615 616
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);
    }
}


617
/**
618
 * umlStateReload:
619 620 621 622 623
 *
 * Function to restart the Uml daemon, it will recheck the configuration
 * files and update its state and the networking
 */
static int
624
umlStateReload(void) {
625 626 627
    if (!uml_driver)
        return 0;

628
    umlDriverLock(uml_driver);
629
    virDomainObjListLoadAllConfigs(uml_driver->domains,
630 631
                                   uml_driver->configDir,
                                   uml_driver->autostartDir, 0,
632
                                   uml_driver->caps,
633
                                   uml_driver->xmlopt,
634
                                   1 << VIR_DOMAIN_VIRT_UML,
635
                                   umlNotifyLoadDomain, uml_driver);
636
    umlDriverUnlock(uml_driver);
637 638 639 640 641

    return 0;
}


642 643
static int
umlShutdownOneVM(virDomainObjPtr dom, void *opaque)
644 645 646
{
    struct uml_driver *driver = opaque;

647
    virObjectLock(dom);
648
    if (virDomainObjIsActive(dom)) {
649
        umlShutdownVMDaemon(driver, dom, VIR_DOMAIN_SHUTOFF_SHUTDOWN);
650 651
        virDomainAuditStop(dom, "shutdown");
    }
652
    virObjectUnlock(dom);
653
    return 0;
654 655
}

656
/**
657
 * umlStateCleanup:
658 659 660 661
 *
 * Shutdown the Uml daemon, it will stop all active domains and networks
 */
static int
662
umlStateCleanup(void) {
663 664 665
    if (!uml_driver)
        return -1;

666
    umlDriverLock(uml_driver);
667
    virNWFilterRegisterCallbackDriver(&umlCallbackDriver);
668 669
    if (uml_driver->inotifyWatch != -1)
        virEventRemoveHandle(uml_driver->inotifyWatch);
670
    VIR_FORCE_CLOSE(uml_driver->inotifyFD);
671
    virObjectUnref(uml_driver->caps);
672
    virObjectUnref(uml_driver->xmlopt);
673

674 675
    /* shutdown active VMs
     * XXX allow them to stay around & reconnect */
676
    virDomainObjListForEach(uml_driver->domains, umlShutdownOneVM, uml_driver);
677

678
    virObjectUnref(uml_driver->domains);
679

680 681
    virDomainEventStateFree(uml_driver->domainEventState);

682 683 684 685 686
    VIR_FREE(uml_driver->logDir);
    VIR_FREE(uml_driver->configDir);
    VIR_FREE(uml_driver->autostartDir);
    VIR_FREE(uml_driver->monitorDir);

687 688
    umlProcessAutoDestroyShutdown(uml_driver);

689
    umlDriverUnlock(uml_driver);
690
    virMutexDestroy(&uml_driver->lock);
691 692 693 694 695 696
    VIR_FREE(uml_driver);

    return 0;
}


697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730
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;
    }

731 732
    if (!(dom = virDomainObjListFindByUUID(data->driver->domains,
                                           uuid))) {
733 734 735 736 737 738 739 740 741 742 743 744
        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)
745
        virDomainObjListRemove(data->driver->domains, dom);
746 747

    if (dom)
748
        virObjectUnlock(dom);
749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794
    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;
}


795
static int umlReadPidFile(struct uml_driver *driver,
796 797 798 799 800 801 802 803
                          virDomainObjPtr vm)
{
    int rc = -1;
    FILE *file;
    char *pidfile = NULL;
    int retries = 0;

    vm->pid = -1;
804
    if (virAsprintf(&pidfile, "%s/%s/pid",
805
                    driver->monitorDir, vm->def->name) < 0)
806 807 808 809 810 811 812 813 814 815 816 817 818 819
        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;
820
        VIR_FORCE_FCLOSE(file);
821 822 823
        goto cleanup;
    }

824
    if (VIR_FCLOSE(file) < 0)
825 826 827 828 829 830
        goto cleanup;

    rc = 0;

 cleanup:
    if (rc != 0)
831
        virReportSystemError(errno,
832 833
                             _("failed to read pid: %s"),
                             pidfile);
834 835 836 837
    VIR_FREE(pidfile);
    return rc;
}

838
static int umlMonitorAddress(const struct uml_driver *driver,
839 840 841
                             virDomainObjPtr vm,
                             struct sockaddr_un *addr) {
    char *sockname;
C
Chris Lalancette 已提交
842
    int retval = 0;
843

844
    if (virAsprintf(&sockname, "%s/%s/mconsole",
845
                    driver->monitorDir, vm->def->name) < 0)
846 847
        return -1;

848
    memset(addr, 0, sizeof(*addr));
849
    addr->sun_family = AF_UNIX;
C
Chris Lalancette 已提交
850
    if (virStrcpyStatic(addr->sun_path, sockname) == NULL) {
851
        virReportError(VIR_ERR_INTERNAL_ERROR,
C
Chris Lalancette 已提交
852 853 854
                       _("Unix path %s too long for destination"), sockname);
        retval = -1;
    }
855
    VIR_FREE(sockname);
C
Chris Lalancette 已提交
856
    return retval;
857 858
}

859
static int umlOpenMonitor(struct uml_driver *driver,
860 861 862 863
                          virDomainObjPtr vm) {
    struct sockaddr_un addr;
    struct stat sb;
    int retries = 0;
864
    umlDomainObjPrivatePtr priv = vm->privateData;
865

866
    if (umlMonitorAddress(driver, vm, &addr) < 0)
867 868
        return -1;

869
    VIR_DEBUG("Dest address for monitor is '%s'", addr.sun_path);
870 871 872
restat:
    if (stat(addr.sun_path, &sb) < 0) {
        if (errno == ENOENT &&
873
            retries++ < 50) {
874 875 876 877 878 879
            usleep(1000 * 100);
            goto restat;
        }
        return -1;
    }

880
    if ((priv->monitor = socket(PF_UNIX, SOCK_DGRAM, 0)) < 0) {
881
        virReportSystemError(errno,
882
                             "%s", _("cannot open socket"));
883 884 885
        return -1;
    }

886
    memset(addr.sun_path, 0, sizeof(addr.sun_path));
E
Eric Blake 已提交
887 888
    snprintf(addr.sun_path + 1, sizeof(addr.sun_path) - 1,
             "libvirt-uml-%u", vm->pid);
889
    VIR_DEBUG("Reply address for monitor is '%s'", addr.sun_path+1);
890
    if (bind(priv->monitor, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
891
        virReportSystemError(errno,
892
                             "%s", _("cannot bind socket"));
893
        VIR_FORCE_CLOSE(priv->monitor);
894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919
        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];
};


920
static int umlMonitorCommand(const struct uml_driver *driver,
921 922 923 924 925 926 927 928 929 930
                             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;
931
    umlDomainObjPrivatePtr priv = vm->privateData;
932

933 934
    VIR_DEBUG("Run command '%s'", cmd);

935 936
    *reply = NULL;

937
    if (umlMonitorAddress(driver, vm, &addr) < 0)
938 939 940 941 942 943 944
        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)) {
945
        virReportSystemError(EINVAL,
946 947
                             _("cannot send too long command %s (%d bytes)"),
                             cmd, req.length);
948 949
        return -1;
    }
C
Chris Lalancette 已提交
950
    if (virStrcpyStatic(req.data, cmd) == NULL) {
951
        virReportError(VIR_ERR_INTERNAL_ERROR,
C
Chris Lalancette 已提交
952 953 954
                       _("Command %s too long for destination"), cmd);
        return -1;
    }
955

956 957
    if (sendto(priv->monitor, &req, sizeof(req), 0,
               (struct sockaddr *)&addr, sizeof(addr)) != sizeof(req)) {
958
        virReportSystemError(errno,
959 960
                             _("cannot send command %s"),
                             cmd);
961 962 963 964
        return -1;
    }

    do {
E
Eric Blake 已提交
965
        ssize_t nbytes;
966
        addrlen = sizeof(addr);
967
        nbytes = recvfrom(priv->monitor, &res, sizeof(res), 0,
968
                          (struct sockaddr *)&addr, &addrlen);
E
Eric Blake 已提交
969 970 971
        if (nbytes < 0) {
            if (errno == EAGAIN || errno == EINTR)
                continue;
972
            virReportSystemError(errno, _("cannot read reply %s"), cmd);
973 974
            goto error;
        }
975 976 977
        /* 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) {
978 979 980
            virReportSystemError(0, _("incomplete reply %s"), cmd);
            goto error;
        }
981

982
        if (VIR_REALLOC_N(retdata, retlen + res.length) < 0)
983 984 985 986 987 988 989 990 991 992
            goto error;
        memcpy(retdata + retlen, res.data, res.length);
        retlen += res.length - 1;
        retdata[retlen] = '\0';

        if (res.error)
            ret = -1;

    } while (res.extra);

993 994
    VIR_DEBUG("Command reply is '%s'", NULLSTR(retdata));

995 996 997 998
    if (ret < 0)
        VIR_FREE(retdata);
    else
        *reply = retdata;
999 1000 1001 1002 1003 1004 1005 1006 1007

    return ret;

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


1008
static void umlCleanupTapDevices(virDomainObjPtr vm) {
1009
    size_t i;
1010

1011
    for (i = 0; i < vm->def->nnets; i++) {
1012 1013 1014 1015 1016 1017
        virDomainNetDefPtr def = vm->def->nets[i];

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

1018
        ignore_value(virNetDevTapDelete(def->ifname));
1019 1020 1021
    }
}

1022 1023
static int umlStartVMDaemon(virConnectPtr conn,
                            struct uml_driver *driver,
1024 1025
                            virDomainObjPtr vm,
                            bool autoDestroy) {
1026
    int ret = -1;
1027 1028
    char *logfile;
    int logfd = -1;
1029
    umlDomainObjPrivatePtr priv = vm->privateData;
D
Daniel P. Berrange 已提交
1030
    virCommandPtr cmd = NULL;
1031
    size_t i;
1032

D
Daniel P. Berrange 已提交
1033
    if (virDomainObjIsActive(vm)) {
1034
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
1035
                       _("VM is already active"));
1036 1037 1038 1039
        return -1;
    }

    if (!vm->def->os.kernel) {
1040
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1041
                       _("no kernel specified"));
1042 1043 1044 1045 1046 1047
        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 已提交
1048
    if (!virFileIsExecutable(vm->def->os.kernel)) {
1049
        virReportSystemError(errno,
1050 1051
                             _("Cannot find UML kernel %s"),
                             vm->def->os.kernel);
1052 1053 1054
        return -1;
    }

1055
    if (virFileMakePath(driver->logDir) < 0) {
1056
        virReportSystemError(errno,
1057 1058
                             _("cannot create log directory %s"),
                             driver->logDir);
1059 1060 1061
        return -1;
    }

1062
    if (virAsprintf(&logfile, "%s/%s.log",
1063
                    driver->logDir, vm->def->name) < 0)
1064 1065 1066 1067
        return -1;

    if ((logfd = open(logfile, O_CREAT | O_TRUNC | O_WRONLY,
                      S_IRUSR | S_IWUSR)) < 0) {
1068
        virReportSystemError(errno,
1069 1070
                             _("failed to create logfile %s"),
                             logfile);
1071 1072 1073 1074 1075
        VIR_FREE(logfile);
        return -1;
    }
    VIR_FREE(logfile);

E
Eric Blake 已提交
1076 1077 1078
    if (virSetCloseExec(logfd) < 0) {
        virReportSystemError(errno, "%s",
                             _("Unable to set VM logfile close-on-exec flag"));
1079
        VIR_FORCE_CLOSE(logfd);
1080 1081 1082
        return -1;
    }

1083 1084 1085 1086 1087
    /* 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");
1088
    if (virDomainObjSetDefTransient(driver->caps, driver->xmlopt,
1089
                                    vm, true) < 0) {
1090 1091 1092 1093
        VIR_FORCE_CLOSE(logfd);
        return -1;
    }

1094 1095
    if (!(cmd = umlBuildCommandLine(conn, driver, vm)))
        goto cleanup;
1096

1097
    for (i = 0; i < vm->def->nconsoles; i++) {
1098
        VIR_FREE(vm->def->consoles[i]->info.alias);
1099
        if (virAsprintf(&vm->def->consoles[i]->info.alias, "console%zu", i) < 0)
1100 1101 1102
            goto cleanup;
    }

D
Daniel P. Berrange 已提交
1103
    virCommandWriteArgLog(cmd, logfd);
1104

1105
    priv->monitor = -1;
1106

D
Daniel P. Berrange 已提交
1107 1108 1109 1110 1111 1112
    virCommandClearCaps(cmd);
    virCommandSetOutputFD(cmd, &logfd);
    virCommandSetErrorFD(cmd, &logfd);
    virCommandDaemonize(cmd);

    ret = virCommandRun(cmd, NULL);
1113 1114
    if (ret < 0)
        goto cleanup;
1115

1116
    if (autoDestroy &&
1117
        (ret = umlProcessAutoDestroyAdd(driver, vm, conn)) < 0)
1118 1119
        goto cleanup;

1120
    ret = virDomainObjSetDefTransient(driver->caps, driver->xmlopt, vm, false);
1121
cleanup:
1122
    VIR_FORCE_CLOSE(logfd);
D
Daniel P. Berrange 已提交
1123
    virCommandFree(cmd);
1124

1125 1126
    if (ret < 0) {
        virDomainConfVMNWFilterTeardown(vm);
1127
        umlCleanupTapDevices(vm);
1128 1129 1130 1131 1132 1133
        if (vm->newDef) {
            virDomainDefFree(vm->def);
            vm->def = vm->newDef;
            vm->def->id = -1;
            vm->newDef = NULL;
        }
1134 1135
    }

1136 1137
    /* NB we don't mark it running here - we do that async
       with inotify */
1138 1139 1140
    /* XXX what if someone else tries to start it again
       before we get the inotification ? Sounds like
       trouble.... */
1141
    /* XXX this is bad for events too. must fix this better */
1142 1143 1144 1145

    return ret;
}

1146
static void umlShutdownVMDaemon(struct uml_driver *driver,
J
Jiri Denemark 已提交
1147 1148
                                virDomainObjPtr vm,
                                virDomainShutoffReason reason)
1149 1150
{
    int ret;
1151 1152
    umlDomainObjPrivatePtr priv = vm->privateData;

D
Daniel P. Berrange 已提交
1153
    if (!virDomainObjIsActive(vm))
1154 1155
        return;

1156
    virProcessKill(vm->pid, SIGTERM);
1157

1158
    VIR_FORCE_CLOSE(priv->monitor);
1159 1160

    if ((ret = waitpid(vm->pid, NULL, 0)) != vm->pid) {
1161
        VIR_WARN("Got unexpected pid %d != %d",
1162 1163 1164 1165 1166
               ret, vm->pid);
    }

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

1169
    virDomainConfVMNWFilterTeardown(vm);
1170 1171 1172 1173
    umlCleanupTapDevices(vm);

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

1175 1176 1177 1178 1179 1180
    if (vm->newDef) {
        virDomainDefFree(vm->def);
        vm->def = vm->newDef;
        vm->def->id = -1;
        vm->newDef = NULL;
    }
1181 1182 1183 1184

    driver->nactive--;
    if (!driver->nactive && driver->inhibitCallback)
        driver->inhibitCallback(false, driver->inhibitOpaque);
1185 1186 1187
}


1188 1189 1190
static virDrvOpenStatus umlConnectOpen(virConnectPtr conn,
                                       virConnectAuthPtr auth ATTRIBUTE_UNUSED,
                                       unsigned int flags)
E
Eric Blake 已提交
1191 1192 1193
{
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

1194 1195 1196
    if (conn->uri == NULL) {
        if (uml_driver == NULL)
            return VIR_DRV_OPEN_DECLINED;
1197

1198 1199 1200
        if (!(conn->uri = virURIParse(uml_driver->privileged ?
                                      "uml:///system" :
                                      "uml:///session")))
1201 1202 1203
            return VIR_DRV_OPEN_ERROR;
    } else {
        if (conn->uri->scheme == NULL ||
1204
            STRNEQ(conn->uri->scheme, "uml"))
1205 1206 1207 1208 1209
            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;
1210 1211


1212
        /* Check path and tell them correct path if they made a mistake */
1213
        if (uml_driver->privileged) {
1214 1215
            if (STRNEQ(conn->uri->path, "/system") &&
                STRNEQ(conn->uri->path, "/session")) {
1216
                virReportError(VIR_ERR_INTERNAL_ERROR,
1217 1218 1219 1220 1221
                               _("unexpected UML URI path '%s', try uml:///system"),
                               conn->uri->path);
                return VIR_DRV_OPEN_ERROR;
            }
        } else {
1222
            if (STRNEQ(conn->uri->path, "/session")) {
1223
                virReportError(VIR_ERR_INTERNAL_ERROR,
1224 1225 1226 1227
                               _("unexpected UML URI path '%s', try uml:///session"),
                               conn->uri->path);
                return VIR_DRV_OPEN_ERROR;
            }
1228
        }
1229 1230 1231

        /* URI was good, but driver isn't active */
        if (uml_driver == NULL) {
1232
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1233
                           _("uml state driver is not active"));
1234 1235 1236 1237
            return VIR_DRV_OPEN_ERROR;
        }
    }

1238 1239 1240
    if (virConnectOpenEnsureACL(conn) < 0)
        return VIR_DRV_OPEN_ERROR;

1241 1242 1243 1244 1245
    conn->privateData = uml_driver;

    return VIR_DRV_OPEN_SUCCESS;
}

1246
static int umlConnectClose(virConnectPtr conn) {
1247 1248 1249
    struct uml_driver *driver = conn->privateData;

    umlDriverLock(driver);
1250
    umlProcessAutoDestroyRun(driver, conn);
1251
    umlDriverUnlock(driver);
1252 1253 1254 1255 1256 1257

    conn->privateData = NULL;

    return 0;
}

1258 1259 1260 1261
static const char *umlConnectGetType(virConnectPtr conn) {
    if (virConnectGetTypeEnsureACL(conn) < 0)
        return NULL;

1262 1263 1264 1265
    return "UML";
}


1266
static int umlConnectIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED)
1267 1268 1269 1270 1271 1272
{
    /* Trivially secure, since always inside the daemon */
    return 1;
}


1273
static int umlConnectIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED)
1274 1275 1276 1277 1278 1279
{
    /* Not encrypted, but remote driver takes care of that */
    return 0;
}


1280
static int umlConnectIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED)
1281 1282 1283 1284 1285
{
    return 1;
}


1286
static char *umlConnectGetCapabilities(virConnectPtr conn) {
1287 1288 1289
    struct uml_driver *driver = (struct uml_driver *)conn->privateData;
    char *xml;

1290 1291 1292
    if (virConnectGetCapabilitiesEnsureACL(conn) < 0)
        return NULL;

1293
    umlDriverLock(driver);
1294
    if ((xml = virCapabilitiesFormatXML(driver->caps)) == NULL)
1295
        virReportOOMError();
1296
    umlDriverUnlock(driver);
1297 1298 1299 1300 1301 1302

    return xml;
}



1303
static int umlGetProcessInfo(unsigned long long *cpuTime, pid_t pid)
1304 1305
{
    char *proc;
1306 1307 1308
    FILE *pidinfo;
    unsigned long long usertime, systime;

1309
    if (virAsprintf(&proc, "/proc/%lld/stat", (long long) pid) < 0) {
1310 1311 1312 1313 1314 1315
        return -1;
    }

    if (!(pidinfo = fopen(proc, "r"))) {
        /* VM probably shut down, so fake 0 */
        *cpuTime = 0;
1316
        VIR_FREE(proc);
1317 1318 1319
        return 0;
    }

1320 1321
    VIR_FREE(proc);

1322 1323
    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");
1324
        VIR_FORCE_FCLOSE(pidinfo);
1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336
        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);

1337
    VIR_FORCE_FCLOSE(pidinfo);
1338 1339 1340 1341 1342 1343 1344 1345

    return 0;
}


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

1349
    umlDriverLock(driver);
1350
    vm = virDomainObjListFindByID(driver->domains, id);
1351 1352
    umlDriverUnlock(driver);

1353
    if (!vm) {
1354
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
1355
        goto cleanup;
1356 1357
    }

1358 1359 1360
    if (virDomainLookupByIDEnsureACL(conn, vm->def) < 0)
        goto cleanup;

1361 1362
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
    if (dom) dom->id = vm->def->id;
1363 1364

cleanup:
1365
    if (vm)
1366
        virObjectUnlock(vm);
1367 1368
    return dom;
}
1369

1370 1371 1372
static virDomainPtr umlDomainLookupByUUID(virConnectPtr conn,
                                            const unsigned char *uuid) {
    struct uml_driver *driver = (struct uml_driver *)conn->privateData;
1373 1374
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
1375

1376
    umlDriverLock(driver);
1377
    vm = virDomainObjListFindByUUID(driver->domains, uuid);
1378 1379
    umlDriverUnlock(driver);

1380
    if (!vm) {
1381
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
1382
        goto cleanup;
1383 1384
    }

1385 1386 1387
    if (virDomainLookupByUUIDEnsureACL(conn, vm->def) < 0)
        goto cleanup;

1388 1389
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
    if (dom) dom->id = vm->def->id;
1390 1391

cleanup:
1392
    if (vm)
1393
        virObjectUnlock(vm);
1394 1395
    return dom;
}
1396

1397 1398 1399
static virDomainPtr umlDomainLookupByName(virConnectPtr conn,
                                            const char *name) {
    struct uml_driver *driver = (struct uml_driver *)conn->privateData;
1400 1401
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
1402

1403
    umlDriverLock(driver);
1404
    vm = virDomainObjListFindByName(driver->domains, name);
1405 1406
    umlDriverUnlock(driver);

1407
    if (!vm) {
1408
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
1409
        goto cleanup;
1410 1411
    }

1412 1413 1414
    if (virDomainLookupByNameEnsureACL(conn, vm->def) < 0)
        goto cleanup;

1415 1416
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
    if (dom) dom->id = vm->def->id;
1417 1418

cleanup:
1419
    if (vm)
1420
        virObjectUnlock(vm);
1421 1422 1423
    return dom;
}

1424 1425 1426 1427 1428 1429 1430 1431

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

    umlDriverLock(driver);
1432
    obj = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1433 1434
    umlDriverUnlock(driver);
    if (!obj) {
1435
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
1436 1437
        goto cleanup;
    }
1438 1439 1440 1441

    if (virDomainIsActiveEnsureACL(dom->conn, obj->def) < 0)
        goto cleanup;

1442 1443 1444 1445
    ret = virDomainObjIsActive(obj);

cleanup:
    if (obj)
1446
        virObjectUnlock(obj);
1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457
    return ret;
}


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

    umlDriverLock(driver);
1458
    obj = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1459 1460
    umlDriverUnlock(driver);
    if (!obj) {
1461
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
1462 1463
        goto cleanup;
    }
1464 1465 1466 1467

    if (virDomainIsPersistentEnsureACL(dom->conn, obj->def) < 0)
        goto cleanup;

1468 1469 1470 1471
    ret = obj->persistent;

cleanup:
    if (obj)
1472
        virObjectUnlock(obj);
1473 1474 1475
    return ret;
}

1476 1477 1478 1479 1480 1481 1482
static int umlDomainIsUpdated(virDomainPtr dom)
{
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr obj;
    int ret = -1;

    umlDriverLock(driver);
1483
    obj = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1484 1485
    umlDriverUnlock(driver);
    if (!obj) {
1486
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
1487 1488
        goto cleanup;
    }
1489 1490 1491 1492

    if (virDomainIsUpdatedEnsureACL(dom->conn, obj->def) < 0)
        goto cleanup;

1493 1494 1495 1496
    ret = obj->updated;

cleanup:
    if (obj)
1497
        virObjectUnlock(obj);
1498 1499
    return ret;
}
1500

1501
static int umlConnectGetVersion(virConnectPtr conn, unsigned long *version) {
1502
    struct uml_driver *driver = conn->privateData;
1503
    struct utsname ut;
1504
    int ret = -1;
1505

1506 1507 1508
    if (virConnectGetVersionEnsureACL(conn) < 0)
        return -1;

1509
    umlDriverLock(driver);
1510 1511 1512 1513

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

1514
        if (virParseVersionString(ut.release, &driver->umlVersion, true) < 0) {
1515
            virReportError(VIR_ERR_INTERNAL_ERROR,
1516 1517 1518
                           _("cannot parse version %s"), ut.release);
            goto cleanup;
        }
1519 1520
    }

1521 1522 1523 1524 1525 1526
    *version = driver->umlVersion;
    ret = 0;

cleanup:
    umlDriverUnlock(driver);
    return ret;
1527 1528
}

1529

1530
static char *umlConnectGetHostname(virConnectPtr conn)
1531
{
1532 1533 1534
    if (virConnectGetHostnameEnsureACL(conn) < 0)
        return NULL;

1535 1536 1537 1538
    return virGetHostname();
}


1539
static int umlConnectListDomains(virConnectPtr conn, int *ids, int nids) {
1540
    struct uml_driver *driver = conn->privateData;
1541
    int n;
1542

1543 1544 1545
    if (virConnectListDomainsEnsureACL(conn) < 0)
        return -1;

1546
    umlDriverLock(driver);
1547 1548
    n = virDomainObjListGetActiveIDs(driver->domains, ids, nids,
                                     virConnectListDomainsCheckACL, conn);
1549
    umlDriverUnlock(driver);
1550

1551
    return n;
1552
}
1553
static int umlConnectNumOfDomains(virConnectPtr conn) {
1554
    struct uml_driver *driver = conn->privateData;
1555
    int n;
1556

1557 1558 1559
    if (virConnectNumOfDomainsEnsureACL(conn) < 0)
        return -1;

1560
    umlDriverLock(driver);
1561 1562
    n = virDomainObjListNumOfDomains(driver->domains, true,
                                     virConnectNumOfDomainsCheckACL, conn);
1563
    umlDriverUnlock(driver);
1564 1565 1566

    return n;
}
1567 1568
static virDomainPtr umlDomainCreateXML(virConnectPtr conn, const char *xml,
                                       unsigned int flags) {
1569
    struct uml_driver *driver = conn->privateData;
1570
    virDomainDefPtr def;
1571
    virDomainObjPtr vm = NULL;
1572
    virDomainPtr dom = NULL;
1573
    virDomainEventPtr event = NULL;
1574

1575
    virCheckFlags(VIR_DOMAIN_START_AUTODESTROY, NULL);
1576

1577
    umlDriverLock(driver);
1578 1579
    if (!(def = virDomainDefParseString(xml, driver->caps, driver->xmlopt,
                                        1 << VIR_DOMAIN_VIRT_UML,
1580
                                        VIR_DOMAIN_XML_INACTIVE)))
1581
        goto cleanup;
1582

1583 1584 1585
    if (virDomainCreateXMLEnsureACL(conn, def) < 0)
        goto cleanup;

1586
    if (!(vm = virDomainObjListAdd(driver->domains, def,
1587
                                   driver->xmlopt,
1588 1589
                                   VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
                                   NULL)))
1590 1591
        goto cleanup;
    def = NULL;
1592

1593 1594
    if (umlStartVMDaemon(conn, driver, vm,
                         (flags & VIR_DOMAIN_START_AUTODESTROY)) < 0) {
1595
        virDomainAuditStart(vm, "booted", false);
1596 1597
        virDomainObjListRemove(driver->domains,
                               vm);
1598 1599
        vm = NULL;
        goto cleanup;
1600
    }
1601
    virDomainAuditStart(vm, "booted", true);
1602 1603 1604
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_BOOTED);
1605 1606 1607

    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
    if (dom) dom->id = vm->def->id;
1608 1609 1610

cleanup:
    virDomainDefFree(def);
1611
    if (vm)
1612
        virObjectUnlock(vm);
1613 1614
    if (event)
        umlDomainEventQueue(driver, event);
1615
    umlDriverUnlock(driver);
1616 1617 1618 1619
    return dom;
}


1620 1621
static int umlDomainShutdownFlags(virDomainPtr dom,
                                  unsigned int flags) {
1622 1623
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
1624
    char *info = NULL;
1625
    int ret = -1;
1626

1627 1628
    virCheckFlags(0, -1);

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

1638 1639 1640
    if (virDomainShutdownFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

1641 1642
#if 0
    if (umlMonitorCommand(driver, vm, "system_powerdown", &info) < 0) {
1643
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
1644
                       _("shutdown operation failed"));
1645
        goto cleanup;
1646
    }
1647
    ret = 0;
1648 1649
#endif

1650 1651
cleanup:
    VIR_FREE(info);
1652
    if (vm)
1653
        virObjectUnlock(vm);
1654
    return ret;
1655 1656
}

1657 1658 1659 1660 1661
static int
umlDomainShutdown(virDomainPtr dom)
{
    return umlDomainShutdownFlags(dom, 0);
}
1662

1663 1664 1665 1666
static int
umlDomainDestroyFlags(virDomainPtr dom,
                      unsigned int flags)
{
1667 1668
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
1669
    virDomainEventPtr event = NULL;
1670
    int ret = -1;
1671

1672 1673
    virCheckFlags(0, -1);

1674
    umlDriverLock(driver);
1675
    vm = virDomainObjListFindByID(driver->domains, dom->id);
1676
    if (!vm) {
1677
        virReportError(VIR_ERR_NO_DOMAIN,
1678
                       _("no domain with matching id %d"), dom->id);
1679
        goto cleanup;
1680 1681
    }

1682 1683 1684
    if (virDomainDestroyFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

1685
    umlShutdownVMDaemon(driver, vm, VIR_DOMAIN_SHUTOFF_DESTROYED);
1686
    virDomainAuditStop(vm, "destroyed");
1687 1688 1689
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
1690
    if (!vm->persistent) {
1691 1692
        virDomainObjListRemove(driver->domains,
                               vm);
1693 1694 1695
        vm = NULL;
    }
    ret = 0;
1696

1697
cleanup:
1698
    if (vm)
1699
        virObjectUnlock(vm);
1700 1701
    if (event)
        umlDomainEventQueue(driver, event);
1702
    umlDriverUnlock(driver);
1703
    return ret;
1704 1705 1706
}


1707 1708 1709 1710 1711 1712
static int umlDomainDestroy(virDomainPtr dom)
{
    return umlDomainDestroyFlags(dom, 0);
}


1713
static char *umlDomainGetOSType(virDomainPtr dom) {
1714 1715 1716
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *type = NULL;
1717

1718
    umlDriverLock(driver);
1719
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1720
    umlDriverUnlock(driver);
1721
    if (!vm) {
1722
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
1723
                       _("no domain with matching uuid"));
1724
        goto cleanup;
1725 1726
    }

1727 1728 1729 1730 1731
    if (virDomainGetOSTypeEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

    if (VIR_STRDUP(type, vm->def->os.type) < 0)
        goto cleanup;
1732 1733

cleanup:
1734
    if (vm)
1735
        virObjectUnlock(vm);
1736 1737 1738 1739
    return type;
}

/* Returns max memory in kb, 0 if error */
1740 1741 1742
static unsigned long long
umlDomainGetMaxMemory(virDomainPtr dom)
{
1743 1744
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
1745
    unsigned long long ret = 0;
1746

1747
    umlDriverLock(driver);
1748
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1749 1750
    umlDriverUnlock(driver);

1751 1752 1753 1754
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];

        virUUIDFormat(dom->uuid, uuidstr);
1755
        virReportError(VIR_ERR_NO_DOMAIN,
1756 1757
                       _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
1758
    }
1759 1760 1761 1762

    if (virDomainGetMaxMemoryEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

1763
    ret = vm->def->mem.max_balloon;
1764

1765
cleanup:
1766
    if (vm)
1767
        virObjectUnlock(vm);
1768
    return ret;
1769 1770 1771
}

static int umlDomainSetMaxMemory(virDomainPtr dom, unsigned long newmax) {
1772 1773 1774
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
1775

1776
    umlDriverLock(driver);
1777
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1778 1779
    umlDriverUnlock(driver);

1780 1781 1782 1783
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];

        virUUIDFormat(dom->uuid, uuidstr);
1784
        virReportError(VIR_ERR_NO_DOMAIN,
1785
                       _("no domain with matching uuid '%s'"), uuidstr);
1786
        goto cleanup;
1787 1788
    }

1789 1790 1791
    if (virDomainSetMaxMemoryEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

1792
    if (newmax < vm->def->mem.cur_balloon) {
1793
        virReportError(VIR_ERR_INVALID_ARG, "%s",
1794
                       _("cannot set max memory lower than current memory"));
1795
        goto cleanup;
1796 1797
    }

1798
    vm->def->mem.max_balloon = newmax;
1799 1800 1801
    ret = 0;

cleanup:
1802
    if (vm)
1803
        virObjectUnlock(vm);
1804
    return ret;
1805 1806 1807
}

static int umlDomainSetMemory(virDomainPtr dom, unsigned long newmem) {
1808 1809 1810
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
1811

1812
    umlDriverLock(driver);
1813
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1814 1815
    umlDriverUnlock(driver);

1816 1817 1818 1819
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];

        virUUIDFormat(dom->uuid, uuidstr);
1820
        virReportError(VIR_ERR_NO_DOMAIN,
1821
                       _("no domain with matching uuid '%s'"), uuidstr);
1822
        goto cleanup;
1823 1824
    }

1825 1826 1827
    if (virDomainSetMemoryEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

D
Daniel P. Berrange 已提交
1828
    if (virDomainObjIsActive(vm)) {
1829
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
1830
                       _("cannot set memory of an active domain"));
1831
        goto cleanup;
1832 1833
    }

1834
    if (newmem > vm->def->mem.max_balloon) {
1835
        virReportError(VIR_ERR_INVALID_ARG, "%s",
1836
                       _("cannot set memory higher than max memory"));
1837
        goto cleanup;
1838 1839
    }

1840
    vm->def->mem.cur_balloon = newmem;
1841 1842 1843
    ret = 0;

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

static int umlDomainGetInfo(virDomainPtr dom,
                              virDomainInfoPtr info) {
1851 1852 1853 1854
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;

1855
    umlDriverLock(driver);
1856
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1857 1858
    umlDriverUnlock(driver);

1859
    if (!vm) {
1860
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
1861
                       _("no domain with matching uuid"));
1862
        goto cleanup;
1863 1864
    }

1865 1866 1867
    if (virDomainGetInfoEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

D
Daniel P. Berrange 已提交
1870
    if (!virDomainObjIsActive(vm)) {
1871 1872 1873
        info->cpuTime = 0;
    } else {
        if (umlGetProcessInfo(&(info->cpuTime), vm->pid) < 0) {
1874
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
1875
                           _("cannot read cputime for domain"));
1876
            goto cleanup;
1877 1878 1879
        }
    }

1880 1881
    info->maxMem = vm->def->mem.max_balloon;
    info->memory = vm->def->mem.cur_balloon;
1882
    info->nrVirtCpu = vm->def->vcpus;
1883 1884 1885
    ret = 0;

cleanup:
1886
    if (vm)
1887
        virObjectUnlock(vm);
1888
    return ret;
1889 1890 1891
}


1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904
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);
1905
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1906 1907 1908
    umlDriverUnlock(driver);

    if (!vm) {
1909
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
1910 1911 1912 1913
                       _("no domain with matching uuid"));
        goto cleanup;
    }

1914 1915 1916
    if (virDomainGetStateEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

J
Jiri Denemark 已提交
1917
    *state = virDomainObjGetState(vm, reason);
1918 1919 1920 1921
    ret = 0;

cleanup:
    if (vm)
1922
        virObjectUnlock(vm);
1923 1924 1925 1926
    return ret;
}


1927
static char *umlDomainGetXMLDesc(virDomainPtr dom,
E
Eric Blake 已提交
1928 1929
                                 unsigned int flags)
{
1930 1931 1932 1933
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *ret = NULL;

1934
    /* Flags checked by virDomainDefFormat */
E
Eric Blake 已提交
1935

1936
    umlDriverLock(driver);
1937
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1938 1939
    umlDriverUnlock(driver);

1940
    if (!vm) {
1941
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
1942
                       _("no domain with matching uuid"));
1943
        goto cleanup;
1944 1945
    }

1946 1947 1948
    if (virDomainGetXMLDescEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

1949
    ret = virDomainDefFormat((flags & VIR_DOMAIN_XML_INACTIVE) && vm->newDef ?
1950 1951 1952 1953
                             vm->newDef : vm->def,
                             flags);

cleanup:
1954
    if (vm)
1955
        virObjectUnlock(vm);
1956
    return ret;
1957 1958 1959
}


1960 1961
static int umlConnectListDefinedDomains(virConnectPtr conn,
                                        char **const names, int nnames) {
1962
    struct uml_driver *driver = conn->privateData;
1963
    int n;
1964

1965 1966 1967
    if (virConnectListDefinedDomainsEnsureACL(conn) < 0)
        return -1;

1968
    umlDriverLock(driver);
1969 1970
    n = virDomainObjListGetInactiveNames(driver->domains, names, nnames,
                                         virConnectListDefinedDomainsCheckACL, conn);
1971
    umlDriverUnlock(driver);
1972

1973
    return n;
1974 1975
}

1976
static int umlConnectNumOfDefinedDomains(virConnectPtr conn) {
1977
    struct uml_driver *driver = conn->privateData;
1978
    int n;
1979

1980 1981 1982
    if (virConnectNumOfDefinedDomainsEnsureACL(conn) < 0)
        return -1;

1983
    umlDriverLock(driver);
1984 1985
    n = virDomainObjListNumOfDomains(driver->domains, false,
                                     virConnectNumOfDefinedDomainsCheckACL, conn);
1986
    umlDriverUnlock(driver);
1987 1988 1989 1990 1991

    return n;
}


1992
static int umlDomainCreateWithFlags(virDomainPtr dom, unsigned int flags) {
1993 1994
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
1995
    virDomainEventPtr event = NULL;
1996
    int ret = -1;
1997

1998
    virCheckFlags(VIR_DOMAIN_START_AUTODESTROY, -1);
1999

2000
    umlDriverLock(driver);
2001
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
2002

2003
    if (!vm) {
2004
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
2005
                       _("no domain with matching uuid"));
2006
        goto cleanup;
2007 2008
    }

2009 2010 2011
    if (virDomainCreateWithFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2012 2013
    ret = umlStartVMDaemon(dom->conn, driver, vm,
                           (flags & VIR_DOMAIN_START_AUTODESTROY));
2014
    virDomainAuditStart(vm, "booted", ret >= 0);
2015 2016 2017 2018
    if (ret == 0)
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_STARTED,
                                         VIR_DOMAIN_EVENT_STARTED_BOOTED);
2019 2020

cleanup:
2021
    if (vm)
2022
        virObjectUnlock(vm);
2023 2024
    if (event)
        umlDomainEventQueue(driver, event);
2025
    umlDriverUnlock(driver);
2026
    return ret;
2027 2028
}

2029 2030
static int umlDomainCreate(virDomainPtr dom) {
    return umlDomainCreateWithFlags(dom, 0);
2031
}
2032

2033
static virDomainPtr umlDomainDefineXML(virConnectPtr conn, const char *xml) {
2034
    struct uml_driver *driver = conn->privateData;
2035
    virDomainDefPtr def;
2036
    virDomainObjPtr vm = NULL;
2037
    virDomainPtr dom = NULL;
2038

2039
    umlDriverLock(driver);
2040 2041
    if (!(def = virDomainDefParseString(xml, driver->caps, driver->xmlopt,
                                        1 << VIR_DOMAIN_VIRT_UML,
2042
                                        VIR_DOMAIN_XML_INACTIVE)))
2043
        goto cleanup;
2044

2045 2046 2047
    if (virDomainDefineXMLEnsureACL(conn, def) < 0)
        goto cleanup;

2048
    if (!(vm = virDomainObjListAdd(driver->domains, def,
2049
                                   driver->xmlopt,
2050
                                   0, NULL)))
2051 2052
        goto cleanup;
    def = NULL;
2053 2054
    vm->persistent = 1;

2055
    if (virDomainSaveConfig(driver->configDir,
2056
                            vm->newDef ? vm->newDef : vm->def) < 0) {
2057 2058
        virDomainObjListRemove(driver->domains,
                               vm);
2059
        vm = NULL;
2060
        goto cleanup;
2061 2062 2063 2064
    }

    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
    if (dom) dom->id = vm->def->id;
2065 2066 2067

cleanup:
    virDomainDefFree(def);
2068
    if (vm)
2069
        virObjectUnlock(vm);
2070
    umlDriverUnlock(driver);
2071 2072 2073
    return dom;
}

2074 2075 2076
static int umlDomainUndefineFlags(virDomainPtr dom,
                                  unsigned int flags)
{
2077 2078 2079
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
2080

2081 2082
    virCheckFlags(0, -1);

2083
    umlDriverLock(driver);
2084
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
2085
    if (!vm) {
2086
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
2087
                       _("no domain with matching uuid"));
2088
        goto cleanup;
2089 2090
    }

2091 2092 2093
    if (virDomainUndefineFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2094
    if (!vm->persistent) {
2095
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
2096
                       _("cannot undefine transient domain"));
2097
        goto cleanup;
2098 2099
    }

2100
    if (virDomainDeleteConfig(driver->configDir, driver->autostartDir, vm) < 0)
2101
        goto cleanup;
2102

2103 2104 2105
    if (virDomainObjIsActive(vm)) {
        vm->persistent = 0;
    } else {
2106
        virDomainObjListRemove(driver->domains, vm);
2107 2108 2109
        vm = NULL;
    }

2110
    ret = 0;
2111

2112
cleanup:
2113
    if (vm)
2114
        virObjectUnlock(vm);
2115
    umlDriverUnlock(driver);
2116
    return ret;
2117 2118 2119
}


2120 2121 2122 2123 2124
static int umlDomainUndefine(virDomainPtr dom)
{
    return umlDomainUndefineFlags(dom, 0);
}

2125 2126 2127 2128
static int umlDomainAttachUmlDisk(struct uml_driver *driver,
                                  virDomainObjPtr vm,
                                  virDomainDiskDefPtr disk)
{
2129
    size_t i;
2130 2131 2132
    char *cmd = NULL;
    char *reply = NULL;

2133
    for (i = 0; i < vm->def->ndisks; i++) {
2134
        if (STREQ(vm->def->disks[i]->dst, disk->dst)) {
2135
            virReportError(VIR_ERR_OPERATION_FAILED,
2136 2137 2138 2139 2140 2141
                           _("target %s already exists"), disk->dst);
            return -1;
        }
    }

    if (!disk->src) {
2142
        virReportError(VIR_ERR_INTERNAL_ERROR,
2143 2144 2145 2146
                       "%s", _("disk source path is missing"));
        goto error;
    }

2147
    if (virAsprintf(&cmd, "config %s=%s", disk->dst, disk->src) < 0)
2148 2149 2150 2151 2152
        return -1;

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

2153
    if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0)
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
        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);

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

2190 2191 2192
    if (virDomainAttachDeviceEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2193
    if (!virDomainObjIsActive(vm)) {
2194
        virReportError(VIR_ERR_OPERATION_INVALID,
2195 2196 2197 2198
                       "%s", _("cannot attach device on inactive domain"));
        goto cleanup;
    }

2199
    dev = virDomainDeviceDefParse(xml, vm->def, driver->caps, driver->xmlopt,
2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210
                                  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 {
2211
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
2212 2213 2214 2215
                           _("disk bus '%s' cannot be hotplugged."),
                           virDomainDiskBusTypeToString(dev->data.disk->bus));
        }
    } else {
2216
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
2217 2218 2219 2220 2221 2222 2223 2224 2225
                       _("device type '%s' cannot be attached"),
                       virDomainDeviceTypeToString(dev->type));
        goto cleanup;
    }

cleanup:

    virDomainDeviceDefFree(dev);
    if (vm)
2226
        virObjectUnlock(vm);
2227 2228 2229 2230 2231
    umlDriverUnlock(driver);
    return ret;
}


2232 2233 2234 2235 2236 2237 2238
static int
umlDomainAttachDeviceFlags(virDomainPtr dom,
                           const char *xml,
                           unsigned int flags)
{
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG, -1);

2239
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
2240
        virReportError(VIR_ERR_OPERATION_INVALID,
2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252
                       "%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)
{
2253 2254
    size_t i;
    int ret = -1;
2255 2256 2257 2258
    virDomainDiskDefPtr detach = NULL;
    char *cmd;
    char *reply;

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

    if (i == vm->def->ndisks) {
2266
        virReportError(VIR_ERR_OPERATION_FAILED,
2267 2268 2269 2270 2271 2272
                       _("disk %s not found"), dev->data.disk->dst);
        return -1;
    }

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

2273
    if (virAsprintf(&cmd, "remove %s", detach->dst) < 0)
2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300
        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);
2301
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
2302 2303 2304
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
2305
        virReportError(VIR_ERR_NO_DOMAIN,
2306 2307 2308 2309
                       _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

2310 2311 2312
    if (virDomainDetachDeviceEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2313
    if (!virDomainObjIsActive(vm)) {
2314
        virReportError(VIR_ERR_OPERATION_INVALID,
2315 2316 2317 2318
                       "%s", _("cannot detach device on inactive domain"));
        goto cleanup;
    }

2319
    dev = virDomainDeviceDefParse(xml, vm->def, driver->caps, driver->xmlopt,
2320 2321 2322 2323 2324 2325 2326 2327 2328
                                  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 {
2329
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2330 2331 2332
                           _("This type of disk cannot be hot unplugged"));
        }
    } else {
2333
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
2334 2335 2336 2337 2338 2339
                       "%s", _("This type of device cannot be hot unplugged"));
    }

cleanup:
    virDomainDeviceDefFree(dev);
    if (vm)
2340
        virObjectUnlock(vm);
2341 2342 2343 2344 2345
    umlDriverUnlock(driver);
    return ret;
}


2346 2347 2348 2349 2350 2351 2352
static int
umlDomainDetachDeviceFlags(virDomainPtr dom,
                           const char *xml,
                           unsigned int flags)
{
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG, -1);

2353
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
2354
        virReportError(VIR_ERR_OPERATION_INVALID,
2355 2356 2357 2358 2359 2360 2361
                       "%s", _("cannot modify the persistent configuration of a domain"));
        return -1;
    }

    return umlDomainDetachDevice(dom, xml);
}

2362 2363 2364

static int umlDomainGetAutostart(virDomainPtr dom,
                            int *autostart) {
2365 2366 2367
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
2368

2369
    umlDriverLock(driver);
2370
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
2371

2372
    if (!vm) {
2373
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
2374
                       _("no domain with matching uuid"));
2375
        goto cleanup;
2376 2377
    }

2378 2379 2380
    if (virDomainGetAutostartEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2381
    *autostart = vm->autostart;
2382
    ret = 0;
2383

2384
cleanup:
2385
    if (vm)
2386
        virObjectUnlock(vm);
2387
    umlDriverUnlock(driver);
2388
    return ret;
2389 2390 2391 2392
}

static int umlDomainSetAutostart(virDomainPtr dom,
                                   int autostart) {
2393
    struct uml_driver *driver = dom->conn->privateData;
2394
    virDomainObjPtr vm;
2395 2396 2397
    char *configFile = NULL, *autostartLink = NULL;
    int ret = -1;

2398
    umlDriverLock(driver);
2399
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
2400

2401
    if (!vm) {
2402
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
2403
                       _("no domain with matching uuid"));
2404
        goto cleanup;
2405 2406
    }

2407 2408 2409
    if (virDomainSetAutostartEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2410
    if (!vm->persistent) {
2411
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
2412
                       _("cannot set autostart for transient domain"));
2413
        goto cleanup;
2414 2415 2416 2417
    }

    autostart = (autostart != 0);

2418
    if (vm->autostart != autostart) {
2419
        if ((configFile = virDomainConfigFile(driver->configDir, vm->def->name)) == NULL)
2420
            goto cleanup;
2421
        if ((autostartLink = virDomainConfigFile(driver->autostartDir, vm->def->name)) == NULL)
2422
            goto cleanup;
2423

2424
        if (autostart) {
2425 2426
            if (virFileMakePath(driver->autostartDir) < 0) {
                virReportSystemError(errno,
2427 2428
                                     _("cannot create autostart directory %s"),
                                     driver->autostartDir);
2429 2430
                goto cleanup;
            }
2431

2432
            if (symlink(configFile, autostartLink) < 0) {
2433
                virReportSystemError(errno,
2434 2435
                                     _("Failed to create symlink '%s to '%s'"),
                                     autostartLink, configFile);
2436 2437 2438 2439
                goto cleanup;
            }
        } else {
            if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
2440
                virReportSystemError(errno,
2441 2442
                                     _("Failed to delete symlink '%s'"),
                                     autostartLink);
2443 2444
                goto cleanup;
            }
2445 2446
        }

2447
        vm->autostart = autostart;
2448 2449 2450 2451 2452 2453
    }
    ret = 0;

cleanup:
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
2454
    if (vm)
2455
        virObjectUnlock(vm);
2456
    umlDriverUnlock(driver);
2457 2458 2459 2460 2461
    return ret;
}


static int
2462 2463 2464 2465
umlDomainBlockPeek(virDomainPtr dom,
                   const char *path,
                   unsigned long long offset, size_t size,
                   void *buffer,
E
Eric Blake 已提交
2466
                   unsigned int flags)
2467
{
2468 2469
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
2470 2471
    int fd = -1, ret = -1;
    const char *actual;
2472

E
Eric Blake 已提交
2473 2474
    virCheckFlags(0, -1);

2475
    umlDriverLock(driver);
2476
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
2477 2478
    umlDriverUnlock(driver);

2479
    if (!vm) {
2480
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
2481
                       _("no domain with matching uuid"));
2482
        goto cleanup;
2483 2484
    }

2485 2486 2487
    if (virDomainBlockPeekEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2488
    if (!path || path[0] == '\0') {
2489
        virReportError(VIR_ERR_INVALID_ARG, "%s",
2490
                       _("NULL or empty path"));
2491
        goto cleanup;
2492 2493 2494
    }

    /* Check the path belongs to this domain. */
2495
    if (!(actual = virDomainDiskPathByName(vm->def, path))) {
2496
        virReportError(VIR_ERR_INVALID_ARG,
2497 2498
                       _("invalid path '%s'"), path);
        goto cleanup;
2499
    }
2500
    path = actual;
2501

2502 2503 2504 2505 2506 2507 2508
    /* 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;
    }
2509

2510 2511 2512 2513 2514 2515 2516 2517 2518
    /* 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;
2519 2520
    }

2521 2522
    ret = 0;

2523
cleanup:
2524
    VIR_FORCE_CLOSE(fd);
2525
    if (vm)
2526
        virObjectUnlock(vm);
2527 2528 2529 2530
    return ret;
}


2531 2532
static int
umlDomainOpenConsole(virDomainPtr dom,
2533
                     const char *dev_name,
2534 2535 2536 2537 2538 2539 2540 2541
                     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;
2542
    size_t i;
2543 2544 2545 2546 2547

    virCheckFlags(0, -1);

    umlDriverLock(driver);
    virUUIDFormat(dom->uuid, uuidstr);
2548
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
2549
    if (!vm) {
2550
        virReportError(VIR_ERR_NO_DOMAIN,
2551 2552 2553 2554
                       _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

2555 2556 2557
    if (virDomainOpenConsoleEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2558
    if (!virDomainObjIsActive(vm)) {
2559
        virReportError(VIR_ERR_OPERATION_INVALID,
2560 2561 2562 2563
                        "%s", _("domain is not running"));
        goto cleanup;
    }

2564
    if (dev_name) {
2565
        for (i = 0; i < vm->def->nconsoles; i++) {
2566 2567 2568 2569 2570 2571
            if (vm->def->consoles[i]->info.alias &&
                STREQ(vm->def->consoles[i]->info.alias, dev_name)) {
                chr = vm->def->consoles[i];
                break;
            }
        }
2572
    } else {
2573 2574
        if (vm->def->nconsoles)
            chr = vm->def->consoles[0];
2575 2576 2577 2578 2579
        else if (vm->def->nserials)
            chr = vm->def->serials[0];
    }

    if (!chr) {
2580
        virReportError(VIR_ERR_INTERNAL_ERROR,
2581 2582
                       _("cannot find console device '%s'"),
                       dev_name ? dev_name : _("default"));
2583 2584 2585
        goto cleanup;
    }

2586
    if (chr->source.type != VIR_DOMAIN_CHR_TYPE_PTY) {
2587
        virReportError(VIR_ERR_INTERNAL_ERROR,
2588
                        _("character device %s is not using a PTY"), dev_name);
2589 2590 2591
        goto cleanup;
    }

2592
    if (virFDStreamOpenFile(st, chr->source.data.file.path,
E
Eric Blake 已提交
2593
                            0, 0, O_RDWR) < 0)
2594 2595 2596 2597 2598
        goto cleanup;

    ret = 0;
cleanup:
    if (vm)
2599
        virObjectUnlock(vm);
2600 2601 2602 2603
    umlDriverUnlock(driver);
    return ret;
}

2604

2605
static int
2606 2607 2608 2609
umlConnectDomainEventRegister(virConnectPtr conn,
                              virConnectDomainEventCallback callback,
                              void *opaque,
                              virFreeCallback freecb)
2610 2611 2612 2613
{
    struct uml_driver *driver = conn->privateData;
    int ret;

2614 2615 2616
    if (virConnectDomainEventRegisterEnsureACL(conn) < 0)
        return -1;

2617
    umlDriverLock(driver);
2618 2619 2620
    ret = virDomainEventStateRegister(conn,
                                      driver->domainEventState,
                                      callback, opaque, freecb);
2621 2622 2623 2624 2625 2626
    umlDriverUnlock(driver);

    return ret;
}

static int
2627 2628
umlConnectDomainEventDeregister(virConnectPtr conn,
                                virConnectDomainEventCallback callback)
2629 2630 2631 2632
{
    struct uml_driver *driver = conn->privateData;
    int ret;

2633 2634 2635
    if (virConnectDomainEventDeregisterEnsureACL(conn) < 0)
        return -1;

2636 2637 2638 2639 2640 2641 2642 2643 2644 2645
    umlDriverLock(driver);
    ret = virDomainEventStateDeregister(conn,
                                        driver->domainEventState,
                                        callback);
    umlDriverUnlock(driver);

    return ret;
}

static int
2646 2647 2648 2649 2650 2651
umlConnectDomainEventRegisterAny(virConnectPtr conn,
                                 virDomainPtr dom,
                                 int eventID,
                                 virConnectDomainEventGenericCallback callback,
                                 void *opaque,
                                 virFreeCallback freecb)
2652 2653 2654 2655
{
    struct uml_driver *driver = conn->privateData;
    int ret;

2656 2657 2658
    if (virConnectDomainEventRegisterAnyEnsureACL(conn) < 0)
        return -1;

2659
    umlDriverLock(driver);
2660 2661 2662 2663
    if (virDomainEventStateRegisterID(conn,
                                      driver->domainEventState,
                                      dom, eventID,
                                      callback, opaque, freecb, &ret) < 0)
2664
        ret = -1;
2665 2666 2667 2668 2669 2670 2671
    umlDriverUnlock(driver);

    return ret;
}


static int
2672 2673
umlConnectDomainEventDeregisterAny(virConnectPtr conn,
                                   int callbackID)
2674 2675 2676 2677
{
    struct uml_driver *driver = conn->privateData;
    int ret;

2678 2679 2680
    if (virConnectDomainEventDeregisterAnyEnsureACL(conn) < 0)
        return -1;

2681
    umlDriverLock(driver);
2682 2683 2684
    ret = virDomainEventStateDeregisterID(conn,
                                          driver->domainEventState,
                                          callbackID);
2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697
    umlDriverUnlock(driver);

    return ret;
}


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

2698 2699 2700
static int umlConnectListAllDomains(virConnectPtr conn,
                                    virDomainPtr **domains,
                                    unsigned int flags)
2701 2702 2703 2704
{
    struct uml_driver *driver = conn->privateData;
    int ret = -1;

O
Osier Yang 已提交
2705
    virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
2706

2707 2708 2709
    if (virConnectListAllDomainsEnsureACL(conn) < 0)
        return -1;

2710
    umlDriverLock(driver);
2711 2712
    ret = virDomainObjListExport(driver->domains, conn, domains,
                                 virConnectListAllDomainsCheckACL, flags);
2713 2714 2715 2716 2717
    umlDriverUnlock(driver);

    return ret;
}

2718

2719
static int
2720
umlNodeGetInfo(virConnectPtr conn,
2721 2722
               virNodeInfoPtr nodeinfo)
{
2723 2724 2725
    if (virNodeGetInfoEnsureACL(conn) < 0)
        return -1;

2726 2727 2728 2729 2730
    return nodeGetInfo(nodeinfo);
}


static int
2731
umlNodeGetCPUStats(virConnectPtr conn,
2732 2733 2734 2735 2736
                   int cpuNum,
                   virNodeCPUStatsPtr params,
                   int *nparams,
                   unsigned int flags)
{
2737 2738 2739
    if (virNodeGetCPUStatsEnsureACL(conn) < 0)
        return -1;

2740 2741 2742 2743 2744
    return nodeGetCPUStats(cpuNum, params, nparams, flags);
}


static int
2745
umlNodeGetMemoryStats(virConnectPtr conn,
2746 2747 2748 2749 2750
                      int cellNum,
                      virNodeMemoryStatsPtr params,
                      int *nparams,
                      unsigned int flags)
{
2751 2752 2753
    if (virNodeGetMemoryStatsEnsureACL(conn) < 0)
        return -1;

2754 2755 2756 2757 2758
    return nodeGetMemoryStats(cellNum, params, nparams, flags);
}


static int
2759
umlNodeGetCellsFreeMemory(virConnectPtr conn,
2760 2761 2762 2763
                          unsigned long long *freeMems,
                          int startCell,
                          int maxCells)
{
2764 2765 2766
    if (virNodeGetCellsFreeMemoryEnsureACL(conn) < 0)
        return -1;

2767 2768 2769 2770 2771
    return nodeGetCellsFreeMemory(freeMems, startCell, maxCells);
}


static unsigned long long
2772
umlNodeGetFreeMemory(virConnectPtr conn)
2773
{
2774 2775 2776
    if (virNodeGetFreeMemoryEnsureACL(conn) < 0)
        return 0;

2777 2778 2779 2780 2781
    return nodeGetFreeMemory();
}


static int
2782
umlNodeGetMemoryParameters(virConnectPtr conn,
2783 2784 2785 2786
                           virTypedParameterPtr params,
                           int *nparams,
                           unsigned int flags)
{
2787 2788 2789
    if (virNodeGetMemoryParametersEnsureACL(conn) < 0)
        return -1;

2790 2791 2792 2793 2794
    return nodeGetMemoryParameters(params, nparams, flags);
}


static int
2795
umlNodeSetMemoryParameters(virConnectPtr conn,
2796 2797 2798 2799
                           virTypedParameterPtr params,
                           int nparams,
                           unsigned int flags)
{
2800 2801 2802
    if (virNodeSetMemoryParametersEnsureACL(conn) < 0)
        return -1;

2803 2804 2805 2806 2807
    return nodeSetMemoryParameters(params, nparams, flags);
}


static int
2808
umlNodeGetCPUMap(virConnectPtr conn,
2809 2810 2811 2812
                 unsigned char **cpumap,
                 unsigned int *online,
                 unsigned int flags)
{
2813 2814 2815
    if (virNodeGetCPUMapEnsureACL(conn) < 0)
        return -1;

2816 2817 2818
    return nodeGetCPUMap(cpumap, online, flags);
}

2819

2820
static int
2821
umlNodeSuspendForDuration(virConnectPtr conn,
2822 2823 2824 2825
                          unsigned int target,
                          unsigned long long duration,
                          unsigned int flags)
{
2826 2827 2828
    if (virNodeSuspendForDurationEnsureACL(conn) < 0)
        return -1;

2829 2830 2831 2832
    return nodeSuspendForDuration(target, duration, flags);
}


2833
static virDriver umlDriver = {
2834 2835
    .no = VIR_DRV_UML,
    .name = "UML",
2836 2837 2838 2839
    .connectOpen = umlConnectOpen, /* 0.5.0 */
    .connectClose = umlConnectClose, /* 0.5.0 */
    .connectGetType = umlConnectGetType, /* 0.5.0 */
    .connectGetVersion = umlConnectGetVersion, /* 0.5.0 */
2840
    .connectGetHostname = umlConnectGetHostname, /* 0.5.0 */
2841
    .nodeGetInfo = umlNodeGetInfo, /* 0.5.0 */
2842 2843 2844 2845 2846
    .connectGetCapabilities = umlConnectGetCapabilities, /* 0.5.0 */
    .connectListDomains = umlConnectListDomains, /* 0.5.0 */
    .connectNumOfDomains = umlConnectNumOfDomains, /* 0.5.0 */
    .connectListAllDomains = umlConnectListAllDomains, /* 0.9.13 */
    .domainCreateXML = umlDomainCreateXML, /* 0.5.0 */
2847 2848 2849 2850
    .domainLookupByID = umlDomainLookupByID, /* 0.5.0 */
    .domainLookupByUUID = umlDomainLookupByUUID, /* 0.5.0 */
    .domainLookupByName = umlDomainLookupByName, /* 0.5.0 */
    .domainShutdown = umlDomainShutdown, /* 0.5.0 */
2851
    .domainShutdownFlags = umlDomainShutdownFlags, /* 0.9.10 */
2852
    .domainDestroy = umlDomainDestroy, /* 0.5.0 */
2853
    .domainDestroyFlags = umlDomainDestroyFlags, /* 0.9.4 */
2854 2855 2856 2857 2858 2859 2860
    .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 */
2861 2862 2863 2864 2865
    .connectListDefinedDomains = umlConnectListDefinedDomains, /* 0.5.0 */
    .connectNumOfDefinedDomains = umlConnectNumOfDefinedDomains, /* 0.5.0 */
    .domainCreate = umlDomainCreate, /* 0.5.0 */
    .domainCreateWithFlags = umlDomainCreateWithFlags, /* 0.8.2 */
    .domainDefineXML = umlDomainDefineXML, /* 0.5.0 */
2866
    .domainUndefine = umlDomainUndefine, /* 0.5.0 */
2867
    .domainUndefineFlags = umlDomainUndefineFlags, /* 0.9.4 */
2868 2869 2870 2871 2872 2873 2874
    .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 */
2875 2876 2877 2878 2879
    .nodeGetCPUStats = umlNodeGetCPUStats, /* 0.9.3 */
    .nodeGetMemoryStats = umlNodeGetMemoryStats, /* 0.9.3 */
    .nodeGetCellsFreeMemory = umlNodeGetCellsFreeMemory, /* 0.5.0 */
    .nodeGetFreeMemory = umlNodeGetFreeMemory, /* 0.5.0 */
    .nodeGetCPUMap = umlNodeGetCPUMap, /* 1.0.0 */
2880 2881 2882 2883
    .connectDomainEventRegister = umlConnectDomainEventRegister, /* 0.9.4 */
    .connectDomainEventDeregister = umlConnectDomainEventDeregister, /* 0.9.4 */
    .connectIsEncrypted = umlConnectIsEncrypted, /* 0.7.3 */
    .connectIsSecure = umlConnectIsSecure, /* 0.7.3 */
2884 2885 2886
    .domainIsActive = umlDomainIsActive, /* 0.7.3 */
    .domainIsPersistent = umlDomainIsPersistent, /* 0.7.3 */
    .domainIsUpdated = umlDomainIsUpdated, /* 0.8.6 */
2887 2888
    .connectDomainEventRegisterAny = umlConnectDomainEventRegisterAny, /* 0.9.4 */
    .connectDomainEventDeregisterAny = umlConnectDomainEventDeregisterAny, /* 0.9.4 */
2889
    .domainOpenConsole = umlDomainOpenConsole, /* 0.8.6 */
2890
    .connectIsAlive = umlConnectIsAlive, /* 0.9.8 */
2891
    .nodeSuspendForDuration = umlNodeSuspendForDuration, /* 0.9.8 */
2892 2893
    .nodeGetMemoryParameters = umlNodeGetMemoryParameters, /* 0.10.2 */
    .nodeSetMemoryParameters = umlNodeSetMemoryParameters, /* 0.10.2 */
2894 2895 2896
};

static virStateDriver umlStateDriver = {
2897
    .name = "UML",
2898
    .stateInitialize = umlStateInitialize,
2899
    .stateAutoStart = umlStateAutoStart,
2900 2901
    .stateCleanup = umlStateCleanup,
    .stateReload = umlStateReload,
2902 2903 2904 2905 2906 2907 2908
};

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