uml_driver.c 72.8 KB
Newer Older
1 2 3
/*
 * uml_driver.c: core driver methods for managing UML guests
 *
4
 * Copyright (C) 2006-2013 Red Hat, Inc.
5 6 7 8 9 10 11 12 13 14 15 16 17
 * Copyright (C) 2006-2008 Daniel P. Berrange
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with this library.  If not, see
O
Osier Yang 已提交
19
 * <http://www.gnu.org/licenses/>.
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
 *
 * Author: Daniel P. Berrange <berrange@redhat.com>
 */

#include <config.h>

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

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

70 71
#define VIR_FROM_THIS VIR_FROM_UML

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

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

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

92

93 94
static int umlShutdown(void);

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

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

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

    return priv;
}

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

    VIR_FREE(priv);
}


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

125

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

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

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


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

static struct uml_driver *uml_driver = NULL;

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

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

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

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

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

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

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

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


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

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

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

static int
276
umlIdentifyChrPTY(struct uml_driver *driver,
277 278 279 280
                  virDomainObjPtr dom)
{
    int i;

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

    for (i = 0 ; i < dom->def->nserials; i++)
288
        if (dom->def->serials[i]->source.type == VIR_DOMAIN_CHR_TYPE_PTY &&
289
            umlIdentifyOneChrPTY(driver, dom,
290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307
                                 dom->def->serials[i], "ssl") < 0)
            return -1;

    return 0;
}

static void
umlInotifyEvent(int watch,
                int fd,
                int events ATTRIBUTE_UNUSED,
                void *data)
{
    char buf[1024];
    struct inotify_event *e;
    int got;
    char *tmp, *name;
    struct uml_driver *driver = data;
    virDomainObjPtr dom;
308
    virDomainEventPtr event = NULL;
309

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

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

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

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

        if (got < e->len)
332
            goto cleanup;
333 334 335 336 337 338

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

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

339
        dom = virDomainObjListFindByName(driver->domains, name);
340 341 342 343 344 345

        if (!dom) {
            continue;
        }

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

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

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

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

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

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

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

cleanup:
    umlDriverUnlock(driver);
421 422 423 424 425 426 427 428
}

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

436 437 438 439 440
    virDomainXMLPrivateDataCallbacks privcb = {
        .alloc = umlDomainObjPrivateAlloc,
        .free = umlDomainObjPrivateFree,
    };

441 442 443
    if (VIR_ALLOC(uml_driver) < 0)
        return -1;

444
    uml_driver->privileged = privileged;
445 446
    uml_driver->inhibitCallback = callback;
    uml_driver->inhibitOpaque = opaque;
447

448 449 450 451
    if (virMutexInit(&uml_driver->lock) < 0) {
        VIR_FREE(uml_driver);
        return -1;
    }
452 453
    umlDriverLock(uml_driver);

454 455
    /* Don't have a dom0 so start from 1 */
    uml_driver->nextvmid = 1;
456
    uml_driver->inotifyWatch = -1;
457

458
    if (!(uml_driver->domains = virDomainObjListNew()))
459 460
        goto error;

461
    uml_driver->domainEventState = virDomainEventStateNew();
462 463 464
    if (!uml_driver->domainEventState)
        goto error;

465
    userdir = virGetUserDirectory();
466
    if (!userdir)
467
        goto error;
468

469
    if (privileged) {
470
        if (virAsprintf(&uml_driver->logDir,
471
                        "%s/log/libvirt/uml", LOCALSTATEDIR) == -1)
472 473
            goto out_of_memory;

474
        if ((base = strdup(SYSCONFDIR "/libvirt")) == NULL)
475
            goto out_of_memory;
476 477

        if (virAsprintf(&uml_driver->monitorDir,
478
                        "%s/run/libvirt/uml-guest", LOCALSTATEDIR) == -1)
479
            goto out_of_memory;
480
    } else {
481
        base = virGetUserConfigDirectory();
482 483
        if (!base)
            goto error;
484

485
        if (virAsprintf(&uml_driver->logDir,
486
                        "%s/uml/log", base) == -1)
487 488
            goto out_of_memory;

489 490 491 492
        if (virAsprintf(&uml_driver->monitorDir,
                        "%s/.uml", userdir) == -1)
            goto out_of_memory;
    }
493

494
    /* Configuration paths are either $XDG_CONFIG_HOME/libvirt/uml/... (session) or
495 496
     * /etc/libvirt/uml/... (system).
     */
497
    if (virAsprintf(&uml_driver->configDir, "%s/uml", base) == -1)
498 499
        goto out_of_memory;

500
    if (virAsprintf(&uml_driver->autostartDir, "%s/uml/autostart", base) == -1)
501 502 503 504 505 506 507
        goto out_of_memory;

    VIR_FREE(base);

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

508
    if (!(uml_driver->xmlopt = virDomainXMLOptionNew(NULL, &privcb, NULL)))
509
        goto error;
510 511

    if ((uml_driver->inotifyFD = inotify_init()) < 0) {
512
        VIR_ERROR(_("cannot initialize inotify"));
513
        goto error;
514 515
    }

516
    if (virFileMakePath(uml_driver->monitorDir) < 0) {
517
        char ebuf[1024];
D
Daniel Veillard 已提交
518
        VIR_ERROR(_("Failed to create monitor directory %s: %s"),
519 520
                  uml_driver->monitorDir,
                  virStrerror(errno, ebuf, sizeof(ebuf)));
521
        goto error;
522 523
    }

524
    VIR_INFO("Adding inotify watch on %s", uml_driver->monitorDir);
525 526 527
    if (inotify_add_watch(uml_driver->inotifyFD,
                          uml_driver->monitorDir,
                          IN_CREATE | IN_MODIFY | IN_DELETE) < 0) {
528 529 530 531
        char ebuf[1024];
        VIR_ERROR(_("Failed to create inotify watch on %s: %s"),
                  uml_driver->monitorDir,
                  virStrerror(errno, ebuf, sizeof(ebuf)));
532
        goto error;
533 534
    }

535 536
    if ((uml_driver->inotifyWatch =
         virEventAddHandle(uml_driver->inotifyFD, POLLIN,
537 538
                           umlInotifyEvent, uml_driver, NULL)) < 0)
        goto error;
539

540 541 542
    if (umlProcessAutoDestroyInit(uml_driver) < 0)
        goto error;

543
    if (virDomainObjListLoadAllConfigs(uml_driver->domains,
544 545
                                       uml_driver->configDir,
                                       uml_driver->autostartDir, 0,
546
                                       uml_driver->caps,
547
                                       uml_driver->xmlopt,
548
                                       1 << VIR_DOMAIN_VIRT_UML,
549
                                       NULL, NULL) < 0)
550 551
        goto error;

552 553
    umlDriverUnlock(uml_driver);

554 555
    umlAutostartConfigs(uml_driver);

556 557
    VIR_FREE(userdir);

558
    virNWFilterRegisterCallbackDriver(&umlCallbackDriver);
559 560
    return 0;

561
out_of_memory:
562
    VIR_ERROR(_("umlStartup: out of memory"));
563 564

error:
565
    VIR_FREE(userdir);
566
    VIR_FREE(base);
567 568
    umlDriverUnlock(uml_driver);
    umlShutdown();
569 570 571
    return -1;
}

572 573 574 575 576 577 578 579 580 581 582 583 584 585 586
static void umlNotifyLoadDomain(virDomainObjPtr vm, int newVM, void *opaque)
{
    struct uml_driver *driver = opaque;

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


587 588 589 590 591 592 593 594 595 596 597
/**
 * umlReload:
 *
 * Function to restart the Uml daemon, it will recheck the configuration
 * files and update its state and the networking
 */
static int
umlReload(void) {
    if (!uml_driver)
        return 0;

598
    umlDriverLock(uml_driver);
599
    virDomainObjListLoadAllConfigs(uml_driver->domains,
600 601
                                   uml_driver->configDir,
                                   uml_driver->autostartDir, 0,
602
                                   uml_driver->caps,
603
                                   uml_driver->xmlopt,
604
                                   1 << VIR_DOMAIN_VIRT_UML,
605
                                   umlNotifyLoadDomain, uml_driver);
606
    umlDriverUnlock(uml_driver);
607 608 609 610 611

    return 0;
}


612 613
static int
umlShutdownOneVM(virDomainObjPtr dom, void *opaque)
614 615 616
{
    struct uml_driver *driver = opaque;

617
    virObjectLock(dom);
618
    if (virDomainObjIsActive(dom)) {
619
        umlShutdownVMDaemon(driver, dom, VIR_DOMAIN_SHUTOFF_SHUTDOWN);
620 621
        virDomainAuditStop(dom, "shutdown");
    }
622
    virObjectUnlock(dom);
623
    return 0;
624 625
}

626 627 628 629 630 631 632 633 634 635
/**
 * umlShutdown:
 *
 * Shutdown the Uml daemon, it will stop all active domains and networks
 */
static int
umlShutdown(void) {
    if (!uml_driver)
        return -1;

636
    umlDriverLock(uml_driver);
637
    virNWFilterRegisterCallbackDriver(&umlCallbackDriver);
638 639
    if (uml_driver->inotifyWatch != -1)
        virEventRemoveHandle(uml_driver->inotifyWatch);
640
    VIR_FORCE_CLOSE(uml_driver->inotifyFD);
641
    virObjectUnref(uml_driver->caps);
642
    virObjectUnref(uml_driver->xmlopt);
643

644 645
    /* shutdown active VMs
     * XXX allow them to stay around & reconnect */
646
    virDomainObjListForEach(uml_driver->domains, umlShutdownOneVM, uml_driver);
647

648
    virObjectUnref(uml_driver->domains);
649

650 651
    virDomainEventStateFree(uml_driver->domainEventState);

652 653 654 655 656
    VIR_FREE(uml_driver->logDir);
    VIR_FREE(uml_driver->configDir);
    VIR_FREE(uml_driver->autostartDir);
    VIR_FREE(uml_driver->monitorDir);

657 658
    umlProcessAutoDestroyShutdown(uml_driver);

659
    umlDriverUnlock(uml_driver);
660
    virMutexDestroy(&uml_driver->lock);
661 662 663 664 665 666
    VIR_FREE(uml_driver);

    return 0;
}


667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700
static int umlProcessAutoDestroyInit(struct uml_driver *driver)
{
    if (!(driver->autodestroy = virHashCreate(5, NULL)))
        return -1;

    return 0;
}

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

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

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

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

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

701 702
    if (!(dom = virDomainObjListFindByUUID(data->driver->domains,
                                           uuid))) {
703 704 705 706 707 708 709 710 711 712 713 714
        VIR_DEBUG("No domain object to kill");
        return;
    }

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

    if (dom && !dom->persistent)
715
        virDomainObjListRemove(data->driver->domains, dom);
716 717

    if (dom)
718
        virObjectUnlock(dom);
719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764
    if (event)
        umlDomainEventQueue(data->driver, event);
    virHashRemoveEntry(data->driver->autodestroy, uuidstr);
}

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

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

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

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


765
static int umlReadPidFile(struct uml_driver *driver,
766 767 768 769 770 771 772 773
                          virDomainObjPtr vm)
{
    int rc = -1;
    FILE *file;
    char *pidfile = NULL;
    int retries = 0;

    vm->pid = -1;
774 775
    if (virAsprintf(&pidfile, "%s/%s/pid",
                    driver->monitorDir, vm->def->name) < 0) {
776
        virReportOOMError();
777 778 779 780 781 782 783 784 785 786 787 788 789 790 791
        return -1;
    }

reopen:
    if (!(file = fopen(pidfile, "r"))) {
        if (errno == ENOENT &&
            retries++ < 50) {
            usleep(1000 * 100);
            goto reopen;
        }
        goto cleanup;
    }

    if (fscanf(file, "%d", &vm->pid) != 1) {
        errno = EINVAL;
792
        VIR_FORCE_FCLOSE(file);
793 794 795
        goto cleanup;
    }

796
    if (VIR_FCLOSE(file) < 0)
797 798 799 800 801 802
        goto cleanup;

    rc = 0;

 cleanup:
    if (rc != 0)
803
        virReportSystemError(errno,
804 805
                             _("failed to read pid: %s"),
                             pidfile);
806 807 808 809
    VIR_FREE(pidfile);
    return rc;
}

810
static int umlMonitorAddress(const struct uml_driver *driver,
811 812 813
                             virDomainObjPtr vm,
                             struct sockaddr_un *addr) {
    char *sockname;
C
Chris Lalancette 已提交
814
    int retval = 0;
815

816 817
    if (virAsprintf(&sockname, "%s/%s/mconsole",
                    driver->monitorDir, vm->def->name) < 0) {
818
        virReportOOMError();
819 820 821
        return -1;
    }

822
    memset(addr, 0, sizeof(*addr));
823
    addr->sun_family = AF_UNIX;
C
Chris Lalancette 已提交
824
    if (virStrcpyStatic(addr->sun_path, sockname) == NULL) {
825
        virReportError(VIR_ERR_INTERNAL_ERROR,
C
Chris Lalancette 已提交
826 827 828
                       _("Unix path %s too long for destination"), sockname);
        retval = -1;
    }
829
    VIR_FREE(sockname);
C
Chris Lalancette 已提交
830
    return retval;
831 832
}

833
static int umlOpenMonitor(struct uml_driver *driver,
834 835 836 837
                          virDomainObjPtr vm) {
    struct sockaddr_un addr;
    struct stat sb;
    int retries = 0;
838
    umlDomainObjPrivatePtr priv = vm->privateData;
839

840
    if (umlMonitorAddress(driver, vm, &addr) < 0)
841 842
        return -1;

843
    VIR_DEBUG("Dest address for monitor is '%s'", addr.sun_path);
844 845 846
restat:
    if (stat(addr.sun_path, &sb) < 0) {
        if (errno == ENOENT &&
847
            retries++ < 50) {
848 849 850 851 852 853
            usleep(1000 * 100);
            goto restat;
        }
        return -1;
    }

854
    if ((priv->monitor = socket(PF_UNIX, SOCK_DGRAM, 0)) < 0) {
855
        virReportSystemError(errno,
856
                             "%s", _("cannot open socket"));
857 858 859
        return -1;
    }

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


894
static int umlMonitorCommand(const struct uml_driver *driver,
895 896 897 898 899 900 901 902 903 904
                             const virDomainObjPtr vm,
                             const char *cmd,
                             char **reply)
{
    struct monitor_request req;
    struct monitor_response res;
    char *retdata = NULL;
    int retlen = 0, ret = 0;
    struct sockaddr_un addr;
    unsigned int addrlen;
905
    umlDomainObjPrivatePtr priv = vm->privateData;
906

907 908
    VIR_DEBUG("Run command '%s'", cmd);

909 910
    *reply = NULL;

911
    if (umlMonitorAddress(driver, vm, &addr) < 0)
912 913 914 915 916 917 918
        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)) {
919
        virReportSystemError(EINVAL,
920 921
                             _("cannot send too long command %s (%d bytes)"),
                             cmd, req.length);
922 923
        return -1;
    }
C
Chris Lalancette 已提交
924
    if (virStrcpyStatic(req.data, cmd) == NULL) {
925
        virReportError(VIR_ERR_INTERNAL_ERROR,
C
Chris Lalancette 已提交
926 927 928
                       _("Command %s too long for destination"), cmd);
        return -1;
    }
929

930 931
    if (sendto(priv->monitor, &req, sizeof(req), 0,
               (struct sockaddr *)&addr, sizeof(addr)) != sizeof(req)) {
932
        virReportSystemError(errno,
933 934
                             _("cannot send command %s"),
                             cmd);
935 936 937 938
        return -1;
    }

    do {
E
Eric Blake 已提交
939
        ssize_t nbytes;
940
        addrlen = sizeof(addr);
941
        nbytes = recvfrom(priv->monitor, &res, sizeof(res), 0,
942
                          (struct sockaddr *)&addr, &addrlen);
E
Eric Blake 已提交
943 944 945
        if (nbytes < 0) {
            if (errno == EAGAIN || errno == EINTR)
                continue;
946
            virReportSystemError(errno, _("cannot read reply %s"), cmd);
947 948
            goto error;
        }
949 950 951
        /* 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) {
952 953 954
            virReportSystemError(0, _("incomplete reply %s"), cmd);
            goto error;
        }
955 956

        if (VIR_REALLOC_N(retdata, retlen + res.length) < 0) {
957
            virReportOOMError();
958 959 960 961 962 963 964 965 966 967 968
            goto error;
        }
        memcpy(retdata + retlen, res.data, res.length);
        retlen += res.length - 1;
        retdata[retlen] = '\0';

        if (res.error)
            ret = -1;

    } while (res.extra);

969 970
    VIR_DEBUG("Command reply is '%s'", NULLSTR(retdata));

971 972 973 974
    if (ret < 0)
        VIR_FREE(retdata);
    else
        *reply = retdata;
975 976 977 978 979 980 981 982 983

    return ret;

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


984
static void umlCleanupTapDevices(virDomainObjPtr vm) {
985 986 987 988 989 990 991 992 993
    int i;

    for (i = 0 ; i < vm->def->nnets ; i++) {
        virDomainNetDefPtr def = vm->def->nets[i];

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

994
        ignore_value(virNetDevTapDelete(def->ifname));
995 996 997
    }
}

998 999
static int umlStartVMDaemon(virConnectPtr conn,
                            struct uml_driver *driver,
1000 1001
                            virDomainObjPtr vm,
                            bool autoDestroy) {
1002
    int ret = -1;
1003 1004
    char *logfile;
    int logfd = -1;
1005
    umlDomainObjPrivatePtr priv = vm->privateData;
D
Daniel P. Berrange 已提交
1006
    virCommandPtr cmd = NULL;
1007
    size_t i;
1008

D
Daniel P. Berrange 已提交
1009
    if (virDomainObjIsActive(vm)) {
1010
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
1011
                       _("VM is already active"));
1012 1013 1014 1015
        return -1;
    }

    if (!vm->def->os.kernel) {
1016
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1017
                       _("no kernel specified"));
1018 1019 1020 1021 1022 1023
        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 已提交
1024
    if (!virFileIsExecutable(vm->def->os.kernel)) {
1025
        virReportSystemError(errno,
1026 1027
                             _("Cannot find UML kernel %s"),
                             vm->def->os.kernel);
1028 1029 1030
        return -1;
    }

1031
    if (virFileMakePath(driver->logDir) < 0) {
1032
        virReportSystemError(errno,
1033 1034
                             _("cannot create log directory %s"),
                             driver->logDir);
1035 1036 1037
        return -1;
    }

1038 1039
    if (virAsprintf(&logfile, "%s/%s.log",
                    driver->logDir, vm->def->name) < 0) {
1040
        virReportOOMError();
1041 1042 1043 1044 1045
        return -1;
    }

    if ((logfd = open(logfile, O_CREAT | O_TRUNC | O_WRONLY,
                      S_IRUSR | S_IWUSR)) < 0) {
1046
        virReportSystemError(errno,
1047 1048
                             _("failed to create logfile %s"),
                             logfile);
1049 1050 1051 1052 1053
        VIR_FREE(logfile);
        return -1;
    }
    VIR_FREE(logfile);

E
Eric Blake 已提交
1054 1055 1056
    if (virSetCloseExec(logfd) < 0) {
        virReportSystemError(errno, "%s",
                             _("Unable to set VM logfile close-on-exec flag"));
1057
        VIR_FORCE_CLOSE(logfd);
1058 1059 1060
        return -1;
    }

1061 1062 1063 1064 1065
    /* 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");
1066
    if (virDomainObjSetDefTransient(driver->caps, driver->xmlopt,
1067
                                    vm, true) < 0) {
1068 1069 1070 1071
        VIR_FORCE_CLOSE(logfd);
        return -1;
    }

1072 1073
    if (!(cmd = umlBuildCommandLine(conn, driver, vm)))
        goto cleanup;
1074

1075 1076 1077 1078 1079 1080 1081 1082
    for (i = 0 ; i < vm->def->nconsoles ; i++) {
        VIR_FREE(vm->def->consoles[i]->info.alias);
        if (virAsprintf(&vm->def->consoles[i]->info.alias, "console%zu", i) < 0) {
            virReportOOMError();
            goto cleanup;
        }
    }

D
Daniel P. Berrange 已提交
1083
    virCommandWriteArgLog(cmd, logfd);
1084

1085
    priv->monitor = -1;
1086

D
Daniel P. Berrange 已提交
1087 1088 1089 1090 1091 1092
    virCommandClearCaps(cmd);
    virCommandSetOutputFD(cmd, &logfd);
    virCommandSetErrorFD(cmd, &logfd);
    virCommandDaemonize(cmd);

    ret = virCommandRun(cmd, NULL);
1093 1094
    if (ret < 0)
        goto cleanup;
1095

1096
    if (autoDestroy &&
1097
        (ret = umlProcessAutoDestroyAdd(driver, vm, conn)) < 0)
1098 1099
        goto cleanup;

1100
    ret = virDomainObjSetDefTransient(driver->caps, driver->xmlopt, vm, false);
1101
cleanup:
1102
    VIR_FORCE_CLOSE(logfd);
D
Daniel P. Berrange 已提交
1103
    virCommandFree(cmd);
1104

1105 1106
    if (ret < 0) {
        virDomainConfVMNWFilterTeardown(vm);
1107
        umlCleanupTapDevices(vm);
1108 1109 1110 1111 1112 1113
        if (vm->newDef) {
            virDomainDefFree(vm->def);
            vm->def = vm->newDef;
            vm->def->id = -1;
            vm->newDef = NULL;
        }
1114 1115
    }

1116 1117
    /* NB we don't mark it running here - we do that async
       with inotify */
1118 1119 1120
    /* XXX what if someone else tries to start it again
       before we get the inotification ? Sounds like
       trouble.... */
1121
    /* XXX this is bad for events too. must fix this better */
1122 1123 1124 1125

    return ret;
}

1126
static void umlShutdownVMDaemon(struct uml_driver *driver,
J
Jiri Denemark 已提交
1127 1128
                                virDomainObjPtr vm,
                                virDomainShutoffReason reason)
1129 1130
{
    int ret;
1131 1132
    umlDomainObjPrivatePtr priv = vm->privateData;

D
Daniel P. Berrange 已提交
1133
    if (!virDomainObjIsActive(vm))
1134 1135
        return;

1136
    virProcessKill(vm->pid, SIGTERM);
1137

1138
    VIR_FORCE_CLOSE(priv->monitor);
1139 1140

    if ((ret = waitpid(vm->pid, NULL, 0)) != vm->pid) {
1141
        VIR_WARN("Got unexpected pid %d != %d",
1142 1143 1144 1145 1146
               ret, vm->pid);
    }

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

1149
    virDomainConfVMNWFilterTeardown(vm);
1150 1151 1152 1153
    umlCleanupTapDevices(vm);

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

1155 1156 1157 1158 1159 1160
    if (vm->newDef) {
        virDomainDefFree(vm->def);
        vm->def = vm->newDef;
        vm->def->id = -1;
        vm->newDef = NULL;
    }
1161 1162 1163 1164

    driver->nactive--;
    if (!driver->nactive && driver->inhibitCallback)
        driver->inhibitCallback(false, driver->inhibitOpaque);
1165 1166 1167 1168 1169
}


static virDrvOpenStatus umlOpen(virConnectPtr conn,
                                virConnectAuthPtr auth ATTRIBUTE_UNUSED,
E
Eric Blake 已提交
1170 1171 1172 1173
                                unsigned int flags)
{
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

1174 1175 1176
    if (conn->uri == NULL) {
        if (uml_driver == NULL)
            return VIR_DRV_OPEN_DECLINED;
1177

1178 1179 1180
        if (!(conn->uri = virURIParse(uml_driver->privileged ?
                                      "uml:///system" :
                                      "uml:///session")))
1181 1182 1183
            return VIR_DRV_OPEN_ERROR;
    } else {
        if (conn->uri->scheme == NULL ||
1184
            STRNEQ(conn->uri->scheme, "uml"))
1185 1186 1187 1188 1189
            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;
1190 1191


1192
        /* Check path and tell them correct path if they made a mistake */
1193
        if (uml_driver->privileged) {
1194 1195
            if (STRNEQ(conn->uri->path, "/system") &&
                STRNEQ(conn->uri->path, "/session")) {
1196
                virReportError(VIR_ERR_INTERNAL_ERROR,
1197 1198 1199 1200 1201
                               _("unexpected UML URI path '%s', try uml:///system"),
                               conn->uri->path);
                return VIR_DRV_OPEN_ERROR;
            }
        } else {
1202
            if (STRNEQ(conn->uri->path, "/session")) {
1203
                virReportError(VIR_ERR_INTERNAL_ERROR,
1204 1205 1206 1207
                               _("unexpected UML URI path '%s', try uml:///session"),
                               conn->uri->path);
                return VIR_DRV_OPEN_ERROR;
            }
1208
        }
1209 1210 1211

        /* URI was good, but driver isn't active */
        if (uml_driver == NULL) {
1212
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1213
                           _("uml state driver is not active"));
1214 1215 1216 1217 1218 1219 1220 1221 1222 1223
            return VIR_DRV_OPEN_ERROR;
        }
    }

    conn->privateData = uml_driver;

    return VIR_DRV_OPEN_SUCCESS;
}

static int umlClose(virConnectPtr conn) {
1224 1225 1226
    struct uml_driver *driver = conn->privateData;

    umlDriverLock(driver);
1227
    umlProcessAutoDestroyRun(driver, conn);
1228
    umlDriverUnlock(driver);
1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239

    conn->privateData = NULL;

    return 0;
}

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


1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253
static int umlIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED)
{
    /* Trivially secure, since always inside the daemon */
    return 1;
}


static int umlIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED)
{
    /* Not encrypted, but remote driver takes care of that */
    return 0;
}


1254 1255 1256 1257 1258 1259
static int umlIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED)
{
    return 1;
}


1260 1261 1262 1263
static char *umlGetCapabilities(virConnectPtr conn) {
    struct uml_driver *driver = (struct uml_driver *)conn->privateData;
    char *xml;

1264
    umlDriverLock(driver);
1265
    if ((xml = virCapabilitiesFormatXML(driver->caps)) == NULL)
1266
        virReportOOMError();
1267
    umlDriverUnlock(driver);
1268 1269 1270 1271 1272 1273

    return xml;
}



1274
static int umlGetProcessInfo(unsigned long long *cpuTime, pid_t pid)
1275 1276
{
    char *proc;
1277 1278 1279
    FILE *pidinfo;
    unsigned long long usertime, systime;

1280
    if (virAsprintf(&proc, "/proc/%lld/stat", (long long) pid) < 0) {
1281 1282 1283 1284 1285 1286
        return -1;
    }

    if (!(pidinfo = fopen(proc, "r"))) {
        /* VM probably shut down, so fake 0 */
        *cpuTime = 0;
1287
        VIR_FREE(proc);
1288 1289 1290
        return 0;
    }

1291 1292
    VIR_FREE(proc);

1293 1294
    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");
1295
        VIR_FORCE_FCLOSE(pidinfo);
1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307
        return -1;
    }

    /* We got jiffies
     * We want nanoseconds
     * _SC_CLK_TCK is jiffies per second
     * So calulate thus....
     */
    *cpuTime = 1000ull * 1000ull * 1000ull * (usertime + systime) / (unsigned long long)sysconf(_SC_CLK_TCK);

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

1308
    VIR_FORCE_FCLOSE(pidinfo);
1309 1310 1311 1312 1313 1314 1315 1316

    return 0;
}


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

1320
    umlDriverLock(driver);
1321
    vm = virDomainObjListFindByID(driver->domains, id);
1322 1323
    umlDriverUnlock(driver);

1324
    if (!vm) {
1325
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
1326
        goto cleanup;
1327 1328 1329 1330
    }

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

cleanup:
1333
    if (vm)
1334
        virObjectUnlock(vm);
1335 1336
    return dom;
}
1337

1338 1339 1340
static virDomainPtr umlDomainLookupByUUID(virConnectPtr conn,
                                            const unsigned char *uuid) {
    struct uml_driver *driver = (struct uml_driver *)conn->privateData;
1341 1342
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
1343

1344
    umlDriverLock(driver);
1345
    vm = virDomainObjListFindByUUID(driver->domains, uuid);
1346 1347
    umlDriverUnlock(driver);

1348
    if (!vm) {
1349
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
1350
        goto cleanup;
1351 1352 1353 1354
    }

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

cleanup:
1357
    if (vm)
1358
        virObjectUnlock(vm);
1359 1360
    return dom;
}
1361

1362 1363 1364
static virDomainPtr umlDomainLookupByName(virConnectPtr conn,
                                            const char *name) {
    struct uml_driver *driver = (struct uml_driver *)conn->privateData;
1365 1366
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
1367

1368
    umlDriverLock(driver);
1369
    vm = virDomainObjListFindByName(driver->domains, name);
1370 1371
    umlDriverUnlock(driver);

1372
    if (!vm) {
1373
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
1374
        goto cleanup;
1375 1376 1377 1378
    }

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

cleanup:
1381
    if (vm)
1382
        virObjectUnlock(vm);
1383 1384 1385
    return dom;
}

1386 1387 1388 1389 1390 1391 1392 1393

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

    umlDriverLock(driver);
1394
    obj = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1395 1396
    umlDriverUnlock(driver);
    if (!obj) {
1397
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
1398 1399 1400 1401 1402 1403
        goto cleanup;
    }
    ret = virDomainObjIsActive(obj);

cleanup:
    if (obj)
1404
        virObjectUnlock(obj);
1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415
    return ret;
}


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

    umlDriverLock(driver);
1416
    obj = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1417 1418
    umlDriverUnlock(driver);
    if (!obj) {
1419
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
1420 1421 1422 1423 1424 1425
        goto cleanup;
    }
    ret = obj->persistent;

cleanup:
    if (obj)
1426
        virObjectUnlock(obj);
1427 1428 1429
    return ret;
}

1430 1431 1432 1433 1434 1435 1436
static int umlDomainIsUpdated(virDomainPtr dom)
{
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr obj;
    int ret = -1;

    umlDriverLock(driver);
1437
    obj = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1438 1439
    umlDriverUnlock(driver);
    if (!obj) {
1440
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
1441 1442 1443 1444 1445 1446
        goto cleanup;
    }
    ret = obj->updated;

cleanup:
    if (obj)
1447
        virObjectUnlock(obj);
1448 1449
    return ret;
}
1450

1451
static int umlGetVersion(virConnectPtr conn, unsigned long *version) {
1452
    struct uml_driver *driver = conn->privateData;
1453
    struct utsname ut;
1454
    int ret = -1;
1455

1456
    umlDriverLock(driver);
1457 1458 1459 1460

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

1461
        if (virParseVersionString(ut.release, &driver->umlVersion, true) < 0) {
1462
            virReportError(VIR_ERR_INTERNAL_ERROR,
1463 1464 1465
                           _("cannot parse version %s"), ut.release);
            goto cleanup;
        }
1466 1467
    }

1468 1469 1470 1471 1472 1473
    *version = driver->umlVersion;
    ret = 0;

cleanup:
    umlDriverUnlock(driver);
    return ret;
1474 1475 1476
}

static int umlListDomains(virConnectPtr conn, int *ids, int nids) {
1477
    struct uml_driver *driver = conn->privateData;
1478
    int n;
1479

1480
    umlDriverLock(driver);
1481
    n = virDomainObjListGetActiveIDs(driver->domains, ids, nids);
1482
    umlDriverUnlock(driver);
1483

1484
    return n;
1485 1486
}
static int umlNumDomains(virConnectPtr conn) {
1487
    struct uml_driver *driver = conn->privateData;
1488
    int n;
1489

1490
    umlDriverLock(driver);
1491
    n = virDomainObjListNumOfDomains(driver->domains, 1);
1492
    umlDriverUnlock(driver);
1493 1494 1495 1496

    return n;
}
static virDomainPtr umlDomainCreate(virConnectPtr conn, const char *xml,
1497
                                      unsigned int flags) {
1498
    struct uml_driver *driver = conn->privateData;
1499
    virDomainDefPtr def;
1500
    virDomainObjPtr vm = NULL;
1501
    virDomainPtr dom = NULL;
1502
    virDomainEventPtr event = NULL;
1503

1504
    virCheckFlags(VIR_DOMAIN_START_AUTODESTROY, NULL);
1505

1506
    umlDriverLock(driver);
1507 1508
    if (!(def = virDomainDefParseString(xml, driver->caps, driver->xmlopt,
                                        1 << VIR_DOMAIN_VIRT_UML,
1509
                                        VIR_DOMAIN_XML_INACTIVE)))
1510
        goto cleanup;
1511

1512
    if (!(vm = virDomainObjListAdd(driver->domains, def,
1513
                                   driver->xmlopt,
1514 1515
                                   VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
                                   NULL)))
1516 1517
        goto cleanup;
    def = NULL;
1518

1519 1520
    if (umlStartVMDaemon(conn, driver, vm,
                         (flags & VIR_DOMAIN_START_AUTODESTROY)) < 0) {
1521
        virDomainAuditStart(vm, "booted", false);
1522 1523
        virDomainObjListRemove(driver->domains,
                               vm);
1524 1525
        vm = NULL;
        goto cleanup;
1526
    }
1527
    virDomainAuditStart(vm, "booted", true);
1528 1529 1530
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_BOOTED);
1531 1532 1533

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

cleanup:
    virDomainDefFree(def);
1537
    if (vm)
1538
        virObjectUnlock(vm);
1539 1540
    if (event)
        umlDomainEventQueue(driver, event);
1541
    umlDriverUnlock(driver);
1542 1543 1544 1545
    return dom;
}


1546 1547
static int umlDomainShutdownFlags(virDomainPtr dom,
                                  unsigned int flags) {
1548 1549
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
1550
    char *info = NULL;
1551
    int ret = -1;
1552

1553 1554
    virCheckFlags(0, -1);

1555
    umlDriverLock(driver);
1556
    vm = virDomainObjListFindByID(driver->domains, dom->id);
1557
    umlDriverUnlock(driver);
1558
    if (!vm) {
1559
        virReportError(VIR_ERR_NO_DOMAIN,
1560
                       _("no domain with matching id %d"), dom->id);
1561
        goto cleanup;
1562 1563 1564 1565
    }

#if 0
    if (umlMonitorCommand(driver, vm, "system_powerdown", &info) < 0) {
1566
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
1567
                       _("shutdown operation failed"));
1568
        goto cleanup;
1569
    }
1570
    ret = 0;
1571 1572
#endif

1573 1574
cleanup:
    VIR_FREE(info);
1575
    if (vm)
1576
        virObjectUnlock(vm);
1577
    return ret;
1578 1579
}

1580 1581 1582 1583 1584
static int
umlDomainShutdown(virDomainPtr dom)
{
    return umlDomainShutdownFlags(dom, 0);
}
1585

1586 1587 1588 1589
static int
umlDomainDestroyFlags(virDomainPtr dom,
                      unsigned int flags)
{
1590 1591
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
1592
    virDomainEventPtr event = NULL;
1593
    int ret = -1;
1594

1595 1596
    virCheckFlags(0, -1);

1597
    umlDriverLock(driver);
1598
    vm = virDomainObjListFindByID(driver->domains, dom->id);
1599
    if (!vm) {
1600
        virReportError(VIR_ERR_NO_DOMAIN,
1601
                       _("no domain with matching id %d"), dom->id);
1602
        goto cleanup;
1603 1604
    }

1605
    umlShutdownVMDaemon(driver, vm, VIR_DOMAIN_SHUTOFF_DESTROYED);
1606
    virDomainAuditStop(vm, "destroyed");
1607 1608 1609
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
1610
    if (!vm->persistent) {
1611 1612
        virDomainObjListRemove(driver->domains,
                               vm);
1613 1614 1615
        vm = NULL;
    }
    ret = 0;
1616

1617
cleanup:
1618
    if (vm)
1619
        virObjectUnlock(vm);
1620 1621
    if (event)
        umlDomainEventQueue(driver, event);
1622
    umlDriverUnlock(driver);
1623
    return ret;
1624 1625 1626
}


1627 1628 1629 1630 1631 1632
static int umlDomainDestroy(virDomainPtr dom)
{
    return umlDomainDestroyFlags(dom, 0);
}


1633
static char *umlDomainGetOSType(virDomainPtr dom) {
1634 1635 1636
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *type = NULL;
1637

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

1647
    if (!(type = strdup(vm->def->os.type)))
1648
        virReportOOMError();
1649 1650

cleanup:
1651
    if (vm)
1652
        virObjectUnlock(vm);
1653 1654 1655 1656
    return type;
}

/* Returns max memory in kb, 0 if error */
1657 1658 1659
static unsigned long long
umlDomainGetMaxMemory(virDomainPtr dom)
{
1660 1661
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
1662
    unsigned long long ret = 0;
1663

1664
    umlDriverLock(driver);
1665
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1666 1667
    umlDriverUnlock(driver);

1668 1669 1670 1671
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];

        virUUIDFormat(dom->uuid, uuidstr);
1672
        virReportError(VIR_ERR_NO_DOMAIN,
1673 1674
                       _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
1675
    }
1676
    ret = vm->def->mem.max_balloon;
1677

1678
cleanup:
1679
    if (vm)
1680
        virObjectUnlock(vm);
1681
    return ret;
1682 1683 1684
}

static int umlDomainSetMaxMemory(virDomainPtr dom, unsigned long newmax) {
1685 1686 1687
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
1688

1689
    umlDriverLock(driver);
1690
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1691 1692
    umlDriverUnlock(driver);

1693 1694 1695 1696
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];

        virUUIDFormat(dom->uuid, uuidstr);
1697
        virReportError(VIR_ERR_NO_DOMAIN,
1698
                       _("no domain with matching uuid '%s'"), uuidstr);
1699
        goto cleanup;
1700 1701
    }

1702
    if (newmax < vm->def->mem.cur_balloon) {
1703
        virReportError(VIR_ERR_INVALID_ARG, "%s",
1704
                       _("cannot set max memory lower than current memory"));
1705
        goto cleanup;
1706 1707
    }

1708
    vm->def->mem.max_balloon = newmax;
1709 1710 1711
    ret = 0;

cleanup:
1712
    if (vm)
1713
        virObjectUnlock(vm);
1714
    return ret;
1715 1716 1717
}

static int umlDomainSetMemory(virDomainPtr dom, unsigned long newmem) {
1718 1719 1720
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
1721

1722
    umlDriverLock(driver);
1723
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1724 1725
    umlDriverUnlock(driver);

1726 1727 1728 1729
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];

        virUUIDFormat(dom->uuid, uuidstr);
1730
        virReportError(VIR_ERR_NO_DOMAIN,
1731
                       _("no domain with matching uuid '%s'"), uuidstr);
1732
        goto cleanup;
1733 1734
    }

D
Daniel P. Berrange 已提交
1735
    if (virDomainObjIsActive(vm)) {
1736
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
1737
                       _("cannot set memory of an active domain"));
1738
        goto cleanup;
1739 1740
    }

1741
    if (newmem > vm->def->mem.max_balloon) {
1742
        virReportError(VIR_ERR_INVALID_ARG, "%s",
1743
                       _("cannot set memory higher than max memory"));
1744
        goto cleanup;
1745 1746
    }

1747
    vm->def->mem.cur_balloon = newmem;
1748 1749 1750
    ret = 0;

cleanup:
1751
    if (vm)
1752
        virObjectUnlock(vm);
1753
    return ret;
1754 1755 1756 1757
}

static int umlDomainGetInfo(virDomainPtr dom,
                              virDomainInfoPtr info) {
1758 1759 1760 1761
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;

1762
    umlDriverLock(driver);
1763
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1764 1765
    umlDriverUnlock(driver);

1766
    if (!vm) {
1767
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
1768
                       _("no domain with matching uuid"));
1769
        goto cleanup;
1770 1771
    }

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

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

1784 1785
    info->maxMem = vm->def->mem.max_balloon;
    info->memory = vm->def->mem.cur_balloon;
1786
    info->nrVirtCpu = vm->def->vcpus;
1787 1788 1789
    ret = 0;

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


1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808
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);
1809
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1810 1811 1812
    umlDriverUnlock(driver);

    if (!vm) {
1813
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
1814 1815 1816 1817
                       _("no domain with matching uuid"));
        goto cleanup;
    }

J
Jiri Denemark 已提交
1818
    *state = virDomainObjGetState(vm, reason);
1819 1820 1821 1822
    ret = 0;

cleanup:
    if (vm)
1823
        virObjectUnlock(vm);
1824 1825 1826 1827
    return ret;
}


1828
static char *umlDomainGetXMLDesc(virDomainPtr dom,
E
Eric Blake 已提交
1829 1830
                                 unsigned int flags)
{
1831 1832 1833 1834
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *ret = NULL;

1835
    /* Flags checked by virDomainDefFormat */
E
Eric Blake 已提交
1836

1837
    umlDriverLock(driver);
1838
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1839 1840
    umlDriverUnlock(driver);

1841
    if (!vm) {
1842
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
1843
                       _("no domain with matching uuid"));
1844
        goto cleanup;
1845 1846
    }

1847
    ret = virDomainDefFormat((flags & VIR_DOMAIN_XML_INACTIVE) && vm->newDef ?
1848 1849 1850 1851
                             vm->newDef : vm->def,
                             flags);

cleanup:
1852
    if (vm)
1853
        virObjectUnlock(vm);
1854
    return ret;
1855 1856 1857 1858 1859
}


static int umlListDefinedDomains(virConnectPtr conn,
                            char **const names, int nnames) {
1860
    struct uml_driver *driver = conn->privateData;
1861
    int n;
1862

1863
    umlDriverLock(driver);
1864
    n = virDomainObjListGetInactiveNames(driver->domains, names, nnames);
1865
    umlDriverUnlock(driver);
1866

1867
    return n;
1868 1869 1870
}

static int umlNumDefinedDomains(virConnectPtr conn) {
1871
    struct uml_driver *driver = conn->privateData;
1872
    int n;
1873

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

    return n;
}


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

1888
    virCheckFlags(VIR_DOMAIN_START_AUTODESTROY, -1);
1889

1890
    umlDriverLock(driver);
1891
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1892

1893
    if (!vm) {
1894
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
1895
                       _("no domain with matching uuid"));
1896
        goto cleanup;
1897 1898
    }

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

cleanup:
1908
    if (vm)
1909
        virObjectUnlock(vm);
1910 1911
    if (event)
        umlDomainEventQueue(driver, event);
1912
    umlDriverUnlock(driver);
1913
    return ret;
1914 1915
}

1916 1917 1918
static int umlDomainStart(virDomainPtr dom) {
    return umlDomainStartWithFlags(dom, 0);
}
1919 1920

static virDomainPtr umlDomainDefine(virConnectPtr conn, const char *xml) {
1921
    struct uml_driver *driver = conn->privateData;
1922
    virDomainDefPtr def;
1923
    virDomainObjPtr vm = NULL;
1924
    virDomainPtr dom = NULL;
1925

1926
    umlDriverLock(driver);
1927 1928
    if (!(def = virDomainDefParseString(xml, driver->caps, driver->xmlopt,
                                        1 << VIR_DOMAIN_VIRT_UML,
1929
                                        VIR_DOMAIN_XML_INACTIVE)))
1930
        goto cleanup;
1931

1932
    if (!(vm = virDomainObjListAdd(driver->domains, def,
1933
                                   driver->xmlopt,
1934
                                   0, NULL)))
1935 1936
        goto cleanup;
    def = NULL;
1937 1938
    vm->persistent = 1;

1939
    if (virDomainSaveConfig(driver->configDir,
1940
                            vm->newDef ? vm->newDef : vm->def) < 0) {
1941 1942
        virDomainObjListRemove(driver->domains,
                               vm);
1943
        vm = NULL;
1944
        goto cleanup;
1945 1946 1947 1948
    }

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

cleanup:
    virDomainDefFree(def);
1952
    if (vm)
1953
        virObjectUnlock(vm);
1954
    umlDriverUnlock(driver);
1955 1956 1957
    return dom;
}

1958 1959 1960
static int umlDomainUndefineFlags(virDomainPtr dom,
                                  unsigned int flags)
{
1961 1962 1963
    struct uml_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
1964

1965 1966
    virCheckFlags(0, -1);

1967
    umlDriverLock(driver);
1968
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1969
    if (!vm) {
1970
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
1971
                       _("no domain with matching uuid"));
1972
        goto cleanup;
1973 1974 1975
    }

    if (!vm->persistent) {
1976
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
1977
                       _("cannot undefine transient domain"));
1978
        goto cleanup;
1979 1980
    }

1981
    if (virDomainDeleteConfig(driver->configDir, driver->autostartDir, vm) < 0)
1982
        goto cleanup;
1983

1984 1985 1986
    if (virDomainObjIsActive(vm)) {
        vm->persistent = 0;
    } else {
1987
        virDomainObjListRemove(driver->domains, vm);
1988 1989 1990
        vm = NULL;
    }

1991
    ret = 0;
1992

1993
cleanup:
1994
    if (vm)
1995
        virObjectUnlock(vm);
1996
    umlDriverUnlock(driver);
1997
    return ret;
1998 1999 2000
}


2001 2002 2003 2004 2005
static int umlDomainUndefine(virDomainPtr dom)
{
    return umlDomainUndefineFlags(dom, 0);
}

2006 2007 2008 2009 2010 2011 2012 2013 2014 2015
static int umlDomainAttachUmlDisk(struct uml_driver *driver,
                                  virDomainObjPtr vm,
                                  virDomainDiskDefPtr disk)
{
    int i;
    char *cmd = NULL;
    char *reply = NULL;

    for (i = 0 ; i < vm->def->ndisks ; i++) {
        if (STREQ(vm->def->disks[i]->dst, disk->dst)) {
2016
            virReportError(VIR_ERR_OPERATION_FAILED,
2017 2018 2019 2020 2021 2022
                           _("target %s already exists"), disk->dst);
            return -1;
        }
    }

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

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

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

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

    virDomainDiskInsertPreAlloced(vm->def, disk);

    VIR_FREE(reply);
    VIR_FREE(cmd);

    return 0;

error:

    VIR_FREE(reply);
    VIR_FREE(cmd);

    return -1;
}


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

    umlDriverLock(driver);

2066
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
2067 2068 2069
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
2070
        virReportError(VIR_ERR_NO_DOMAIN,
2071 2072 2073 2074 2075
                       _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

    if (!virDomainObjIsActive(vm)) {
2076
        virReportError(VIR_ERR_OPERATION_INVALID,
2077 2078 2079 2080
                       "%s", _("cannot attach device on inactive domain"));
        goto cleanup;
    }

2081
    dev = virDomainDeviceDefParse(xml, vm->def, driver->caps, driver->xmlopt,
2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092
                                  VIR_DOMAIN_XML_INACTIVE);

    if (dev == NULL)
        goto cleanup;

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

cleanup:

    virDomainDeviceDefFree(dev);
    if (vm)
2108
        virObjectUnlock(vm);
2109 2110 2111 2112 2113
    umlDriverUnlock(driver);
    return ret;
}


2114 2115 2116 2117 2118 2119 2120
static int
umlDomainAttachDeviceFlags(virDomainPtr dom,
                           const char *xml,
                           unsigned int flags)
{
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG, -1);

2121
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
2122
        virReportError(VIR_ERR_OPERATION_INVALID,
2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146
                       "%s", _("cannot modify the persistent configuration of a domain"));
        return -1;
    }

    return umlDomainAttachDevice(dom, xml);
}


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

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

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

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

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

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

    virDomainDiskRemove(vm->def, i);

    virDomainDiskDefFree(detach);

    ret = 0;

    VIR_FREE(reply);

cleanup:
    VIR_FREE(cmd);

    return ret;
}


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

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

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

2199
    dev = virDomainDeviceDefParse(xml, vm->def, driver->caps, driver->xmlopt,
2200 2201 2202 2203 2204 2205 2206 2207 2208
                                  VIR_DOMAIN_XML_INACTIVE);
    if (dev == NULL)
        goto cleanup;

    if (dev->type == VIR_DOMAIN_DEVICE_DISK &&
        dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
        if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_UML)
            ret = umlDomainDetachUmlDisk(driver, vm, dev);
        else {
2209
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2210 2211 2212
                           _("This type of disk cannot be hot unplugged"));
        }
    } else {
2213
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
2214 2215 2216 2217 2218 2219
                       "%s", _("This type of device cannot be hot unplugged"));
    }

cleanup:
    virDomainDeviceDefFree(dev);
    if (vm)
2220
        virObjectUnlock(vm);
2221 2222 2223 2224 2225
    umlDriverUnlock(driver);
    return ret;
}


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

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

    return umlDomainDetachDevice(dom, xml);
}

2242 2243 2244

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

2249
    umlDriverLock(driver);
2250
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
2251

2252
    if (!vm) {
2253
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
2254
                       _("no domain with matching uuid"));
2255
        goto cleanup;
2256 2257 2258
    }

    *autostart = vm->autostart;
2259
    ret = 0;
2260

2261
cleanup:
2262
    if (vm)
2263
        virObjectUnlock(vm);
2264
    umlDriverUnlock(driver);
2265
    return ret;
2266 2267 2268 2269
}

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

2275
    umlDriverLock(driver);
2276
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
2277

2278
    if (!vm) {
2279
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
2280
                       _("no domain with matching uuid"));
2281
        goto cleanup;
2282 2283 2284
    }

    if (!vm->persistent) {
2285
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
2286
                       _("cannot set autostart for transient domain"));
2287
        goto cleanup;
2288 2289 2290 2291
    }

    autostart = (autostart != 0);

2292
    if (vm->autostart != autostart) {
2293
        if ((configFile = virDomainConfigFile(driver->configDir, vm->def->name)) == NULL)
2294
            goto cleanup;
2295
        if ((autostartLink = virDomainConfigFile(driver->autostartDir, vm->def->name)) == NULL)
2296
            goto cleanup;
2297

2298
        if (autostart) {
2299 2300
            if (virFileMakePath(driver->autostartDir) < 0) {
                virReportSystemError(errno,
2301 2302
                                     _("cannot create autostart directory %s"),
                                     driver->autostartDir);
2303 2304
                goto cleanup;
            }
2305

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

2321
        vm->autostart = autostart;
2322 2323 2324 2325 2326 2327
    }
    ret = 0;

cleanup:
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
2328
    if (vm)
2329
        virObjectUnlock(vm);
2330
    umlDriverUnlock(driver);
2331 2332 2333 2334 2335
    return ret;
}


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

E
Eric Blake 已提交
2347 2348
    virCheckFlags(0, -1);

2349
    umlDriverLock(driver);
2350
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
2351 2352
    umlDriverUnlock(driver);

2353
    if (!vm) {
2354
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
2355
                       _("no domain with matching uuid"));
2356
        goto cleanup;
2357 2358 2359
    }

    if (!path || path[0] == '\0') {
2360
        virReportError(VIR_ERR_INVALID_ARG, "%s",
2361
                       _("NULL or empty path"));
2362
        goto cleanup;
2363 2364 2365
    }

    /* Check the path belongs to this domain. */
2366
    if (!(actual = virDomainDiskPathByName(vm->def, path))) {
2367
        virReportError(VIR_ERR_INVALID_ARG,
2368 2369
                       _("invalid path '%s'"), path);
        goto cleanup;
2370
    }
2371
    path = actual;
2372

2373 2374 2375 2376 2377 2378 2379
    /* 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;
    }
2380

2381 2382 2383 2384 2385 2386 2387 2388 2389
    /* 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;
2390 2391
    }

2392 2393
    ret = 0;

2394
cleanup:
2395
    VIR_FORCE_CLOSE(fd);
2396
    if (vm)
2397
        virObjectUnlock(vm);
2398 2399 2400 2401
    return ret;
}


2402 2403
static int
umlDomainOpenConsole(virDomainPtr dom,
2404
                     const char *dev_name,
2405 2406 2407 2408 2409 2410 2411 2412
                     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;
2413
    size_t i;
2414 2415 2416 2417 2418

    virCheckFlags(0, -1);

    umlDriverLock(driver);
    virUUIDFormat(dom->uuid, uuidstr);
2419
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
2420
    if (!vm) {
2421
        virReportError(VIR_ERR_NO_DOMAIN,
2422 2423 2424 2425 2426
                       _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

    if (!virDomainObjIsActive(vm)) {
2427
        virReportError(VIR_ERR_OPERATION_INVALID,
2428 2429 2430 2431
                        "%s", _("domain is not running"));
        goto cleanup;
    }

2432
    if (dev_name) {
2433 2434 2435 2436 2437 2438 2439
        for (i = 0 ; i < vm->def->nconsoles ; i++) {
            if (vm->def->consoles[i]->info.alias &&
                STREQ(vm->def->consoles[i]->info.alias, dev_name)) {
                chr = vm->def->consoles[i];
                break;
            }
        }
2440
    } else {
2441 2442
        if (vm->def->nconsoles)
            chr = vm->def->consoles[0];
2443 2444 2445 2446 2447
        else if (vm->def->nserials)
            chr = vm->def->serials[0];
    }

    if (!chr) {
2448
        virReportError(VIR_ERR_INTERNAL_ERROR,
2449 2450
                       _("cannot find console device '%s'"),
                       dev_name ? dev_name : _("default"));
2451 2452 2453
        goto cleanup;
    }

2454
    if (chr->source.type != VIR_DOMAIN_CHR_TYPE_PTY) {
2455
        virReportError(VIR_ERR_INTERNAL_ERROR,
2456
                        _("character device %s is not using a PTY"), dev_name);
2457 2458 2459
        goto cleanup;
    }

2460
    if (virFDStreamOpenFile(st, chr->source.data.file.path,
E
Eric Blake 已提交
2461
                            0, 0, O_RDWR) < 0)
2462 2463 2464 2465 2466
        goto cleanup;

    ret = 0;
cleanup:
    if (vm)
2467
        virObjectUnlock(vm);
2468 2469 2470 2471
    umlDriverUnlock(driver);
    return ret;
}

2472

2473 2474 2475 2476 2477 2478 2479 2480 2481 2482
static int
umlDomainEventRegister(virConnectPtr conn,
                       virConnectDomainEventCallback callback,
                       void *opaque,
                       virFreeCallback freecb)
{
    struct uml_driver *driver = conn->privateData;
    int ret;

    umlDriverLock(driver);
2483 2484 2485
    ret = virDomainEventStateRegister(conn,
                                      driver->domainEventState,
                                      callback, opaque, freecb);
2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518
    umlDriverUnlock(driver);

    return ret;
}

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

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

    return ret;
}

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

    umlDriverLock(driver);
2519 2520 2521 2522
    if (virDomainEventStateRegisterID(conn,
                                      driver->domainEventState,
                                      dom, eventID,
                                      callback, opaque, freecb, &ret) < 0)
2523
        ret = -1;
2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537
    umlDriverUnlock(driver);

    return ret;
}


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

    umlDriverLock(driver);
2538 2539 2540
    ret = virDomainEventStateDeregisterID(conn,
                                          driver->domainEventState,
                                          callbackID);
2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553
    umlDriverUnlock(driver);

    return ret;
}


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

2554 2555 2556 2557 2558 2559 2560
static int umlListAllDomains(virConnectPtr conn,
                             virDomainPtr **domains,
                             unsigned int flags)
{
    struct uml_driver *driver = conn->privateData;
    int ret = -1;

O
Osier Yang 已提交
2561
    virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
2562 2563

    umlDriverLock(driver);
2564
    ret = virDomainObjListExport(driver->domains, conn, domains, flags);
2565 2566 2567 2568 2569
    umlDriverUnlock(driver);

    return ret;
}

2570 2571


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

static virStateDriver umlStateDriver = {
2636
    .name = "UML",
2637 2638 2639 2640 2641 2642 2643 2644 2645 2646
    .initialize = umlStartup,
    .cleanup = umlShutdown,
    .reload = umlReload,
};

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