uml_driver.c 78.3 KB
Newer Older
1 2 3
/*
 * uml_driver.c: core driver methods for managing UML guests
 *
4
 * Copyright (C) 2006-2015 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
 *
 * Author: Daniel P. Berrange <berrange@redhat.com>
 */

#include <config.h>

#include <sys/types.h>
#include <sys/poll.h>
#include <stdarg.h>
#include <unistd.h>
#include <sys/utsname.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <pwd.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <sys/inotify.h>
38
#include <sys/un.h>
39 40 41

#include "uml_driver.h"
#include "uml_conf.h"
42
#include "virbuffer.h"
43
#include "virhostcpu.h"
44
#include "virhostmem.h"
45
#include "capabilities.h"
46
#include "viralloc.h"
47
#include "viruuid.h"
48
#include "domain_conf.h"
49
#include "domain_audit.h"
50
#include "datatypes.h"
51
#include "virlog.h"
52
#include "domain_nwfilter.h"
E
Eric Blake 已提交
53
#include "virfile.h"
54
#include "virfdstream.h"
55
#include "configmake.h"
56
#include "virnetdevtap.h"
57
#include "virnodesuspend.h"
58
#include "virprocess.h"
M
Martin Kletzander 已提交
59
#include "viruri.h"
60
#include "virstring.h"
61
#include "viraccessapicheck.h"
62

63 64
#define VIR_FROM_THIS VIR_FROM_UML

65 66
VIR_LOG_INIT("uml.uml_driver");

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

74 75 76 77 78 79 80 81 82 83
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);

84

85
static int umlStateCleanup(void);
86

87
static void *umlDomainObjPrivateAlloc(void *opaque ATTRIBUTE_UNUSED)
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
{
    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);
}


108 109
static void umlDriverLock(struct uml_driver *driver)
{
110
    virMutexLock(&driver->lock);
111 112 113
}
static void umlDriverUnlock(struct uml_driver *driver)
{
114
    virMutexUnlock(&driver->lock);
115 116
}

117

118
static int umlOpenMonitor(struct uml_driver *driver,
119
                          virDomainObjPtr vm);
120
static int umlReadPidFile(struct uml_driver *driver,
121 122 123 124
                          virDomainObjPtr vm);

static int umlStartVMDaemon(virConnectPtr conn,
                            struct uml_driver *driver,
125 126
                            virDomainObjPtr vm,
                            bool autoDestroy);
127

128
static void umlShutdownVMDaemon(struct uml_driver *driver,
J
Jiri Denemark 已提交
129 130
                                virDomainObjPtr vm,
                                virDomainShutoffReason reason);
131 132


133
static int umlMonitorCommand(const struct uml_driver *driver,
134
                             const virDomainObj *vm,
135 136
                             const char *cmd,
                             char **reply);
137

138
static struct uml_driver *uml_driver;
139

140 141 142 143 144 145 146
static virDomainObjPtr
umlDomObjFromDomainLocked(struct uml_driver *driver,
                          const unsigned char *uuid)
{
    virDomainObjPtr vm;
    char uuidstr[VIR_UUID_STRING_BUFLEN];

147
    if (!(vm = virDomainObjListFindByUUID(driver->domains, uuid))) {
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
        virUUIDFormat(uuid, uuidstr);

        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
        return NULL;
    }

    return vm;
}


static virDomainObjPtr
umlDomObjFromDomain(struct uml_driver *driver,
                    const unsigned char *uuid)
{
    virDomainObjPtr vm;

    umlDriverLock(driver);
    vm = umlDomObjFromDomainLocked(driver, uuid);
    umlDriverUnlock(driver);
    return vm;
}


172 173 174 175 176
struct umlAutostartData {
    struct uml_driver *driver;
    virConnectPtr conn;
};

177 178 179
static int
umlAutostartDomain(virDomainObjPtr vm,
                   void *opaque)
180 181
{
    const struct umlAutostartData *data = opaque;
182
    int ret = 0;
183
    virObjectLock(vm);
184
    if (vm->autostart &&
D
Daniel P. Berrange 已提交
185
        !virDomainObjIsActive(vm)) {
186
        virResetLastError();
187
        ret = umlStartVMDaemon(data->conn, data->driver, vm, false);
188 189
        virDomainAuditStart(vm, "booted", ret >= 0);
        if (ret < 0) {
190 191
            virReportError(VIR_ERR_INTERNAL_ERROR, _("Failed to autostart VM '%s': %s"),
                           vm->def->name, virGetLastErrorMessage());
192
        } else {
193
            virObjectEventPtr event =
194
                virDomainEventLifecycleNewFromObj(vm,
195 196
                                         VIR_DOMAIN_EVENT_STARTED,
                                         VIR_DOMAIN_EVENT_STARTED_BOOTED);
197
            virObjectEventStateQueue(data->driver->domainEventState, event);
198 199
        }
    }
200
    virObjectUnlock(vm);
201
    return ret;
202
}
203 204

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

217 218
    struct umlAutostartData data = { driver, conn };

219
    umlDriverLock(driver);
220
    virDomainObjListForEach(driver->domains, umlAutostartDomain, &data);
221
    umlDriverUnlock(driver);
222

223
    virObjectUnref(conn);
224 225 226 227
}


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

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

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

static int
267
umlIdentifyChrPTY(struct uml_driver *driver,
268 269
                  virDomainObjPtr dom)
{
270
    size_t i;
271

272
    for (i = 0; i < dom->def->nconsoles; i++)
273
        if (dom->def->consoles[i]->source->type == VIR_DOMAIN_CHR_TYPE_PTY)
274
        if (umlIdentifyOneChrPTY(driver, dom,
275
                                 dom->def->consoles[i], "con") < 0)
276 277
            return -1;

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

301
    umlDriverLock(driver);
302
    if (watch != driver->inotifyWatch)
303
        goto cleanup;
304

305
 reread:
306 307 308 309
    got = read(fd, buf, sizeof(buf));
    if (got == -1) {
        if (errno == EINTR)
            goto reread;
310
        goto cleanup;
311 312 313 314
    }

    tmp = buf;
    while (got) {
315
        if (got < sizeof(e))
316
            goto cleanup; /* bad */
317

318 319 320
        memcpy(&e, tmp, sizeof(e));
        tmp += sizeof(e);
        got -= sizeof(e);
321

322
        if (got < e.len)
323
            goto cleanup;
324

325 326
        tmp += e.len;
        got -= e.len;
327

328
        name = (char *)&(e.name);
329

330
        dom = virDomainObjListFindByName(driver->domains, name);
331

332
        if (!dom)
333 334
            continue;

335
        if (e.mask & IN_DELETE) {
336
            VIR_DEBUG("Got inotify domain shutdown '%s'", name);
D
Daniel P. Berrange 已提交
337
            if (!virDomainObjIsActive(dom)) {
338
                virDomainObjEndAPI(&dom);
339 340 341
                continue;
            }

342
            umlShutdownVMDaemon(driver, dom, VIR_DOMAIN_SHUTOFF_SHUTDOWN);
343
            virDomainAuditStop(dom, "shutdown");
344
            event = virDomainEventLifecycleNewFromObj(dom,
345 346
                                             VIR_DOMAIN_EVENT_STOPPED,
                                             VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN);
347
            if (!dom->persistent)
348
                virDomainObjListRemove(driver->domains, dom);
349
        } else if (e.mask & (IN_CREATE | IN_MODIFY)) {
350
            VIR_DEBUG("Got inotify domain startup '%s'", name);
D
Daniel P. Berrange 已提交
351
            if (virDomainObjIsActive(dom)) {
352
                virDomainObjEndAPI(&dom);
353 354 355
                continue;
            }

356
            if (umlReadPidFile(driver, dom) < 0) {
357
                virDomainObjEndAPI(&dom);
358 359 360 361
                continue;
            }

            dom->def->id = driver->nextvmid++;
362 363 364 365 366

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

J
Jiri Denemark 已提交
367 368
            virDomainObjSetState(dom, VIR_DOMAIN_RUNNING,
                                 VIR_DOMAIN_RUNNING_BOOTED);
369

370
            if (umlOpenMonitor(driver, dom) < 0) {
371
                VIR_WARN("Could not open monitor for new domain");
372
                umlShutdownVMDaemon(driver, dom,
J
Jiri Denemark 已提交
373
                                    VIR_DOMAIN_SHUTOFF_FAILED);
374
                virDomainAuditStop(dom, "failed");
375
                event = virDomainEventLifecycleNewFromObj(dom,
376 377
                                                 VIR_DOMAIN_EVENT_STOPPED,
                                                 VIR_DOMAIN_EVENT_STOPPED_FAILED);
378
                if (!dom->persistent)
379
                    virDomainObjListRemove(driver->domains, dom);
380
            } else if (umlIdentifyChrPTY(driver, dom) < 0) {
381
                VIR_WARN("Could not identify character devices for new domain");
382
                umlShutdownVMDaemon(driver, dom,
J
Jiri Denemark 已提交
383
                                    VIR_DOMAIN_SHUTOFF_FAILED);
384
                virDomainAuditStop(dom, "failed");
385
                event = virDomainEventLifecycleNewFromObj(dom,
386 387
                                                 VIR_DOMAIN_EVENT_STOPPED,
                                                 VIR_DOMAIN_EVENT_STOPPED_FAILED);
388
                if (!dom->persistent)
389
                    virDomainObjListRemove(driver->domains, dom);
390
            }
391
        }
392
        virDomainObjEndAPI(&dom);
393 394
        virObjectEventStateQueue(driver->domainEventState, event);
        event = NULL;
395
    }
396

397
 cleanup:
398
    umlDriverUnlock(driver);
399 400
}

401 402 403

static int
umlDomainDeviceDefPostParse(virDomainDeviceDefPtr dev,
404 405
                            const virDomainDef *def ATTRIBUTE_UNUSED,
                            virCapsPtr caps ATTRIBUTE_UNUSED,
406
                            unsigned int parseFlags ATTRIBUTE_UNUSED,
407 408
                            void *opaque ATTRIBUTE_UNUSED,
                            void *parseOpaque ATTRIBUTE_UNUSED)
409 410 411 412 413 414
{
    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;

415 416 417 418 419 420 421 422 423 424
    /* forbid capabilities mode hostdev in this kind of hypervisor */
    if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV &&
        dev->data.hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("hostdev mode 'capabilities' is not "
                         "supported in %s"),
                       virDomainVirtTypeToString(def->virtType));
        return -1;
    }

425 426 427 428
    return 0;
}


429
static int
430
umlDomainDefPostParse(virDomainDefPtr def ATTRIBUTE_UNUSED,
431
                      virCapsPtr caps ATTRIBUTE_UNUSED,
432
                      unsigned int parseFlags ATTRIBUTE_UNUSED,
433 434
                      void *opaque ATTRIBUTE_UNUSED,
                      void *parseOpaque ATTRIBUTE_UNUSED)
435 436 437 438 439
{
    return 0;
}


440 441
virDomainDefParserConfig umlDriverDomainDefParserConfig = {
    .devicesPostParseCallback = umlDomainDeviceDefPostParse,
442
    .domainPostParseCallback = umlDomainDefPostParse,
443 444 445
};


446 447 448 449 450 451
/**
 * umlStartup:
 *
 * Initialization function for the Uml daemon
 */
static int
452 453 454
umlStateInitialize(bool privileged,
                   virStateInhibitCallback callback,
                   void *opaque)
455
{
456
    char *base = NULL;
457
    char *userdir = NULL;
458

459 460 461 462 463
    virDomainXMLPrivateDataCallbacks privcb = {
        .alloc = umlDomainObjPrivateAlloc,
        .free = umlDomainObjPrivateFree,
    };

464 465 466
    if (VIR_ALLOC(uml_driver) < 0)
        return -1;

467
    uml_driver->privileged = privileged;
468 469
    uml_driver->inhibitCallback = callback;
    uml_driver->inhibitOpaque = opaque;
470

471 472 473 474
    if (virMutexInit(&uml_driver->lock) < 0) {
        VIR_FREE(uml_driver);
        return -1;
    }
475 476
    umlDriverLock(uml_driver);

477 478
    /* Don't have a dom0 so start from 1 */
    uml_driver->nextvmid = 1;
479
    uml_driver->inotifyWatch = -1;
480

481
    if (!(uml_driver->domains = virDomainObjListNew()))
482 483
        goto error;

484
    uml_driver->domainEventState = virObjectEventStateNew();
485 486 487
    if (!uml_driver->domainEventState)
        goto error;

488
    userdir = virGetUserDirectory();
489
    if (!userdir)
490
        goto error;
491

492
    if (privileged) {
493
        if (virAsprintf(&uml_driver->logDir,
494
                        "%s/log/libvirt/uml", LOCALSTATEDIR) == -1)
495 496
            goto out_of_memory;

497 498
        if (VIR_STRDUP(base, SYSCONFDIR "/libvirt") < 0)
            goto error;
499 500

        if (virAsprintf(&uml_driver->monitorDir,
501
                        "%s/run/libvirt/uml-guest", LOCALSTATEDIR) == -1)
502
            goto out_of_memory;
503
    } else {
504
        base = virGetUserConfigDirectory();
505 506
        if (!base)
            goto error;
507

508
        if (virAsprintf(&uml_driver->logDir,
509
                        "%s/uml/log", base) == -1)
510 511
            goto out_of_memory;

512 513 514 515
        if (virAsprintf(&uml_driver->monitorDir,
                        "%s/.uml", userdir) == -1)
            goto out_of_memory;
    }
516

517
    /* Configuration paths are either $XDG_CONFIG_HOME/libvirt/uml/... (session) or
518 519
     * /etc/libvirt/uml/... (system).
     */
520
    if (virAsprintf(&uml_driver->configDir, "%s/uml", base) == -1)
521 522
        goto out_of_memory;

523
    if (virAsprintf(&uml_driver->autostartDir, "%s/uml/autostart", base) == -1)
524 525 526 527 528 529 530
        goto out_of_memory;

    VIR_FREE(base);

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

531
    if (!(uml_driver->xmlopt = virDomainXMLOptionNew(&umlDriverDomainDefParserConfig,
532
                                                     &privcb, NULL, NULL, NULL)))
533
        goto error;
534 535

    if ((uml_driver->inotifyFD = inotify_init()) < 0) {
536
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot initialize inotify"));
537
        goto error;
538 539
    }

540
    if (virFileMakePath(uml_driver->monitorDir) < 0) {
541 542
        virReportSystemError(errno, _("Failed to create monitor directory %s"),
                             uml_driver->monitorDir);
543
        goto error;
544 545
    }

546
    VIR_INFO("Adding inotify watch on %s", uml_driver->monitorDir);
547 548 549
    if (inotify_add_watch(uml_driver->inotifyFD,
                          uml_driver->monitorDir,
                          IN_CREATE | IN_MODIFY | IN_DELETE) < 0) {
550 551
        virReportSystemError(errno, _("Failed to create inotify watch on %s"),
                             uml_driver->monitorDir);
552
        goto error;
553 554
    }

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

560 561 562
    if (umlProcessAutoDestroyInit(uml_driver) < 0)
        goto error;

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

571 572
    umlDriverUnlock(uml_driver);

573 574
    VIR_FREE(userdir);

575 576
    return 0;

577
 out_of_memory:
578
    virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("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
static void umlNotifyLoadDomain(virDomainObjPtr vm, int newVM, void *opaque)
{
    struct uml_driver *driver = opaque;

    if (newVM) {
607
        virObjectEventPtr event =
608
            virDomainEventLifecycleNewFromObj(vm,
609 610
                                     VIR_DOMAIN_EVENT_DEFINED,
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED);
611
        virObjectEventStateQueue(driver->domainEventState, event);
612 613 614 615
    }
}


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

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

    return 0;
}


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

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

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

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

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

677
    virObjectUnref(uml_driver->domains);
678

679
    virObjectUnref(uml_driver->domainEventState);
680

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

686 687
    umlProcessAutoDestroyShutdown(uml_driver);

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

    return 0;
}


696 697 698 699 700 701 702 703 704 705 706 707 708
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;
};

709 710 711
static int umlProcessAutoDestroyDom(void *payload,
                                    const void *name,
                                    void *opaque)
712 713 714 715 716 717
{
    struct umlProcessAutoDestroyData *data = opaque;
    virConnectPtr conn = payload;
    const char *uuidstr = name;
    unsigned char uuid[VIR_UUID_BUFLEN];
    virDomainObjPtr dom;
718
    virObjectEventPtr event = NULL;
719 720 721 722

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

    if (data->conn != conn)
723
        return 0;
724 725 726

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

730
    if (!(dom = virDomainObjListFindByUUID(data->driver->domains, uuid))) {
731
        VIR_DEBUG("No domain object to kill");
732
        return 0;
733 734 735 736 737
    }

    VIR_DEBUG("Killing domain");
    umlShutdownVMDaemon(data->driver, dom, VIR_DOMAIN_SHUTOFF_DESTROYED);
    virDomainAuditStop(dom, "destroyed");
738
    event = virDomainEventLifecycleNewFromObj(dom,
739 740 741
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_DESTROYED);

742
    if (!dom->persistent)
743
        virDomainObjListRemove(data->driver->domains, dom);
744

745
    virDomainObjEndAPI(&dom);
746
    virObjectEventStateQueue(data->driver->domainEventState, event);
747
    virHashRemoveEntry(data->driver->autodestroy, uuidstr);
748
    return 0;
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
}

/*
 * 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;
}


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

    vm->pid = -1;
801
    if (virAsprintf(&pidfile, "%s/%s/pid",
802
                    driver->monitorDir, vm->def->name) < 0)
803 804
        return -1;

805
 reopen:
806 807 808 809 810 811 812 813 814 815 816
    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;
817
        VIR_FORCE_FCLOSE(file);
818 819 820
        goto cleanup;
    }

821
    if (VIR_FCLOSE(file) < 0)
822 823 824 825 826 827
        goto cleanup;

    rc = 0;

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

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

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

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

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

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

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

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

885
    memset(addr.sun_path, 0, sizeof(addr.sun_path));
E
Eric Blake 已提交
886 887
    snprintf(addr.sun_path + 1, sizeof(addr.sun_path) - 1,
             "libvirt-uml-%u", vm->pid);
888
    VIR_DEBUG("Reply address for monitor is '%s'", addr.sun_path+1);
889
    if (bind(priv->monitor, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
890
        virReportSystemError(errno,
891
                             "%s", _("cannot bind socket"));
892
        VIR_FORCE_CLOSE(priv->monitor);
893 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
        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];
};


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

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

934 935
    *reply = NULL;

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

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

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

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

        if (res.error)
            ret = -1;

    } while (res.extra);

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

994 995 996 997
    if (ret < 0)
        VIR_FREE(retdata);
    else
        *reply = retdata;
998 999 1000

    return ret;

1001
 error:
1002 1003 1004 1005 1006
    VIR_FREE(retdata);
    return -1;
}


1007 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 1019
        ignore_value(virNetDevTapDelete(def->ifname,
                                        def->backend.tap));
1020 1021 1022
    }
}

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

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

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

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

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

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

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

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

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

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

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

1106
    priv->monitor = -1;
1107

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

J
Ján Tomko 已提交
1113
    if (virCommandRun(cmd, NULL) < 0)
1114
        goto cleanup;
1115

1116
    if (autoDestroy &&
J
Ján Tomko 已提交
1117
        umlProcessAutoDestroyAdd(driver, vm, conn) < 0)
1118 1119
        goto cleanup;

1120
    ret = 0;
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
        virDomainObjRemoveTransientDef(vm);
1129 1130
    }

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

    return ret;
}

1141
static void umlShutdownVMDaemon(struct uml_driver *driver,
J
Jiri Denemark 已提交
1142 1143
                                virDomainObjPtr vm,
                                virDomainShutoffReason reason)
1144 1145
{
    int ret;
1146 1147
    umlDomainObjPrivatePtr priv = vm->privateData;

D
Daniel P. Berrange 已提交
1148
    if (!virDomainObjIsActive(vm))
1149 1150
        return;

1151
    virProcessKill(vm->pid, SIGTERM);
1152

1153
    VIR_FORCE_CLOSE(priv->monitor);
1154 1155

    if ((ret = waitpid(vm->pid, NULL, 0)) != vm->pid) {
1156
        VIR_WARN("Got unexpected pid %d != %d",
1157 1158 1159 1160 1161
               ret, vm->pid);
    }

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

1164
    virDomainConfVMNWFilterTeardown(vm);
1165 1166 1167 1168
    umlCleanupTapDevices(vm);

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

1170
    virDomainObjRemoveTransientDef(vm);
1171 1172 1173 1174

    driver->nactive--;
    if (!driver->nactive && driver->inhibitCallback)
        driver->inhibitCallback(false, driver->inhibitOpaque);
1175 1176 1177
}


1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188
static int umlConnectURIProbe(char **uri)
{
    if (uml_driver == NULL)
        return 0;

    return VIR_STRDUP(*uri, uml_driver->privileged ?
                      "uml:///system" :
                      "uml:///session");
}


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

1196 1197 1198 1199 1200 1201 1202
    /* URI was good, but driver isn't active */
    if (uml_driver == NULL) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("uml state driver is not active"));
        return VIR_DRV_OPEN_ERROR;
    }

1203 1204 1205 1206 1207 1208 1209 1210
    /* Check path and tell them correct path if they made a mistake */
    if (uml_driver->privileged) {
        if (STRNEQ(conn->uri->path, "/system") &&
            STRNEQ(conn->uri->path, "/session")) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected UML URI path '%s', try uml:///system"),
                           conn->uri->path);
            return VIR_DRV_OPEN_ERROR;
1211
        }
1212 1213 1214 1215 1216
    } else {
        if (STRNEQ(conn->uri->path, "/session")) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected UML URI path '%s', try uml:///session"),
                           conn->uri->path);
1217 1218 1219 1220
            return VIR_DRV_OPEN_ERROR;
        }
    }

1221 1222 1223
    if (virConnectOpenEnsureACL(conn) < 0)
        return VIR_DRV_OPEN_ERROR;

1224 1225 1226 1227 1228
    conn->privateData = uml_driver;

    return VIR_DRV_OPEN_SUCCESS;
}

1229 1230
static int umlConnectClose(virConnectPtr conn)
{
1231 1232 1233
    struct uml_driver *driver = conn->privateData;

    umlDriverLock(driver);
1234
    umlProcessAutoDestroyRun(driver, conn);
1235
    umlDriverUnlock(driver);
1236 1237 1238 1239 1240 1241

    conn->privateData = NULL;

    return 0;
}

1242 1243 1244 1245
static const char *umlConnectGetType(virConnectPtr conn) {
    if (virConnectGetTypeEnsureACL(conn) < 0)
        return NULL;

1246 1247 1248 1249
    return "UML";
}


1250
static int umlConnectIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED)
1251 1252 1253 1254 1255 1256
{
    /* Trivially secure, since always inside the daemon */
    return 1;
}


1257
static int umlConnectIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED)
1258 1259 1260 1261 1262 1263
{
    /* Not encrypted, but remote driver takes care of that */
    return 0;
}


1264
static int umlConnectIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED)
1265 1266 1267 1268 1269
{
    return 1;
}


1270
static char *umlConnectGetCapabilities(virConnectPtr conn) {
1271 1272 1273
    struct uml_driver *driver = (struct uml_driver *)conn->privateData;
    char *xml;

1274 1275 1276
    if (virConnectGetCapabilitiesEnsureACL(conn) < 0)
        return NULL;

1277
    umlDriverLock(driver);
1278
    xml = virCapabilitiesFormatXML(driver->caps);
1279
    umlDriverUnlock(driver);
1280 1281 1282 1283 1284 1285

    return xml;
}



1286
static int umlGetProcessInfo(unsigned long long *cpuTime, pid_t pid)
1287 1288
{
    char *proc;
1289 1290 1291
    FILE *pidinfo;
    unsigned long long usertime, systime;

1292
    if (virAsprintf(&proc, "/proc/%lld/stat", (long long)pid) < 0)
1293 1294 1295 1296 1297
        return -1;

    if (!(pidinfo = fopen(proc, "r"))) {
        /* VM probably shut down, so fake 0 */
        *cpuTime = 0;
1298
        VIR_FREE(proc);
1299 1300 1301
        return 0;
    }

1302 1303
    VIR_FREE(proc);

1304 1305
    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");
1306
        VIR_FORCE_FCLOSE(pidinfo);
1307 1308 1309 1310 1311 1312
        return -1;
    }

    /* We got jiffies
     * We want nanoseconds
     * _SC_CLK_TCK is jiffies per second
N
Nehal J Wani 已提交
1313
     * So calculate thus....
1314 1315 1316 1317 1318
     */
    *cpuTime = 1000ull * 1000ull * 1000ull * (usertime + systime) / (unsigned long long)sysconf(_SC_CLK_TCK);

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

1319
    VIR_FORCE_FCLOSE(pidinfo);
1320 1321 1322 1323 1324 1325

    return 0;
}


static virDomainPtr umlDomainLookupByID(virConnectPtr conn,
1326 1327
                                          int id)
{
1328
    struct uml_driver *driver = (struct uml_driver *)conn->privateData;
1329 1330
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
1331

1332
    umlDriverLock(driver);
1333
    vm = virDomainObjListFindByID(driver->domains, id);
1334 1335
    umlDriverUnlock(driver);

1336
    if (!vm) {
1337 1338
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching id '%d'"), id);
1339
        goto cleanup;
1340 1341
    }

1342 1343 1344
    if (virDomainLookupByIDEnsureACL(conn, vm->def) < 0)
        goto cleanup;

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

1347
 cleanup:
1348
    virDomainObjEndAPI(&vm);
1349 1350
    return dom;
}
1351

1352
static virDomainPtr umlDomainLookupByUUID(virConnectPtr conn,
1353
                                          const unsigned char *uuid)
1354
{
1355
    struct uml_driver *driver = (struct uml_driver *)conn->privateData;
1356 1357
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
1358

1359 1360
    if (!(vm = umlDomObjFromDomain(driver, uuid)))
        return NULL;
1361

1362 1363 1364
    if (virDomainLookupByUUIDEnsureACL(conn, vm->def) < 0)
        goto cleanup;

1365
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid, vm->def->id);
1366

1367
 cleanup:
1368
    virDomainObjEndAPI(&vm);
1369 1370
    return dom;
}
1371

1372
static virDomainPtr umlDomainLookupByName(virConnectPtr conn,
1373 1374
                                            const char *name)
{
1375
    struct uml_driver *driver = (struct uml_driver *)conn->privateData;
1376 1377
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
1378

1379
    umlDriverLock(driver);
1380
    vm = virDomainObjListFindByName(driver->domains, name);
1381 1382
    umlDriverUnlock(driver);

1383
    if (!vm) {
1384 1385
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching name '%s'"), name);
1386
        goto cleanup;
1387 1388
    }

1389 1390 1391
    if (virDomainLookupByNameEnsureACL(conn, vm->def) < 0)
        goto cleanup;

1392
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid, vm->def->id);
1393

1394
 cleanup:
1395
    virDomainObjEndAPI(&vm);
1396 1397 1398
    return dom;
}

1399 1400 1401 1402 1403 1404 1405

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

1406 1407
    if (!(obj = umlDomObjFromDomain(driver, dom->uuid)))
        return -1;
1408 1409 1410 1411

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

1412 1413
    ret = virDomainObjIsActive(obj);

1414
 cleanup:
1415
    virDomainObjEndAPI(&obj);
1416 1417 1418 1419 1420 1421 1422 1423 1424 1425
    return ret;
}


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

1426 1427
    if (!(obj = umlDomObjFromDomain(driver, dom->uuid)))
        return -1;
1428 1429 1430 1431

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

1432 1433
    ret = obj->persistent;

1434
 cleanup:
1435
    virDomainObjEndAPI(&obj);
1436 1437 1438
    return ret;
}

1439 1440 1441 1442 1443 1444
static int umlDomainIsUpdated(virDomainPtr dom)
{
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr obj;
    int ret = -1;

1445 1446
    if (!(obj = umlDomObjFromDomain(driver, dom->uuid)))
        return -1;
1447 1448 1449 1450

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

1451 1452
    ret = obj->updated;

1453
 cleanup:
1454
    virDomainObjEndAPI(&obj);
1455 1456
    return ret;
}
1457

1458 1459
static int umlConnectGetVersion(virConnectPtr conn, unsigned long *version)
{
1460
    struct uml_driver *driver = conn->privateData;
1461
    struct utsname ut;
1462
    int ret = -1;
1463

1464 1465 1466
    if (virConnectGetVersionEnsureACL(conn) < 0)
        return -1;

1467
    umlDriverLock(driver);
1468 1469 1470 1471

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

1472
        if (virParseVersionString(ut.release, &driver->umlVersion, true) < 0) {
1473
            virReportError(VIR_ERR_INTERNAL_ERROR,
1474 1475 1476
                           _("cannot parse version %s"), ut.release);
            goto cleanup;
        }
1477 1478
    }

1479 1480 1481
    *version = driver->umlVersion;
    ret = 0;

1482
 cleanup:
1483 1484
    umlDriverUnlock(driver);
    return ret;
1485 1486
}

1487

1488
static char *umlConnectGetHostname(virConnectPtr conn)
1489
{
1490 1491 1492
    if (virConnectGetHostnameEnsureACL(conn) < 0)
        return NULL;

1493 1494 1495 1496
    return virGetHostname();
}


1497 1498
static int umlConnectListDomains(virConnectPtr conn, int *ids, int nids)
{
1499
    struct uml_driver *driver = conn->privateData;
1500
    int n;
1501

1502 1503 1504
    if (virConnectListDomainsEnsureACL(conn) < 0)
        return -1;

1505
    umlDriverLock(driver);
1506 1507
    n = virDomainObjListGetActiveIDs(driver->domains, ids, nids,
                                     virConnectListDomainsCheckACL, conn);
1508
    umlDriverUnlock(driver);
1509

1510
    return n;
1511
}
1512 1513
static int umlConnectNumOfDomains(virConnectPtr conn)
{
1514
    struct uml_driver *driver = conn->privateData;
1515
    int n;
1516

1517 1518 1519
    if (virConnectNumOfDomainsEnsureACL(conn) < 0)
        return -1;

1520
    umlDriverLock(driver);
1521 1522
    n = virDomainObjListNumOfDomains(driver->domains, true,
                                     virConnectNumOfDomainsCheckACL, conn);
1523
    umlDriverUnlock(driver);
1524 1525 1526

    return n;
}
1527
static virDomainPtr umlDomainCreateXML(virConnectPtr conn, const char *xml,
1528 1529
                                       unsigned int flags)
{
1530
    struct uml_driver *driver = conn->privateData;
1531
    virDomainDefPtr def;
1532
    virDomainObjPtr vm = NULL;
1533
    virDomainPtr dom = NULL;
1534
    virObjectEventPtr event = NULL;
1535
    unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
1536

1537 1538 1539 1540
    virCheckFlags(VIR_DOMAIN_START_AUTODESTROY |
                  VIR_DOMAIN_START_VALIDATE, NULL);

    if (flags & VIR_DOMAIN_START_VALIDATE)
1541
        parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA;
1542

1543
    virNWFilterReadLockFilterUpdates();
1544
    umlDriverLock(driver);
1545
    if (!(def = virDomainDefParseString(xml, driver->caps, driver->xmlopt,
1546
                                        NULL, parse_flags)))
1547
        goto cleanup;
1548

1549 1550 1551
    if (virDomainCreateXMLEnsureACL(conn, def) < 0)
        goto cleanup;

1552
    if (!(vm = virDomainObjListAdd(driver->domains, def,
1553
                                   driver->xmlopt,
1554
                                   VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
1555 1556
                                   VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
                                   NULL)))
1557 1558
        goto cleanup;
    def = NULL;
1559

1560 1561
    if (umlStartVMDaemon(conn, driver, vm,
                         (flags & VIR_DOMAIN_START_AUTODESTROY)) < 0) {
1562
        virDomainAuditStart(vm, "booted", false);
1563
        if (!vm->persistent)
1564
            virDomainObjListRemove(driver->domains, vm);
1565
        goto cleanup;
1566
    }
1567
    virDomainAuditStart(vm, "booted", true);
1568
    event = virDomainEventLifecycleNewFromObj(vm,
1569 1570
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_BOOTED);
1571

1572
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid, vm->def->id);
1573

1574
 cleanup:
1575
    virDomainDefFree(def);
1576
    virDomainObjEndAPI(&vm);
1577
    virObjectEventStateQueue(driver->domainEventState, event);
1578
    umlDriverUnlock(driver);
1579
    virNWFilterUnlockFilterUpdates();
1580 1581 1582 1583
    return dom;
}


1584
static int umlDomainShutdownFlags(virDomainPtr dom,
1585 1586
                                  unsigned int flags)
{
1587 1588
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
1589
    char *info = NULL;
1590
    int ret = -1;
1591

1592 1593
    virCheckFlags(0, -1);

1594 1595
    if (!(vm = umlDomObjFromDomain(driver, dom->uuid)))
        return -1;
1596

1597
    if (virDomainShutdownFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
1598 1599
        goto cleanup;

1600 1601
#if 0
    if (umlMonitorCommand(driver, vm, "system_powerdown", &info) < 0) {
1602
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
1603
                       _("shutdown operation failed"));
1604
        goto cleanup;
1605
    }
1606
    ret = 0;
1607 1608
#endif

1609
 cleanup:
1610
    VIR_FREE(info);
1611
    virDomainObjEndAPI(&vm);
1612
    return ret;
1613 1614
}

1615 1616 1617 1618 1619
static int
umlDomainShutdown(virDomainPtr dom)
{
    return umlDomainShutdownFlags(dom, 0);
}
1620

1621 1622 1623 1624
static int
umlDomainDestroyFlags(virDomainPtr dom,
                      unsigned int flags)
{
1625 1626
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
1627
    virObjectEventPtr event = NULL;
1628
    int ret = -1;
1629

1630 1631
    virCheckFlags(0, -1);

1632
    umlDriverLock(driver);
1633 1634
    if (!(vm = umlDomObjFromDomainLocked(driver, dom->uuid)))
        return -1;
1635

1636 1637 1638
    if (virDomainDestroyFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

1639
    umlShutdownVMDaemon(driver, vm, VIR_DOMAIN_SHUTOFF_DESTROYED);
1640
    virDomainAuditStop(vm, "destroyed");
1641
    event = virDomainEventLifecycleNewFromObj(vm,
1642 1643
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
1644
    if (!vm->persistent)
1645
        virDomainObjListRemove(driver->domains, vm);
1646
    ret = 0;
1647

1648
 cleanup:
1649
    virDomainObjEndAPI(&vm);
1650
    virObjectEventStateQueue(driver->domainEventState, event);
1651
    umlDriverUnlock(driver);
1652
    return ret;
1653 1654 1655
}


1656 1657 1658 1659 1660 1661
static int umlDomainDestroy(virDomainPtr dom)
{
    return umlDomainDestroyFlags(dom, 0);
}


1662
static char *umlDomainGetOSType(virDomainPtr dom) {
1663 1664 1665
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *type = NULL;
1666

1667 1668
    if (!(vm = umlDomObjFromDomain(driver, dom->uuid)))
        return NULL;
1669

1670 1671 1672
    if (virDomainGetOSTypeEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

1673
    if (VIR_STRDUP(type, virDomainOSTypeToString(vm->def->os.type)) < 0)
1674
        goto cleanup;
1675

1676
 cleanup:
1677
    virDomainObjEndAPI(&vm);
1678 1679 1680 1681
    return type;
}

/* Returns max memory in kb, 0 if error */
1682 1683 1684
static unsigned long long
umlDomainGetMaxMemory(virDomainPtr dom)
{
1685 1686
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
1687
    unsigned long long ret = 0;
1688

1689 1690
    if (!(vm = umlDomObjFromDomain(driver, dom->uuid)))
        return -1;
1691 1692 1693 1694

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

1695
    ret = virDomainDefGetMemoryTotal(vm->def);
1696

1697
 cleanup:
1698
    virDomainObjEndAPI(&vm);
1699
    return ret;
1700 1701
}

1702 1703
static int umlDomainSetMaxMemory(virDomainPtr dom, unsigned long newmax)
{
1704 1705 1706
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
1707

1708 1709
    if (!(vm = umlDomObjFromDomain(driver, dom->uuid)))
        return -1;
1710

1711 1712 1713
    if (virDomainSetMaxMemoryEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

1714
    if (newmax < vm->def->mem.cur_balloon) {
1715
        virReportError(VIR_ERR_INVALID_ARG, "%s",
1716
                       _("cannot set max memory lower than current memory"));
1717
        goto cleanup;
1718 1719
    }

1720
    virDomainDefSetMemoryTotal(vm->def, newmax);
1721 1722
    ret = 0;

1723
 cleanup:
1724
    virDomainObjEndAPI(&vm);
1725
    return ret;
1726 1727
}

1728 1729
static int umlDomainSetMemory(virDomainPtr dom, unsigned long newmem)
{
1730 1731 1732
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
1733

1734 1735
    if (!(vm = umlDomObjFromDomain(driver, dom->uuid)))
        return -1;
1736

1737 1738 1739
    if (virDomainSetMemoryEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

D
Daniel P. Berrange 已提交
1740
    if (virDomainObjIsActive(vm)) {
1741
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
1742
                       _("cannot set memory of an active domain"));
1743
        goto cleanup;
1744 1745
    }

1746
    if (newmem > virDomainDefGetMemoryTotal(vm->def)) {
1747
        virReportError(VIR_ERR_INVALID_ARG, "%s",
1748
                       _("cannot set memory higher than max memory"));
1749
        goto cleanup;
1750 1751
    }

1752
    vm->def->mem.cur_balloon = newmem;
1753 1754
    ret = 0;

1755
 cleanup:
1756
    virDomainObjEndAPI(&vm);
1757
    return ret;
1758 1759 1760
}

static int umlDomainGetInfo(virDomainPtr dom,
1761 1762
                              virDomainInfoPtr info)
{
1763 1764 1765 1766
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;

1767 1768
    if (!(vm = umlDomObjFromDomain(driver, dom->uuid)))
        return -1;
1769

1770 1771 1772
    if (virDomainGetInfoEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

D
Daniel P. Berrange 已提交
1775
    if (!virDomainObjIsActive(vm)) {
1776 1777 1778
        info->cpuTime = 0;
    } else {
        if (umlGetProcessInfo(&(info->cpuTime), vm->pid) < 0) {
1779
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
1780
                           _("cannot read cputime for domain"));
1781
            goto cleanup;
1782 1783 1784
        }
    }

1785
    info->maxMem = virDomainDefGetMemoryTotal(vm->def);
1786
    info->memory = vm->def->mem.cur_balloon;
1787
    info->nrVirtCpu = virDomainDefGetVcpus(vm->def);
1788 1789
    ret = 0;

1790
 cleanup:
1791
    virDomainObjEndAPI(&vm);
1792
    return ret;
1793 1794 1795
}


1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807
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);

1808 1809
    if (!(vm = umlDomObjFromDomain(driver, dom->uuid)))
        return -1;
1810

1811 1812 1813
    if (virDomainGetStateEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

J
Jiri Denemark 已提交
1814
    *state = virDomainObjGetState(vm, reason);
1815 1816
    ret = 0;

1817
 cleanup:
1818
    virDomainObjEndAPI(&vm);
1819 1820 1821 1822
    return ret;
}


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

1830
    /* Flags checked by virDomainDefFormat */
E
Eric Blake 已提交
1831

1832
    umlDriverLock(driver);
1833
    if (!(vm = umlDomObjFromDomainLocked(driver, dom->uuid)))
1834
        goto cleanup;
1835

1836 1837 1838
    if (virDomainGetXMLDescEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

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

1843
 cleanup:
1844
    virDomainObjEndAPI(&vm);
1845
    return ret;
1846 1847 1848
}


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

1854 1855 1856
    if (virConnectListDefinedDomainsEnsureACL(conn) < 0)
        return -1;

1857
    umlDriverLock(driver);
1858 1859
    n = virDomainObjListGetInactiveNames(driver->domains, names, nnames,
                                         virConnectListDefinedDomainsCheckACL, conn);
1860
    umlDriverUnlock(driver);
1861

1862
    return n;
1863 1864
}

1865 1866
static int umlConnectNumOfDefinedDomains(virConnectPtr conn)
{
1867
    struct uml_driver *driver = conn->privateData;
1868
    int n;
1869

1870 1871 1872
    if (virConnectNumOfDefinedDomainsEnsureACL(conn) < 0)
        return -1;

1873
    umlDriverLock(driver);
1874 1875
    n = virDomainObjListNumOfDomains(driver->domains, false,
                                     virConnectNumOfDefinedDomainsCheckACL, conn);
1876
    umlDriverUnlock(driver);
1877 1878 1879 1880 1881

    return n;
}


1882 1883
static int umlDomainCreateWithFlags(virDomainPtr dom, unsigned int flags)
{
1884 1885
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
1886
    virObjectEventPtr event = NULL;
1887
    int ret = -1;
1888

1889
    virCheckFlags(VIR_DOMAIN_START_AUTODESTROY, -1);
1890

1891
    virNWFilterReadLockFilterUpdates();
1892
    umlDriverLock(driver);
1893
    if (!(vm = umlDomObjFromDomainLocked(driver, dom->uuid)))
1894
        goto cleanup;
1895

1896 1897 1898
    if (virDomainCreateWithFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

1899 1900
    ret = umlStartVMDaemon(dom->conn, driver, vm,
                           (flags & VIR_DOMAIN_START_AUTODESTROY));
1901
    virDomainAuditStart(vm, "booted", ret >= 0);
1902
    if (ret == 0)
1903
        event = virDomainEventLifecycleNewFromObj(vm,
1904 1905
                                         VIR_DOMAIN_EVENT_STARTED,
                                         VIR_DOMAIN_EVENT_STARTED_BOOTED);
1906

1907
 cleanup:
1908
    virDomainObjEndAPI(&vm);
1909
    virObjectEventStateQueue(driver->domainEventState, event);
1910
    umlDriverUnlock(driver);
1911
    virNWFilterUnlockFilterUpdates();
1912
    return ret;
1913 1914
}

1915 1916
static int umlDomainCreate(virDomainPtr dom)
{
1917
    return umlDomainCreateWithFlags(dom, 0);
1918
}
1919

1920 1921
static virDomainPtr
umlDomainDefineXMLFlags(virConnectPtr conn, const char *xml, unsigned int flags)
1922
{
1923
    struct uml_driver *driver = conn->privateData;
1924
    virDomainDefPtr def;
1925
    virDomainObjPtr vm = NULL;
1926
    virDomainPtr dom = NULL;
1927 1928 1929
    unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;

    virCheckFlags(VIR_DOMAIN_DEFINE_VALIDATE, NULL);
1930

1931
    if (flags & VIR_DOMAIN_DEFINE_VALIDATE)
1932
        parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA;
1933

1934
    umlDriverLock(driver);
1935
    if (!(def = virDomainDefParseString(xml, driver->caps, driver->xmlopt,
1936
                                        NULL, parse_flags)))
1937
        goto cleanup;
1938

1939 1940 1941
    if (virXMLCheckIllegalChars("name", def->name, "\n") < 0)
        goto cleanup;

1942
    if (virDomainDefineXMLFlagsEnsureACL(conn, def) < 0)
1943 1944
        goto cleanup;

1945
    if (!(vm = virDomainObjListAdd(driver->domains, def,
1946
                                   driver->xmlopt,
1947
                                   0, NULL)))
1948 1949
        goto cleanup;
    def = NULL;
1950 1951
    vm->persistent = 1;

1952
    if (virDomainSaveConfig(driver->configDir, driver->caps,
1953
                            vm->newDef ? vm->newDef : vm->def) < 0) {
1954
        virDomainObjListRemove(driver->domains, vm);
1955
        goto cleanup;
1956 1957
    }

1958
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid, vm->def->id);
1959

1960
 cleanup:
1961
    virDomainDefFree(def);
1962
    virDomainObjEndAPI(&vm);
1963
    umlDriverUnlock(driver);
1964 1965 1966
    return dom;
}

1967 1968 1969 1970 1971 1972
static virDomainPtr
umlDomainDefineXML(virConnectPtr conn, const char *xml)
{
    return umlDomainDefineXMLFlags(conn, xml, 0);
}

1973 1974 1975
static int umlDomainUndefineFlags(virDomainPtr dom,
                                  unsigned int flags)
{
1976 1977 1978
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
1979

1980 1981
    virCheckFlags(0, -1);

1982
    umlDriverLock(driver);
1983
    if (!(vm = umlDomObjFromDomainLocked(driver, dom->uuid)))
1984
        goto cleanup;
1985

1986 1987 1988
    if (virDomainUndefineFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

1989
    if (!vm->persistent) {
1990
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
1991
                       _("cannot undefine transient domain"));
1992
        goto cleanup;
1993 1994
    }

1995
    if (virDomainDeleteConfig(driver->configDir, driver->autostartDir, vm) < 0)
1996
        goto cleanup;
1997

1998
    if (virDomainObjIsActive(vm))
1999
        vm->persistent = 0;
2000
    else
2001
        virDomainObjListRemove(driver->domains, vm);
2002

2003
    ret = 0;
2004

2005
 cleanup:
2006
    virDomainObjEndAPI(&vm);
2007
    umlDriverUnlock(driver);
2008
    return ret;
2009 2010 2011
}


2012 2013 2014 2015 2016
static int umlDomainUndefine(virDomainPtr dom)
{
    return umlDomainUndefineFlags(dom, 0);
}

2017 2018 2019 2020
static int umlDomainAttachUmlDisk(struct uml_driver *driver,
                                  virDomainObjPtr vm,
                                  virDomainDiskDefPtr disk)
{
2021
    size_t i;
2022 2023 2024
    char *cmd = NULL;
    char *reply = NULL;

2025
    for (i = 0; i < vm->def->ndisks; i++) {
2026
        if (STREQ(vm->def->disks[i]->dst, disk->dst)) {
2027
            virReportError(VIR_ERR_OPERATION_FAILED,
2028 2029 2030 2031 2032
                           _("target %s already exists"), disk->dst);
            return -1;
        }
    }

2033
    if (!virDomainDiskGetSource(disk)) {
2034
        virReportError(VIR_ERR_INTERNAL_ERROR,
2035 2036 2037 2038
                       "%s", _("disk source path is missing"));
        goto error;
    }

2039 2040
    if (virAsprintf(&cmd, "config %s=%s", disk->dst,
                    virDomainDiskGetSource(disk)) < 0)
2041 2042 2043 2044 2045
        return -1;

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

2046
    if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0)
2047 2048 2049 2050 2051 2052 2053 2054 2055
        goto error;

    virDomainDiskInsertPreAlloced(vm->def, disk);

    VIR_FREE(reply);
    VIR_FREE(cmd);

    return 0;

2056
 error:
2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073

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

2074
    if (!(vm = umlDomObjFromDomainLocked(driver, dom->uuid)))
2075 2076
        goto cleanup;

2077 2078 2079
    if (virDomainAttachDeviceEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2080
    if (!virDomainObjIsActive(vm)) {
2081
        virReportError(VIR_ERR_OPERATION_INVALID,
2082 2083 2084 2085
                       "%s", _("cannot attach device on inactive domain"));
        goto cleanup;
    }

2086
    dev = virDomainDeviceDefParse(xml, vm->def, driver->caps, driver->xmlopt,
2087
                                  VIR_DOMAIN_DEF_PARSE_INACTIVE);
2088 2089 2090 2091 2092 2093 2094 2095 2096 2097

    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 {
2098
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
2099 2100 2101 2102
                           _("disk bus '%s' cannot be hotplugged."),
                           virDomainDiskBusTypeToString(dev->data.disk->bus));
        }
    } else {
2103
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
2104 2105 2106 2107 2108
                       _("device type '%s' cannot be attached"),
                       virDomainDeviceTypeToString(dev->type));
        goto cleanup;
    }

2109
 cleanup:
2110 2111

    virDomainDeviceDefFree(dev);
2112
    virDomainObjEndAPI(&vm);
2113 2114 2115 2116 2117
    umlDriverUnlock(driver);
    return ret;
}


2118 2119 2120 2121 2122 2123 2124
static int
umlDomainAttachDeviceFlags(virDomainPtr dom,
                           const char *xml,
                           unsigned int flags)
{
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG, -1);

2125
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
2126
        virReportError(VIR_ERR_OPERATION_INVALID,
2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138
                       "%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)
{
2139 2140
    size_t i;
    int ret = -1;
2141 2142 2143 2144
    virDomainDiskDefPtr detach = NULL;
    char *cmd;
    char *reply;

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

    if (i == vm->def->ndisks) {
2151
        virReportError(VIR_ERR_OPERATION_FAILED,
2152 2153 2154 2155 2156 2157
                       _("disk %s not found"), dev->data.disk->dst);
        return -1;
    }

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

2158
    if (virAsprintf(&cmd, "remove %s", detach->dst) < 0)
2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171
        return -1;

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

    virDomainDiskRemove(vm->def, i);

    virDomainDiskDefFree(detach);

    ret = 0;

    VIR_FREE(reply);

2172
 cleanup:
2173 2174 2175 2176 2177 2178
    VIR_FREE(cmd);

    return ret;
}


2179 2180
static int umlDomainDetachDevice(virDomainPtr dom, const char *xml)
{
2181 2182 2183 2184 2185 2186
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    virDomainDeviceDefPtr dev = NULL;
    int ret = -1;

    umlDriverLock(driver);
2187
    if (!(vm = umlDomObjFromDomainLocked(driver, dom->uuid)))
2188 2189
        goto cleanup;

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

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

2199
    dev = virDomainDeviceDefParse(xml, vm->def, driver->caps, driver->xmlopt,
2200 2201
                                  VIR_DOMAIN_DEF_PARSE_INACTIVE |
                                  VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE);
2202 2203 2204 2205 2206 2207 2208
    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);
2209
        else
2210
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2211 2212
                           _("This type of disk cannot be hot unplugged"));
    } else {
2213
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
2214 2215 2216
                       "%s", _("This type of device cannot be hot unplugged"));
    }

2217
 cleanup:
2218
    virDomainDeviceDefFree(dev);
2219
    virDomainObjEndAPI(&vm);
2220 2221 2222 2223 2224
    umlDriverUnlock(driver);
    return ret;
}


2225 2226 2227 2228 2229 2230 2231
static int
umlDomainDetachDeviceFlags(virDomainPtr dom,
                           const char *xml,
                           unsigned int flags)
{
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG, -1);

2232
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
2233
        virReportError(VIR_ERR_OPERATION_INVALID,
2234 2235 2236 2237 2238 2239 2240
                       "%s", _("cannot modify the persistent configuration of a domain"));
        return -1;
    }

    return umlDomainDetachDevice(dom, xml);
}

2241 2242

static int umlDomainGetAutostart(virDomainPtr dom,
2243 2244
                            int *autostart)
{
2245 2246 2247
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
2248

2249
    umlDriverLock(driver);
2250
    if (!(vm = umlDomObjFromDomainLocked(driver, dom->uuid)))
2251
        goto cleanup;
2252

2253 2254 2255
    if (virDomainGetAutostartEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2256
    *autostart = vm->autostart;
2257
    ret = 0;
2258

2259
 cleanup:
2260
    virDomainObjEndAPI(&vm);
2261
    umlDriverUnlock(driver);
2262
    return ret;
2263 2264 2265
}

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

2273
    umlDriverLock(driver);
2274
    if (!(vm = umlDomObjFromDomainLocked(driver, dom->uuid)))
2275
        goto cleanup;
2276

2277 2278 2279
    if (virDomainSetAutostartEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

    autostart = (autostart != 0);

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

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

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

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

2321
 cleanup:
2322 2323
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
2324
    virDomainObjEndAPI(&vm);
2325
    umlDriverUnlock(driver);
2326 2327 2328 2329 2330
    return ret;
}


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

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

2344 2345
    if (!(vm = umlDomObjFromDomain(driver, dom->uuid)))
        return -1;
2346

2347 2348 2349
    if (virDomainBlockPeekEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

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

2364 2365 2366 2367 2368 2369 2370
    /* 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;
    }
2371

2372 2373 2374 2375
    /* Seek and read. */
    /* NB. Because we configure with AC_SYS_LARGEFILE, off_t should
     * be 64 bits on all platforms.
     */
2376 2377
    if (lseek(fd, offset, SEEK_SET) == (off_t)-1 ||
        saferead(fd, buffer, size) == (ssize_t)-1) {
2378 2379 2380
        virReportSystemError(errno,
                             _("cannot read %s"), path);
        goto cleanup;
2381 2382
    }

2383 2384
    ret = 0;

2385
 cleanup:
2386
    VIR_FORCE_CLOSE(fd);
2387
    virDomainObjEndAPI(&vm);
2388 2389 2390 2391
    return ret;
}


2392 2393
static int
umlDomainOpenConsole(virDomainPtr dom,
2394
                     const char *dev_name,
2395 2396 2397 2398 2399 2400 2401
                     virStreamPtr st,
                     unsigned int flags)
{
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm = NULL;
    int ret = -1;
    virDomainChrDefPtr chr = NULL;
2402
    size_t i;
2403 2404 2405 2406

    virCheckFlags(0, -1);

    umlDriverLock(driver);
2407
    if (!(vm = umlDomObjFromDomainLocked(driver, dom->uuid)))
2408 2409
        goto cleanup;

2410 2411 2412
    if (virDomainOpenConsoleEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2413
    if (virDomainObjCheckActive(vm) < 0)
2414 2415
        goto cleanup;

2416
    if (dev_name) {
2417
        for (i = 0; i < vm->def->nconsoles; i++) {
2418 2419 2420 2421 2422 2423
            if (vm->def->consoles[i]->info.alias &&
                STREQ(vm->def->consoles[i]->info.alias, dev_name)) {
                chr = vm->def->consoles[i];
                break;
            }
        }
2424
    } else {
2425 2426
        if (vm->def->nconsoles)
            chr = vm->def->consoles[0];
2427 2428 2429 2430 2431
        else if (vm->def->nserials)
            chr = vm->def->serials[0];
    }

    if (!chr) {
2432
        virReportError(VIR_ERR_INTERNAL_ERROR,
2433 2434
                       _("cannot find console device '%s'"),
                       dev_name ? dev_name : _("default"));
2435 2436 2437
        goto cleanup;
    }

2438
    if (chr->source->type != VIR_DOMAIN_CHR_TYPE_PTY) {
2439
        virReportError(VIR_ERR_INTERNAL_ERROR,
2440 2441
                        _("character device %s is not using a PTY"),
                       dev_name ? dev_name : NULLSTR(chr->info.alias));
2442 2443 2444
        goto cleanup;
    }

2445
    if (virFDStreamOpenFile(st, chr->source->data.file.path,
E
Eric Blake 已提交
2446
                            0, 0, O_RDWR) < 0)
2447 2448 2449
        goto cleanup;

    ret = 0;
2450
 cleanup:
2451
    virDomainObjEndAPI(&vm);
2452 2453 2454 2455
    umlDriverUnlock(driver);
    return ret;
}

2456

2457
static int
2458 2459 2460 2461
umlConnectDomainEventRegister(virConnectPtr conn,
                              virConnectDomainEventCallback callback,
                              void *opaque,
                              virFreeCallback freecb)
2462 2463
{
    struct uml_driver *driver = conn->privateData;
2464
    int ret = 0;
2465

2466 2467 2468
    if (virConnectDomainEventRegisterEnsureACL(conn) < 0)
        return -1;

2469
    umlDriverLock(driver);
2470 2471 2472 2473
    if (virDomainEventStateRegister(conn,
                                    driver->domainEventState,
                                    callback, opaque, freecb) < 0)
        ret = -1;
2474 2475 2476 2477 2478 2479
    umlDriverUnlock(driver);

    return ret;
}

static int
2480 2481
umlConnectDomainEventDeregister(virConnectPtr conn,
                                virConnectDomainEventCallback callback)
2482 2483
{
    struct uml_driver *driver = conn->privateData;
2484
    int ret = 0;
2485

2486 2487 2488
    if (virConnectDomainEventDeregisterEnsureACL(conn) < 0)
        return -1;

2489
    umlDriverLock(driver);
2490 2491 2492 2493
    if (virDomainEventStateDeregister(conn,
                                      driver->domainEventState,
                                      callback) < 0)
        ret = -1;
2494 2495 2496 2497 2498 2499
    umlDriverUnlock(driver);

    return ret;
}

static int
2500 2501 2502 2503 2504 2505
umlConnectDomainEventRegisterAny(virConnectPtr conn,
                                 virDomainPtr dom,
                                 int eventID,
                                 virConnectDomainEventGenericCallback callback,
                                 void *opaque,
                                 virFreeCallback freecb)
2506 2507 2508 2509
{
    struct uml_driver *driver = conn->privateData;
    int ret;

2510 2511 2512
    if (virConnectDomainEventRegisterAnyEnsureACL(conn) < 0)
        return -1;

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

    return ret;
}


static int
2526 2527
umlConnectDomainEventDeregisterAny(virConnectPtr conn,
                                   int callbackID)
2528 2529
{
    struct uml_driver *driver = conn->privateData;
2530
    int ret = 0;
2531

2532 2533 2534
    if (virConnectDomainEventDeregisterAnyEnsureACL(conn) < 0)
        return -1;

2535
    umlDriverLock(driver);
2536 2537
    if (virObjectEventStateDeregisterID(conn,
                                        driver->domainEventState,
2538
                                        callbackID, true) < 0)
2539
        ret = -1;
2540 2541 2542 2543 2544 2545
    umlDriverUnlock(driver);

    return ret;
}


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

O
Osier Yang 已提交
2553
    virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
2554

2555 2556 2557
    if (virConnectListAllDomainsEnsureACL(conn) < 0)
        return -1;

2558
    umlDriverLock(driver);
2559 2560
    ret = virDomainObjListExport(driver->domains, conn, domains,
                                 virConnectListAllDomainsCheckACL, flags);
2561 2562 2563 2564 2565
    umlDriverUnlock(driver);

    return ret;
}

2566

2567
static int
2568
umlNodeGetInfo(virConnectPtr conn,
2569 2570
               virNodeInfoPtr nodeinfo)
{
2571 2572 2573
    if (virNodeGetInfoEnsureACL(conn) < 0)
        return -1;

M
Martin Kletzander 已提交
2574
    return virCapabilitiesGetNodeInfo(nodeinfo);
2575 2576 2577 2578
}


static int
2579
umlNodeGetCPUStats(virConnectPtr conn,
2580 2581 2582 2583 2584
                   int cpuNum,
                   virNodeCPUStatsPtr params,
                   int *nparams,
                   unsigned int flags)
{
2585 2586 2587
    if (virNodeGetCPUStatsEnsureACL(conn) < 0)
        return -1;

2588
    return virHostCPUGetStats(cpuNum, params, nparams, flags);
2589 2590 2591 2592
}


static int
2593
umlNodeGetMemoryStats(virConnectPtr conn,
2594 2595 2596 2597 2598
                      int cellNum,
                      virNodeMemoryStatsPtr params,
                      int *nparams,
                      unsigned int flags)
{
2599 2600 2601
    if (virNodeGetMemoryStatsEnsureACL(conn) < 0)
        return -1;

2602
    return virHostMemGetStats(cellNum, params, nparams, flags);
2603 2604 2605 2606
}


static int
2607
umlNodeGetCellsFreeMemory(virConnectPtr conn,
2608 2609 2610 2611
                          unsigned long long *freeMems,
                          int startCell,
                          int maxCells)
{
2612 2613 2614
    if (virNodeGetCellsFreeMemoryEnsureACL(conn) < 0)
        return -1;

2615
    return virHostMemGetCellsFree(freeMems, startCell, maxCells);
2616 2617 2618 2619
}


static unsigned long long
2620
umlNodeGetFreeMemory(virConnectPtr conn)
2621
{
2622 2623
    unsigned long long freeMem;

2624 2625 2626
    if (virNodeGetFreeMemoryEnsureACL(conn) < 0)
        return 0;

2627
    if (virHostMemGetInfo(NULL, &freeMem) < 0)
2628 2629 2630
        return 0;

    return freeMem;
2631 2632 2633 2634
}


static int
2635
umlNodeGetMemoryParameters(virConnectPtr conn,
2636 2637 2638 2639
                           virTypedParameterPtr params,
                           int *nparams,
                           unsigned int flags)
{
2640 2641 2642
    if (virNodeGetMemoryParametersEnsureACL(conn) < 0)
        return -1;

2643
    return virHostMemGetParameters(params, nparams, flags);
2644 2645 2646 2647
}


static int
2648
umlNodeSetMemoryParameters(virConnectPtr conn,
2649 2650 2651 2652
                           virTypedParameterPtr params,
                           int nparams,
                           unsigned int flags)
{
2653 2654 2655
    if (virNodeSetMemoryParametersEnsureACL(conn) < 0)
        return -1;

2656
    return virHostMemSetParameters(params, nparams, flags);
2657 2658 2659 2660
}


static int
2661
umlNodeGetCPUMap(virConnectPtr conn,
2662 2663 2664 2665
                 unsigned char **cpumap,
                 unsigned int *online,
                 unsigned int flags)
{
2666 2667 2668
    if (virNodeGetCPUMapEnsureACL(conn) < 0)
        return -1;

2669
    return virHostCPUGetMap(cpumap, online, flags);
2670 2671
}

2672

2673
static int
2674
umlNodeSuspendForDuration(virConnectPtr conn,
2675 2676 2677 2678
                          unsigned int target,
                          unsigned long long duration,
                          unsigned int flags)
{
2679 2680 2681
    if (virNodeSuspendForDurationEnsureACL(conn) < 0)
        return -1;

2682
    return virNodeSuspend(target, duration, flags);
2683 2684 2685
}


2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699
static int
umlNodeGetFreePages(virConnectPtr conn,
                    unsigned int npages,
                    unsigned int *pages,
                    int startCell,
                    unsigned int cellCount,
                    unsigned long long *counts,
                    unsigned int flags)
{
    virCheckFlags(0, -1);

    if (virNodeGetFreePagesEnsureACL(conn) < 0)
        return -1;

2700
    return virHostMemGetFreePages(npages, pages, startCell, cellCount, counts);
2701 2702 2703
}


2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719
static int
umlNodeAllocPages(virConnectPtr conn,
                  unsigned int npages,
                  unsigned int *pageSizes,
                  unsigned long long *pageCounts,
                  int startCell,
                  unsigned int cellCount,
                  unsigned int flags)
{
    bool add = !(flags & VIR_NODE_ALLOC_PAGES_SET);

    virCheckFlags(VIR_NODE_ALLOC_PAGES_SET, -1);

    if (virNodeAllocPagesEnsureACL(conn) < 0)
        return -1;

2720 2721
    return virHostMemAllocPages(npages, pageSizes, pageCounts,
                                startCell, cellCount, add);
2722 2723 2724
}


2725 2726 2727 2728 2729 2730 2731 2732 2733
static int
umlDomainHasManagedSaveImage(virDomainPtr dom, unsigned int flags)
{
    struct uml_driver *driver = dom->conn->privateData;
    int ret = -1;
    virDomainObjPtr vm;

    virCheckFlags(0, -1);

2734 2735
    if (!(vm = umlDomObjFromDomain(driver, dom->uuid)))
        return -1;
2736 2737 2738 2739 2740 2741 2742

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

    ret = 0;

 cleanup:
2743
    virDomainObjEndAPI(&vm);
2744 2745 2746 2747
    return ret;
}


2748
static virHypervisorDriver umlHypervisorDriver = {
2749
    .name = "UML",
2750
    .connectURIProbe = umlConnectURIProbe,
2751 2752 2753 2754
    .connectOpen = umlConnectOpen, /* 0.5.0 */
    .connectClose = umlConnectClose, /* 0.5.0 */
    .connectGetType = umlConnectGetType, /* 0.5.0 */
    .connectGetVersion = umlConnectGetVersion, /* 0.5.0 */
2755
    .connectGetHostname = umlConnectGetHostname, /* 0.5.0 */
2756
    .nodeGetInfo = umlNodeGetInfo, /* 0.5.0 */
2757 2758 2759 2760 2761
    .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 */
2762 2763 2764 2765
    .domainLookupByID = umlDomainLookupByID, /* 0.5.0 */
    .domainLookupByUUID = umlDomainLookupByUUID, /* 0.5.0 */
    .domainLookupByName = umlDomainLookupByName, /* 0.5.0 */
    .domainShutdown = umlDomainShutdown, /* 0.5.0 */
2766
    .domainShutdownFlags = umlDomainShutdownFlags, /* 0.9.10 */
2767
    .domainDestroy = umlDomainDestroy, /* 0.5.0 */
2768
    .domainDestroyFlags = umlDomainDestroyFlags, /* 0.9.4 */
2769 2770 2771 2772 2773 2774 2775
    .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 */
2776 2777 2778 2779 2780
    .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 */
2781
    .domainDefineXMLFlags = umlDomainDefineXMLFlags, /* 1.2.12 */
2782
    .domainUndefine = umlDomainUndefine, /* 0.5.0 */
2783
    .domainUndefineFlags = umlDomainUndefineFlags, /* 0.9.4 */
2784 2785 2786 2787 2788 2789 2790
    .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 */
2791 2792 2793 2794 2795
    .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 */
2796 2797 2798 2799
    .connectDomainEventRegister = umlConnectDomainEventRegister, /* 0.9.4 */
    .connectDomainEventDeregister = umlConnectDomainEventDeregister, /* 0.9.4 */
    .connectIsEncrypted = umlConnectIsEncrypted, /* 0.7.3 */
    .connectIsSecure = umlConnectIsSecure, /* 0.7.3 */
2800 2801 2802
    .domainIsActive = umlDomainIsActive, /* 0.7.3 */
    .domainIsPersistent = umlDomainIsPersistent, /* 0.7.3 */
    .domainIsUpdated = umlDomainIsUpdated, /* 0.8.6 */
2803 2804
    .connectDomainEventRegisterAny = umlConnectDomainEventRegisterAny, /* 0.9.4 */
    .connectDomainEventDeregisterAny = umlConnectDomainEventDeregisterAny, /* 0.9.4 */
2805
    .domainOpenConsole = umlDomainOpenConsole, /* 0.8.6 */
2806
    .connectIsAlive = umlConnectIsAlive, /* 0.9.8 */
2807
    .nodeSuspendForDuration = umlNodeSuspendForDuration, /* 0.9.8 */
2808 2809
    .nodeGetMemoryParameters = umlNodeGetMemoryParameters, /* 0.10.2 */
    .nodeSetMemoryParameters = umlNodeSetMemoryParameters, /* 0.10.2 */
2810
    .nodeGetFreePages = umlNodeGetFreePages, /* 1.2.6 */
2811
    .nodeAllocPages = umlNodeAllocPages, /* 1.2.9 */
2812
    .domainHasManagedSaveImage = umlDomainHasManagedSaveImage, /* 1.2.13 */
2813 2814
};

2815
static virConnectDriver umlConnectDriver = {
2816
    .localOnly = true,
2817
    .uriSchemes = (const char *[]){ "uml", NULL },
2818 2819 2820
    .hypervisorDriver = &umlHypervisorDriver,
};

2821
static virStateDriver umlStateDriver = {
2822
    .name = "UML",
2823
    .stateInitialize = umlStateInitialize,
2824
    .stateAutoStart = umlStateAutoStart,
2825 2826
    .stateCleanup = umlStateCleanup,
    .stateReload = umlStateReload,
2827 2828
};

2829 2830
int umlRegister(void)
{
2831 2832
    if (virRegisterConnectDriver(&umlConnectDriver,
                                 true) < 0)
2833 2834 2835
        return -1;
    if (virRegisterStateDriver(&umlStateDriver) < 0)
        return -1;
2836 2837
    return 0;
}