qemu_conf.c 55.4 KB
Newer Older
D
Daniel P. Berrange 已提交
1 2 3
/*
 * config.c: VM configuration management
 *
4
 * Copyright (C) 2006, 2007, 2008, 2009 Red Hat, Inc.
D
Daniel P. Berrange 已提交
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 * Copyright (C) 2006 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
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
 *
 * Author: Daniel P. Berrange <berrange@redhat.com>
 */

24
#include <config.h>
25

D
Daniel P. Berrange 已提交
26 27 28 29 30
#include <dirent.h>
#include <string.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
31
#include <stdlib.h>
D
Daniel P. Berrange 已提交
32 33 34
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
35
#include <sys/wait.h>
36
#include <arpa/inet.h>
37
#include <sys/utsname.h>
D
Daniel P. Berrange 已提交
38

39
#include "virterror_internal.h"
40
#include "qemu_conf.h"
41
#include "uuid.h"
42
#include "buf.h"
D
Daniel P. Berrange 已提交
43
#include "conf.h"
44
#include "util.h"
45
#include "memory.h"
J
Jim Meyering 已提交
46
#include "verify.h"
47 48
#include "datatypes.h"
#include "xml.h"
49
#include "nodeinfo.h"
50
#include "logging.h"
51

52 53
#define VIR_FROM_THIS VIR_FROM_QEMU

54 55 56 57 58 59
VIR_ENUM_DECL(virDomainDiskQEMUBus)
VIR_ENUM_IMPL(virDomainDiskQEMUBus, VIR_DOMAIN_DISK_BUS_LAST,
              "ide",
              "floppy",
              "scsi",
              "virtio",
60
              "xen",
61 62
              "usb",
              "uml")
63

64

65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
VIR_ENUM_DECL(qemuDiskCacheV1)
VIR_ENUM_DECL(qemuDiskCacheV2)

VIR_ENUM_IMPL(qemuDiskCacheV1, VIR_DOMAIN_DISK_CACHE_LAST,
              "default",
              "off",
              "off", /* writethrough not supported, so for safety, disable */
              "on"); /* Old 'on' was equivalent to 'writeback' */

VIR_ENUM_IMPL(qemuDiskCacheV2, VIR_DOMAIN_DISK_CACHE_LAST,
              "default",
              "none",
              "writethrough",
              "writeback");


D
Daniel P. Berrange 已提交
81 82 83 84 85 86
int qemudLoadDriverConfig(struct qemud_driver *driver,
                          const char *filename) {
    virConfPtr conf;
    virConfValuePtr p;

    /* Setup 2 critical defaults */
87
    if (!(driver->vncListen = strdup("127.0.0.1"))) {
88
        virReportOOMError(NULL);
89 90
        return -1;
    }
D
Daniel P. Berrange 已提交
91
    if (!(driver->vncTLSx509certdir = strdup(SYSCONF_DIR "/pki/libvirt-vnc"))) {
92
        virReportOOMError(NULL);
D
Daniel P. Berrange 已提交
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
        return -1;
    }

    /* Just check the file is readable before opening it, otherwise
     * libvirt emits an error.
     */
    if (access (filename, R_OK) == -1) return 0;

    conf = virConfReadFile (filename);
    if (!conf) return 0;


#define CHECK_TYPE(name,typ) if (p && p->type != (typ)) {               \
        qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,      \
                         "remoteReadConfigFile: %s: %s: expected type " #typ "\n", \
                         filename, (name));                             \
        virConfFree(conf);                                              \
        return -1;                                                      \
    }

    p = virConfGetValue (conf, "vnc_tls");
    CHECK_TYPE ("vnc_tls", VIR_CONF_LONG);
    if (p) driver->vncTLS = p->l;

    p = virConfGetValue (conf, "vnc_tls_x509_verify");
    CHECK_TYPE ("vnc_tls_x509_verify", VIR_CONF_LONG);
    if (p) driver->vncTLSx509verify = p->l;

    p = virConfGetValue (conf, "vnc_tls_x509_cert_dir");
    CHECK_TYPE ("vnc_tls_x509_cert_dir", VIR_CONF_STRING);
    if (p && p->str) {
124
        VIR_FREE(driver->vncTLSx509certdir);
D
Daniel P. Berrange 已提交
125
        if (!(driver->vncTLSx509certdir = strdup(p->str))) {
126
            virReportOOMError(NULL);
D
Daniel P. Berrange 已提交
127 128 129 130 131 132 133 134
            virConfFree(conf);
            return -1;
        }
    }

    p = virConfGetValue (conf, "vnc_listen");
    CHECK_TYPE ("vnc_listen", VIR_CONF_STRING);
    if (p && p->str) {
J
Jim Meyering 已提交
135
        VIR_FREE(driver->vncListen);
136
        if (!(driver->vncListen = strdup(p->str))) {
137
            virReportOOMError(NULL);
138 139 140
            virConfFree(conf);
            return -1;
        }
D
Daniel P. Berrange 已提交
141 142
    }

143 144 145 146 147 148 149 150 151 152 153
    p = virConfGetValue (conf, "vnc_password");
    CHECK_TYPE ("vnc_password", VIR_CONF_STRING);
    if (p && p->str) {
        VIR_FREE(driver->vncPassword);
        if (!(driver->vncPassword = strdup(p->str))) {
            virReportOOMError(NULL);
            virConfFree(conf);
            return -1;
        }
    }

154
    p = virConfGetValue (conf, "security_driver");
J
Jim Meyering 已提交
155
    CHECK_TYPE ("security_driver", VIR_CONF_STRING);
156 157 158 159 160 161 162 163
    if (p && p->str) {
        if (!(driver->securityDriverName = strdup(p->str))) {
            virReportOOMError(NULL);
            virConfFree(conf);
            return -1;
        }
    }

164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
    p = virConfGetValue (conf, "vnc_sasl");
    CHECK_TYPE ("vnc_sasl", VIR_CONF_LONG);
    if (p) driver->vncSASL = p->l;

    p = virConfGetValue (conf, "vnc_sasl_dir");
    CHECK_TYPE ("vnc_sasl_dir", VIR_CONF_STRING);
    if (p && p->str) {
        VIR_FREE(driver->vncSASLdir);
        if (!(driver->vncSASLdir = strdup(p->str))) {
            virReportOOMError(NULL);
            virConfFree(conf);
            return -1;
        }
    }

D
Daniel P. Berrange 已提交
179 180 181 182
    virConfFree (conf);
    return 0;
}

D
Daniel P. Berrange 已提交
183 184
/* The list of possible machine types for various architectures,
   as supported by QEMU - taken from 'qemu -M ?' for each arch */
185 186
static const char *const arch_info_hvm_x86_machines[] = {
    "pc", "isapc"
D
Daniel P. Berrange 已提交
187
};
188 189
static const char *const arch_info_hvm_mips_machines[] = {
    "mips"
D
Daniel P. Berrange 已提交
190
};
191 192
static const char *const arch_info_hvm_sparc_machines[] = {
    "sun4m"
D
Daniel P. Berrange 已提交
193
};
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
static const char *const arch_info_hvm_ppc_machines[] = {
    "g3bw", "mac99", "prep"
};

static const char *const arch_info_xen_x86_machines[] = {
    "xenner"
};

struct qemu_feature_flags {
    const char *name;
    const int default_on;
    const int toggle;
};

struct qemu_arch_info {
    const char *arch;
    int wordsize;
    const char *const *machines;
    int nmachines;
    const char *binary;
214
    const char *altbinary;
215 216
    const struct qemu_feature_flags *flags;
    int nflags;
D
Daniel P. Berrange 已提交
217 218
};

219
/* Feature flags for the architecture info */
J
Jim Meyering 已提交
220
static const struct qemu_feature_flags const arch_info_i686_flags [] = {
221 222
    { "pae",  1, 0 },
    { "nonpae",  1, 0 },
223 224 225 226
    { "acpi", 1, 1 },
    { "apic", 1, 0 },
};

J
Jim Meyering 已提交
227
static const struct qemu_feature_flags const arch_info_x86_64_flags [] = {
228 229 230 231
    { "acpi", 1, 1 },
    { "apic", 1, 0 },
};

D
Daniel P. Berrange 已提交
232
/* The archicture tables for supported QEMU archs */
233 234
static const struct qemu_arch_info const arch_info_hvm[] = {
    {  "i686", 32, arch_info_hvm_x86_machines, 2,
235
       "/usr/bin/qemu", "/usr/bin/qemu-system-x86_64", arch_info_i686_flags, 4 },
236
    {  "x86_64", 64, arch_info_hvm_x86_machines, 2,
237
       "/usr/bin/qemu-system-x86_64", NULL, arch_info_x86_64_flags, 2 },
238
    {  "mips", 32, arch_info_hvm_mips_machines, 1,
239
       "/usr/bin/qemu-system-mips", NULL, NULL, 0 },
240
    {  "mipsel", 32, arch_info_hvm_mips_machines, 1,
241
       "/usr/bin/qemu-system-mipsel", NULL, NULL, 0 },
242
    {  "sparc", 32, arch_info_hvm_sparc_machines, 1,
243
       "/usr/bin/qemu-system-sparc", NULL, NULL, 0 },
244
    {  "ppc", 32, arch_info_hvm_ppc_machines, 3,
245
       "/usr/bin/qemu-system-ppc", NULL, NULL, 0 },
D
Daniel P. Berrange 已提交
246 247
};

248 249
static const struct qemu_arch_info const arch_info_xen[] = {
    {  "i686", 32, arch_info_xen_x86_machines, 1,
250
       "/usr/bin/xenner", NULL, arch_info_i686_flags, 4 },
251
    {  "x86_64", 64, arch_info_xen_x86_machines, 1,
252
       "/usr/bin/xenner", NULL, arch_info_x86_64_flags, 2 },
253
};
D
Daniel P. Berrange 已提交
254

255 256 257 258 259 260
static int
qemudCapsInitGuest(virCapsPtr caps,
                   const char *hostmachine,
                   const struct qemu_arch_info *info,
                   int hvm) {
    virCapsGuestPtr guest;
261 262 263 264 265
    int i;
    int hasbase = 0;
    int hasaltbase = 0;
    int haskvm = 0;
    int haskqemu = 0;
266 267
    const char *kvmbin = NULL;

268 269 270
    /* Check for existance of base emulator, or alternate base
     * which can be used with magic cpu choice
     */
271
    hasbase = (access(info->binary, X_OK) == 0);
272
    hasaltbase = (info->altbinary && access(info->altbinary, X_OK) == 0);
273

274 275 276 277 278 279 280 281
    /* Can use acceleration for KVM/KQEMU if
     *  - host & guest arches match
     * Or
     *  - hostarch is x86_64 and guest arch is i686
     * The latter simply needs "-cpu qemu32"
     */
    if (STREQ(info->arch, hostmachine) ||
        (STREQ(hostmachine, "x86_64") && STREQ(info->arch, "i686"))) {
282 283 284 285
        const char *const kvmbins[] = { "/usr/bin/qemu-kvm", /* Fedora */
                                        "/usr/bin/kvm" }; /* Upstream .spec */

        for (i = 0; i < ARRAY_CARDINALITY(kvmbins); ++i) {
286 287 288
            if (access(kvmbins[i], X_OK) == 0 &&
                access("/dev/kvm", F_OK) == 0) {
                haskvm = 1;
289 290 291 292
                kvmbin = kvmbins[i];
                break;
            }
        }
293 294 295

        if (access("/dev/kqemu", F_OK) == 0)
            haskqemu = 1;
296 297
    }

298 299

    if (!hasbase && !hasaltbase && !haskvm)
300
        return 0;
D
Daniel P. Berrange 已提交
301

302 303
    /* We register kvm as the base emulator too, since we can
     * just give -no-kvm to disable acceleration if required */
304 305 306 307
    if ((guest = virCapabilitiesAddGuest(caps,
                                         hvm ? "hvm" : "xen",
                                         info->arch,
                                         info->wordsize,
308 309
                                         (hasbase ? info->binary :
                                          (hasaltbase ? info->altbinary : kvmbin)),
310 311 312 313
                                         NULL,
                                         info->nmachines,
                                         info->machines)) == NULL)
        return -1;
D
Daniel P. Berrange 已提交
314

315
    if (hvm) {
316
        if (virCapabilitiesAddGuestDomain(guest,
317 318 319 320 321 322
                                          "qemu",
                                          NULL,
                                          NULL,
                                          0,
                                          NULL) == NULL)
            return -1;
D
Daniel P. Berrange 已提交
323

324 325 326 327 328 329 330 331
        if (haskqemu &&
            virCapabilitiesAddGuestDomain(guest,
                                          "kqemu",
                                          NULL,
                                          NULL,
                                          0,
                                          NULL) == NULL)
            return -1;
332

333 334 335 336 337 338 339 340
        if (haskvm &&
            virCapabilitiesAddGuestDomain(guest,
                                          "kvm",
                                          kvmbin,
                                          NULL,
                                          0,
                                          NULL) == NULL)
            return -1;
341 342 343 344 345 346 347 348 349
    } else {
        if (virCapabilitiesAddGuestDomain(guest,
                                          "kvm",
                                          NULL,
                                          NULL,
                                          0,
                                          NULL) == NULL)
            return -1;
    }
D
Daniel P. Berrange 已提交
350

351 352 353 354 355 356 357
    if (info->nflags) {
        for (i = 0 ; i < info->nflags ; i++) {
            if (virCapabilitiesAddGuestFeature(guest,
                                               info->flags[i].name,
                                               info->flags[i].default_on,
                                               info->flags[i].toggle) == NULL)
                return -1;
D
Daniel P. Berrange 已提交
358 359 360
        }
    }

361
    return 0;
D
Daniel P. Berrange 已提交
362 363
}

364 365 366 367
virCapsPtr qemudCapsInit(void) {
    struct utsname utsname;
    virCapsPtr caps;
    int i;
D
Daniel P. Berrange 已提交
368

369 370 371 372
    /* Really, this never fails - look at the man-page. */
    uname (&utsname);

    if ((caps = virCapabilitiesNew(utsname.machine,
373
                                   1, 1)) == NULL)
374 375
        goto no_memory;

376 377 378
    /* Using KVM's mac prefix for QEMU too */
    virCapabilitiesSetMacPrefix(caps, (unsigned char[]){ 0x52, 0x54, 0x00 });

379
    if (virCapsInitNUMA(caps) < 0)
380 381
        goto no_memory;

382 383 384
    virCapabilitiesAddHostMigrateTransport(caps,
                                           "tcp");

385
    /* First the pure HVM guests */
J
Jim Meyering 已提交
386
    for (i = 0 ; i < ARRAY_CARDINALITY(arch_info_hvm) ; i++)
387 388 389 390 391
        if (qemudCapsInitGuest(caps,
                               utsname.machine,
                               &arch_info_hvm[i], 1) < 0)
            goto no_memory;

392
    /* Then possibly the Xen paravirt guests (ie Xenner */
393 394
    if (access("/usr/bin/xenner", X_OK) == 0 &&
        access("/dev/kvm", F_OK) == 0) {
J
Jim Meyering 已提交
395
        for (i = 0 ; i < ARRAY_CARDINALITY(arch_info_xen) ; i++)
396 397 398 399 400 401 402 403 404
            /* Allow Xen 32-on-32, 32-on-64 and 64-on-64 */
            if (STREQ(arch_info_xen[i].arch, utsname.machine) ||
                (STREQ(utsname.machine, "x86_64") &&
                 STREQ(arch_info_xen[i].arch, "i686"))) {
                if (qemudCapsInitGuest(caps,
                                       utsname.machine,
                                       &arch_info_xen[i], 0) < 0)
                    goto no_memory;
            }
D
Daniel P. Berrange 已提交
405 406
    }

407 408 409 410 411
    return caps;

 no_memory:
    virCapabilitiesFree(caps);
    return NULL;
D
Daniel P. Berrange 已提交
412 413
}

414

415 416 417 418 419
int qemudExtractVersionInfo(const char *qemu,
                            unsigned int *retversion,
                            unsigned int *retflags) {
    const char *const qemuarg[] = { qemu, "-help", NULL };
    const char *const qemuenv[] = { "LC_ALL=C", NULL };
420
    pid_t child;
421
    int newstdout = -1;
422
    int ret = -1, status;
423
    unsigned int major, minor, micro;
424
    unsigned int version, kvm_version;
425 426 427 428 429 430 431 432 433 434
    unsigned int flags = 0;

    if (retflags)
        *retflags = 0;
    if (retversion)
        *retversion = 0;

    if (virExec(NULL, qemuarg, qemuenv, NULL,
                &child, -1, &newstdout, NULL, VIR_EXEC_NONE) < 0)
        return -1;
435

436
    char *help = NULL;
437
    enum { MAX_HELP_OUTPUT_SIZE = 1024*64 };
438
    int len = virFileReadLimFD(newstdout, MAX_HELP_OUTPUT_SIZE, &help);
439 440 441
    if (len < 0) {
        virReportSystemError(NULL, errno, "%s",
                             _("Unable to read QEMU help output"));
442
        goto cleanup2;
443
    }
444

445 446 447 448
    if (sscanf(help, "QEMU PC emulator version %u.%u.%u (kvm-%u)",
               &major, &minor, &micro, &kvm_version) != 4)
        kvm_version = 0;

449 450 451 452 453 454 455 456
    if (!kvm_version &&
        sscanf(help, "QEMU PC emulator version %u.%u.%u",
               &major, &minor, &micro) != 3) {
        char *eol = strchr(help, '\n');
        if (eol) *eol = '\0';
        qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                         _("cannot parse QEMU version number in '%s'"),
                         help);
457
        goto cleanup2;
458
    }
459

460
    version = (major * 1000 * 1000) + (minor * 1000) + micro;
461

462 463
    if (strstr(help, "-no-kqemu"))
        flags |= QEMUD_CMD_FLAG_KQEMU;
464 465
    if (strstr(help, "-no-kvm"))
        flags |= QEMUD_CMD_FLAG_KVM;
466 467 468 469
    if (strstr(help, "-no-reboot"))
        flags |= QEMUD_CMD_FLAG_NO_REBOOT;
    if (strstr(help, "-name"))
        flags |= QEMUD_CMD_FLAG_NAME;
470 471 472 473
    if (strstr(help, "-uuid"))
        flags |= QEMUD_CMD_FLAG_UUID;
    if (strstr(help, "-domid"))
        flags |= QEMUD_CMD_FLAG_DOMID;
474
    if (strstr(help, "-drive")) {
475
        flags |= QEMUD_CMD_FLAG_DRIVE;
476 477 478
        if (strstr(help, "cache=writethrough|writeback|none"))
            flags |= QEMUD_CMD_FLAG_DRIVE_CACHE_V2;
    }
479 480 481 482
    if (strstr(help, "boot=on"))
        flags |= QEMUD_CMD_FLAG_DRIVE_BOOT;
    if (version >= 9000)
        flags |= QEMUD_CMD_FLAG_VNC_COLON;
483 484
    if (kvm_version >= 74)
        flags |= QEMUD_CMD_FLAG_VNET_HDR;
485

486 487
    /*
     * Handling of -incoming arg with varying features
488 489
     *  -incoming tcp    (kvm >= 79, qemu >= 0.10.0)
     *  -incoming exec   (kvm >= 80, qemu >= 0.10.0)
490 491 492 493 494 495 496 497 498 499 500 501
     *  -incoming stdio  (all earlier kvm)
     *
     * NB, there was a pre-kvm-79 'tcp' support, but it
     * was broken, because it blocked the monitor console
     * while waiting for data, so pretend it doesn't exist
     */
    if (kvm_version >= 79) {
        flags |= QEMUD_CMD_FLAG_MIGRATE_QEMU_TCP;
        if (kvm_version >= 80)
            flags |= QEMUD_CMD_FLAG_MIGRATE_QEMU_EXEC;
    } else if (kvm_version > 0) {
        flags |= QEMUD_CMD_FLAG_MIGRATE_KVM_STDIO;
502 503 504
    } else if (version >= 10000) {
        flags |= QEMUD_CMD_FLAG_MIGRATE_QEMU_TCP;
        flags |= QEMUD_CMD_FLAG_MIGRATE_QEMU_EXEC;
505 506
    }

507 508 509 510
    if (retversion)
        *retversion = version;
    if (retflags)
        *retflags = flags;
511

512
    ret = 0;
513

514 515
    qemudDebug("Version %d %d %d  Cooked version: %d, with flags ? %d",
               major, minor, micro, version, flags);
516 517
    if (kvm_version)
        qemudDebug("KVM version %d detected", kvm_version);
518

519
cleanup2:
520
    VIR_FREE(help);
521 522
    if (close(newstdout) < 0)
        ret = -1;
523

524 525 526 527 528
rewait:
    if (waitpid(child, &status, 0) != child) {
        if (errno == EINTR)
            goto rewait;

529 530
        VIR_ERROR(_("Unexpected exit status from qemu %d pid %lu"),
                  WEXITSTATUS(status), (unsigned long)child);
531 532 533 534 535 536
        ret = -1;
    }
    /* Check & log unexpected exit status, but don't fail,
     * as there's really no need to throw an error if we did
     * actually read a valid version number above */
    if (WEXITSTATUS(status) != 0) {
537
        VIR_WARN(_("Unexpected exit status '%d', qemu probably failed"),
538
                 WEXITSTATUS(status));
539
    }
540 541

    return ret;
542 543
}

544 545 546 547 548 549 550 551 552 553 554 555 556 557
static void
uname_normalize (struct utsname *ut)
{
    uname(ut);

    /* Map i386, i486, i586 to i686.  */
    if (ut->machine[0] == 'i' &&
        ut->machine[1] != '\0' &&
        ut->machine[2] == '8' &&
        ut->machine[3] == '6' &&
        ut->machine[4] == '\0')
        ut->machine[1] = '6';
}

558
int qemudExtractVersion(virConnectPtr conn,
559 560
                        struct qemud_driver *driver) {
    const char *binary;
561
    struct stat sb;
562
    struct utsname ut;
563

564
    if (driver->qemuVersion > 0)
565 566
        return 0;

567
    uname_normalize(&ut);
568 569
    if ((binary = virCapabilitiesDefaultGuestEmulator(driver->caps,
                                                      "hvm",
570
                                                      ut.machine,
571 572
                                                      "qemu")) == NULL)
        return -1;
573

574
    if (stat(binary, &sb) < 0) {
575
        char ebuf[1024];
576 577
        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                         _("Cannot find QEMU binary %s: %s"), binary,
578
                         virStrerror(errno, ebuf, sizeof ebuf));
579
        return -1;
580 581
    }

582
    if (qemudExtractVersionInfo(binary, &driver->qemuVersion, NULL) < 0) {
583 584
        return -1;
    }
D
Daniel P. Berrange 已提交
585

586
    return 0;
D
Daniel P. Berrange 已提交
587 588 589
}


590
static char *
591 592
qemudNetworkIfaceConnect(virConnectPtr conn,
                         struct qemud_driver *driver,
593 594 595
                         int **tapfds,
                         int *ntapfds,
                         virDomainNetDefPtr net,
596 597
                         int vlan,
                         int vnet_hdr)
598
{
599
    char *brname;
600 601 602 603 604
    char tapfdstr[4+3+32+7];
    char *retval = NULL;
    int err;
    int tapfd = -1;

605
    if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
606 607 608
        virNetworkPtr network = virNetworkLookupByName(conn,
                                                      net->data.network.name);
        if (!network) {
609
            qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
610
                             _("Network '%s' not found"),
611
                             net->data.network.name);
612
            goto error;
613 614 615 616 617 618
        }
        brname = virNetworkGetBridgeName(network);

        virNetworkFree(network);

        if (brname == NULL) {
619 620
            goto error;
        }
621 622
    } else if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
        brname = net->data.bridge.brname;
623
    } else {
624
        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
625
                         _("Network type %d is not supported"), net->type);
626 627 628
        goto error;
    }

629 630 631 632 633
    if (!net->ifname ||
        STRPREFIX(net->ifname, "vnet") ||
        strchr(net->ifname, '%')) {
        VIR_FREE(net->ifname);
        if (!(net->ifname = strdup("vnet%d"))) {
634
            virReportOOMError(conn);
635 636 637 638
            goto error;
        }
    }

639
    char ebuf[1024];
640
    if (!driver->brctl && (err = brInit(&driver->brctl))) {
641
        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
642
                         _("cannot initialize bridge support: %s"),
643
                         virStrerror(err, ebuf, sizeof ebuf));
644 645 646
        goto error;
    }

647
    if ((err = brAddTap(driver->brctl, brname,
648
                        &net->ifname, vnet_hdr, &tapfd))) {
649 650 651 652 653 654 655 656 657
        if (errno == ENOTSUP) {
            /* In this particular case, give a better diagnostic. */
            qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                             _("Failed to add tap interface to bridge. "
                               "%s is not a bridge device"), brname);
        } else {
            qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                             _("Failed to add tap interface '%s' "
                               "to bridge '%s' : %s"),
658
                             net->ifname, brname, virStrerror(err, ebuf, sizeof ebuf));
659
        }
660 661 662
        goto error;
    }

663 664
    snprintf(tapfdstr, sizeof(tapfdstr),
             "tap,fd=%d,script=,vlan=%d,ifname=%s",
665
             tapfd, vlan, net->ifname);
666 667 668 669

    if (!(retval = strdup(tapfdstr)))
        goto no_memory;

670
    if (VIR_REALLOC_N(*tapfds, (*ntapfds)+1) < 0)
671 672
        goto no_memory;

673
    (*tapfds)[(*ntapfds)++] = tapfd;
674 675 676 677

    return retval;

 no_memory:
678
    virReportOOMError(conn);
679
 error:
680
    VIR_FREE(retval);
681 682 683 684 685
    if (tapfd != -1)
        close(tapfd);
    return NULL;
}

686

687
static int qemudBuildCommandLineChrDevStr(virDomainChrDefPtr dev,
688 689 690
                                          char *buf,
                                          int buflen)
{
691 692
    switch (dev->type) {
    case VIR_DOMAIN_CHR_TYPE_NULL:
693 694 695 696
        strncpy(buf, "null", buflen);
        buf[buflen-1] = '\0';
        break;

697
    case VIR_DOMAIN_CHR_TYPE_VC:
698 699 700 701
        strncpy(buf, "vc", buflen);
        buf[buflen-1] = '\0';
        break;

702
    case VIR_DOMAIN_CHR_TYPE_PTY:
703 704 705 706
        strncpy(buf, "pty", buflen);
        buf[buflen-1] = '\0';
        break;

707
    case VIR_DOMAIN_CHR_TYPE_DEV:
708
        if (snprintf(buf, buflen, "%s",
709
                     dev->data.file.path) >= buflen)
710 711 712
            return -1;
        break;

713
    case VIR_DOMAIN_CHR_TYPE_FILE:
714
        if (snprintf(buf, buflen, "file:%s",
715
                     dev->data.file.path) >= buflen)
716 717 718
            return -1;
        break;

719
    case VIR_DOMAIN_CHR_TYPE_PIPE:
720
        if (snprintf(buf, buflen, "pipe:%s",
721
                     dev->data.file.path) >= buflen)
722 723 724
            return -1;
        break;

725
    case VIR_DOMAIN_CHR_TYPE_STDIO:
726 727 728 729
        strncpy(buf, "stdio", buflen);
        buf[buflen-1] = '\0';
        break;

730
    case VIR_DOMAIN_CHR_TYPE_UDP:
731
        if (snprintf(buf, buflen, "udp:%s:%s@%s:%s",
732 733 734 735
                     dev->data.udp.connectHost,
                     dev->data.udp.connectService,
                     dev->data.udp.bindHost,
                     dev->data.udp.bindService) >= buflen)
736 737 738
            return -1;
        break;

739
    case VIR_DOMAIN_CHR_TYPE_TCP:
740 741 742 743
        if (dev->data.tcp.protocol == VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET) {
            if (snprintf(buf, buflen, "telnet:%s:%s%s",
                         dev->data.tcp.host,
                         dev->data.tcp.service,
744
                         dev->data.tcp.listen ? ",server,nowait" : "") >= buflen)
745 746 747 748 749
                return -1;
        } else {
            if (snprintf(buf, buflen, "tcp:%s:%s%s",
                         dev->data.tcp.host,
                         dev->data.tcp.service,
750
                         dev->data.tcp.listen ? ",server,nowait" : "") >= buflen)
751 752
                return -1;
        }
753 754
        break;

755
    case VIR_DOMAIN_CHR_TYPE_UNIX:
756
        if (snprintf(buf, buflen, "unix:%s%s",
757
                     dev->data.nix.path,
758
                     dev->data.nix.listen ? ",server,nowait" : "") >= buflen)
759 760 761 762 763 764 765
            return -1;
        break;
    }

    return 0;
}

D
Daniel P. Berrange 已提交
766 767 768 769
/*
 * Constructs a argv suitable for launching qemu with config defined
 * for a given virtual machine.
 */
770 771
int qemudBuildCommandLine(virConnectPtr conn,
                          struct qemud_driver *driver,
772
                          virDomainDefPtr def,
773
                          unsigned int qemuCmdFlags,
774
                          const char ***retargv,
775
                          const char ***retenv,
776 777 778
                          int **tapfds,
                          int *ntapfds,
                          const char *migrateFrom) {
779
    int i;
D
Daniel P. Berrange 已提交
780 781
    char memory[50];
    char vcpus[50];
782
    char boot[VIR_DOMAIN_BOOT_LAST];
783 784
    struct utsname ut;
    int disableKQEMU = 0;
785
    int disableKVM = 0;
786
    int qargc = 0, qarga = 0;
787
    const char **qargv = NULL;
788 789
    int qenvc = 0, qenva = 0;
    const char **qenv = NULL;
790
    const char *emulator;
791 792
    char uuid[VIR_UUID_STRING_BUFLEN];
    char domid[50];
793
    const char *cpu = NULL;
D
Daniel P. Berrange 已提交
794

795
    uname_normalize(&ut);
796

797
    virUUIDFormat(def->uuid, uuid);
798

799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825
    /* Migration is very annoying due to wildly varying syntax & capabilities
     * over time of KVM / QEMU codebases
     */
    if (migrateFrom) {
        if (STRPREFIX(migrateFrom, "tcp")) {
            if (!(qemuCmdFlags & QEMUD_CMD_FLAG_MIGRATE_QEMU_TCP)) {
                qemudReportError(conn, NULL, NULL, VIR_ERR_NO_SUPPORT,
                                 "%s", _("TCP migration is not supported with this QEMU binary"));
                return -1;
            }
        } else if (STREQ(migrateFrom, "stdio")) {
            if (qemuCmdFlags & QEMUD_CMD_FLAG_MIGRATE_QEMU_EXEC) {
                migrateFrom = "exec:cat";
            } else if (!(qemuCmdFlags & QEMUD_CMD_FLAG_MIGRATE_KVM_STDIO)) {
                qemudReportError(conn, NULL, NULL, VIR_ERR_NO_SUPPORT,
                                 "%s", _("STDIO migration is not supported with this QEMU binary"));
                return -1;
            }
        } else if (STRPREFIX(migrateFrom, "exec")) {
            if (!(qemuCmdFlags & QEMUD_CMD_FLAG_MIGRATE_QEMU_EXEC)) {
                qemudReportError(conn, NULL, NULL, VIR_ERR_NO_SUPPORT,
                                 "%s", _("STDIO migration is not supported with this QEMU binary"));
                return -1;
            }
        }
    }

826
    emulator = def->emulator;
827
    if (!emulator)
828
        emulator = virDomainDefDefaultEmulator(conn, def, driver->caps);
829 830 831 832
    if (!emulator)
        return -1;


833 834
    /* Need to explicitly disable KQEMU if
     * 1. Arch matches host arch
835
     * 2. Guest domain is 'qemu'
836 837
     * 3. The qemu binary has the -no-kqemu flag
     */
838
    if ((qemuCmdFlags & QEMUD_CMD_FLAG_KQEMU) &&
839 840
        STREQ(ut.machine, def->os.arch) &&
        def->virtType == VIR_DOMAIN_VIRT_QEMU)
841 842
        disableKQEMU = 1;

843 844 845 846 847 848
    /* Need to explicitly disable KVM if
     * 1. Arch matches host arch
     * 2. Guest domain is 'qemu'
     * 3. The qemu binary has the -no-kvm flag
     */
    if ((qemuCmdFlags & QEMUD_CMD_FLAG_KVM) &&
849 850
        STREQ(ut.machine, def->os.arch) &&
        def->virtType == VIR_DOMAIN_VIRT_QEMU)
851 852 853 854 855 856 857 858 859 860 861 862 863 864
        disableKVM = 1;

    /*
     * Need to force a 32-bit guest CPU type if
     *
     *  1. guest OS is i686
     *  2. host OS is x86_64
     *  3. emulator is qemu-kvm or kvm
     *
     * Or
     *
     *  1. guest OS is i686
     *  2. emulator is qemu-system-x86_64
     */
865
    if (STREQ(def->os.arch, "i686") &&
866 867 868 869 870
        ((STREQ(ut.machine, "x86_64") &&
          strstr(emulator, "kvm")) ||
         strstr(emulator, "x86_64")))
        cpu = "qemu32";

871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891
#define ADD_ARG_SPACE                                                   \
    do { \
        if (qargc == qarga) {                                           \
            qarga += 10;                                                \
            if (VIR_REALLOC_N(qargv, qarga) < 0)                        \
                goto no_memory;                                         \
        }                                                               \
    } while (0)

#define ADD_ARG(thisarg)                                                \
    do {                                                                \
        ADD_ARG_SPACE;                                                  \
        qargv[qargc++] = thisarg;                                       \
    } while (0)

#define ADD_ARG_LIT(thisarg)                                            \
    do {                                                                \
        ADD_ARG_SPACE;                                                  \
        if ((qargv[qargc++] = strdup(thisarg)) == NULL)                 \
            goto no_memory;                                             \
    } while (0)
D
Daniel P. Berrange 已提交
892

893 894 895 896
#define ADD_USBDISK(thisarg)                                            \
    do {                                                                \
        ADD_ARG_LIT("-usbdevice");                                      \
        ADD_ARG_SPACE;                                                  \
897 898
        if ((virAsprintf((char **)&(qargv[qargc++]),                    \
                         "disk:%s", thisarg)) == -1) {                  \
899 900 901 902
            goto no_memory;                                             \
        }                                                               \
    } while (0)

903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924
#define ADD_ENV_SPACE                                                   \
    do {                                                                \
        if (qenvc == qenva) {                                           \
            qenva += 10;                                                \
            if (VIR_REALLOC_N(qenv, qenva) < 0)                         \
                goto no_memory;                                         \
        }                                                               \
    } while (0)

#define ADD_ENV(thisarg)                                                \
    do {                                                                \
        ADD_ENV_SPACE;                                                  \
        qenv[qenvc++] = thisarg;                                        \
    } while (0)

#define ADD_ENV_LIT(thisarg)                                            \
    do {                                                                \
        ADD_ENV_SPACE;                                                  \
        if ((qenv[qenvc++] = strdup(thisarg)) == NULL)                  \
            goto no_memory;                                             \
    } while (0)

925
#define ADD_ENV_PAIR(envname, val)                                      \
926 927 928
    do {                                                                \
        char *envval;                                                   \
        ADD_ENV_SPACE;                                                  \
929 930 931 932 933 934 935 936
        if (virAsprintf(&envval, "%s=%s", envname, val) < 0)            \
            goto no_memory;                                             \
        qenv[qenvc++] = envval;                                         \
    } while (0)

#define ADD_ENV_COPY(envname)                                           \
    do {                                                                \
        char *val = getenv(envname);                                    \
937
        if (val != NULL) {                                              \
938
            ADD_ENV_PAIR(envname, val);                                 \
939 940 941
        }                                                               \
    } while (0)

942 943 944 945
    /* Set '-m MB' based on maxmem, because the lower 'memory' limit
     * is set post-startup using the balloon driver. If balloon driver
     * is not supported, then they're out of luck anyway
     */
946 947 948
    snprintf(memory, sizeof(memory), "%lu", def->maxmem/1024);
    snprintf(vcpus, sizeof(vcpus), "%lu", def->vcpus);
    snprintf(domid, sizeof(domid), "%d", def->id);
D
Daniel P. Berrange 已提交
949

950 951 952 953 954 955 956 957 958 959
    ADD_ENV_LIT("LC_ALL=C");

    ADD_ENV_COPY("LD_PRELOAD");
    ADD_ENV_COPY("LD_LIBRARY_PATH");
    ADD_ENV_COPY("PATH");
    ADD_ENV_COPY("HOME");
    ADD_ENV_COPY("USER");
    ADD_ENV_COPY("LOGNAME");
    ADD_ENV_COPY("TMPDIR");

960
    ADD_ARG_LIT(emulator);
961
    ADD_ARG_LIT("-S");
962 963 964 965 966

    /* This should *never* be NULL, since we always provide
     * a machine in the capabilities data for QEMU. So this
     * check is just here as a safety in case the unexpected
     * happens */
967
    if (def->os.machine) {
968
        ADD_ARG_LIT("-M");
969
        ADD_ARG_LIT(def->os.machine);
970
    }
971 972 973 974
    if (cpu) {
        ADD_ARG_LIT("-cpu");
        ADD_ARG_LIT(cpu);
    }
975

976 977
    if (disableKQEMU)
        ADD_ARG_LIT("-no-kqemu");
978 979
    if (disableKVM)
        ADD_ARG_LIT("-no-kvm");
980 981 982 983
    ADD_ARG_LIT("-m");
    ADD_ARG_LIT(memory);
    ADD_ARG_LIT("-smp");
    ADD_ARG_LIT(vcpus);
D
Daniel P. Berrange 已提交
984

985
    if (qemuCmdFlags & QEMUD_CMD_FLAG_NAME) {
986
        ADD_ARG_LIT("-name");
987
        ADD_ARG_LIT(def->name);
988
    }
989 990 991 992 993 994 995 996 997
    if (qemuCmdFlags & QEMUD_CMD_FLAG_UUID) {
        ADD_ARG_LIT("-uuid");
        ADD_ARG_LIT(uuid);
    }
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DOMID) {
        ADD_ARG_LIT("-domid");
        ADD_ARG_LIT(domid);
    }

998 999 1000 1001 1002 1003 1004
    /*
     * NB, -nographic *MUST* come before any serial, or monitor
     * or parallel port flags due to QEMU craziness, where it
     * decides to change the serial port & monitor to be on stdout
     * if you ask for nographic. So we have to make sure we override
     * these defaults ourselves...
     */
1005
    if (!def->graphics)
1006
        ADD_ARG_LIT("-nographic");
1007

1008 1009
    ADD_ARG_LIT("-monitor");
    ADD_ARG_LIT("pty");
D
Daniel P. Berrange 已提交
1010

1011
    if (def->localtime)
1012
        ADD_ARG_LIT("-localtime");
1013

1014
    if ((qemuCmdFlags & QEMUD_CMD_FLAG_NO_REBOOT) &&
1015
        def->onReboot != VIR_DOMAIN_LIFECYCLE_RESTART)
1016
        ADD_ARG_LIT("-no-reboot");
D
Daniel P. Berrange 已提交
1017

1018
    if (!(def->features & (1 << VIR_DOMAIN_FEATURE_ACPI)))
1019
        ADD_ARG_LIT("-no-acpi");
D
Daniel P. Berrange 已提交
1020

1021 1022 1023
    if (!def->os.bootloader) {
        for (i = 0 ; i < def->os.nBootDevs ; i++) {
            switch (def->os.bootDevs[i]) {
1024
            case VIR_DOMAIN_BOOT_CDROM:
D
Daniel P. Berrange 已提交
1025 1026
                boot[i] = 'd';
                break;
1027
            case VIR_DOMAIN_BOOT_FLOPPY:
D
Daniel P. Berrange 已提交
1028 1029
                boot[i] = 'a';
                break;
1030
            case VIR_DOMAIN_BOOT_DISK:
D
Daniel P. Berrange 已提交
1031 1032
                boot[i] = 'c';
                break;
1033
            case VIR_DOMAIN_BOOT_NET:
D
Daniel P. Berrange 已提交
1034 1035 1036 1037 1038 1039 1040
                boot[i] = 'n';
                break;
            default:
                boot[i] = 'c';
                break;
            }
        }
1041
        boot[def->os.nBootDevs] = '\0';
1042 1043
        ADD_ARG_LIT("-boot");
        ADD_ARG_LIT(boot);
D
Daniel P. Berrange 已提交
1044

1045
        if (def->os.kernel) {
1046
            ADD_ARG_LIT("-kernel");
1047
            ADD_ARG_LIT(def->os.kernel);
D
Daniel P. Berrange 已提交
1048
        }
1049
        if (def->os.initrd) {
1050
            ADD_ARG_LIT("-initrd");
1051
            ADD_ARG_LIT(def->os.initrd);
D
Daniel P. Berrange 已提交
1052
        }
1053
        if (def->os.cmdline) {
1054
            ADD_ARG_LIT("-append");
1055
            ADD_ARG_LIT(def->os.cmdline);
D
Daniel P. Berrange 已提交
1056 1057
        }
    } else {
1058
        ADD_ARG_LIT("-bootloader");
1059
        ADD_ARG_LIT(def->os.bootloader);
D
Daniel P. Berrange 已提交
1060 1061
    }

1062 1063
    for (i = 0 ; i < def->ndisks ; i++) {
        virDomainDiskDefPtr disk = def->disks[i];
1064 1065 1066 1067 1068 1069 1070 1071 1072 1073

        if (disk->driverName != NULL &&
            !STREQ(disk->driverName, "qemu")) {
            qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                             _("unsupported driver name '%s' for disk '%s'"),
                             disk->driverName, disk->src);
            goto error;
        }
    }

1074
    /* If QEMU supports -drive param instead of old -hda, -hdb, -cdrom .. */
1075
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DRIVE) {
1076 1077 1078
        int bootCD = 0, bootFloppy = 0, bootDisk = 0;

        /* If QEMU supports boot=on for -drive param... */
1079
        if (qemuCmdFlags & QEMUD_CMD_FLAG_DRIVE_BOOT) {
1080 1081
            for (i = 0 ; i < def->os.nBootDevs ; i++) {
                switch (def->os.bootDevs[i]) {
1082
                case VIR_DOMAIN_BOOT_CDROM:
1083 1084
                    bootCD = 1;
                    break;
1085
                case VIR_DOMAIN_BOOT_FLOPPY:
1086 1087
                    bootFloppy = 1;
                    break;
1088
                case VIR_DOMAIN_BOOT_DISK:
1089 1090 1091
                    bootDisk = 1;
                    break;
                }
1092
            }
1093
        }
D
Daniel P. Berrange 已提交
1094

1095
        for (i = 0 ; i < def->ndisks ; i++) {
1096 1097
            virBuffer opt = VIR_BUFFER_INITIALIZER;
            char *optstr;
1098
            int bootable = 0;
1099
            virDomainDiskDefPtr disk = def->disks[i];
1100
            int idx = virDiskNameToIndex(disk->dst);
1101
            const char *bus = virDomainDiskQEMUBusTypeToString(disk->bus);
D
Daniel P. Berrange 已提交
1102

1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113
            if (disk->bus == VIR_DOMAIN_DISK_BUS_USB) {
                if (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
                    ADD_USBDISK(disk->src);
                } else {
                    qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                                     _("unsupported usb disk type for '%s'"), disk->src);
                    goto error;
                }
                continue;
            }

1114 1115 1116 1117 1118 1119 1120
            if (idx < 0) {
                qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                                 _("unsupported disk type '%s'"), disk->dst);
                goto error;
            }

            switch (disk->device) {
1121
            case VIR_DOMAIN_DISK_DEVICE_CDROM:
1122 1123 1124
                bootable = bootCD;
                bootCD = 0;
                break;
1125
            case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
1126 1127 1128
                bootable = bootFloppy;
                bootFloppy = 0;
                break;
1129
            case VIR_DOMAIN_DISK_DEVICE_DISK:
1130 1131 1132 1133 1134
                bootable = bootDisk;
                bootDisk = 0;
                break;
            }

1135 1136 1137 1138 1139 1140 1141 1142 1143
            virBufferVSprintf(&opt, "file=%s", disk->src ? disk->src : "");
            virBufferVSprintf(&opt, ",if=%s", bus);
            if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM)
                virBufferAddLit(&opt, ",media=cdrom");
            virBufferVSprintf(&opt, ",index=%d", idx);
            if (bootable &&
                disk->device == VIR_DOMAIN_DISK_DEVICE_DISK)
                virBufferAddLit(&opt, ",boot=on");
            if (disk->driverType)
1144
                virBufferVSprintf(&opt, ",format=%s", disk->driverType);
1145

1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156
            if (disk->cachemode) {
                const char *mode =
                    (qemuCmdFlags & QEMUD_CMD_FLAG_DRIVE_CACHE_V2) ?
                    qemuDiskCacheV2TypeToString(disk->cachemode) :
                    qemuDiskCacheV1TypeToString(disk->cachemode);

                virBufferVSprintf(&opt, ",cache=%s", mode);
            } else if (disk->shared && !disk->readonly) {
                virBufferAddLit(&opt, ",cache=off");
            }

1157 1158 1159 1160 1161 1162
            if (virBufferError(&opt)) {
                virReportOOMError(conn);
                goto error;
            }

            optstr = virBufferContentAndReset(&opt);
1163

1164
            ADD_ARG_LIT("-drive");
1165
            ADD_ARG(optstr);
1166 1167
        }
    } else {
1168
        for (i = 0 ; i < def->ndisks ; i++) {
1169 1170
            char dev[NAME_MAX];
            char file[PATH_MAX];
1171
            virDomainDiskDefPtr disk = def->disks[i];
1172

1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183
            if (disk->bus == VIR_DOMAIN_DISK_BUS_USB) {
                if (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
                    ADD_USBDISK(disk->src);
                } else {
                    qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                                     _("unsupported usb disk type for '%s'"), disk->src);
                    goto error;
                }
                continue;
            }

1184
            if (STREQ(disk->dst, "hdc") &&
1185 1186
                disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
                if (disk->src) {
1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203
                    snprintf(dev, NAME_MAX, "-%s", "cdrom");
                } else {
                    continue;
                }
            } else {
                if (STRPREFIX(disk->dst, "hd") ||
                    STRPREFIX(disk->dst, "fd")) {
                    snprintf(dev, NAME_MAX, "-%s", disk->dst);
                } else {
                    qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                                     _("unsupported disk type '%s'"), disk->dst);
                    goto error;
                }
            }

            snprintf(file, PATH_MAX, "%s", disk->src);

1204 1205
            ADD_ARG_LIT(dev);
            ADD_ARG_LIT(file);
1206
        }
D
Daniel P. Berrange 已提交
1207 1208
    }

1209
    if (!def->nnets) {
1210 1211
        ADD_ARG_LIT("-net");
        ADD_ARG_LIT("none");
D
Daniel P. Berrange 已提交
1212
    } else {
1213
        int vlan = 0;
1214
        for (i = 0 ; i < def->nnets ; i++) {
1215
            char nic[100];
1216
            virDomainNetDefPtr net = def->nets[i];
1217

1218 1219
            if (snprintf(nic, sizeof(nic),
                         "nic,macaddr=%02x:%02x:%02x:%02x:%02x:%02x,vlan=%d%s%s",
1220 1221 1222
                         net->mac[0], net->mac[1],
                         net->mac[2], net->mac[3],
                         net->mac[4], net->mac[5],
1223
                         vlan,
1224 1225
                         (net->model ? ",model=" : ""),
                         (net->model ? net->model : "")) >= sizeof(nic))
1226
                goto error;
D
Daniel P. Berrange 已提交
1227

1228 1229 1230
            ADD_ARG_LIT("-net");
            ADD_ARG_LIT(nic);
            ADD_ARG_LIT("-net");
1231

1232
            switch (net->type) {
1233 1234
            case VIR_DOMAIN_NET_TYPE_NETWORK:
            case VIR_DOMAIN_NET_TYPE_BRIDGE:
1235
                {
1236 1237 1238 1239 1240 1241 1242 1243 1244 1245
                    char *tap;
                    int vnet_hdr = 0;

                    if (qemuCmdFlags & QEMUD_CMD_FLAG_VNET_HDR &&
                        net->model && STREQ(net->model, "virtio"))
                        vnet_hdr = 1;

                    tap = qemudNetworkIfaceConnect(conn, driver,
                                                   tapfds, ntapfds,
                                                   net, vlan, vnet_hdr);
1246 1247 1248 1249 1250
                    if (tap == NULL)
                        goto error;
                    ADD_ARG(tap);
                    break;
                }
1251

1252
            case VIR_DOMAIN_NET_TYPE_ETHERNET:
1253
                {
1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265
                    virBuffer buf = VIR_BUFFER_INITIALIZER;

                    virBufferAddLit(&buf, "tap");
                    if (net->ifname)
                        virBufferVSprintf(&buf, ",ifname=%s", net->ifname);
                    if (net->data.ethernet.script)
                        virBufferVSprintf(&buf, ",script=%s", net->data.ethernet.script);
                    virBufferVSprintf(&buf, ",vlan=%d", vlan);
                    if (virBufferError(&buf))
                        goto error;

                    ADD_ARG(virBufferContentAndReset(&buf));
1266 1267 1268
                }
                break;

1269 1270 1271
            case VIR_DOMAIN_NET_TYPE_CLIENT:
            case VIR_DOMAIN_NET_TYPE_SERVER:
            case VIR_DOMAIN_NET_TYPE_MCAST:
1272 1273 1274 1275
                {
                    char arg[PATH_MAX];
                    const char *mode = NULL;
                    switch (net->type) {
1276
                    case VIR_DOMAIN_NET_TYPE_CLIENT:
1277 1278
                        mode = "connect";
                        break;
1279
                    case VIR_DOMAIN_NET_TYPE_SERVER:
1280 1281
                        mode = "listen";
                        break;
1282
                    case VIR_DOMAIN_NET_TYPE_MCAST:
1283 1284 1285 1286 1287
                        mode = "mcast";
                        break;
                    }
                    if (snprintf(arg, PATH_MAX-1, "socket,%s=%s:%d,vlan=%d",
                                 mode,
1288 1289
                                 net->data.socket.address,
                                 net->data.socket.port,
1290 1291 1292
                                 vlan) >= (PATH_MAX-1))
                        goto error;

1293
                    ADD_ARG_LIT(arg);
1294 1295 1296
                }
                break;

1297
            case VIR_DOMAIN_NET_TYPE_USER:
1298 1299 1300 1301 1302 1303
            default:
                {
                    char arg[PATH_MAX];
                    if (snprintf(arg, PATH_MAX-1, "user,vlan=%d", vlan) >= (PATH_MAX-1))
                        goto error;

1304
                    ADD_ARG_LIT(arg);
1305
                }
1306
            }
D
Daniel P. Berrange 已提交
1307

1308
            vlan++;
D
Daniel P. Berrange 已提交
1309 1310 1311
        }
    }

1312
    if (!def->nserials) {
1313 1314
        ADD_ARG_LIT("-serial");
        ADD_ARG_LIT("none");
1315
    } else {
1316
        for (i = 0 ; i < def->nserials ; i++) {
1317
            char buf[4096];
1318
            virDomainChrDefPtr serial = def->serials[i];
1319 1320 1321 1322

            if (qemudBuildCommandLineChrDevStr(serial, buf, sizeof(buf)) < 0)
                goto error;

1323 1324
            ADD_ARG_LIT("-serial");
            ADD_ARG_LIT(buf);
1325 1326 1327
        }
    }

1328
    if (!def->nparallels) {
1329 1330
        ADD_ARG_LIT("-parallel");
        ADD_ARG_LIT("none");
1331
    } else {
1332
        for (i = 0 ; i < def->nparallels ; i++) {
1333
            char buf[4096];
1334
            virDomainChrDefPtr parallel = def->parallels[i];
1335 1336 1337 1338

            if (qemudBuildCommandLineChrDevStr(parallel, buf, sizeof(buf)) < 0)
                goto error;

1339 1340
            ADD_ARG_LIT("-parallel");
            ADD_ARG_LIT(buf);
1341 1342 1343
        }
    }

1344
    ADD_ARG_LIT("-usb");
1345 1346
    for (i = 0 ; i < def->ninputs ; i++) {
        virDomainInputDefPtr input = def->inputs[i];
1347

1348
        if (input->bus == VIR_DOMAIN_INPUT_BUS_USB) {
1349
            ADD_ARG_LIT("-usbdevice");
1350
            ADD_ARG_LIT(input->type == VIR_DOMAIN_INPUT_TYPE_MOUSE ? "mouse" : "tablet");
1351 1352 1353
        }
    }

1354 1355
    if ((def->ngraphics == 1) &&
        def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
1356 1357
        virBuffer opt = VIR_BUFFER_INITIALIZER;
        char *optstr;
D
Daniel P. Berrange 已提交
1358

1359
        if (qemuCmdFlags & QEMUD_CMD_FLAG_VNC_COLON) {
1360 1361
            if (def->graphics[0]->data.vnc.listenAddr)
                virBufferAdd(&opt, def->graphics[0]->data.vnc.listenAddr, -1);
1362 1363 1364 1365
            else if (driver->vncListen)
                virBufferAdd(&opt, driver->vncListen, -1);

            virBufferVSprintf(&opt, ":%d",
1366
                              def->graphics[0]->data.vnc.port - 5900);
1367

1368
            if (def->graphics[0]->data.vnc.passwd ||
1369 1370 1371
                driver->vncPassword)
                virBufferAddLit(&opt, ",password");

D
Daniel P. Berrange 已提交
1372
            if (driver->vncTLS) {
1373
                virBufferAddLit(&opt, ",tls");
D
Daniel P. Berrange 已提交
1374
                if (driver->vncTLSx509verify) {
1375 1376
                    virBufferVSprintf(&opt, ",x509verify=%s",
                                      driver->vncTLSx509certdir);
D
Daniel P. Berrange 已提交
1377
                } else {
1378 1379
                    virBufferVSprintf(&opt, ",x509=%s",
                                      driver->vncTLSx509certdir);
D
Daniel P. Berrange 已提交
1380 1381
                }
            }
1382 1383 1384 1385 1386 1387 1388 1389 1390

            if (driver->vncSASL) {
                virBufferAddLit(&opt, ",sasl");

                if (driver->vncSASLdir)
                    ADD_ENV_PAIR("SASL_CONF_DIR", driver->vncSASLdir);

                /* TODO: Support ACLs later */
            }
D
Daniel P. Berrange 已提交
1391
        } else {
1392
            virBufferVSprintf(&opt, "%d",
1393
                              def->graphics[0]->data.vnc.port - 5900);
D
Daniel P. Berrange 已提交
1394
        }
1395 1396 1397 1398
        if (virBufferError(&opt))
            goto no_memory;

        optstr = virBufferContentAndReset(&opt);
1399

1400
        ADD_ARG_LIT("-vnc");
1401
        ADD_ARG(optstr);
1402
        if (def->graphics[0]->data.vnc.keymap) {
1403
            ADD_ARG_LIT("-k");
1404
            ADD_ARG_LIT(def->graphics[0]->data.vnc.keymap);
1405
        }
1406 1407
    } else if ((def->ngraphics == 1) &&
               def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) {
1408 1409 1410
        char *xauth = NULL;
        char *display = NULL;

1411
        if (def->graphics[0]->data.sdl.xauth &&
1412
            virAsprintf(&xauth, "XAUTHORITY=%s",
1413
                        def->graphics[0]->data.sdl.xauth) < 0)
1414
            goto no_memory;
1415
        if (def->graphics[0]->data.sdl.display &&
1416
            virAsprintf(&display, "DISPLAY=%s",
1417
                        def->graphics[0]->data.sdl.display) < 0) {
1418 1419 1420 1421 1422 1423 1424 1425
            VIR_FREE(xauth);
            goto no_memory;
        }

        if (xauth)
            ADD_ENV(xauth);
        if (display)
            ADD_ENV(display);
1426
        if (def->graphics[0]->data.sdl.fullscreen)
1427
            ADD_ARG_LIT("-full-screen");
D
Daniel P. Berrange 已提交
1428 1429
    }

D
Daniel Veillard 已提交
1430
    /* Add sound hardware */
1431
    if (def->nsounds) {
D
Daniel Veillard 已提交
1432
        int size = 100;
1433 1434
        char *modstr;
        if (VIR_ALLOC_N(modstr, size+1) < 0)
D
Daniel Veillard 已提交
1435 1436
            goto no_memory;

1437 1438
        for (i = 0 ; i < def->nsounds && size > 0 ; i++) {
            virDomainSoundDefPtr sound = def->sounds[i];
1439
            const char *model = virDomainSoundModelTypeToString(sound->model);
D
Daniel Veillard 已提交
1440
            if (!model) {
1441
                VIR_FREE(modstr);
1442 1443 1444
                qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                                 "%s", _("invalid sound model"));
                goto error;
D
Daniel Veillard 已提交
1445 1446 1447
            }
            strncat(modstr, model, size);
            size -= strlen(model);
1448
            if (i < (def->nsounds - 1))
D
Daniel Veillard 已提交
1449 1450
               strncat(modstr, ",", size--);
        }
1451 1452
        ADD_ARG_LIT("-soundhw");
        ADD_ARG(modstr);
D
Daniel Veillard 已提交
1453 1454
    }

1455
    /* Add host passthrough hardware */
1456
    for (i = 0 ; i < def->nhostdevs ; i++) {
1457 1458
        int ret;
        char* usbdev;
1459
        char* pcidev;
1460
        virDomainHostdevDefPtr hostdev = def->hostdevs[i];
1461

1462
        /* USB */
1463 1464
        if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
            hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {
1465
            if(hostdev->source.subsys.u.usb.vendor) {
1466
                    ret = virAsprintf(&usbdev, "host:%.4x:%.4x",
1467 1468
                               hostdev->source.subsys.u.usb.vendor,
                               hostdev->source.subsys.u.usb.product);
1469 1470

            } else {
1471
                    ret = virAsprintf(&usbdev, "host:%.3d.%.3d",
1472 1473
                               hostdev->source.subsys.u.usb.bus,
                               hostdev->source.subsys.u.usb.device);
1474
            }
1475
            if (ret < 0)
1476
                goto error;
1477

1478 1479 1480 1481
            ADD_ARG_LIT("-usbdevice");
            ADD_ARG_LIT(usbdev);
            VIR_FREE(usbdev);
        }
1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497

        /* PCI */
        if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
            hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) {
            ret = virAsprintf(&pcidev, "host=%.2x:%.2x.%.1x",
                           hostdev->source.subsys.u.pci.bus,
                           hostdev->source.subsys.u.pci.slot,
                           hostdev->source.subsys.u.pci.function);
            if (ret < 0) {
                pcidev = NULL;
                goto error;
            }
            ADD_ARG_LIT("-pcidevice");
            ADD_ARG_LIT(pcidev);
            VIR_FREE(pcidev);
        }
1498 1499
    }

1500
    if (migrateFrom) {
1501
        ADD_ARG_LIT("-incoming");
1502
        ADD_ARG_LIT(migrateFrom);
1503 1504
    }

1505
    ADD_ARG(NULL);
1506
    ADD_ENV(NULL);
D
Daniel P. Berrange 已提交
1507

1508
    *retargv = qargv;
1509
    *retenv = qenv;
D
Daniel P. Berrange 已提交
1510 1511 1512
    return 0;

 no_memory:
1513
    virReportOOMError(conn);
1514
 error:
1515 1516
    if (tapfds &&
        *tapfds) {
1517
        for (i = 0; i < *ntapfds; i++)
1518 1519 1520
            close((*tapfds)[i]);
        VIR_FREE(*tapfds);
        *ntapfds = 0;
1521
    }
1522 1523
    if (qargv) {
        for (i = 0 ; i < qargc ; i++)
1524 1525
            VIR_FREE((qargv)[i]);
        VIR_FREE(qargv);
D
Daniel P. Berrange 已提交
1526
    }
1527 1528 1529 1530 1531
    if (qenv) {
        for (i = 0 ; i < qenvc ; i++)
            VIR_FREE((qenv)[i]);
        VIR_FREE(qenv);
    }
D
Daniel P. Berrange 已提交
1532
    return -1;
1533 1534 1535 1536

#undef ADD_ARG
#undef ADD_ARG_LIT
#undef ADD_ARG_SPACE
1537 1538 1539 1540 1541
#undef ADD_USBDISK
#undef ADD_ENV
#undef ADD_ENV_COPY
#undef ADD_ENV_LIT
#undef ADD_ENV_SPACE
D
Daniel P. Berrange 已提交
1542
}
1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586


/* Called from SAX on parsing errors in the XML. */
static void
catchXMLError (void *ctx, const char *msg ATTRIBUTE_UNUSED, ...)
{
    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;

    if (ctxt) {
        virConnectPtr conn = ctxt->_private;

        if (ctxt->lastError.level == XML_ERR_FATAL &&
            ctxt->lastError.message != NULL) {
            qemudReportError (conn, NULL, NULL, VIR_ERR_XML_DETAIL,
                                  _("at line %d: %s"),
                                  ctxt->lastError.line,
                                  ctxt->lastError.message);
        }
    }
}


/**
 * qemudDomainStatusParseFile
 *
 * read the last known status of a domain
 *
 * Returns 0 on success
 */
qemudDomainStatusPtr
qemudDomainStatusParseFile(virConnectPtr conn,
                           virCapsPtr caps,
                           const char *filename, int flags)
{
    xmlParserCtxtPtr pctxt = NULL;
    xmlXPathContextPtr ctxt = NULL;
    xmlDocPtr xml = NULL;
    xmlNodePtr root, config_root;
    virDomainDefPtr def = NULL;
    char *tmp = NULL;
    long val;
    qemudDomainStatusPtr status = NULL;

    if (VIR_ALLOC(status) < 0) {
1587
        virReportOOMError(conn);
1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616
        goto error;
    }

    /* Set up a parser context so we can catch the details of XML errors. */
    pctxt = xmlNewParserCtxt ();
    if (!pctxt || !pctxt->sax)
        goto error;
    pctxt->sax->error = catchXMLError;
    pctxt->_private = conn;

    if (conn) virResetError (&conn->err);
    xml = xmlCtxtReadFile (pctxt, filename, NULL,
                           XML_PARSE_NOENT | XML_PARSE_NONET |
                           XML_PARSE_NOWARNING);
    if (!xml) {
        if (conn && conn->err.code == VIR_ERR_NONE)
              qemudReportError(conn, NULL, NULL, VIR_ERR_XML_ERROR,
                                   "%s", _("failed to parse xml document"));
        goto error;
    }

    if ((root = xmlDocGetRootElement(xml)) == NULL) {
        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                              "%s", _("missing root element"));
        goto error;
    }

    ctxt = xmlXPathNewContext(xml);
    if (ctxt == NULL) {
1617
        virReportOOMError(conn);
1618 1619 1620 1621 1622 1623 1624 1625 1626 1627
        goto error;
    }

    if (!xmlStrEqual(root->name, BAD_CAST "domstatus")) {
        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                             "%s", _("incorrect root element"));
        goto error;
    }

    ctxt->node = root;
1628
    if(!(tmp = virXPathString(conn, "string(./@state)", ctxt))) {
1629 1630 1631
        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                             "%s", _("invalid domain state"));
        goto error;
1632 1633 1634 1635
    } else {
        status->state = virDomainStateTypeFromString(tmp);
        VIR_FREE(tmp);
    }
1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687

    if((virXPathLong(conn, "string(./@pid)", ctxt, &val)) < 0) {
        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                             "%s", _("invalid pid"));
        goto error;
    } else
        status->pid = (pid_t)val;

    if(!(tmp = virXPathString(conn, "string(./monitor[1]/@path)", ctxt))) {
        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                             "%s", _("no monitor path"));
        goto error;
    } else
        status->monitorpath = tmp;

    if(!(config_root = virXPathNode(conn, "./domain", ctxt))) {
        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                             "%s", _("no domain config"));
        goto error;
    }
    if(!(def = virDomainDefParseNode(conn, caps, xml, config_root, flags)))
        goto error;
    else
        status->def = def;

cleanup:
    xmlFreeParserCtxt (pctxt);
    xmlXPathFreeContext(ctxt);
    xmlFreeDoc (xml);
    return status;

error:
    VIR_FREE(tmp);
    VIR_FREE(status);
    goto cleanup;
}


/**
 * qemudDomainStatusFormat
 *
 * Get the state of a running domain as XML
 *
 * Returns xml on success
 */
static char*
qemudDomainStatusFormat(virConnectPtr conn,
                        virDomainObjPtr vm)
{
    char *config_xml = NULL, *xml = NULL;
    virBuffer buf = VIR_BUFFER_INITIALIZER;

1688 1689 1690
    virBufferVSprintf(&buf, "<domstatus state='%s' pid='%d'>\n",
                      virDomainStateTypeToString(vm->state),
                      vm->pid);
1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733
    virBufferEscapeString(&buf, "  <monitor path='%s'/>\n", vm->monitorpath);

    if (!(config_xml = virDomainDefFormat(conn,
                                          vm->def,
                                          VIR_DOMAIN_XML_SECURE)))
        goto cleanup;

    virBufferAdd(&buf, config_xml, strlen(config_xml));
    virBufferAddLit(&buf, "</domstatus>\n");

    xml = virBufferContentAndReset(&buf);
cleanup:
    VIR_FREE(config_xml);
    return xml;
}


/**
 * qemudSaveDomainStatus
 *
 * Save the current status of a running domain
 *
 * Returns 0 on success
 */
int
qemudSaveDomainStatus(virConnectPtr conn,
                      struct qemud_driver *driver,
                      virDomainObjPtr vm)
{
    int ret = -1;
    char *xml = NULL;

    if (!(xml = qemudDomainStatusFormat(conn, vm)))
        goto cleanup;

    if ((ret = virDomainSaveXML(conn, driver->stateDir, vm->def, xml)))
        goto cleanup;

    ret = 0;
cleanup:
    VIR_FREE(xml);
    return ret;
}