uml_driver.c 83.5 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 38 39 40 41 42
 *
 * Author: Daniel P. Berrange <berrange@redhat.com>
 */

#include <config.h>

#include <sys/types.h>
#include <sys/poll.h>
#include <limits.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/utsname.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <pwd.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <sys/inotify.h>
43
#include <sys/un.h>
44 45 46

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

69 70
#define VIR_FROM_THIS VIR_FROM_UML

71 72
VIR_LOG_INIT("uml.uml_driver");

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

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

90

91
static int umlStateCleanup(void);
92

93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
static void *umlDomainObjPrivateAlloc(void)
{
    umlDomainObjPrivatePtr priv;

    if (VIR_ALLOC(priv) < 0)
        return NULL;

    priv->monitor = -1;
    priv->monitorWatch = -1;

    return priv;
}

static void umlDomainObjPrivateFree(void *data)
{
    umlDomainObjPrivatePtr priv = data;

    VIR_FREE(priv);
}


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

123

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

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

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


141
static int umlMonitorCommand(const struct uml_driver *driver,
142
                             const virDomainObj *vm,
143 144
                             const char *cmd,
                             char **reply);
145

146
static struct uml_driver *uml_driver;
147

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

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

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

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

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

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

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

219 220
    struct umlAutostartData data = { driver, conn };

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

225
    virObjectUnref(conn);
226 227 228 229
}


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

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

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

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

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

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

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

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

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

320 321 322
        memcpy(&e, tmp, sizeof(e));
        tmp += sizeof(e);
        got -= sizeof(e);
323

324
        if (got < e.len)
325
            goto cleanup;
326

327 328
        tmp += e.len;
        got -= e.len;
329

330
        name = (char *)&(e.name);
331

332
        dom = virDomainObjListFindByName(driver->domains, name);
333

334
        if (!dom)
335 336
            continue;

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

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

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

            dom->def->id = driver->nextvmid++;
364 365 366 367 368

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

J
Jiri Denemark 已提交
369 370
            virDomainObjSetState(dom, VIR_DOMAIN_RUNNING,
                                 VIR_DOMAIN_RUNNING_BOOTED);
371

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

401
 cleanup:
402
    umlDriverUnlock(driver);
403 404
}

405 406 407

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

418 419 420 421 422 423 424 425 426 427
    /* 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;
    }

428 429 430 431
    return 0;
}


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


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


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

461 462 463 464 465
    virDomainXMLPrivateDataCallbacks privcb = {
        .alloc = umlDomainObjPrivateAlloc,
        .free = umlDomainObjPrivateFree,
    };

466 467 468
    if (VIR_ALLOC(uml_driver) < 0)
        return -1;

469
    uml_driver->privileged = privileged;
470 471
    uml_driver->inhibitCallback = callback;
    uml_driver->inhibitOpaque = opaque;
472

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

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

483
    if (!(uml_driver->domains = virDomainObjListNew()))
484 485
        goto error;

486
    uml_driver->domainEventState = virObjectEventStateNew();
487 488 489
    if (!uml_driver->domainEventState)
        goto error;

490
    userdir = virGetUserDirectory();
491
    if (!userdir)
492
        goto error;
493

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

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

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

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

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

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

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

    VIR_FREE(base);

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

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

    if ((uml_driver->inotifyFD = inotify_init()) < 0) {
538
        VIR_ERROR(_("cannot initialize inotify"));
539
        goto error;
540 541
    }

542
    if (virFileMakePath(uml_driver->monitorDir) < 0) {
543
        char ebuf[1024];
D
Daniel Veillard 已提交
544
        VIR_ERROR(_("Failed to create monitor directory %s: %s"),
545 546
                  uml_driver->monitorDir,
                  virStrerror(errno, ebuf, sizeof(ebuf)));
547
        goto error;
548 549
    }

550
    VIR_INFO("Adding inotify watch on %s", uml_driver->monitorDir);
551 552 553
    if (inotify_add_watch(uml_driver->inotifyFD,
                          uml_driver->monitorDir,
                          IN_CREATE | IN_MODIFY | IN_DELETE) < 0) {
554 555 556 557
        char ebuf[1024];
        VIR_ERROR(_("Failed to create inotify watch on %s: %s"),
                  uml_driver->monitorDir,
                  virStrerror(errno, ebuf, sizeof(ebuf)));
558
        goto error;
559 560
    }

561 562
    if ((uml_driver->inotifyWatch =
         virEventAddHandle(uml_driver->inotifyFD, POLLIN,
563 564
                           umlInotifyEvent, uml_driver, NULL)) < 0)
        goto error;
565

566 567 568
    if (umlProcessAutoDestroyInit(uml_driver) < 0)
        goto error;

569
    if (virDomainObjListLoadAllConfigs(uml_driver->domains,
570 571
                                       uml_driver->configDir,
                                       uml_driver->autostartDir, 0,
572
                                       uml_driver->caps,
573
                                       uml_driver->xmlopt,
574
                                       NULL, NULL) < 0)
575 576
        goto error;

577 578
    umlDriverUnlock(uml_driver);

579 580
    VIR_FREE(userdir);

581
    virNWFilterRegisterCallbackDriver(&umlCallbackDriver);
582 583
    return 0;

584
 out_of_memory:
585
    VIR_ERROR(_("umlStartup: out of memory"));
586

587
 error:
588
    VIR_FREE(userdir);
589
    VIR_FREE(base);
590
    umlDriverUnlock(uml_driver);
591
    umlStateCleanup();
592 593 594
    return -1;
}

595 596 597 598 599 600 601 602 603 604 605 606 607 608
/**
 * umlStateAutoStart:
 *
 * Function to autostart the Uml daemons
 */
static void
umlStateAutoStart(void)
{
    if (!uml_driver)
        return;

    umlAutostartConfigs(uml_driver);
}

609 610 611 612 613
static void umlNotifyLoadDomain(virDomainObjPtr vm, int newVM, void *opaque)
{
    struct uml_driver *driver = opaque;

    if (newVM) {
614
        virObjectEventPtr event =
615
            virDomainEventLifecycleNewFromObj(vm,
616 617 618 619 620 621 622 623
                                     VIR_DOMAIN_EVENT_DEFINED,
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED);
        if (event)
            umlDomainEventQueue(driver, event);
    }
}


624
/**
625
 * umlStateReload:
626 627 628 629 630
 *
 * Function to restart the Uml daemon, it will recheck the configuration
 * files and update its state and the networking
 */
static int
631 632
umlStateReload(void)
{
633 634 635
    if (!uml_driver)
        return 0;

636
    umlDriverLock(uml_driver);
637
    virDomainObjListLoadAllConfigs(uml_driver->domains,
638 639
                                   uml_driver->configDir,
                                   uml_driver->autostartDir, 0,
640
                                   uml_driver->caps,
641
                                   uml_driver->xmlopt,
642
                                   umlNotifyLoadDomain, uml_driver);
643
    umlDriverUnlock(uml_driver);
644 645 646 647 648

    return 0;
}


649 650
static int
umlShutdownOneVM(virDomainObjPtr dom, void *opaque)
651 652 653
{
    struct uml_driver *driver = opaque;

654
    virObjectLock(dom);
655
    if (virDomainObjIsActive(dom)) {
656
        umlShutdownVMDaemon(driver, dom, VIR_DOMAIN_SHUTOFF_SHUTDOWN);
657 658
        virDomainAuditStop(dom, "shutdown");
    }
659
    virObjectUnlock(dom);
660
    return 0;
661 662
}

663
/**
664
 * umlStateCleanup:
665 666 667 668
 *
 * Shutdown the Uml daemon, it will stop all active domains and networks
 */
static int
669 670
umlStateCleanup(void)
{
671 672 673
    if (!uml_driver)
        return -1;

674
    umlDriverLock(uml_driver);
675
    virNWFilterRegisterCallbackDriver(&umlCallbackDriver);
676 677
    if (uml_driver->inotifyWatch != -1)
        virEventRemoveHandle(uml_driver->inotifyWatch);
678
    VIR_FORCE_CLOSE(uml_driver->inotifyFD);
679
    virObjectUnref(uml_driver->caps);
680
    virObjectUnref(uml_driver->xmlopt);
681

682 683
    /* shutdown active VMs
     * XXX allow them to stay around & reconnect */
684
    virDomainObjListForEach(uml_driver->domains, umlShutdownOneVM, uml_driver);
685

686
    virObjectUnref(uml_driver->domains);
687

688
    virObjectEventStateFree(uml_driver->domainEventState);
689

690 691 692 693 694
    VIR_FREE(uml_driver->logDir);
    VIR_FREE(uml_driver->configDir);
    VIR_FREE(uml_driver->autostartDir);
    VIR_FREE(uml_driver->monitorDir);

695 696
    umlProcessAutoDestroyShutdown(uml_driver);

697
    umlDriverUnlock(uml_driver);
698
    virMutexDestroy(&uml_driver->lock);
699 700 701 702 703 704
    VIR_FREE(uml_driver);

    return 0;
}


705 706 707 708 709 710 711 712 713 714 715 716 717
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;
};

718 719 720
static int umlProcessAutoDestroyDom(void *payload,
                                    const void *name,
                                    void *opaque)
721 722 723 724 725 726
{
    struct umlProcessAutoDestroyData *data = opaque;
    virConnectPtr conn = payload;
    const char *uuidstr = name;
    unsigned char uuid[VIR_UUID_BUFLEN];
    virDomainObjPtr dom;
727
    virObjectEventPtr event = NULL;
728 729 730 731

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

    if (data->conn != conn)
732
        return 0;
733 734 735

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

739 740
    if (!(dom = virDomainObjListFindByUUID(data->driver->domains,
                                           uuid))) {
741
        VIR_DEBUG("No domain object to kill");
742
        return 0;
743 744 745 746 747
    }

    VIR_DEBUG("Killing domain");
    umlShutdownVMDaemon(data->driver, dom, VIR_DOMAIN_SHUTOFF_DESTROYED);
    virDomainAuditStop(dom, "destroyed");
748
    event = virDomainEventLifecycleNewFromObj(dom,
749 750 751 752
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_DESTROYED);

    if (dom && !dom->persistent)
753
        virDomainObjListRemove(data->driver->domains, dom);
754 755

    if (dom)
756
        virObjectUnlock(dom);
757 758 759
    if (event)
        umlDomainEventQueue(data->driver, event);
    virHashRemoveEntry(data->driver->autodestroy, uuidstr);
760
    return 0;
761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803
}

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


804
static int umlReadPidFile(struct uml_driver *driver,
805 806 807 808 809 810 811 812
                          virDomainObjPtr vm)
{
    int rc = -1;
    FILE *file;
    char *pidfile = NULL;
    int retries = 0;

    vm->pid = -1;
813
    if (virAsprintf(&pidfile, "%s/%s/pid",
814
                    driver->monitorDir, vm->def->name) < 0)
815 816
        return -1;

817
 reopen:
818 819 820 821 822 823 824 825 826 827 828
    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;
829
        VIR_FORCE_FCLOSE(file);
830 831 832
        goto cleanup;
    }

833
    if (VIR_FCLOSE(file) < 0)
834 835 836 837 838 839
        goto cleanup;

    rc = 0;

 cleanup:
    if (rc != 0)
840
        virReportSystemError(errno,
841 842
                             _("failed to read pid: %s"),
                             pidfile);
843 844 845 846
    VIR_FREE(pidfile);
    return rc;
}

847
static int umlMonitorAddress(const struct uml_driver *driver,
848 849 850
                             const virDomainObj *vm,
                             struct sockaddr_un *addr)
{
851
    char *sockname;
C
Chris Lalancette 已提交
852
    int retval = 0;
853

854
    if (virAsprintf(&sockname, "%s/%s/mconsole",
855
                    driver->monitorDir, vm->def->name) < 0)
856 857
        return -1;

858
    memset(addr, 0, sizeof(*addr));
859
    addr->sun_family = AF_UNIX;
C
Chris Lalancette 已提交
860
    if (virStrcpyStatic(addr->sun_path, sockname) == NULL) {
861
        virReportError(VIR_ERR_INTERNAL_ERROR,
C
Chris Lalancette 已提交
862 863 864
                       _("Unix path %s too long for destination"), sockname);
        retval = -1;
    }
865
    VIR_FREE(sockname);
C
Chris Lalancette 已提交
866
    return retval;
867 868
}

869
static int umlOpenMonitor(struct uml_driver *driver,
870 871
                          virDomainObjPtr vm)
{
872 873 874
    struct sockaddr_un addr;
    struct stat sb;
    int retries = 0;
875
    umlDomainObjPrivatePtr priv = vm->privateData;
876

877
    if (umlMonitorAddress(driver, vm, &addr) < 0)
878 879
        return -1;

880
    VIR_DEBUG("Dest address for monitor is '%s'", addr.sun_path);
881
 restat:
882 883
    if (stat(addr.sun_path, &sb) < 0) {
        if (errno == ENOENT &&
884
            retries++ < 50) {
885 886 887 888 889 890
            usleep(1000 * 100);
            goto restat;
        }
        return -1;
    }

891
    if ((priv->monitor = socket(PF_UNIX, SOCK_DGRAM, 0)) < 0) {
892
        virReportSystemError(errno,
893
                             "%s", _("cannot open socket"));
894 895 896
        return -1;
    }

897
    memset(addr.sun_path, 0, sizeof(addr.sun_path));
E
Eric Blake 已提交
898 899
    snprintf(addr.sun_path + 1, sizeof(addr.sun_path) - 1,
             "libvirt-uml-%u", vm->pid);
900
    VIR_DEBUG("Reply address for monitor is '%s'", addr.sun_path+1);
901
    if (bind(priv->monitor, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
902
        virReportSystemError(errno,
903
                             "%s", _("cannot bind socket"));
904
        VIR_FORCE_CLOSE(priv->monitor);
905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930
        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];
};


931
static int umlMonitorCommand(const struct uml_driver *driver,
932
                             const virDomainObj *vm,
933 934 935 936 937 938 939 940 941
                             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;
942
    umlDomainObjPrivatePtr priv = vm->privateData;
943

944 945
    VIR_DEBUG("Run command '%s'", cmd);

946 947
    *reply = NULL;

948
    if (umlMonitorAddress(driver, vm, &addr) < 0)
949 950 951 952 953 954 955
        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)) {
956
        virReportSystemError(EINVAL,
957 958
                             _("cannot send too long command %s (%d bytes)"),
                             cmd, req.length);
959 960
        return -1;
    }
C
Chris Lalancette 已提交
961
    if (virStrcpyStatic(req.data, cmd) == NULL) {
962
        virReportError(VIR_ERR_INTERNAL_ERROR,
C
Chris Lalancette 已提交
963 964 965
                       _("Command %s too long for destination"), cmd);
        return -1;
    }
966

967 968
    if (sendto(priv->monitor, &req, sizeof(req), 0,
               (struct sockaddr *)&addr, sizeof(addr)) != sizeof(req)) {
969
        virReportSystemError(errno,
970 971
                             _("cannot send command %s"),
                             cmd);
972 973 974 975
        return -1;
    }

    do {
E
Eric Blake 已提交
976
        ssize_t nbytes;
977
        addrlen = sizeof(addr);
978
        nbytes = recvfrom(priv->monitor, &res, sizeof(res), 0,
979
                          (struct sockaddr *)&addr, &addrlen);
E
Eric Blake 已提交
980 981 982
        if (nbytes < 0) {
            if (errno == EAGAIN || errno == EINTR)
                continue;
983
            virReportSystemError(errno, _("cannot read reply %s"), cmd);
984 985
            goto error;
        }
986 987 988
        /* 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) {
989 990 991
            virReportSystemError(0, _("incomplete reply %s"), cmd);
            goto error;
        }
992

993
        if (VIR_REALLOC_N(retdata, retlen + res.length) < 0)
994 995 996 997 998 999 1000 1001 1002 1003
            goto error;
        memcpy(retdata + retlen, res.data, res.length);
        retlen += res.length - 1;
        retdata[retlen] = '\0';

        if (res.error)
            ret = -1;

    } while (res.extra);

1004 1005
    VIR_DEBUG("Command reply is '%s'", NULLSTR(retdata));

1006 1007 1008 1009
    if (ret < 0)
        VIR_FREE(retdata);
    else
        *reply = retdata;
1010 1011 1012

    return ret;

1013
 error:
1014 1015 1016 1017 1018
    VIR_FREE(retdata);
    return -1;
}


1019 1020
static void umlCleanupTapDevices(virDomainObjPtr vm)
{
1021
    size_t i;
1022

1023
    for (i = 0; i < vm->def->nnets; i++) {
1024 1025 1026 1027 1028 1029
        virDomainNetDefPtr def = vm->def->nets[i];

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

1030 1031
        ignore_value(virNetDevTapDelete(def->ifname,
                                        def->backend.tap));
1032 1033 1034
    }
}

1035 1036
static int umlStartVMDaemon(virConnectPtr conn,
                            struct uml_driver *driver,
1037
                            virDomainObjPtr vm,
1038 1039
                            bool autoDestroy)
{
1040
    int ret = -1;
1041 1042
    char *logfile;
    int logfd = -1;
1043
    umlDomainObjPrivatePtr priv = vm->privateData;
D
Daniel P. Berrange 已提交
1044
    virCommandPtr cmd = NULL;
1045
    size_t i;
1046

D
Daniel P. Berrange 已提交
1047
    if (virDomainObjIsActive(vm)) {
1048
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
1049
                       _("VM is already active"));
1050 1051 1052 1053
        return -1;
    }

    if (!vm->def->os.kernel) {
1054
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1055
                       _("no kernel specified"));
1056 1057 1058 1059 1060 1061
        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 已提交
1062
    if (!virFileIsExecutable(vm->def->os.kernel)) {
1063
        virReportSystemError(errno,
1064 1065
                             _("Cannot find UML kernel %s"),
                             vm->def->os.kernel);
1066 1067 1068
        return -1;
    }

1069
    if (virFileMakePath(driver->logDir) < 0) {
1070
        virReportSystemError(errno,
1071 1072
                             _("cannot create log directory %s"),
                             driver->logDir);
1073 1074 1075
        return -1;
    }

1076
    if (virAsprintf(&logfile, "%s/%s.log",
1077
                    driver->logDir, vm->def->name) < 0)
1078 1079 1080 1081
        return -1;

    if ((logfd = open(logfile, O_CREAT | O_TRUNC | O_WRONLY,
                      S_IRUSR | S_IWUSR)) < 0) {
1082
        virReportSystemError(errno,
1083 1084
                             _("failed to create logfile %s"),
                             logfile);
1085 1086 1087 1088 1089
        VIR_FREE(logfile);
        return -1;
    }
    VIR_FREE(logfile);

E
Eric Blake 已提交
1090 1091 1092
    if (virSetCloseExec(logfd) < 0) {
        virReportSystemError(errno, "%s",
                             _("Unable to set VM logfile close-on-exec flag"));
1093
        VIR_FORCE_CLOSE(logfd);
1094 1095 1096
        return -1;
    }

1097 1098 1099 1100 1101
    /* 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");
1102
    if (virDomainObjSetDefTransient(driver->caps, driver->xmlopt, vm) < 0) {
1103 1104 1105 1106
        VIR_FORCE_CLOSE(logfd);
        return -1;
    }

1107 1108
    if (!(cmd = umlBuildCommandLine(conn, driver, vm)))
        goto cleanup;
1109

1110
    for (i = 0; i < vm->def->nconsoles; i++) {
1111
        VIR_FREE(vm->def->consoles[i]->info.alias);
1112
        if (virAsprintf(&vm->def->consoles[i]->info.alias, "console%zu", i) < 0)
1113 1114 1115
            goto cleanup;
    }

D
Daniel P. Berrange 已提交
1116
    virCommandWriteArgLog(cmd, logfd);
1117

1118
    priv->monitor = -1;
1119

D
Daniel P. Berrange 已提交
1120 1121 1122 1123 1124
    virCommandClearCaps(cmd);
    virCommandSetOutputFD(cmd, &logfd);
    virCommandSetErrorFD(cmd, &logfd);
    virCommandDaemonize(cmd);

J
Ján Tomko 已提交
1125
    if (virCommandRun(cmd, NULL) < 0)
1126
        goto cleanup;
1127

1128
    if (autoDestroy &&
J
Ján Tomko 已提交
1129
        umlProcessAutoDestroyAdd(driver, vm, conn) < 0)
1130 1131
        goto cleanup;

1132
    ret = 0;
1133
 cleanup:
1134
    VIR_FORCE_CLOSE(logfd);
D
Daniel P. Berrange 已提交
1135
    virCommandFree(cmd);
1136

1137 1138
    if (ret < 0) {
        virDomainConfVMNWFilterTeardown(vm);
1139
        umlCleanupTapDevices(vm);
1140 1141 1142 1143 1144 1145
        if (vm->newDef) {
            virDomainDefFree(vm->def);
            vm->def = vm->newDef;
            vm->def->id = -1;
            vm->newDef = NULL;
        }
1146 1147
    }

1148 1149
    /* NB we don't mark it running here - we do that async
       with inotify */
1150 1151 1152
    /* XXX what if someone else tries to start it again
       before we get the inotification ? Sounds like
       trouble.... */
1153
    /* XXX this is bad for events too. must fix this better */
1154 1155 1156 1157

    return ret;
}

1158
static void umlShutdownVMDaemon(struct uml_driver *driver,
J
Jiri Denemark 已提交
1159 1160
                                virDomainObjPtr vm,
                                virDomainShutoffReason reason)
1161 1162
{
    int ret;
1163 1164
    umlDomainObjPrivatePtr priv = vm->privateData;

D
Daniel P. Berrange 已提交
1165
    if (!virDomainObjIsActive(vm))
1166 1167
        return;

1168
    virProcessKill(vm->pid, SIGTERM);
1169

1170
    VIR_FORCE_CLOSE(priv->monitor);
1171 1172

    if ((ret = waitpid(vm->pid, NULL, 0)) != vm->pid) {
1173
        VIR_WARN("Got unexpected pid %d != %d",
1174 1175 1176 1177 1178
               ret, vm->pid);
    }

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

1181
    virDomainConfVMNWFilterTeardown(vm);
1182 1183 1184 1185
    umlCleanupTapDevices(vm);

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

1187 1188 1189 1190 1191 1192
    if (vm->newDef) {
        virDomainDefFree(vm->def);
        vm->def = vm->newDef;
        vm->def->id = -1;
        vm->newDef = NULL;
    }
1193 1194 1195 1196

    driver->nactive--;
    if (!driver->nactive && driver->inhibitCallback)
        driver->inhibitCallback(false, driver->inhibitOpaque);
1197 1198 1199
}


1200 1201 1202
static virDrvOpenStatus umlConnectOpen(virConnectPtr conn,
                                       virConnectAuthPtr auth ATTRIBUTE_UNUSED,
                                       unsigned int flags)
E
Eric Blake 已提交
1203 1204 1205
{
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

1206 1207 1208
    if (conn->uri == NULL) {
        if (uml_driver == NULL)
            return VIR_DRV_OPEN_DECLINED;
1209

1210 1211 1212
        if (!(conn->uri = virURIParse(uml_driver->privileged ?
                                      "uml:///system" :
                                      "uml:///session")))
1213 1214 1215
            return VIR_DRV_OPEN_ERROR;
    } else {
        if (conn->uri->scheme == NULL ||
1216
            STRNEQ(conn->uri->scheme, "uml"))
1217 1218 1219 1220 1221
            return VIR_DRV_OPEN_DECLINED;

        /* Allow remote driver to deal with URIs with hostname server */
        if (conn->uri->server != NULL)
            return VIR_DRV_OPEN_DECLINED;
1222 1223


1224
        /* Check path and tell them correct path if they made a mistake */
1225
        if (uml_driver->privileged) {
1226 1227
            if (STRNEQ(conn->uri->path, "/system") &&
                STRNEQ(conn->uri->path, "/session")) {
1228
                virReportError(VIR_ERR_INTERNAL_ERROR,
1229 1230 1231 1232 1233
                               _("unexpected UML URI path '%s', try uml:///system"),
                               conn->uri->path);
                return VIR_DRV_OPEN_ERROR;
            }
        } else {
1234
            if (STRNEQ(conn->uri->path, "/session")) {
1235
                virReportError(VIR_ERR_INTERNAL_ERROR,
1236 1237 1238 1239
                               _("unexpected UML URI path '%s', try uml:///session"),
                               conn->uri->path);
                return VIR_DRV_OPEN_ERROR;
            }
1240
        }
1241 1242 1243

        /* URI was good, but driver isn't active */
        if (uml_driver == NULL) {
1244
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1245
                           _("uml state driver is not active"));
1246 1247 1248 1249
            return VIR_DRV_OPEN_ERROR;
        }
    }

1250 1251 1252
    if (virConnectOpenEnsureACL(conn) < 0)
        return VIR_DRV_OPEN_ERROR;

1253 1254 1255 1256 1257
    conn->privateData = uml_driver;

    return VIR_DRV_OPEN_SUCCESS;
}

1258 1259
static int umlConnectClose(virConnectPtr conn)
{
1260 1261 1262
    struct uml_driver *driver = conn->privateData;

    umlDriverLock(driver);
1263
    umlProcessAutoDestroyRun(driver, conn);
1264
    umlDriverUnlock(driver);
1265 1266 1267 1268 1269 1270

    conn->privateData = NULL;

    return 0;
}

1271 1272 1273 1274
static const char *umlConnectGetType(virConnectPtr conn) {
    if (virConnectGetTypeEnsureACL(conn) < 0)
        return NULL;

1275 1276 1277 1278
    return "UML";
}


1279
static int umlConnectIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED)
1280 1281 1282 1283 1284 1285
{
    /* Trivially secure, since always inside the daemon */
    return 1;
}


1286
static int umlConnectIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED)
1287 1288 1289 1290 1291 1292
{
    /* Not encrypted, but remote driver takes care of that */
    return 0;
}


1293
static int umlConnectIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED)
1294 1295 1296 1297 1298
{
    return 1;
}


1299
static char *umlConnectGetCapabilities(virConnectPtr conn) {
1300 1301 1302
    struct uml_driver *driver = (struct uml_driver *)conn->privateData;
    char *xml;

1303 1304 1305
    if (virConnectGetCapabilitiesEnsureACL(conn) < 0)
        return NULL;

1306
    umlDriverLock(driver);
1307
    xml = virCapabilitiesFormatXML(driver->caps);
1308
    umlDriverUnlock(driver);
1309 1310 1311 1312 1313 1314

    return xml;
}



1315
static int umlGetProcessInfo(unsigned long long *cpuTime, pid_t pid)
1316 1317
{
    char *proc;
1318 1319 1320
    FILE *pidinfo;
    unsigned long long usertime, systime;

1321
    if (virAsprintf(&proc, "/proc/%lld/stat", (long long) pid) < 0)
1322 1323 1324 1325 1326
        return -1;

    if (!(pidinfo = fopen(proc, "r"))) {
        /* VM probably shut down, so fake 0 */
        *cpuTime = 0;
1327
        VIR_FREE(proc);
1328 1329 1330
        return 0;
    }

1331 1332
    VIR_FREE(proc);

1333 1334
    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");
1335
        VIR_FORCE_FCLOSE(pidinfo);
1336 1337 1338 1339 1340 1341
        return -1;
    }

    /* We got jiffies
     * We want nanoseconds
     * _SC_CLK_TCK is jiffies per second
N
Nehal J Wani 已提交
1342
     * So calculate thus....
1343 1344 1345 1346 1347
     */
    *cpuTime = 1000ull * 1000ull * 1000ull * (usertime + systime) / (unsigned long long)sysconf(_SC_CLK_TCK);

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

1348
    VIR_FORCE_FCLOSE(pidinfo);
1349 1350 1351 1352 1353 1354

    return 0;
}


static virDomainPtr umlDomainLookupByID(virConnectPtr conn,
1355 1356
                                          int id)
{
1357
    struct uml_driver *driver = (struct uml_driver *)conn->privateData;
1358 1359
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
1360

1361
    umlDriverLock(driver);
1362
    vm = virDomainObjListFindByID(driver->domains, id);
1363 1364
    umlDriverUnlock(driver);

1365
    if (!vm) {
1366
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
1367
        goto cleanup;
1368 1369
    }

1370 1371 1372
    if (virDomainLookupByIDEnsureACL(conn, vm->def) < 0)
        goto cleanup;

1373 1374
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
    if (dom) dom->id = vm->def->id;
1375

1376
 cleanup:
1377
    if (vm)
1378
        virObjectUnlock(vm);
1379 1380
    return dom;
}
1381

1382
static virDomainPtr umlDomainLookupByUUID(virConnectPtr conn,
1383 1384
                                            const unsigned char *uuid)
{
1385
    struct uml_driver *driver = (struct uml_driver *)conn->privateData;
1386 1387
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
1388

1389
    umlDriverLock(driver);
1390
    vm = virDomainObjListFindByUUID(driver->domains, uuid);
1391 1392
    umlDriverUnlock(driver);

1393
    if (!vm) {
1394
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
1395
        goto cleanup;
1396 1397
    }

1398 1399 1400
    if (virDomainLookupByUUIDEnsureACL(conn, vm->def) < 0)
        goto cleanup;

1401 1402
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
    if (dom) dom->id = vm->def->id;
1403

1404
 cleanup:
1405
    if (vm)
1406
        virObjectUnlock(vm);
1407 1408
    return dom;
}
1409

1410
static virDomainPtr umlDomainLookupByName(virConnectPtr conn,
1411 1412
                                            const char *name)
{
1413
    struct uml_driver *driver = (struct uml_driver *)conn->privateData;
1414 1415
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
1416

1417
    umlDriverLock(driver);
1418
    vm = virDomainObjListFindByName(driver->domains, name);
1419 1420
    umlDriverUnlock(driver);

1421
    if (!vm) {
1422
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
1423
        goto cleanup;
1424 1425
    }

1426 1427 1428
    if (virDomainLookupByNameEnsureACL(conn, vm->def) < 0)
        goto cleanup;

1429 1430
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
    if (dom) dom->id = vm->def->id;
1431

1432
 cleanup:
1433
    virDomainObjEndAPI(&vm);
1434 1435 1436
    return dom;
}

1437 1438 1439 1440 1441 1442 1443 1444

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

    umlDriverLock(driver);
1445
    obj = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1446 1447
    umlDriverUnlock(driver);
    if (!obj) {
1448
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
1449 1450
        goto cleanup;
    }
1451 1452 1453 1454

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

1455 1456
    ret = virDomainObjIsActive(obj);

1457
 cleanup:
1458
    if (obj)
1459
        virObjectUnlock(obj);
1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470
    return ret;
}


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

    umlDriverLock(driver);
1471
    obj = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1472 1473
    umlDriverUnlock(driver);
    if (!obj) {
1474
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
1475 1476
        goto cleanup;
    }
1477 1478 1479 1480

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

1481 1482
    ret = obj->persistent;

1483
 cleanup:
1484
    if (obj)
1485
        virObjectUnlock(obj);
1486 1487 1488
    return ret;
}

1489 1490 1491 1492 1493 1494 1495
static int umlDomainIsUpdated(virDomainPtr dom)
{
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr obj;
    int ret = -1;

    umlDriverLock(driver);
1496
    obj = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1497 1498
    umlDriverUnlock(driver);
    if (!obj) {
1499
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
1500 1501
        goto cleanup;
    }
1502 1503 1504 1505

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

1506 1507
    ret = obj->updated;

1508
 cleanup:
1509
    if (obj)
1510
        virObjectUnlock(obj);
1511 1512
    return ret;
}
1513

1514 1515
static int umlConnectGetVersion(virConnectPtr conn, unsigned long *version)
{
1516
    struct uml_driver *driver = conn->privateData;
1517
    struct utsname ut;
1518
    int ret = -1;
1519

1520 1521 1522
    if (virConnectGetVersionEnsureACL(conn) < 0)
        return -1;

1523
    umlDriverLock(driver);
1524 1525 1526 1527

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

1528
        if (virParseVersionString(ut.release, &driver->umlVersion, true) < 0) {
1529
            virReportError(VIR_ERR_INTERNAL_ERROR,
1530 1531 1532
                           _("cannot parse version %s"), ut.release);
            goto cleanup;
        }
1533 1534
    }

1535 1536 1537
    *version = driver->umlVersion;
    ret = 0;

1538
 cleanup:
1539 1540
    umlDriverUnlock(driver);
    return ret;
1541 1542
}

1543

1544
static char *umlConnectGetHostname(virConnectPtr conn)
1545
{
1546 1547 1548
    if (virConnectGetHostnameEnsureACL(conn) < 0)
        return NULL;

1549 1550 1551 1552
    return virGetHostname();
}


1553 1554
static int umlConnectListDomains(virConnectPtr conn, int *ids, int nids)
{
1555
    struct uml_driver *driver = conn->privateData;
1556
    int n;
1557

1558 1559 1560
    if (virConnectListDomainsEnsureACL(conn) < 0)
        return -1;

1561
    umlDriverLock(driver);
1562 1563
    n = virDomainObjListGetActiveIDs(driver->domains, ids, nids,
                                     virConnectListDomainsCheckACL, conn);
1564
    umlDriverUnlock(driver);
1565

1566
    return n;
1567
}
1568 1569
static int umlConnectNumOfDomains(virConnectPtr conn)
{
1570
    struct uml_driver *driver = conn->privateData;
1571
    int n;
1572

1573 1574 1575
    if (virConnectNumOfDomainsEnsureACL(conn) < 0)
        return -1;

1576
    umlDriverLock(driver);
1577 1578
    n = virDomainObjListNumOfDomains(driver->domains, true,
                                     virConnectNumOfDomainsCheckACL, conn);
1579
    umlDriverUnlock(driver);
1580 1581 1582

    return n;
}
1583
static virDomainPtr umlDomainCreateXML(virConnectPtr conn, const char *xml,
1584 1585
                                       unsigned int flags)
{
1586
    struct uml_driver *driver = conn->privateData;
1587
    virDomainDefPtr def;
1588
    virDomainObjPtr vm = NULL;
1589
    virDomainPtr dom = NULL;
1590
    virObjectEventPtr event = NULL;
1591
    unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
1592

1593 1594 1595 1596
    virCheckFlags(VIR_DOMAIN_START_AUTODESTROY |
                  VIR_DOMAIN_START_VALIDATE, NULL);

    if (flags & VIR_DOMAIN_START_VALIDATE)
1597
        parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA;
1598

1599
    virNWFilterReadLockFilterUpdates();
1600
    umlDriverLock(driver);
1601
    if (!(def = virDomainDefParseString(xml, driver->caps, driver->xmlopt,
1602
                                        parse_flags)))
1603
        goto cleanup;
1604

1605 1606 1607
    if (virDomainCreateXMLEnsureACL(conn, def) < 0)
        goto cleanup;

1608
    if (!(vm = virDomainObjListAdd(driver->domains, def,
1609
                                   driver->xmlopt,
1610
                                   VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
1611 1612
                                   VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
                                   NULL)))
1613 1614
        goto cleanup;
    def = NULL;
1615

1616 1617
    if (umlStartVMDaemon(conn, driver, vm,
                         (flags & VIR_DOMAIN_START_AUTODESTROY)) < 0) {
1618
        virDomainAuditStart(vm, "booted", false);
1619 1620 1621 1622
        if (!vm->persistent) {
            virDomainObjListRemove(driver->domains, vm);
            vm = NULL;
        }
1623
        goto cleanup;
1624
    }
1625
    virDomainAuditStart(vm, "booted", true);
1626
    event = virDomainEventLifecycleNewFromObj(vm,
1627 1628
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_BOOTED);
1629 1630 1631

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

1633
 cleanup:
1634
    virDomainDefFree(def);
1635
    if (vm)
1636
        virObjectUnlock(vm);
1637 1638
    if (event)
        umlDomainEventQueue(driver, event);
1639
    umlDriverUnlock(driver);
1640
    virNWFilterUnlockFilterUpdates();
1641 1642 1643 1644
    return dom;
}


1645
static int umlDomainShutdownFlags(virDomainPtr dom,
1646 1647
                                  unsigned int flags)
{
1648 1649
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
1650
    char *info = NULL;
1651
    int ret = -1;
1652

1653 1654
    virCheckFlags(0, -1);

1655
    umlDriverLock(driver);
1656
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1657
    umlDriverUnlock(driver);
1658
    if (!vm) {
1659
        virReportError(VIR_ERR_NO_DOMAIN,
1660
                       _("no domain with matching id %d"), dom->id);
1661
        goto cleanup;
1662 1663
    }

1664
    if (virDomainShutdownFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
1665 1666
        goto cleanup;

1667 1668
#if 0
    if (umlMonitorCommand(driver, vm, "system_powerdown", &info) < 0) {
1669
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
1670
                       _("shutdown operation failed"));
1671
        goto cleanup;
1672
    }
1673
    ret = 0;
1674 1675
#endif

1676
 cleanup:
1677
    VIR_FREE(info);
1678
    if (vm)
1679
        virObjectUnlock(vm);
1680
    return ret;
1681 1682
}

1683 1684 1685 1686 1687
static int
umlDomainShutdown(virDomainPtr dom)
{
    return umlDomainShutdownFlags(dom, 0);
}
1688

1689 1690 1691 1692
static int
umlDomainDestroyFlags(virDomainPtr dom,
                      unsigned int flags)
{
1693 1694
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
1695
    virObjectEventPtr event = NULL;
1696
    int ret = -1;
1697

1698 1699
    virCheckFlags(0, -1);

1700
    umlDriverLock(driver);
1701
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1702
    if (!vm) {
1703
        virReportError(VIR_ERR_NO_DOMAIN,
1704
                       _("no domain with matching id %d"), dom->id);
1705
        goto cleanup;
1706 1707
    }

1708 1709 1710
    if (virDomainDestroyFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

1711
    umlShutdownVMDaemon(driver, vm, VIR_DOMAIN_SHUTOFF_DESTROYED);
1712
    virDomainAuditStop(vm, "destroyed");
1713
    event = virDomainEventLifecycleNewFromObj(vm,
1714 1715
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
1716
    if (!vm->persistent) {
1717 1718
        virDomainObjListRemove(driver->domains,
                               vm);
1719 1720 1721
        vm = NULL;
    }
    ret = 0;
1722

1723
 cleanup:
1724
    if (vm)
1725
        virObjectUnlock(vm);
1726 1727
    if (event)
        umlDomainEventQueue(driver, event);
1728
    umlDriverUnlock(driver);
1729
    return ret;
1730 1731 1732
}


1733 1734 1735 1736 1737 1738
static int umlDomainDestroy(virDomainPtr dom)
{
    return umlDomainDestroyFlags(dom, 0);
}


1739
static char *umlDomainGetOSType(virDomainPtr dom) {
1740 1741 1742
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *type = NULL;
1743

1744
    umlDriverLock(driver);
1745
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1746
    umlDriverUnlock(driver);
1747
    if (!vm) {
1748
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
1749
                       _("no domain with matching uuid"));
1750
        goto cleanup;
1751 1752
    }

1753 1754 1755
    if (virDomainGetOSTypeEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

1756
    if (VIR_STRDUP(type, virDomainOSTypeToString(vm->def->os.type)) < 0)
1757
        goto cleanup;
1758

1759
 cleanup:
1760
    if (vm)
1761
        virObjectUnlock(vm);
1762 1763 1764 1765
    return type;
}

/* Returns max memory in kb, 0 if error */
1766 1767 1768
static unsigned long long
umlDomainGetMaxMemory(virDomainPtr dom)
{
1769 1770
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
1771
    unsigned long long ret = 0;
1772

1773
    umlDriverLock(driver);
1774
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1775 1776
    umlDriverUnlock(driver);

1777 1778 1779 1780
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];

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

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

1789
    ret = virDomainDefGetMemoryActual(vm->def);
1790

1791
 cleanup:
1792
    if (vm)
1793
        virObjectUnlock(vm);
1794
    return ret;
1795 1796
}

1797 1798
static int umlDomainSetMaxMemory(virDomainPtr dom, unsigned long newmax)
{
1799 1800 1801
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
1802

1803
    umlDriverLock(driver);
1804
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1805 1806
    umlDriverUnlock(driver);

1807 1808 1809 1810
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];

        virUUIDFormat(dom->uuid, uuidstr);
1811
        virReportError(VIR_ERR_NO_DOMAIN,
1812
                       _("no domain with matching uuid '%s'"), uuidstr);
1813
        goto cleanup;
1814 1815
    }

1816 1817 1818
    if (virDomainSetMaxMemoryEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

1819
    if (newmax < vm->def->mem.cur_balloon) {
1820
        virReportError(VIR_ERR_INVALID_ARG, "%s",
1821
                       _("cannot set max memory lower than current memory"));
1822
        goto cleanup;
1823 1824
    }

1825
    virDomainDefSetMemoryTotal(vm->def, newmax);
1826 1827
    ret = 0;

1828
 cleanup:
1829
    if (vm)
1830
        virObjectUnlock(vm);
1831
    return ret;
1832 1833
}

1834 1835
static int umlDomainSetMemory(virDomainPtr dom, unsigned long newmem)
{
1836 1837 1838
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
1839

1840
    umlDriverLock(driver);
1841
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1842 1843
    umlDriverUnlock(driver);

1844 1845 1846 1847
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];

        virUUIDFormat(dom->uuid, uuidstr);
1848
        virReportError(VIR_ERR_NO_DOMAIN,
1849
                       _("no domain with matching uuid '%s'"), uuidstr);
1850
        goto cleanup;
1851 1852
    }

1853 1854 1855
    if (virDomainSetMemoryEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

D
Daniel P. Berrange 已提交
1856
    if (virDomainObjIsActive(vm)) {
1857
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
1858
                       _("cannot set memory of an active domain"));
1859
        goto cleanup;
1860 1861
    }

1862
    if (newmem > virDomainDefGetMemoryActual(vm->def)) {
1863
        virReportError(VIR_ERR_INVALID_ARG, "%s",
1864
                       _("cannot set memory higher than max memory"));
1865
        goto cleanup;
1866 1867
    }

1868
    vm->def->mem.cur_balloon = newmem;
1869 1870
    ret = 0;

1871
 cleanup:
1872
    if (vm)
1873
        virObjectUnlock(vm);
1874
    return ret;
1875 1876 1877
}

static int umlDomainGetInfo(virDomainPtr dom,
1878 1879
                              virDomainInfoPtr info)
{
1880 1881 1882 1883
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;

1884
    umlDriverLock(driver);
1885
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1886 1887
    umlDriverUnlock(driver);

1888
    if (!vm) {
1889
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
1890
                       _("no domain with matching uuid"));
1891
        goto cleanup;
1892 1893
    }

1894 1895 1896
    if (virDomainGetInfoEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

D
Daniel P. Berrange 已提交
1899
    if (!virDomainObjIsActive(vm)) {
1900 1901 1902
        info->cpuTime = 0;
    } else {
        if (umlGetProcessInfo(&(info->cpuTime), vm->pid) < 0) {
1903
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
1904
                           _("cannot read cputime for domain"));
1905
            goto cleanup;
1906 1907 1908
        }
    }

1909
    info->maxMem = virDomainDefGetMemoryActual(vm->def);
1910
    info->memory = vm->def->mem.cur_balloon;
1911
    info->nrVirtCpu = virDomainDefGetVcpus(vm->def);
1912 1913
    ret = 0;

1914
 cleanup:
1915
    if (vm)
1916
        virObjectUnlock(vm);
1917
    return ret;
1918 1919 1920
}


1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933
static int
umlDomainGetState(virDomainPtr dom,
                  int *state,
                  int *reason,
                  unsigned int flags)
{
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;

    virCheckFlags(0, -1);

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

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

1943 1944 1945
    if (virDomainGetStateEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

J
Jiri Denemark 已提交
1946
    *state = virDomainObjGetState(vm, reason);
1947 1948
    ret = 0;

1949
 cleanup:
1950
    if (vm)
1951
        virObjectUnlock(vm);
1952 1953 1954 1955
    return ret;
}


1956
static char *umlDomainGetXMLDesc(virDomainPtr dom,
E
Eric Blake 已提交
1957 1958
                                 unsigned int flags)
{
1959 1960 1961 1962
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *ret = NULL;

1963
    /* Flags checked by virDomainDefFormat */
E
Eric Blake 已提交
1964

1965
    umlDriverLock(driver);
1966
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1967 1968
    umlDriverUnlock(driver);

1969
    if (!vm) {
1970
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
1971
                       _("no domain with matching uuid"));
1972
        goto cleanup;
1973 1974
    }

1975 1976 1977
    if (virDomainGetXMLDescEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

1978
    ret = virDomainDefFormat((flags & VIR_DOMAIN_XML_INACTIVE) && vm->newDef ?
1979
                             vm->newDef : vm->def, driver->caps,
1980
                             virDomainDefFormatConvertXMLFlags(flags));
1981

1982
 cleanup:
1983
    if (vm)
1984
        virObjectUnlock(vm);
1985
    return ret;
1986 1987 1988
}


1989 1990
static int umlConnectListDefinedDomains(virConnectPtr conn,
                                        char **const names, int nnames) {
1991
    struct uml_driver *driver = conn->privateData;
1992
    int n;
1993

1994 1995 1996
    if (virConnectListDefinedDomainsEnsureACL(conn) < 0)
        return -1;

1997
    umlDriverLock(driver);
1998 1999
    n = virDomainObjListGetInactiveNames(driver->domains, names, nnames,
                                         virConnectListDefinedDomainsCheckACL, conn);
2000
    umlDriverUnlock(driver);
2001

2002
    return n;
2003 2004
}

2005 2006
static int umlConnectNumOfDefinedDomains(virConnectPtr conn)
{
2007
    struct uml_driver *driver = conn->privateData;
2008
    int n;
2009

2010 2011 2012
    if (virConnectNumOfDefinedDomainsEnsureACL(conn) < 0)
        return -1;

2013
    umlDriverLock(driver);
2014 2015
    n = virDomainObjListNumOfDomains(driver->domains, false,
                                     virConnectNumOfDefinedDomainsCheckACL, conn);
2016
    umlDriverUnlock(driver);
2017 2018 2019 2020 2021

    return n;
}


2022 2023
static int umlDomainCreateWithFlags(virDomainPtr dom, unsigned int flags)
{
2024 2025
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
2026
    virObjectEventPtr event = NULL;
2027
    int ret = -1;
2028

2029
    virCheckFlags(VIR_DOMAIN_START_AUTODESTROY, -1);
2030

2031
    virNWFilterReadLockFilterUpdates();
2032
    umlDriverLock(driver);
2033
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
2034

2035
    if (!vm) {
2036
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
2037
                       _("no domain with matching uuid"));
2038
        goto cleanup;
2039 2040
    }

2041 2042 2043
    if (virDomainCreateWithFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2044 2045
    ret = umlStartVMDaemon(dom->conn, driver, vm,
                           (flags & VIR_DOMAIN_START_AUTODESTROY));
2046
    virDomainAuditStart(vm, "booted", ret >= 0);
2047
    if (ret == 0)
2048
        event = virDomainEventLifecycleNewFromObj(vm,
2049 2050
                                         VIR_DOMAIN_EVENT_STARTED,
                                         VIR_DOMAIN_EVENT_STARTED_BOOTED);
2051

2052
 cleanup:
2053
    if (vm)
2054
        virObjectUnlock(vm);
2055 2056
    if (event)
        umlDomainEventQueue(driver, event);
2057
    umlDriverUnlock(driver);
2058
    virNWFilterUnlockFilterUpdates();
2059
    return ret;
2060 2061
}

2062 2063
static int umlDomainCreate(virDomainPtr dom)
{
2064
    return umlDomainCreateWithFlags(dom, 0);
2065
}
2066

2067 2068
static virDomainPtr
umlDomainDefineXMLFlags(virConnectPtr conn, const char *xml, unsigned int flags)
2069
{
2070
    struct uml_driver *driver = conn->privateData;
2071
    virDomainDefPtr def;
2072
    virDomainObjPtr vm = NULL;
2073
    virDomainPtr dom = NULL;
2074 2075 2076
    unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;

    virCheckFlags(VIR_DOMAIN_DEFINE_VALIDATE, NULL);
2077

2078
    if (flags & VIR_DOMAIN_DEFINE_VALIDATE)
2079
        parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA;
2080

2081
    umlDriverLock(driver);
2082
    if (!(def = virDomainDefParseString(xml, driver->caps, driver->xmlopt,
2083
                                        parse_flags)))
2084
        goto cleanup;
2085

2086
    if (virDomainDefineXMLFlagsEnsureACL(conn, def) < 0)
2087 2088
        goto cleanup;

2089
    if (!(vm = virDomainObjListAdd(driver->domains, def,
2090
                                   driver->xmlopt,
2091
                                   0, NULL)))
2092 2093
        goto cleanup;
    def = NULL;
2094 2095
    vm->persistent = 1;

2096
    if (virDomainSaveConfig(driver->configDir, driver->caps,
2097
                            vm->newDef ? vm->newDef : vm->def) < 0) {
2098 2099
        virDomainObjListRemove(driver->domains,
                               vm);
2100
        vm = NULL;
2101
        goto cleanup;
2102 2103 2104 2105
    }

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

2107
 cleanup:
2108
    virDomainDefFree(def);
2109
    if (vm)
2110
        virObjectUnlock(vm);
2111
    umlDriverUnlock(driver);
2112 2113 2114
    return dom;
}

2115 2116 2117 2118 2119 2120
static virDomainPtr
umlDomainDefineXML(virConnectPtr conn, const char *xml)
{
    return umlDomainDefineXMLFlags(conn, xml, 0);
}

2121 2122 2123
static int umlDomainUndefineFlags(virDomainPtr dom,
                                  unsigned int flags)
{
2124 2125 2126
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
2127

2128 2129
    virCheckFlags(0, -1);

2130
    umlDriverLock(driver);
2131
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
2132
    if (!vm) {
2133
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
2134
                       _("no domain with matching uuid"));
2135
        goto cleanup;
2136 2137
    }

2138 2139 2140
    if (virDomainUndefineFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2141
    if (!vm->persistent) {
2142
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
2143
                       _("cannot undefine transient domain"));
2144
        goto cleanup;
2145 2146
    }

2147
    if (virDomainDeleteConfig(driver->configDir, driver->autostartDir, vm) < 0)
2148
        goto cleanup;
2149

2150 2151 2152
    if (virDomainObjIsActive(vm)) {
        vm->persistent = 0;
    } else {
2153
        virDomainObjListRemove(driver->domains, vm);
2154 2155 2156
        vm = NULL;
    }

2157
    ret = 0;
2158

2159
 cleanup:
2160
    if (vm)
2161
        virObjectUnlock(vm);
2162
    umlDriverUnlock(driver);
2163
    return ret;
2164 2165 2166
}


2167 2168 2169 2170 2171
static int umlDomainUndefine(virDomainPtr dom)
{
    return umlDomainUndefineFlags(dom, 0);
}

2172 2173 2174 2175
static int umlDomainAttachUmlDisk(struct uml_driver *driver,
                                  virDomainObjPtr vm,
                                  virDomainDiskDefPtr disk)
{
2176
    size_t i;
2177 2178 2179
    char *cmd = NULL;
    char *reply = NULL;

2180
    for (i = 0; i < vm->def->ndisks; i++) {
2181
        if (STREQ(vm->def->disks[i]->dst, disk->dst)) {
2182
            virReportError(VIR_ERR_OPERATION_FAILED,
2183 2184 2185 2186 2187
                           _("target %s already exists"), disk->dst);
            return -1;
        }
    }

2188
    if (!virDomainDiskGetSource(disk)) {
2189
        virReportError(VIR_ERR_INTERNAL_ERROR,
2190 2191 2192 2193
                       "%s", _("disk source path is missing"));
        goto error;
    }

2194 2195
    if (virAsprintf(&cmd, "config %s=%s", disk->dst,
                    virDomainDiskGetSource(disk)) < 0)
2196 2197 2198 2199 2200
        return -1;

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

2201
    if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0)
2202 2203 2204 2205 2206 2207 2208 2209 2210
        goto error;

    virDomainDiskInsertPreAlloced(vm->def, disk);

    VIR_FREE(reply);
    VIR_FREE(cmd);

    return 0;

2211
 error:
2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228

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

2229
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
2230 2231 2232
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
2233
        virReportError(VIR_ERR_NO_DOMAIN,
2234 2235 2236 2237
                       _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

2238 2239 2240
    if (virDomainAttachDeviceEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2241
    if (!virDomainObjIsActive(vm)) {
2242
        virReportError(VIR_ERR_OPERATION_INVALID,
2243 2244 2245 2246
                       "%s", _("cannot attach device on inactive domain"));
        goto cleanup;
    }

2247
    dev = virDomainDeviceDefParse(xml, vm->def, driver->caps, driver->xmlopt,
2248
                                  VIR_DOMAIN_DEF_PARSE_INACTIVE);
2249 2250 2251 2252 2253 2254 2255 2256 2257 2258

    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 {
2259
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
2260 2261 2262 2263
                           _("disk bus '%s' cannot be hotplugged."),
                           virDomainDiskBusTypeToString(dev->data.disk->bus));
        }
    } else {
2264
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
2265 2266 2267 2268 2269
                       _("device type '%s' cannot be attached"),
                       virDomainDeviceTypeToString(dev->type));
        goto cleanup;
    }

2270
 cleanup:
2271 2272 2273

    virDomainDeviceDefFree(dev);
    if (vm)
2274
        virObjectUnlock(vm);
2275 2276 2277 2278 2279
    umlDriverUnlock(driver);
    return ret;
}


2280 2281 2282 2283 2284 2285 2286
static int
umlDomainAttachDeviceFlags(virDomainPtr dom,
                           const char *xml,
                           unsigned int flags)
{
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG, -1);

2287
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
2288
        virReportError(VIR_ERR_OPERATION_INVALID,
2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300
                       "%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)
{
2301 2302
    size_t i;
    int ret = -1;
2303 2304 2305 2306
    virDomainDiskDefPtr detach = NULL;
    char *cmd;
    char *reply;

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

    if (i == vm->def->ndisks) {
2313
        virReportError(VIR_ERR_OPERATION_FAILED,
2314 2315 2316 2317 2318 2319
                       _("disk %s not found"), dev->data.disk->dst);
        return -1;
    }

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

2320
    if (virAsprintf(&cmd, "remove %s", detach->dst) < 0)
2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333
        return -1;

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

    virDomainDiskRemove(vm->def, i);

    virDomainDiskDefFree(detach);

    ret = 0;

    VIR_FREE(reply);

2334
 cleanup:
2335 2336 2337 2338 2339 2340
    VIR_FREE(cmd);

    return ret;
}


2341 2342
static int umlDomainDetachDevice(virDomainPtr dom, const char *xml)
{
2343 2344 2345 2346 2347 2348
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    virDomainDeviceDefPtr dev = NULL;
    int ret = -1;

    umlDriverLock(driver);
2349
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
2350 2351 2352
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
2353
        virReportError(VIR_ERR_NO_DOMAIN,
2354 2355 2356 2357
                       _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

2358 2359 2360
    if (virDomainDetachDeviceEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2361
    if (!virDomainObjIsActive(vm)) {
2362
        virReportError(VIR_ERR_OPERATION_INVALID,
2363 2364 2365 2366
                       "%s", _("cannot detach device on inactive domain"));
        goto cleanup;
    }

2367
    dev = virDomainDeviceDefParse(xml, vm->def, driver->caps, driver->xmlopt,
2368 2369
                                  VIR_DOMAIN_DEF_PARSE_INACTIVE |
                                  VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE);
2370 2371 2372 2373 2374 2375 2376
    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);
2377
        else
2378
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2379 2380
                           _("This type of disk cannot be hot unplugged"));
    } else {
2381
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
2382 2383 2384
                       "%s", _("This type of device cannot be hot unplugged"));
    }

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


2394 2395 2396 2397 2398 2399 2400
static int
umlDomainDetachDeviceFlags(virDomainPtr dom,
                           const char *xml,
                           unsigned int flags)
{
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG, -1);

2401
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
2402
        virReportError(VIR_ERR_OPERATION_INVALID,
2403 2404 2405 2406 2407 2408 2409
                       "%s", _("cannot modify the persistent configuration of a domain"));
        return -1;
    }

    return umlDomainDetachDevice(dom, xml);
}

2410 2411

static int umlDomainGetAutostart(virDomainPtr dom,
2412 2413
                            int *autostart)
{
2414 2415 2416
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
2417

2418
    umlDriverLock(driver);
2419
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
2420

2421
    if (!vm) {
2422
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
2423
                       _("no domain with matching uuid"));
2424
        goto cleanup;
2425 2426
    }

2427 2428 2429
    if (virDomainGetAutostartEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2430
    *autostart = vm->autostart;
2431
    ret = 0;
2432

2433
 cleanup:
2434
    if (vm)
2435
        virObjectUnlock(vm);
2436
    umlDriverUnlock(driver);
2437
    return ret;
2438 2439 2440
}

static int umlDomainSetAutostart(virDomainPtr dom,
2441 2442
                                   int autostart)
{
2443
    struct uml_driver *driver = dom->conn->privateData;
2444
    virDomainObjPtr vm;
2445 2446 2447
    char *configFile = NULL, *autostartLink = NULL;
    int ret = -1;

2448
    umlDriverLock(driver);
2449
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
2450

2451
    if (!vm) {
2452
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
2453
                       _("no domain with matching uuid"));
2454
        goto cleanup;
2455 2456
    }

2457 2458 2459
    if (virDomainSetAutostartEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2460
    if (!vm->persistent) {
2461
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
2462
                       _("cannot set autostart for transient domain"));
2463
        goto cleanup;
2464 2465 2466 2467
    }

    autostart = (autostart != 0);

2468
    if (vm->autostart != autostart) {
2469
        if ((configFile = virDomainConfigFile(driver->configDir, vm->def->name)) == NULL)
2470
            goto cleanup;
2471
        if ((autostartLink = virDomainConfigFile(driver->autostartDir, vm->def->name)) == NULL)
2472
            goto cleanup;
2473

2474
        if (autostart) {
2475 2476
            if (virFileMakePath(driver->autostartDir) < 0) {
                virReportSystemError(errno,
2477 2478
                                     _("cannot create autostart directory %s"),
                                     driver->autostartDir);
2479 2480
                goto cleanup;
            }
2481

2482
            if (symlink(configFile, autostartLink) < 0) {
2483
                virReportSystemError(errno,
2484 2485
                                     _("Failed to create symlink '%s to '%s'"),
                                     autostartLink, configFile);
2486 2487 2488 2489
                goto cleanup;
            }
        } else {
            if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
2490
                virReportSystemError(errno,
2491 2492
                                     _("Failed to delete symlink '%s'"),
                                     autostartLink);
2493 2494
                goto cleanup;
            }
2495 2496
        }

2497
        vm->autostart = autostart;
2498 2499 2500
    }
    ret = 0;

2501
 cleanup:
2502 2503
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
2504
    if (vm)
2505
        virObjectUnlock(vm);
2506
    umlDriverUnlock(driver);
2507 2508 2509 2510 2511
    return ret;
}


static int
2512 2513 2514 2515
umlDomainBlockPeek(virDomainPtr dom,
                   const char *path,
                   unsigned long long offset, size_t size,
                   void *buffer,
E
Eric Blake 已提交
2516
                   unsigned int flags)
2517
{
2518 2519
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
2520 2521
    int fd = -1, ret = -1;
    const char *actual;
2522

E
Eric Blake 已提交
2523 2524
    virCheckFlags(0, -1);

2525
    umlDriverLock(driver);
2526
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
2527 2528
    umlDriverUnlock(driver);

2529
    if (!vm) {
2530
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
2531
                       _("no domain with matching uuid"));
2532
        goto cleanup;
2533 2534
    }

2535 2536 2537
    if (virDomainBlockPeekEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2538
    if (!path || path[0] == '\0') {
2539
        virReportError(VIR_ERR_INVALID_ARG, "%s",
2540
                       _("NULL or empty path"));
2541
        goto cleanup;
2542 2543 2544
    }

    /* Check the path belongs to this domain. */
2545
    if (!(actual = virDomainDiskPathByName(vm->def, path))) {
2546
        virReportError(VIR_ERR_INVALID_ARG,
2547 2548
                       _("invalid path '%s'"), path);
        goto cleanup;
2549
    }
2550
    path = actual;
2551

2552 2553 2554 2555 2556 2557 2558
    /* 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;
    }
2559

2560 2561 2562 2563 2564 2565 2566 2567 2568
    /* Seek and read. */
    /* NB. Because we configure with AC_SYS_LARGEFILE, off_t should
     * be 64 bits on all platforms.
     */
    if (lseek(fd, offset, SEEK_SET) == (off_t) -1 ||
        saferead(fd, buffer, size) == (ssize_t) -1) {
        virReportSystemError(errno,
                             _("cannot read %s"), path);
        goto cleanup;
2569 2570
    }

2571 2572
    ret = 0;

2573
 cleanup:
2574
    VIR_FORCE_CLOSE(fd);
2575
    if (vm)
2576
        virObjectUnlock(vm);
2577 2578 2579 2580
    return ret;
}


2581 2582
static int
umlDomainOpenConsole(virDomainPtr dom,
2583
                     const char *dev_name,
2584 2585 2586 2587 2588 2589 2590 2591
                     virStreamPtr st,
                     unsigned int flags)
{
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm = NULL;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    int ret = -1;
    virDomainChrDefPtr chr = NULL;
2592
    size_t i;
2593 2594 2595 2596 2597

    virCheckFlags(0, -1);

    umlDriverLock(driver);
    virUUIDFormat(dom->uuid, uuidstr);
2598
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
2599
    if (!vm) {
2600
        virReportError(VIR_ERR_NO_DOMAIN,
2601 2602 2603 2604
                       _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

2605 2606 2607
    if (virDomainOpenConsoleEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2608
    if (!virDomainObjIsActive(vm)) {
2609
        virReportError(VIR_ERR_OPERATION_INVALID,
2610 2611 2612 2613
                        "%s", _("domain is not running"));
        goto cleanup;
    }

2614
    if (dev_name) {
2615
        for (i = 0; i < vm->def->nconsoles; i++) {
2616 2617 2618 2619 2620 2621
            if (vm->def->consoles[i]->info.alias &&
                STREQ(vm->def->consoles[i]->info.alias, dev_name)) {
                chr = vm->def->consoles[i];
                break;
            }
        }
2622
    } else {
2623 2624
        if (vm->def->nconsoles)
            chr = vm->def->consoles[0];
2625 2626 2627 2628 2629
        else if (vm->def->nserials)
            chr = vm->def->serials[0];
    }

    if (!chr) {
2630
        virReportError(VIR_ERR_INTERNAL_ERROR,
2631 2632
                       _("cannot find console device '%s'"),
                       dev_name ? dev_name : _("default"));
2633 2634 2635
        goto cleanup;
    }

2636
    if (chr->source.type != VIR_DOMAIN_CHR_TYPE_PTY) {
2637
        virReportError(VIR_ERR_INTERNAL_ERROR,
2638 2639
                        _("character device %s is not using a PTY"),
                       dev_name ? dev_name : NULLSTR(chr->info.alias));
2640 2641 2642
        goto cleanup;
    }

2643
    if (virFDStreamOpenFile(st, chr->source.data.file.path,
E
Eric Blake 已提交
2644
                            0, 0, O_RDWR) < 0)
2645 2646 2647
        goto cleanup;

    ret = 0;
2648
 cleanup:
2649
    if (vm)
2650
        virObjectUnlock(vm);
2651 2652 2653 2654
    umlDriverUnlock(driver);
    return ret;
}

2655

2656
static int
2657 2658 2659 2660
umlConnectDomainEventRegister(virConnectPtr conn,
                              virConnectDomainEventCallback callback,
                              void *opaque,
                              virFreeCallback freecb)
2661 2662
{
    struct uml_driver *driver = conn->privateData;
2663
    int ret = 0;
2664

2665 2666 2667
    if (virConnectDomainEventRegisterEnsureACL(conn) < 0)
        return -1;

2668
    umlDriverLock(driver);
2669 2670 2671 2672
    if (virDomainEventStateRegister(conn,
                                    driver->domainEventState,
                                    callback, opaque, freecb) < 0)
        ret = -1;
2673 2674 2675 2676 2677 2678
    umlDriverUnlock(driver);

    return ret;
}

static int
2679 2680
umlConnectDomainEventDeregister(virConnectPtr conn,
                                virConnectDomainEventCallback callback)
2681 2682
{
    struct uml_driver *driver = conn->privateData;
2683
    int ret = 0;
2684

2685 2686 2687
    if (virConnectDomainEventDeregisterEnsureACL(conn) < 0)
        return -1;

2688
    umlDriverLock(driver);
2689 2690 2691 2692
    if (virDomainEventStateDeregister(conn,
                                      driver->domainEventState,
                                      callback) < 0)
        ret = -1;
2693 2694 2695 2696 2697 2698
    umlDriverUnlock(driver);

    return ret;
}

static int
2699 2700 2701 2702 2703 2704
umlConnectDomainEventRegisterAny(virConnectPtr conn,
                                 virDomainPtr dom,
                                 int eventID,
                                 virConnectDomainEventGenericCallback callback,
                                 void *opaque,
                                 virFreeCallback freecb)
2705 2706 2707 2708
{
    struct uml_driver *driver = conn->privateData;
    int ret;

2709 2710 2711
    if (virConnectDomainEventRegisterAnyEnsureACL(conn) < 0)
        return -1;

2712
    umlDriverLock(driver);
2713 2714 2715 2716
    if (virDomainEventStateRegisterID(conn,
                                      driver->domainEventState,
                                      dom, eventID,
                                      callback, opaque, freecb, &ret) < 0)
2717
        ret = -1;
2718 2719 2720 2721 2722 2723 2724
    umlDriverUnlock(driver);

    return ret;
}


static int
2725 2726
umlConnectDomainEventDeregisterAny(virConnectPtr conn,
                                   int callbackID)
2727 2728
{
    struct uml_driver *driver = conn->privateData;
2729
    int ret = 0;
2730

2731 2732 2733
    if (virConnectDomainEventDeregisterAnyEnsureACL(conn) < 0)
        return -1;

2734
    umlDriverLock(driver);
2735 2736 2737 2738
    if (virObjectEventStateDeregisterID(conn,
                                        driver->domainEventState,
                                        callbackID) < 0)
        ret = -1;
2739 2740 2741 2742 2743 2744 2745 2746
    umlDriverUnlock(driver);

    return ret;
}


/* driver must be locked before calling */
static void umlDomainEventQueue(struct uml_driver *driver,
2747
                                virObjectEventPtr event)
2748
{
2749
    virObjectEventStateQueue(driver->domainEventState, event);
2750 2751
}

2752 2753 2754
static int umlConnectListAllDomains(virConnectPtr conn,
                                    virDomainPtr **domains,
                                    unsigned int flags)
2755 2756 2757 2758
{
    struct uml_driver *driver = conn->privateData;
    int ret = -1;

O
Osier Yang 已提交
2759
    virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
2760

2761 2762 2763
    if (virConnectListAllDomainsEnsureACL(conn) < 0)
        return -1;

2764
    umlDriverLock(driver);
2765 2766
    ret = virDomainObjListExport(driver->domains, conn, domains,
                                 virConnectListAllDomainsCheckACL, flags);
2767 2768 2769 2770 2771
    umlDriverUnlock(driver);

    return ret;
}

2772

2773
static int
2774
umlNodeGetInfo(virConnectPtr conn,
2775 2776
               virNodeInfoPtr nodeinfo)
{
2777 2778 2779
    if (virNodeGetInfoEnsureACL(conn) < 0)
        return -1;

2780
    return nodeGetInfo(NULL, nodeinfo);
2781 2782 2783 2784
}


static int
2785
umlNodeGetCPUStats(virConnectPtr conn,
2786 2787 2788 2789 2790
                   int cpuNum,
                   virNodeCPUStatsPtr params,
                   int *nparams,
                   unsigned int flags)
{
2791 2792 2793
    if (virNodeGetCPUStatsEnsureACL(conn) < 0)
        return -1;

2794 2795 2796 2797 2798
    return nodeGetCPUStats(cpuNum, params, nparams, flags);
}


static int
2799
umlNodeGetMemoryStats(virConnectPtr conn,
2800 2801 2802 2803 2804
                      int cellNum,
                      virNodeMemoryStatsPtr params,
                      int *nparams,
                      unsigned int flags)
{
2805 2806 2807
    if (virNodeGetMemoryStatsEnsureACL(conn) < 0)
        return -1;

2808
    return nodeGetMemoryStats(NULL, cellNum, params, nparams, flags);
2809 2810 2811 2812
}


static int
2813
umlNodeGetCellsFreeMemory(virConnectPtr conn,
2814 2815 2816 2817
                          unsigned long long *freeMems,
                          int startCell,
                          int maxCells)
{
2818 2819 2820
    if (virNodeGetCellsFreeMemoryEnsureACL(conn) < 0)
        return -1;

2821 2822 2823 2824 2825
    return nodeGetCellsFreeMemory(freeMems, startCell, maxCells);
}


static unsigned long long
2826
umlNodeGetFreeMemory(virConnectPtr conn)
2827
{
2828 2829
    unsigned long long freeMem;

2830 2831 2832
    if (virNodeGetFreeMemoryEnsureACL(conn) < 0)
        return 0;

2833 2834 2835 2836
    if (nodeGetMemory(NULL, &freeMem) < 0)
        return 0;

    return freeMem;
2837 2838 2839 2840
}


static int
2841
umlNodeGetMemoryParameters(virConnectPtr conn,
2842 2843 2844 2845
                           virTypedParameterPtr params,
                           int *nparams,
                           unsigned int flags)
{
2846 2847 2848
    if (virNodeGetMemoryParametersEnsureACL(conn) < 0)
        return -1;

2849 2850 2851 2852 2853
    return nodeGetMemoryParameters(params, nparams, flags);
}


static int
2854
umlNodeSetMemoryParameters(virConnectPtr conn,
2855 2856 2857 2858
                           virTypedParameterPtr params,
                           int nparams,
                           unsigned int flags)
{
2859 2860 2861
    if (virNodeSetMemoryParametersEnsureACL(conn) < 0)
        return -1;

2862 2863 2864 2865 2866
    return nodeSetMemoryParameters(params, nparams, flags);
}


static int
2867
umlNodeGetCPUMap(virConnectPtr conn,
2868 2869 2870 2871
                 unsigned char **cpumap,
                 unsigned int *online,
                 unsigned int flags)
{
2872 2873 2874
    if (virNodeGetCPUMapEnsureACL(conn) < 0)
        return -1;

2875
    return nodeGetCPUMap(NULL, cpumap, online, flags);
2876 2877
}

2878

2879
static int
2880
umlNodeSuspendForDuration(virConnectPtr conn,
2881 2882 2883 2884
                          unsigned int target,
                          unsigned long long duration,
                          unsigned int flags)
{
2885 2886 2887
    if (virNodeSuspendForDurationEnsureACL(conn) < 0)
        return -1;

2888 2889 2890 2891
    return nodeSuspendForDuration(target, duration, flags);
}


2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909
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;

    return nodeGetFreePages(npages, pages, startCell, cellCount, counts);
}


2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930
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;

    return nodeAllocPages(npages, pageSizes, pageCounts,
                          startCell, cellCount, add);
}


2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960
static int
umlDomainHasManagedSaveImage(virDomainPtr dom, unsigned int flags)
{
    struct uml_driver *driver = dom->conn->privateData;
    int ret = -1;
    virDomainObjPtr vm;

    virCheckFlags(0, -1);

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

    if (!vm) {
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
        goto cleanup;
    }

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

    ret = 0;

 cleanup:
    if (vm)
        virObjectUnlock(vm);
    return ret;
}


2961
static virHypervisorDriver umlHypervisorDriver = {
2962
    .name = "UML",
2963 2964 2965 2966
    .connectOpen = umlConnectOpen, /* 0.5.0 */
    .connectClose = umlConnectClose, /* 0.5.0 */
    .connectGetType = umlConnectGetType, /* 0.5.0 */
    .connectGetVersion = umlConnectGetVersion, /* 0.5.0 */
2967
    .connectGetHostname = umlConnectGetHostname, /* 0.5.0 */
2968
    .nodeGetInfo = umlNodeGetInfo, /* 0.5.0 */
2969 2970 2971 2972 2973
    .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 */
2974 2975 2976 2977
    .domainLookupByID = umlDomainLookupByID, /* 0.5.0 */
    .domainLookupByUUID = umlDomainLookupByUUID, /* 0.5.0 */
    .domainLookupByName = umlDomainLookupByName, /* 0.5.0 */
    .domainShutdown = umlDomainShutdown, /* 0.5.0 */
2978
    .domainShutdownFlags = umlDomainShutdownFlags, /* 0.9.10 */
2979
    .domainDestroy = umlDomainDestroy, /* 0.5.0 */
2980
    .domainDestroyFlags = umlDomainDestroyFlags, /* 0.9.4 */
2981 2982 2983 2984 2985 2986 2987
    .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 */
2988 2989 2990 2991 2992
    .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 */
2993
    .domainDefineXMLFlags = umlDomainDefineXMLFlags, /* 1.2.12 */
2994
    .domainUndefine = umlDomainUndefine, /* 0.5.0 */
2995
    .domainUndefineFlags = umlDomainUndefineFlags, /* 0.9.4 */
2996 2997 2998 2999 3000 3001 3002
    .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 */
3003 3004 3005 3006 3007
    .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 */
3008 3009 3010 3011
    .connectDomainEventRegister = umlConnectDomainEventRegister, /* 0.9.4 */
    .connectDomainEventDeregister = umlConnectDomainEventDeregister, /* 0.9.4 */
    .connectIsEncrypted = umlConnectIsEncrypted, /* 0.7.3 */
    .connectIsSecure = umlConnectIsSecure, /* 0.7.3 */
3012 3013 3014
    .domainIsActive = umlDomainIsActive, /* 0.7.3 */
    .domainIsPersistent = umlDomainIsPersistent, /* 0.7.3 */
    .domainIsUpdated = umlDomainIsUpdated, /* 0.8.6 */
3015 3016
    .connectDomainEventRegisterAny = umlConnectDomainEventRegisterAny, /* 0.9.4 */
    .connectDomainEventDeregisterAny = umlConnectDomainEventDeregisterAny, /* 0.9.4 */
3017
    .domainOpenConsole = umlDomainOpenConsole, /* 0.8.6 */
3018
    .connectIsAlive = umlConnectIsAlive, /* 0.9.8 */
3019
    .nodeSuspendForDuration = umlNodeSuspendForDuration, /* 0.9.8 */
3020 3021
    .nodeGetMemoryParameters = umlNodeGetMemoryParameters, /* 0.10.2 */
    .nodeSetMemoryParameters = umlNodeSetMemoryParameters, /* 0.10.2 */
3022
    .nodeGetFreePages = umlNodeGetFreePages, /* 1.2.6 */
3023
    .nodeAllocPages = umlNodeAllocPages, /* 1.2.9 */
3024
    .domainHasManagedSaveImage = umlDomainHasManagedSaveImage, /* 1.2.13 */
3025 3026
};

3027 3028 3029 3030
static virConnectDriver umlConnectDriver = {
    .hypervisorDriver = &umlHypervisorDriver,
};

3031
static virStateDriver umlStateDriver = {
3032
    .name = "UML",
3033
    .stateInitialize = umlStateInitialize,
3034
    .stateAutoStart = umlStateAutoStart,
3035 3036
    .stateCleanup = umlStateCleanup,
    .stateReload = umlStateReload,
3037 3038
};

3039 3040
int umlRegister(void)
{
3041 3042
    if (virRegisterConnectDriver(&umlConnectDriver,
                                 true) < 0)
3043 3044 3045
        return -1;
    if (virRegisterStateDriver(&umlStateDriver) < 0)
        return -1;
3046 3047
    return 0;
}