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 "virhostcpu.h"
49
#include "virhostmem.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 "virfdstream.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
static void *umlDomainObjPrivateAlloc(void *opaque ATTRIBUTE_UNUSED)
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
{
    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 192
            virReportError(VIR_ERR_INTERNAL_ERROR, _("Failed to autostart VM '%s': %s"),
                           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 246
        VIR_FREE(def->source->data.file.path);
        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 412
                            void *opaque ATTRIBUTE_UNUSED,
                            void *parseOpaque ATTRIBUTE_UNUSED)
413 414 415 416 417 418
{
    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;

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

429 430 431 432
    return 0;
}


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


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


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

463 464 465 466 467
    virDomainXMLPrivateDataCallbacks privcb = {
        .alloc = umlDomainObjPrivateAlloc,
        .free = umlDomainObjPrivateFree,
    };

468 469 470
    if (VIR_ALLOC(uml_driver) < 0)
        return -1;

471
    uml_driver->privileged = privileged;
472 473
    uml_driver->inhibitCallback = callback;
    uml_driver->inhibitOpaque = opaque;
474

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

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

485
    if (!(uml_driver->domains = virDomainObjListNew()))
486 487
        goto error;

488
    uml_driver->domainEventState = virObjectEventStateNew();
489 490 491
    if (!uml_driver->domainEventState)
        goto error;

492
    userdir = virGetUserDirectory();
493
    if (!userdir)
494
        goto error;
495

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

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

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

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

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

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

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

    VIR_FREE(base);

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

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

    if ((uml_driver->inotifyFD = inotify_init()) < 0) {
540
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot initialize inotify"));
541
        goto error;
542 543
    }

544
    if (virFileMakePath(uml_driver->monitorDir) < 0) {
545 546
        virReportSystemError(errno, _("Failed to create monitor directory %s"),
                             uml_driver->monitorDir);
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
        virReportSystemError(errno, _("Failed to create inotify watch on %s"),
                             uml_driver->monitorDir);
556
        goto error;
557 558
    }

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

564 565 566
    if (umlProcessAutoDestroyInit(uml_driver) < 0)
        goto error;

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

575 576
    umlDriverUnlock(uml_driver);

577 578
    VIR_FREE(userdir);

579
    virNWFilterRegisterCallbackDriver(&umlCallbackDriver);
580 581
    return 0;

582
 out_of_memory:
583
    virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("umlStartup: out of memory"));
584

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

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

    umlAutostartConfigs(uml_driver);
}

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

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


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

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

    return 0;
}


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

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

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

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

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

684
    virObjectUnref(uml_driver->domains);
685

686
    virObjectUnref(uml_driver->domainEventState);
687

688 689 690 691 692
    VIR_FREE(uml_driver->logDir);
    VIR_FREE(uml_driver->configDir);
    VIR_FREE(uml_driver->autostartDir);
    VIR_FREE(uml_driver->monitorDir);

693 694
    umlProcessAutoDestroyShutdown(uml_driver);

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

    return 0;
}


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

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

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

    if (data->conn != conn)
730
        return 0;
731 732 733

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

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

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

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

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

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


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

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

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

831
    if (VIR_FCLOSE(file) < 0)
832 833 834 835 836 837
        goto cleanup;

    rc = 0;

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

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

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

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

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

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

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

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

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


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

942 943
    VIR_DEBUG("Run command '%s'", cmd);

944 945
    *reply = NULL;

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

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

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

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

        if (res.error)
            ret = -1;

    } while (res.extra);

1002 1003
    VIR_DEBUG("Command reply is '%s'", NULLSTR(retdata));

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

    return ret;

1011
 error:
1012 1013 1014 1015 1016
    VIR_FREE(retdata);
    return -1;
}


1017 1018
static void umlCleanupTapDevices(virDomainObjPtr vm)
{
1019
    size_t i;
1020

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

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

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

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

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

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

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

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

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

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

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

1105 1106
    if (!(cmd = umlBuildCommandLine(conn, driver, vm)))
        goto cleanup;
1107

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

D
Daniel P. Berrange 已提交
1114
    virCommandWriteArgLog(cmd, logfd);
1115

1116
    priv->monitor = -1;
1117

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

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

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

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

1135 1136
    if (ret < 0) {
        virDomainConfVMNWFilterTeardown(vm);
1137
        umlCleanupTapDevices(vm);
1138
        virDomainObjRemoveTransientDef(vm);
1139 1140
    }

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

    return ret;
}

1151
static void umlShutdownVMDaemon(struct uml_driver *driver,
J
Jiri Denemark 已提交
1152 1153
                                virDomainObjPtr vm,
                                virDomainShutoffReason reason)
1154 1155
{
    int ret;
1156 1157
    umlDomainObjPrivatePtr priv = vm->privateData;

D
Daniel P. Berrange 已提交
1158
    if (!virDomainObjIsActive(vm))
1159 1160
        return;

1161
    virProcessKill(vm->pid, SIGTERM);
1162

1163
    VIR_FORCE_CLOSE(priv->monitor);
1164 1165

    if ((ret = waitpid(vm->pid, NULL, 0)) != vm->pid) {
1166
        VIR_WARN("Got unexpected pid %d != %d",
1167 1168 1169 1170 1171
               ret, vm->pid);
    }

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

1174
    virDomainConfVMNWFilterTeardown(vm);
1175 1176 1177 1178
    umlCleanupTapDevices(vm);

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

1180
    virDomainObjRemoveTransientDef(vm);
1181 1182 1183 1184

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


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

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

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


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

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

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

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

    return VIR_DRV_OPEN_SUCCESS;
}

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

    umlDriverLock(driver);
1252
    umlProcessAutoDestroyRun(driver, conn);
1253
    umlDriverUnlock(driver);
1254 1255 1256 1257 1258 1259

    conn->privateData = NULL;

    return 0;
}

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

1264 1265 1266 1267
    return "UML";
}


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


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


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


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

1292 1293 1294
    if (virConnectGetCapabilitiesEnsureACL(conn) < 0)
        return NULL;

1295
    umlDriverLock(driver);
1296
    xml = virCapabilitiesFormatXML(driver->caps);
1297
    umlDriverUnlock(driver);
1298 1299 1300 1301 1302 1303

    return xml;
}



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

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

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

1320 1321
    VIR_FREE(proc);

1322 1323
    if (fscanf(pidinfo, "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %llu %llu", &usertime, &systime) != 2) {
        umlDebug("not enough arg");
1324
        VIR_FORCE_FCLOSE(pidinfo);
1325 1326 1327 1328 1329 1330
        return -1;
    }

    /* We got jiffies
     * We want nanoseconds
     * _SC_CLK_TCK is jiffies per second
N
Nehal J Wani 已提交
1331
     * So calculate thus....
1332 1333 1334 1335 1336
     */
    *cpuTime = 1000ull * 1000ull * 1000ull * (usertime + systime) / (unsigned long long)sysconf(_SC_CLK_TCK);

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

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

    return 0;
}


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1418
 cleanup:
1419
    virDomainObjEndAPI(&vm);
1420 1421 1422
    return dom;
}

1423 1424 1425 1426 1427 1428 1429 1430

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

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

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

1441 1442
    ret = virDomainObjIsActive(obj);

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


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

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

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

1467 1468
    ret = obj->persistent;

1469
 cleanup:
1470
    if (obj)
1471
        virObjectUnlock(obj);
1472 1473 1474
    return ret;
}

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

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

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

1492 1493
    ret = obj->updated;

1494
 cleanup:
1495
    if (obj)
1496
        virObjectUnlock(obj);
1497 1498
    return ret;
}
1499

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

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

1509
    umlDriverLock(driver);
1510 1511 1512 1513

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

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

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

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

1529

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

1535 1536 1537 1538
    return virGetHostname();
}


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

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

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

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

1559 1560 1561
    if (virConnectNumOfDomainsEnsureACL(conn) < 0)
        return -1;

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

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

1579 1580 1581 1582
    virCheckFlags(VIR_DOMAIN_START_AUTODESTROY |
                  VIR_DOMAIN_START_VALIDATE, NULL);

    if (flags & VIR_DOMAIN_START_VALIDATE)
1583
        parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA;
1584

1585
    virNWFilterReadLockFilterUpdates();
1586
    umlDriverLock(driver);
1587
    if (!(def = virDomainDefParseString(xml, driver->caps, driver->xmlopt,
1588
                                        NULL, parse_flags)))
1589
        goto cleanup;
1590

1591 1592 1593
    if (virDomainCreateXMLEnsureACL(conn, def) < 0)
        goto cleanup;

1594
    if (!(vm = virDomainObjListAdd(driver->domains, def,
1595
                                   driver->xmlopt,
1596
                                   VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
1597 1598
                                   VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
                                   NULL)))
1599 1600
        goto cleanup;
    def = NULL;
1601

1602 1603
    if (umlStartVMDaemon(conn, driver, vm,
                         (flags & VIR_DOMAIN_START_AUTODESTROY)) < 0) {
1604
        virDomainAuditStart(vm, "booted", false);
1605 1606 1607 1608
        if (!vm->persistent) {
            virDomainObjListRemove(driver->domains, vm);
            vm = NULL;
        }
1609
        goto cleanup;
1610
    }
1611
    virDomainAuditStart(vm, "booted", true);
1612
    event = virDomainEventLifecycleNewFromObj(vm,
1613 1614
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_BOOTED);
1615

1616
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid, vm->def->id);
1617

1618
 cleanup:
1619
    virDomainDefFree(def);
1620
    if (vm)
1621
        virObjectUnlock(vm);
1622 1623
    if (event)
        umlDomainEventQueue(driver, event);
1624
    umlDriverUnlock(driver);
1625
    virNWFilterUnlockFilterUpdates();
1626 1627 1628 1629
    return dom;
}


1630
static int umlDomainShutdownFlags(virDomainPtr dom,
1631 1632
                                  unsigned int flags)
{
1633 1634
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
1635
    char *info = NULL;
1636
    int ret = -1;
1637

1638 1639
    virCheckFlags(0, -1);

1640
    umlDriverLock(driver);
1641
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1642
    umlDriverUnlock(driver);
1643
    if (!vm) {
1644
        virReportError(VIR_ERR_NO_DOMAIN,
1645
                       _("no domain with matching id %d"), dom->id);
1646
        goto cleanup;
1647 1648
    }

1649
    if (virDomainShutdownFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
1650 1651
        goto cleanup;

1652 1653
#if 0
    if (umlMonitorCommand(driver, vm, "system_powerdown", &info) < 0) {
1654
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
1655
                       _("shutdown operation failed"));
1656
        goto cleanup;
1657
    }
1658
    ret = 0;
1659 1660
#endif

1661
 cleanup:
1662
    VIR_FREE(info);
1663
    if (vm)
1664
        virObjectUnlock(vm);
1665
    return ret;
1666 1667
}

1668 1669 1670 1671 1672
static int
umlDomainShutdown(virDomainPtr dom)
{
    return umlDomainShutdownFlags(dom, 0);
}
1673

1674 1675 1676 1677
static int
umlDomainDestroyFlags(virDomainPtr dom,
                      unsigned int flags)
{
1678 1679
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
1680
    virObjectEventPtr event = NULL;
1681
    int ret = -1;
1682

1683 1684
    virCheckFlags(0, -1);

1685
    umlDriverLock(driver);
1686
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1687
    if (!vm) {
1688
        virReportError(VIR_ERR_NO_DOMAIN,
1689
                       _("no domain with matching id %d"), dom->id);
1690
        goto cleanup;
1691 1692
    }

1693 1694 1695
    if (virDomainDestroyFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

1696
    umlShutdownVMDaemon(driver, vm, VIR_DOMAIN_SHUTOFF_DESTROYED);
1697
    virDomainAuditStop(vm, "destroyed");
1698
    event = virDomainEventLifecycleNewFromObj(vm,
1699 1700
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
1701
    if (!vm->persistent) {
1702 1703
        virDomainObjListRemove(driver->domains,
                               vm);
1704 1705 1706
        vm = NULL;
    }
    ret = 0;
1707

1708
 cleanup:
1709
    if (vm)
1710
        virObjectUnlock(vm);
1711 1712
    if (event)
        umlDomainEventQueue(driver, event);
1713
    umlDriverUnlock(driver);
1714
    return ret;
1715 1716 1717
}


1718 1719 1720 1721 1722 1723
static int umlDomainDestroy(virDomainPtr dom)
{
    return umlDomainDestroyFlags(dom, 0);
}


1724
static char *umlDomainGetOSType(virDomainPtr dom) {
1725 1726 1727
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *type = NULL;
1728

1729
    umlDriverLock(driver);
1730
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1731
    umlDriverUnlock(driver);
1732
    if (!vm) {
1733
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
1734
                       _("no domain with matching uuid"));
1735
        goto cleanup;
1736 1737
    }

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

1741
    if (VIR_STRDUP(type, virDomainOSTypeToString(vm->def->os.type)) < 0)
1742
        goto cleanup;
1743

1744
 cleanup:
1745
    if (vm)
1746
        virObjectUnlock(vm);
1747 1748 1749 1750
    return type;
}

/* Returns max memory in kb, 0 if error */
1751 1752 1753
static unsigned long long
umlDomainGetMaxMemory(virDomainPtr dom)
{
1754 1755
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
1756
    unsigned long long ret = 0;
1757

1758
    umlDriverLock(driver);
1759
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1760 1761
    umlDriverUnlock(driver);

1762 1763 1764 1765
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];

        virUUIDFormat(dom->uuid, uuidstr);
1766
        virReportError(VIR_ERR_NO_DOMAIN,
1767 1768
                       _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
1769
    }
1770 1771 1772 1773

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

1774
    ret = virDomainDefGetMemoryTotal(vm->def);
1775

1776
 cleanup:
1777
    if (vm)
1778
        virObjectUnlock(vm);
1779
    return ret;
1780 1781
}

1782 1783
static int umlDomainSetMaxMemory(virDomainPtr dom, unsigned long newmax)
{
1784 1785 1786
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
1787

1788
    umlDriverLock(driver);
1789
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1790 1791
    umlDriverUnlock(driver);

1792 1793 1794 1795
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];

        virUUIDFormat(dom->uuid, uuidstr);
1796
        virReportError(VIR_ERR_NO_DOMAIN,
1797
                       _("no domain with matching uuid '%s'"), uuidstr);
1798
        goto cleanup;
1799 1800
    }

1801 1802 1803
    if (virDomainSetMaxMemoryEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

1804
    if (newmax < vm->def->mem.cur_balloon) {
1805
        virReportError(VIR_ERR_INVALID_ARG, "%s",
1806
                       _("cannot set max memory lower than current memory"));
1807
        goto cleanup;
1808 1809
    }

1810
    virDomainDefSetMemoryTotal(vm->def, newmax);
1811 1812
    ret = 0;

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

1819 1820
static int umlDomainSetMemory(virDomainPtr dom, unsigned long newmem)
{
1821 1822 1823
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
1824

1825
    umlDriverLock(driver);
1826
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1827 1828
    umlDriverUnlock(driver);

1829 1830 1831 1832
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];

        virUUIDFormat(dom->uuid, uuidstr);
1833
        virReportError(VIR_ERR_NO_DOMAIN,
1834
                       _("no domain with matching uuid '%s'"), uuidstr);
1835
        goto cleanup;
1836 1837
    }

1838 1839 1840
    if (virDomainSetMemoryEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

D
Daniel P. Berrange 已提交
1841
    if (virDomainObjIsActive(vm)) {
1842
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
1843
                       _("cannot set memory of an active domain"));
1844
        goto cleanup;
1845 1846
    }

1847
    if (newmem > virDomainDefGetMemoryTotal(vm->def)) {
1848
        virReportError(VIR_ERR_INVALID_ARG, "%s",
1849
                       _("cannot set memory higher than max memory"));
1850
        goto cleanup;
1851 1852
    }

1853
    vm->def->mem.cur_balloon = newmem;
1854 1855
    ret = 0;

1856
 cleanup:
1857
    if (vm)
1858
        virObjectUnlock(vm);
1859
    return ret;
1860 1861 1862
}

static int umlDomainGetInfo(virDomainPtr dom,
1863 1864
                              virDomainInfoPtr info)
{
1865 1866 1867 1868
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;

1869
    umlDriverLock(driver);
1870
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1871 1872
    umlDriverUnlock(driver);

1873
    if (!vm) {
1874
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
1875
                       _("no domain with matching uuid"));
1876
        goto cleanup;
1877 1878
    }

1879 1880 1881
    if (virDomainGetInfoEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

D
Daniel P. Berrange 已提交
1884
    if (!virDomainObjIsActive(vm)) {
1885 1886 1887
        info->cpuTime = 0;
    } else {
        if (umlGetProcessInfo(&(info->cpuTime), vm->pid) < 0) {
1888
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
1889
                           _("cannot read cputime for domain"));
1890
            goto cleanup;
1891 1892 1893
        }
    }

1894
    info->maxMem = virDomainDefGetMemoryTotal(vm->def);
1895
    info->memory = vm->def->mem.cur_balloon;
1896
    info->nrVirtCpu = virDomainDefGetVcpus(vm->def);
1897 1898
    ret = 0;

1899
 cleanup:
1900
    if (vm)
1901
        virObjectUnlock(vm);
1902
    return ret;
1903 1904 1905
}


1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918
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);
1919
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1920 1921 1922
    umlDriverUnlock(driver);

    if (!vm) {
1923
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
1924 1925 1926 1927
                       _("no domain with matching uuid"));
        goto cleanup;
    }

1928 1929 1930
    if (virDomainGetStateEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

J
Jiri Denemark 已提交
1931
    *state = virDomainObjGetState(vm, reason);
1932 1933
    ret = 0;

1934
 cleanup:
1935
    if (vm)
1936
        virObjectUnlock(vm);
1937 1938 1939 1940
    return ret;
}


1941
static char *umlDomainGetXMLDesc(virDomainPtr dom,
E
Eric Blake 已提交
1942 1943
                                 unsigned int flags)
{
1944 1945 1946 1947
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *ret = NULL;

1948
    /* Flags checked by virDomainDefFormat */
E
Eric Blake 已提交
1949

1950
    umlDriverLock(driver);
1951
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1952 1953
    umlDriverUnlock(driver);

1954
    if (!vm) {
1955
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
1956
                       _("no domain with matching uuid"));
1957
        goto cleanup;
1958 1959
    }

1960 1961 1962
    if (virDomainGetXMLDescEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

1963
    ret = virDomainDefFormat((flags & VIR_DOMAIN_XML_INACTIVE) && vm->newDef ?
1964
                             vm->newDef : vm->def, driver->caps,
1965
                             virDomainDefFormatConvertXMLFlags(flags));
1966

1967
 cleanup:
1968
    if (vm)
1969
        virObjectUnlock(vm);
1970
    return ret;
1971 1972 1973
}


1974 1975
static int umlConnectListDefinedDomains(virConnectPtr conn,
                                        char **const names, int nnames) {
1976
    struct uml_driver *driver = conn->privateData;
1977
    int n;
1978

1979 1980 1981
    if (virConnectListDefinedDomainsEnsureACL(conn) < 0)
        return -1;

1982
    umlDriverLock(driver);
1983 1984
    n = virDomainObjListGetInactiveNames(driver->domains, names, nnames,
                                         virConnectListDefinedDomainsCheckACL, conn);
1985
    umlDriverUnlock(driver);
1986

1987
    return n;
1988 1989
}

1990 1991
static int umlConnectNumOfDefinedDomains(virConnectPtr conn)
{
1992
    struct uml_driver *driver = conn->privateData;
1993
    int n;
1994

1995 1996 1997
    if (virConnectNumOfDefinedDomainsEnsureACL(conn) < 0)
        return -1;

1998
    umlDriverLock(driver);
1999 2000
    n = virDomainObjListNumOfDomains(driver->domains, false,
                                     virConnectNumOfDefinedDomainsCheckACL, conn);
2001
    umlDriverUnlock(driver);
2002 2003 2004 2005 2006

    return n;
}


2007 2008
static int umlDomainCreateWithFlags(virDomainPtr dom, unsigned int flags)
{
2009 2010
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
2011
    virObjectEventPtr event = NULL;
2012
    int ret = -1;
2013

2014
    virCheckFlags(VIR_DOMAIN_START_AUTODESTROY, -1);
2015

2016
    virNWFilterReadLockFilterUpdates();
2017
    umlDriverLock(driver);
2018
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
2019

2020
    if (!vm) {
2021
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
2022
                       _("no domain with matching uuid"));
2023
        goto cleanup;
2024 2025
    }

2026 2027 2028
    if (virDomainCreateWithFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2029 2030
    ret = umlStartVMDaemon(dom->conn, driver, vm,
                           (flags & VIR_DOMAIN_START_AUTODESTROY));
2031
    virDomainAuditStart(vm, "booted", ret >= 0);
2032
    if (ret == 0)
2033
        event = virDomainEventLifecycleNewFromObj(vm,
2034 2035
                                         VIR_DOMAIN_EVENT_STARTED,
                                         VIR_DOMAIN_EVENT_STARTED_BOOTED);
2036

2037
 cleanup:
2038
    if (vm)
2039
        virObjectUnlock(vm);
2040 2041
    if (event)
        umlDomainEventQueue(driver, event);
2042
    umlDriverUnlock(driver);
2043
    virNWFilterUnlockFilterUpdates();
2044
    return ret;
2045 2046
}

2047 2048
static int umlDomainCreate(virDomainPtr dom)
{
2049
    return umlDomainCreateWithFlags(dom, 0);
2050
}
2051

2052 2053
static virDomainPtr
umlDomainDefineXMLFlags(virConnectPtr conn, const char *xml, unsigned int flags)
2054
{
2055
    struct uml_driver *driver = conn->privateData;
2056
    virDomainDefPtr def;
2057
    virDomainObjPtr vm = NULL;
2058
    virDomainPtr dom = NULL;
2059 2060 2061
    unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;

    virCheckFlags(VIR_DOMAIN_DEFINE_VALIDATE, NULL);
2062

2063
    if (flags & VIR_DOMAIN_DEFINE_VALIDATE)
2064
        parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA;
2065

2066
    umlDriverLock(driver);
2067
    if (!(def = virDomainDefParseString(xml, driver->caps, driver->xmlopt,
2068
                                        NULL, parse_flags)))
2069
        goto cleanup;
2070

2071 2072 2073
    if (virXMLCheckIllegalChars("name", def->name, "\n") < 0)
        goto cleanup;

2074
    if (virDomainDefineXMLFlagsEnsureACL(conn, def) < 0)
2075 2076
        goto cleanup;

2077
    if (!(vm = virDomainObjListAdd(driver->domains, def,
2078
                                   driver->xmlopt,
2079
                                   0, NULL)))
2080 2081
        goto cleanup;
    def = NULL;
2082 2083
    vm->persistent = 1;

2084
    if (virDomainSaveConfig(driver->configDir, driver->caps,
2085
                            vm->newDef ? vm->newDef : vm->def) < 0) {
2086 2087
        virDomainObjListRemove(driver->domains,
                               vm);
2088
        vm = NULL;
2089
        goto cleanup;
2090 2091
    }

2092
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid, vm->def->id);
2093

2094
 cleanup:
2095
    virDomainDefFree(def);
2096
    if (vm)
2097
        virObjectUnlock(vm);
2098
    umlDriverUnlock(driver);
2099 2100 2101
    return dom;
}

2102 2103 2104 2105 2106 2107
static virDomainPtr
umlDomainDefineXML(virConnectPtr conn, const char *xml)
{
    return umlDomainDefineXMLFlags(conn, xml, 0);
}

2108 2109 2110
static int umlDomainUndefineFlags(virDomainPtr dom,
                                  unsigned int flags)
{
2111 2112 2113
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
2114

2115 2116
    virCheckFlags(0, -1);

2117
    umlDriverLock(driver);
2118
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
2119
    if (!vm) {
2120
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
2121
                       _("no domain with matching uuid"));
2122
        goto cleanup;
2123 2124
    }

2125 2126 2127
    if (virDomainUndefineFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2128
    if (!vm->persistent) {
2129
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
2130
                       _("cannot undefine transient domain"));
2131
        goto cleanup;
2132 2133
    }

2134
    if (virDomainDeleteConfig(driver->configDir, driver->autostartDir, vm) < 0)
2135
        goto cleanup;
2136

2137 2138 2139
    if (virDomainObjIsActive(vm)) {
        vm->persistent = 0;
    } else {
2140
        virDomainObjListRemove(driver->domains, vm);
2141 2142 2143
        vm = NULL;
    }

2144
    ret = 0;
2145

2146
 cleanup:
2147
    if (vm)
2148
        virObjectUnlock(vm);
2149
    umlDriverUnlock(driver);
2150
    return ret;
2151 2152 2153
}


2154 2155 2156 2157 2158
static int umlDomainUndefine(virDomainPtr dom)
{
    return umlDomainUndefineFlags(dom, 0);
}

2159 2160 2161 2162
static int umlDomainAttachUmlDisk(struct uml_driver *driver,
                                  virDomainObjPtr vm,
                                  virDomainDiskDefPtr disk)
{
2163
    size_t i;
2164 2165 2166
    char *cmd = NULL;
    char *reply = NULL;

2167
    for (i = 0; i < vm->def->ndisks; i++) {
2168
        if (STREQ(vm->def->disks[i]->dst, disk->dst)) {
2169
            virReportError(VIR_ERR_OPERATION_FAILED,
2170 2171 2172 2173 2174
                           _("target %s already exists"), disk->dst);
            return -1;
        }
    }

2175
    if (!virDomainDiskGetSource(disk)) {
2176
        virReportError(VIR_ERR_INTERNAL_ERROR,
2177 2178 2179 2180
                       "%s", _("disk source path is missing"));
        goto error;
    }

2181 2182
    if (virAsprintf(&cmd, "config %s=%s", disk->dst,
                    virDomainDiskGetSource(disk)) < 0)
2183 2184 2185 2186 2187
        return -1;

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

2188
    if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0)
2189 2190 2191 2192 2193 2194 2195 2196 2197
        goto error;

    virDomainDiskInsertPreAlloced(vm->def, disk);

    VIR_FREE(reply);
    VIR_FREE(cmd);

    return 0;

2198
 error:
2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215

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

2216
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
2217 2218 2219
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
2220
        virReportError(VIR_ERR_NO_DOMAIN,
2221 2222 2223 2224
                       _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

2225 2226 2227
    if (virDomainAttachDeviceEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2228
    if (!virDomainObjIsActive(vm)) {
2229
        virReportError(VIR_ERR_OPERATION_INVALID,
2230 2231 2232 2233
                       "%s", _("cannot attach device on inactive domain"));
        goto cleanup;
    }

2234
    dev = virDomainDeviceDefParse(xml, vm->def, driver->caps, driver->xmlopt,
2235
                                  VIR_DOMAIN_DEF_PARSE_INACTIVE);
2236 2237 2238 2239 2240 2241 2242 2243 2244 2245

    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 {
2246
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
2247 2248 2249 2250
                           _("disk bus '%s' cannot be hotplugged."),
                           virDomainDiskBusTypeToString(dev->data.disk->bus));
        }
    } else {
2251
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
2252 2253 2254 2255 2256
                       _("device type '%s' cannot be attached"),
                       virDomainDeviceTypeToString(dev->type));
        goto cleanup;
    }

2257
 cleanup:
2258 2259 2260

    virDomainDeviceDefFree(dev);
    if (vm)
2261
        virObjectUnlock(vm);
2262 2263 2264 2265 2266
    umlDriverUnlock(driver);
    return ret;
}


2267 2268 2269 2270 2271 2272 2273
static int
umlDomainAttachDeviceFlags(virDomainPtr dom,
                           const char *xml,
                           unsigned int flags)
{
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG, -1);

2274
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
2275
        virReportError(VIR_ERR_OPERATION_INVALID,
2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287
                       "%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)
{
2288 2289
    size_t i;
    int ret = -1;
2290 2291 2292 2293
    virDomainDiskDefPtr detach = NULL;
    char *cmd;
    char *reply;

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

    if (i == vm->def->ndisks) {
2300
        virReportError(VIR_ERR_OPERATION_FAILED,
2301 2302 2303 2304 2305 2306
                       _("disk %s not found"), dev->data.disk->dst);
        return -1;
    }

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

2307
    if (virAsprintf(&cmd, "remove %s", detach->dst) < 0)
2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320
        return -1;

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

    virDomainDiskRemove(vm->def, i);

    virDomainDiskDefFree(detach);

    ret = 0;

    VIR_FREE(reply);

2321
 cleanup:
2322 2323 2324 2325 2326 2327
    VIR_FREE(cmd);

    return ret;
}


2328 2329
static int umlDomainDetachDevice(virDomainPtr dom, const char *xml)
{
2330 2331 2332 2333 2334 2335
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    virDomainDeviceDefPtr dev = NULL;
    int ret = -1;

    umlDriverLock(driver);
2336
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
2337 2338 2339
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
2340
        virReportError(VIR_ERR_NO_DOMAIN,
2341 2342 2343 2344
                       _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

2345 2346 2347
    if (virDomainDetachDeviceEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2348
    if (!virDomainObjIsActive(vm)) {
2349
        virReportError(VIR_ERR_OPERATION_INVALID,
2350 2351 2352 2353
                       "%s", _("cannot detach device on inactive domain"));
        goto cleanup;
    }

2354
    dev = virDomainDeviceDefParse(xml, vm->def, driver->caps, driver->xmlopt,
2355 2356
                                  VIR_DOMAIN_DEF_PARSE_INACTIVE |
                                  VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE);
2357 2358 2359 2360 2361 2362 2363
    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);
2364
        else
2365
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2366 2367
                           _("This type of disk cannot be hot unplugged"));
    } else {
2368
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
2369 2370 2371
                       "%s", _("This type of device cannot be hot unplugged"));
    }

2372
 cleanup:
2373 2374
    virDomainDeviceDefFree(dev);
    if (vm)
2375
        virObjectUnlock(vm);
2376 2377 2378 2379 2380
    umlDriverUnlock(driver);
    return ret;
}


2381 2382 2383 2384 2385 2386 2387
static int
umlDomainDetachDeviceFlags(virDomainPtr dom,
                           const char *xml,
                           unsigned int flags)
{
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG, -1);

2388
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
2389
        virReportError(VIR_ERR_OPERATION_INVALID,
2390 2391 2392 2393 2394 2395 2396
                       "%s", _("cannot modify the persistent configuration of a domain"));
        return -1;
    }

    return umlDomainDetachDevice(dom, xml);
}

2397 2398

static int umlDomainGetAutostart(virDomainPtr dom,
2399 2400
                            int *autostart)
{
2401 2402 2403
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
2404

2405
    umlDriverLock(driver);
2406
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
2407

2408
    if (!vm) {
2409
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
2410
                       _("no domain with matching uuid"));
2411
        goto cleanup;
2412 2413
    }

2414 2415 2416
    if (virDomainGetAutostartEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2417
    *autostart = vm->autostart;
2418
    ret = 0;
2419

2420
 cleanup:
2421
    if (vm)
2422
        virObjectUnlock(vm);
2423
    umlDriverUnlock(driver);
2424
    return ret;
2425 2426 2427
}

static int umlDomainSetAutostart(virDomainPtr dom,
2428 2429
                                   int autostart)
{
2430
    struct uml_driver *driver = dom->conn->privateData;
2431
    virDomainObjPtr vm;
2432 2433 2434
    char *configFile = NULL, *autostartLink = NULL;
    int ret = -1;

2435
    umlDriverLock(driver);
2436
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
2437

2438
    if (!vm) {
2439
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
2440
                       _("no domain with matching uuid"));
2441
        goto cleanup;
2442 2443
    }

2444 2445 2446
    if (virDomainSetAutostartEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2447
    if (!vm->persistent) {
2448
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
2449
                       _("cannot set autostart for transient domain"));
2450
        goto cleanup;
2451 2452 2453 2454
    }

    autostart = (autostart != 0);

2455
    if (vm->autostart != autostart) {
2456
        if ((configFile = virDomainConfigFile(driver->configDir, vm->def->name)) == NULL)
2457
            goto cleanup;
2458
        if ((autostartLink = virDomainConfigFile(driver->autostartDir, vm->def->name)) == NULL)
2459
            goto cleanup;
2460

2461
        if (autostart) {
2462 2463
            if (virFileMakePath(driver->autostartDir) < 0) {
                virReportSystemError(errno,
2464 2465
                                     _("cannot create autostart directory %s"),
                                     driver->autostartDir);
2466 2467
                goto cleanup;
            }
2468

2469
            if (symlink(configFile, autostartLink) < 0) {
2470
                virReportSystemError(errno,
2471 2472
                                     _("Failed to create symlink '%s to '%s'"),
                                     autostartLink, configFile);
2473 2474 2475 2476
                goto cleanup;
            }
        } else {
            if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
2477
                virReportSystemError(errno,
2478 2479
                                     _("Failed to delete symlink '%s'"),
                                     autostartLink);
2480 2481
                goto cleanup;
            }
2482 2483
        }

2484
        vm->autostart = autostart;
2485 2486 2487
    }
    ret = 0;

2488
 cleanup:
2489 2490
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
2491
    if (vm)
2492
        virObjectUnlock(vm);
2493
    umlDriverUnlock(driver);
2494 2495 2496 2497 2498
    return ret;
}


static int
2499 2500 2501 2502
umlDomainBlockPeek(virDomainPtr dom,
                   const char *path,
                   unsigned long long offset, size_t size,
                   void *buffer,
E
Eric Blake 已提交
2503
                   unsigned int flags)
2504
{
2505 2506
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
2507 2508
    int fd = -1, ret = -1;
    const char *actual;
2509

E
Eric Blake 已提交
2510 2511
    virCheckFlags(0, -1);

2512
    umlDriverLock(driver);
2513
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
2514 2515
    umlDriverUnlock(driver);

2516
    if (!vm) {
2517
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
2518
                       _("no domain with matching uuid"));
2519
        goto cleanup;
2520 2521
    }

2522 2523 2524
    if (virDomainBlockPeekEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2525
    if (!path || path[0] == '\0') {
2526
        virReportError(VIR_ERR_INVALID_ARG, "%s",
2527
                       _("NULL or empty path"));
2528
        goto cleanup;
2529 2530 2531
    }

    /* Check the path belongs to this domain. */
2532
    if (!(actual = virDomainDiskPathByName(vm->def, path))) {
2533
        virReportError(VIR_ERR_INVALID_ARG,
2534 2535
                       _("invalid path '%s'"), path);
        goto cleanup;
2536
    }
2537
    path = actual;
2538

2539 2540 2541 2542 2543 2544 2545
    /* 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;
    }
2546

2547 2548 2549 2550 2551 2552 2553 2554 2555
    /* 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;
2556 2557
    }

2558 2559
    ret = 0;

2560
 cleanup:
2561
    VIR_FORCE_CLOSE(fd);
2562
    if (vm)
2563
        virObjectUnlock(vm);
2564 2565 2566 2567
    return ret;
}


2568 2569
static int
umlDomainOpenConsole(virDomainPtr dom,
2570
                     const char *dev_name,
2571 2572 2573 2574 2575 2576 2577 2578
                     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;
2579
    size_t i;
2580 2581 2582 2583 2584

    virCheckFlags(0, -1);

    umlDriverLock(driver);
    virUUIDFormat(dom->uuid, uuidstr);
2585
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
2586
    if (!vm) {
2587
        virReportError(VIR_ERR_NO_DOMAIN,
2588 2589 2590 2591
                       _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

2592 2593 2594
    if (virDomainOpenConsoleEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2595
    if (!virDomainObjIsActive(vm)) {
2596
        virReportError(VIR_ERR_OPERATION_INVALID,
2597 2598 2599 2600
                        "%s", _("domain is not running"));
        goto cleanup;
    }

2601
    if (dev_name) {
2602
        for (i = 0; i < vm->def->nconsoles; i++) {
2603 2604 2605 2606 2607 2608
            if (vm->def->consoles[i]->info.alias &&
                STREQ(vm->def->consoles[i]->info.alias, dev_name)) {
                chr = vm->def->consoles[i];
                break;
            }
        }
2609
    } else {
2610 2611
        if (vm->def->nconsoles)
            chr = vm->def->consoles[0];
2612 2613 2614 2615 2616
        else if (vm->def->nserials)
            chr = vm->def->serials[0];
    }

    if (!chr) {
2617
        virReportError(VIR_ERR_INTERNAL_ERROR,
2618 2619
                       _("cannot find console device '%s'"),
                       dev_name ? dev_name : _("default"));
2620 2621 2622
        goto cleanup;
    }

2623
    if (chr->source->type != VIR_DOMAIN_CHR_TYPE_PTY) {
2624
        virReportError(VIR_ERR_INTERNAL_ERROR,
2625 2626
                        _("character device %s is not using a PTY"),
                       dev_name ? dev_name : NULLSTR(chr->info.alias));
2627 2628 2629
        goto cleanup;
    }

2630
    if (virFDStreamOpenFile(st, chr->source->data.file.path,
E
Eric Blake 已提交
2631
                            0, 0, O_RDWR) < 0)
2632 2633 2634
        goto cleanup;

    ret = 0;
2635
 cleanup:
2636
    if (vm)
2637
        virObjectUnlock(vm);
2638 2639 2640 2641
    umlDriverUnlock(driver);
    return ret;
}

2642

2643
static int
2644 2645 2646 2647
umlConnectDomainEventRegister(virConnectPtr conn,
                              virConnectDomainEventCallback callback,
                              void *opaque,
                              virFreeCallback freecb)
2648 2649
{
    struct uml_driver *driver = conn->privateData;
2650
    int ret = 0;
2651

2652 2653 2654
    if (virConnectDomainEventRegisterEnsureACL(conn) < 0)
        return -1;

2655
    umlDriverLock(driver);
2656 2657 2658 2659
    if (virDomainEventStateRegister(conn,
                                    driver->domainEventState,
                                    callback, opaque, freecb) < 0)
        ret = -1;
2660 2661 2662 2663 2664 2665
    umlDriverUnlock(driver);

    return ret;
}

static int
2666 2667
umlConnectDomainEventDeregister(virConnectPtr conn,
                                virConnectDomainEventCallback callback)
2668 2669
{
    struct uml_driver *driver = conn->privateData;
2670
    int ret = 0;
2671

2672 2673 2674
    if (virConnectDomainEventDeregisterEnsureACL(conn) < 0)
        return -1;

2675
    umlDriverLock(driver);
2676 2677 2678 2679
    if (virDomainEventStateDeregister(conn,
                                      driver->domainEventState,
                                      callback) < 0)
        ret = -1;
2680 2681 2682 2683 2684 2685
    umlDriverUnlock(driver);

    return ret;
}

static int
2686 2687 2688 2689 2690 2691
umlConnectDomainEventRegisterAny(virConnectPtr conn,
                                 virDomainPtr dom,
                                 int eventID,
                                 virConnectDomainEventGenericCallback callback,
                                 void *opaque,
                                 virFreeCallback freecb)
2692 2693 2694 2695
{
    struct uml_driver *driver = conn->privateData;
    int ret;

2696 2697 2698
    if (virConnectDomainEventRegisterAnyEnsureACL(conn) < 0)
        return -1;

2699
    umlDriverLock(driver);
2700 2701 2702 2703
    if (virDomainEventStateRegisterID(conn,
                                      driver->domainEventState,
                                      dom, eventID,
                                      callback, opaque, freecb, &ret) < 0)
2704
        ret = -1;
2705 2706 2707 2708 2709 2710 2711
    umlDriverUnlock(driver);

    return ret;
}


static int
2712 2713
umlConnectDomainEventDeregisterAny(virConnectPtr conn,
                                   int callbackID)
2714 2715
{
    struct uml_driver *driver = conn->privateData;
2716
    int ret = 0;
2717

2718 2719 2720
    if (virConnectDomainEventDeregisterAnyEnsureACL(conn) < 0)
        return -1;

2721
    umlDriverLock(driver);
2722 2723
    if (virObjectEventStateDeregisterID(conn,
                                        driver->domainEventState,
2724
                                        callbackID, true) < 0)
2725
        ret = -1;
2726 2727 2728 2729 2730 2731 2732 2733
    umlDriverUnlock(driver);

    return ret;
}


/* driver must be locked before calling */
static void umlDomainEventQueue(struct uml_driver *driver,
2734
                                virObjectEventPtr event)
2735
{
2736
    virObjectEventStateQueue(driver->domainEventState, event);
2737 2738
}

2739 2740 2741
static int umlConnectListAllDomains(virConnectPtr conn,
                                    virDomainPtr **domains,
                                    unsigned int flags)
2742 2743 2744 2745
{
    struct uml_driver *driver = conn->privateData;
    int ret = -1;

O
Osier Yang 已提交
2746
    virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
2747

2748 2749 2750
    if (virConnectListAllDomainsEnsureACL(conn) < 0)
        return -1;

2751
    umlDriverLock(driver);
2752 2753
    ret = virDomainObjListExport(driver->domains, conn, domains,
                                 virConnectListAllDomainsCheckACL, flags);
2754 2755 2756 2757 2758
    umlDriverUnlock(driver);

    return ret;
}

2759

2760
static int
2761
umlNodeGetInfo(virConnectPtr conn,
2762 2763
               virNodeInfoPtr nodeinfo)
{
2764 2765 2766
    if (virNodeGetInfoEnsureACL(conn) < 0)
        return -1;

M
Martin Kletzander 已提交
2767
    return virCapabilitiesGetNodeInfo(nodeinfo);
2768 2769 2770 2771
}


static int
2772
umlNodeGetCPUStats(virConnectPtr conn,
2773 2774 2775 2776 2777
                   int cpuNum,
                   virNodeCPUStatsPtr params,
                   int *nparams,
                   unsigned int flags)
{
2778 2779 2780
    if (virNodeGetCPUStatsEnsureACL(conn) < 0)
        return -1;

2781
    return virHostCPUGetStats(cpuNum, params, nparams, flags);
2782 2783 2784 2785
}


static int
2786
umlNodeGetMemoryStats(virConnectPtr conn,
2787 2788 2789 2790 2791
                      int cellNum,
                      virNodeMemoryStatsPtr params,
                      int *nparams,
                      unsigned int flags)
{
2792 2793 2794
    if (virNodeGetMemoryStatsEnsureACL(conn) < 0)
        return -1;

2795
    return virHostMemGetStats(cellNum, params, nparams, flags);
2796 2797 2798 2799
}


static int
2800
umlNodeGetCellsFreeMemory(virConnectPtr conn,
2801 2802 2803 2804
                          unsigned long long *freeMems,
                          int startCell,
                          int maxCells)
{
2805 2806 2807
    if (virNodeGetCellsFreeMemoryEnsureACL(conn) < 0)
        return -1;

2808
    return virHostMemGetCellsFree(freeMems, startCell, maxCells);
2809 2810 2811 2812
}


static unsigned long long
2813
umlNodeGetFreeMemory(virConnectPtr conn)
2814
{
2815 2816
    unsigned long long freeMem;

2817 2818 2819
    if (virNodeGetFreeMemoryEnsureACL(conn) < 0)
        return 0;

2820
    if (virHostMemGetInfo(NULL, &freeMem) < 0)
2821 2822 2823
        return 0;

    return freeMem;
2824 2825 2826 2827
}


static int
2828
umlNodeGetMemoryParameters(virConnectPtr conn,
2829 2830 2831 2832
                           virTypedParameterPtr params,
                           int *nparams,
                           unsigned int flags)
{
2833 2834 2835
    if (virNodeGetMemoryParametersEnsureACL(conn) < 0)
        return -1;

2836
    return virHostMemGetParameters(params, nparams, flags);
2837 2838 2839 2840
}


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

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


static int
2854
umlNodeGetCPUMap(virConnectPtr conn,
2855 2856 2857 2858
                 unsigned char **cpumap,
                 unsigned int *online,
                 unsigned int flags)
{
2859 2860 2861
    if (virNodeGetCPUMapEnsureACL(conn) < 0)
        return -1;

2862
    return virHostCPUGetMap(cpumap, online, flags);
2863 2864
}

2865

2866
static int
2867
umlNodeSuspendForDuration(virConnectPtr conn,
2868 2869 2870 2871
                          unsigned int target,
                          unsigned long long duration,
                          unsigned int flags)
{
2872 2873 2874
    if (virNodeSuspendForDurationEnsureACL(conn) < 0)
        return -1;

2875
    return virNodeSuspend(target, duration, flags);
2876 2877 2878
}


2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892
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;

2893
    return virHostMemGetFreePages(npages, pages, startCell, cellCount, counts);
2894 2895 2896
}


2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912
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;

2913 2914
    return virHostMemAllocPages(npages, pageSizes, pageCounts,
                                startCell, cellCount, add);
2915 2916 2917
}


2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947
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;
}


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

3014 3015 3016 3017
static virConnectDriver umlConnectDriver = {
    .hypervisorDriver = &umlHypervisorDriver,
};

3018
static virStateDriver umlStateDriver = {
3019
    .name = "UML",
3020
    .stateInitialize = umlStateInitialize,
3021
    .stateAutoStart = umlStateAutoStart,
3022 3023
    .stateCleanup = umlStateCleanup,
    .stateReload = umlStateReload,
3024 3025
};

3026 3027
int umlRegister(void)
{
3028 3029
    if (virRegisterConnectDriver(&umlConnectDriver,
                                 true) < 0)
3030 3031 3032
        return -1;
    if (virRegisterStateDriver(&umlStateDriver) < 0)
        return -1;
3033 3034
    return 0;
}