qemu_conf.c 55.1 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 = (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 373 374 375
    /* Really, this never fails - look at the man-page. */
    uname (&utsname);

    if ((caps = virCapabilitiesNew(utsname.machine,
                                   0, 0)) == NULL)
        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
    /* First the pure HVM guests */
J
Jim Meyering 已提交
383
    for (i = 0 ; i < ARRAY_CARDINALITY(arch_info_hvm) ; i++)
384 385 386 387 388
        if (qemudCapsInitGuest(caps,
                               utsname.machine,
                               &arch_info_hvm[i], 1) < 0)
            goto no_memory;

389
    /* Then possibly the Xen paravirt guests (ie Xenner */
390 391
    if (access("/usr/bin/xenner", X_OK) == 0 &&
        access("/dev/kvm", F_OK) == 0) {
J
Jim Meyering 已提交
392
        for (i = 0 ; i < ARRAY_CARDINALITY(arch_info_xen) ; i++)
393 394 395 396 397 398 399 400 401
            /* 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 已提交
402 403
    }

404 405 406 407 408
    return caps;

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

411

412 413 414 415 416
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 };
417
    pid_t child;
418
    int newstdout = -1;
419
    int ret = -1, status;
420
    unsigned int major, minor, micro;
421
    unsigned int version, kvm_version;
422 423 424 425 426 427 428 429 430 431
    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;
432

433 434 435 436 437
    char *help = NULL;
    enum { MAX_HELP_OUTPUT_SIZE = 8192 };
    int len = virFileReadLimFD(newstdout, MAX_HELP_OUTPUT_SIZE, &help);
    if (len < 0)
        goto cleanup2;
438

439 440 441 442 443 444
    if (sscanf(help, "QEMU PC emulator version %u.%u.%u (kvm-%u)",
               &major, &minor, &micro, &kvm_version) != 4)
        kvm_version = 0;

    if (!kvm_version && sscanf(help, "QEMU PC emulator version %u.%u.%u",
               &major, &minor, &micro) != 3)
445
        goto cleanup2;
446

447
    version = (major * 1000 * 1000) + (minor * 1000) + micro;
448

449 450
    if (strstr(help, "-no-kqemu"))
        flags |= QEMUD_CMD_FLAG_KQEMU;
451 452
    if (strstr(help, "-no-kvm"))
        flags |= QEMUD_CMD_FLAG_KVM;
453 454 455 456
    if (strstr(help, "-no-reboot"))
        flags |= QEMUD_CMD_FLAG_NO_REBOOT;
    if (strstr(help, "-name"))
        flags |= QEMUD_CMD_FLAG_NAME;
457 458 459 460
    if (strstr(help, "-uuid"))
        flags |= QEMUD_CMD_FLAG_UUID;
    if (strstr(help, "-domid"))
        flags |= QEMUD_CMD_FLAG_DOMID;
461
    if (strstr(help, "-drive")) {
462
        flags |= QEMUD_CMD_FLAG_DRIVE;
463 464 465
        if (strstr(help, "cache=writethrough|writeback|none"))
            flags |= QEMUD_CMD_FLAG_DRIVE_CACHE_V2;
    }
466 467 468 469
    if (strstr(help, "boot=on"))
        flags |= QEMUD_CMD_FLAG_DRIVE_BOOT;
    if (version >= 9000)
        flags |= QEMUD_CMD_FLAG_VNC_COLON;
470 471
    if (kvm_version >= 74)
        flags |= QEMUD_CMD_FLAG_VNET_HDR;
472

473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493
    /*
     * Handling of -incoming arg with varying features
     *  -incoming tcp    (kvm >= 79)
     *  -incoming exec   (kvm >= 80)
     *  -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
     *
     * XXX when next QEMU release after 0.9.1 arrives,
     * we'll need to add MIGRATE_QEMU_TCP/EXEC here too
     */
    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;
    }

494 495 496 497
    if (retversion)
        *retversion = version;
    if (retflags)
        *retflags = flags;
498

499
    ret = 0;
500

501 502
    qemudDebug("Version %d %d %d  Cooked version: %d, with flags ? %d",
               major, minor, micro, version, flags);
503 504
    if (kvm_version)
        qemudDebug("KVM version %d detected", kvm_version);
505

506
cleanup2:
507
    VIR_FREE(help);
508 509
    if (close(newstdout) < 0)
        ret = -1;
510

511 512 513 514 515
rewait:
    if (waitpid(child, &status, 0) != child) {
        if (errno == EINTR)
            goto rewait;

516 517
        VIR_ERROR(_("Unexpected exit status from qemu %d pid %lu"),
                  WEXITSTATUS(status), (unsigned long)child);
518 519 520 521 522 523
        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) {
524
        VIR_WARN(_("Unexpected exit status '%d', qemu probably failed"),
525
                 WEXITSTATUS(status));
526
    }
527 528

    return ret;
529 530
}

531 532 533 534 535 536 537 538 539 540 541 542 543 544
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';
}

545
int qemudExtractVersion(virConnectPtr conn,
546 547
                        struct qemud_driver *driver) {
    const char *binary;
548
    struct stat sb;
549
    struct utsname ut;
550

551
    if (driver->qemuVersion > 0)
552 553
        return 0;

554
    uname_normalize(&ut);
555 556
    if ((binary = virCapabilitiesDefaultGuestEmulator(driver->caps,
                                                      "hvm",
557
                                                      ut.machine,
558 559
                                                      "qemu")) == NULL)
        return -1;
560

561
    if (stat(binary, &sb) < 0) {
562
        char ebuf[1024];
563 564
        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                         _("Cannot find QEMU binary %s: %s"), binary,
565
                         virStrerror(errno, ebuf, sizeof ebuf));
566
        return -1;
567 568
    }

569
    if (qemudExtractVersionInfo(binary, &driver->qemuVersion, NULL) < 0) {
570 571
        return -1;
    }
D
Daniel P. Berrange 已提交
572

573
    return 0;
D
Daniel P. Berrange 已提交
574 575 576
}


577
static char *
578 579
qemudNetworkIfaceConnect(virConnectPtr conn,
                         struct qemud_driver *driver,
580 581 582
                         int **tapfds,
                         int *ntapfds,
                         virDomainNetDefPtr net,
583 584
                         int vlan,
                         int vnet_hdr)
585
{
586
    char *brname;
587 588 589 590 591
    char tapfdstr[4+3+32+7];
    char *retval = NULL;
    int err;
    int tapfd = -1;

592
    if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
593 594 595
        virNetworkPtr network = virNetworkLookupByName(conn,
                                                      net->data.network.name);
        if (!network) {
596
            qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
597
                             _("Network '%s' not found"),
598
                             net->data.network.name);
599
            goto error;
600 601 602 603 604 605
        }
        brname = virNetworkGetBridgeName(network);

        virNetworkFree(network);

        if (brname == NULL) {
606 607
            goto error;
        }
608 609
    } else if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
        brname = net->data.bridge.brname;
610
    } else {
611
        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
612
                         _("Network type %d is not supported"), net->type);
613 614 615
        goto error;
    }

616 617 618 619 620
    if (!net->ifname ||
        STRPREFIX(net->ifname, "vnet") ||
        strchr(net->ifname, '%')) {
        VIR_FREE(net->ifname);
        if (!(net->ifname = strdup("vnet%d"))) {
621
            virReportOOMError(conn);
622 623 624 625
            goto error;
        }
    }

626
    char ebuf[1024];
627
    if (!driver->brctl && (err = brInit(&driver->brctl))) {
628
        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
629
                         _("cannot initialize bridge support: %s"),
630
                         virStrerror(err, ebuf, sizeof ebuf));
631 632 633
        goto error;
    }

634
    if ((err = brAddTap(driver->brctl, brname,
635
                        &net->ifname, vnet_hdr, &tapfd))) {
636 637 638 639 640 641 642 643 644
        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"),
645
                             net->ifname, brname, virStrerror(err, ebuf, sizeof ebuf));
646
        }
647 648 649
        goto error;
    }

650 651
    snprintf(tapfdstr, sizeof(tapfdstr),
             "tap,fd=%d,script=,vlan=%d,ifname=%s",
652
             tapfd, vlan, net->ifname);
653 654 655 656

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

657
    if (VIR_REALLOC_N(*tapfds, (*ntapfds)+1) < 0)
658 659
        goto no_memory;

660
    (*tapfds)[(*ntapfds)++] = tapfd;
661 662 663 664

    return retval;

 no_memory:
665
    virReportOOMError(conn);
666
 error:
667
    VIR_FREE(retval);
668 669 670 671 672
    if (tapfd != -1)
        close(tapfd);
    return NULL;
}

673

674
static int qemudBuildCommandLineChrDevStr(virDomainChrDefPtr dev,
675 676 677
                                          char *buf,
                                          int buflen)
{
678 679
    switch (dev->type) {
    case VIR_DOMAIN_CHR_TYPE_NULL:
680 681 682 683
        strncpy(buf, "null", buflen);
        buf[buflen-1] = '\0';
        break;

684
    case VIR_DOMAIN_CHR_TYPE_VC:
685 686 687 688
        strncpy(buf, "vc", buflen);
        buf[buflen-1] = '\0';
        break;

689
    case VIR_DOMAIN_CHR_TYPE_PTY:
690 691 692 693
        strncpy(buf, "pty", buflen);
        buf[buflen-1] = '\0';
        break;

694
    case VIR_DOMAIN_CHR_TYPE_DEV:
695
        if (snprintf(buf, buflen, "%s",
696
                     dev->data.file.path) >= buflen)
697 698 699
            return -1;
        break;

700
    case VIR_DOMAIN_CHR_TYPE_FILE:
701
        if (snprintf(buf, buflen, "file:%s",
702
                     dev->data.file.path) >= buflen)
703 704 705
            return -1;
        break;

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

712
    case VIR_DOMAIN_CHR_TYPE_STDIO:
713 714 715 716
        strncpy(buf, "stdio", buflen);
        buf[buflen-1] = '\0';
        break;

717
    case VIR_DOMAIN_CHR_TYPE_UDP:
718
        if (snprintf(buf, buflen, "udp:%s:%s@%s:%s",
719 720 721 722
                     dev->data.udp.connectHost,
                     dev->data.udp.connectService,
                     dev->data.udp.bindHost,
                     dev->data.udp.bindService) >= buflen)
723 724 725
            return -1;
        break;

726
    case VIR_DOMAIN_CHR_TYPE_TCP:
727 728 729 730
        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,
731
                         dev->data.tcp.listen ? ",server,nowait" : "") >= buflen)
732 733 734 735 736
                return -1;
        } else {
            if (snprintf(buf, buflen, "tcp:%s:%s%s",
                         dev->data.tcp.host,
                         dev->data.tcp.service,
737
                         dev->data.tcp.listen ? ",server,nowait" : "") >= buflen)
738 739
                return -1;
        }
740 741
        break;

742
    case VIR_DOMAIN_CHR_TYPE_UNIX:
743
        if (snprintf(buf, buflen, "unix:%s%s",
744
                     dev->data.nix.path,
745
                     dev->data.nix.listen ? ",server,nowait" : "") >= buflen)
746 747 748 749 750 751 752
            return -1;
        break;
    }

    return 0;
}

D
Daniel P. Berrange 已提交
753 754 755 756
/*
 * Constructs a argv suitable for launching qemu with config defined
 * for a given virtual machine.
 */
757 758
int qemudBuildCommandLine(virConnectPtr conn,
                          struct qemud_driver *driver,
759
                          virDomainObjPtr vm,
760
                          unsigned int qemuCmdFlags,
761
                          const char ***retargv,
762
                          const char ***retenv,
763 764 765
                          int **tapfds,
                          int *ntapfds,
                          const char *migrateFrom) {
766
    int i;
D
Daniel P. Berrange 已提交
767 768
    char memory[50];
    char vcpus[50];
769
    char boot[VIR_DOMAIN_BOOT_LAST];
770 771
    struct utsname ut;
    int disableKQEMU = 0;
772
    int disableKVM = 0;
773
    int qargc = 0, qarga = 0;
774
    const char **qargv = NULL;
775 776
    int qenvc = 0, qenva = 0;
    const char **qenv = NULL;
777
    const char *emulator;
778 779
    char uuid[VIR_UUID_STRING_BUFLEN];
    char domid[50];
780
    char *pidfile;
781
    const char *cpu = NULL;
D
Daniel P. Berrange 已提交
782

783
    uname_normalize(&ut);
784

785 786
    virUUIDFormat(vm->def->uuid, uuid);

787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813
    /* 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;
            }
        }
    }

814 815 816 817 818 819 820
    emulator = vm->def->emulator;
    if (!emulator)
        emulator = virDomainDefDefaultEmulator(conn, vm->def, driver->caps);
    if (!emulator)
        return -1;


821 822
    /* Need to explicitly disable KQEMU if
     * 1. Arch matches host arch
823
     * 2. Guest domain is 'qemu'
824 825
     * 3. The qemu binary has the -no-kqemu flag
     */
826
    if ((qemuCmdFlags & QEMUD_CMD_FLAG_KQEMU) &&
827
        STREQ(ut.machine, vm->def->os.arch) &&
828
        vm->def->virtType == VIR_DOMAIN_VIRT_QEMU)
829 830
        disableKQEMU = 1;

831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858
    /* 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) &&
        STREQ(ut.machine, vm->def->os.arch) &&
        vm->def->virtType == VIR_DOMAIN_VIRT_QEMU)
        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
     */
    if (STREQ(vm->def->os.arch, "i686") &&
        ((STREQ(ut.machine, "x86_64") &&
          strstr(emulator, "kvm")) ||
         strstr(emulator, "x86_64")))
        cpu = "qemu32";

859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879
#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 已提交
880

881 882 883 884
#define ADD_USBDISK(thisarg)                                            \
    do {                                                                \
        ADD_ARG_LIT("-usbdevice");                                      \
        ADD_ARG_SPACE;                                                  \
885 886
        if ((virAsprintf((char **)&(qargv[qargc++]),                    \
                         "disk:%s", thisarg)) == -1) {                  \
887 888 889 890
            goto no_memory;                                             \
        }                                                               \
    } while (0)

891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912
#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)

913
#define ADD_ENV_PAIR(envname, val)                                      \
914 915 916
    do {                                                                \
        char *envval;                                                   \
        ADD_ENV_SPACE;                                                  \
917 918 919 920 921 922 923 924
        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);                                    \
925
        if (val != NULL) {                                              \
926
            ADD_ENV_PAIR(envname, val);                                 \
927 928 929
        }                                                               \
    } while (0)

930
    snprintf(memory, sizeof(memory), "%lu", vm->def->memory/1024);
931
    snprintf(vcpus, sizeof(vcpus), "%lu", vm->def->vcpus);
932
    snprintf(domid, sizeof(domid), "%d", vm->def->id);
933 934 935
    pidfile = virFilePid(driver->stateDir, vm->def->name);
    if (!pidfile)
        goto error;
D
Daniel P. Berrange 已提交
936

937 938 939 940 941 942 943 944 945 946
    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");

947
    ADD_ARG_LIT(emulator);
948
    ADD_ARG_LIT("-S");
949 950 951 952 953 954 955 956 957

    /* 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 */
    if (vm->def->os.machine) {
        ADD_ARG_LIT("-M");
        ADD_ARG_LIT(vm->def->os.machine);
    }
958 959 960 961
    if (cpu) {
        ADD_ARG_LIT("-cpu");
        ADD_ARG_LIT(cpu);
    }
962

963 964
    if (disableKQEMU)
        ADD_ARG_LIT("-no-kqemu");
965 966
    if (disableKVM)
        ADD_ARG_LIT("-no-kvm");
967 968 969 970
    ADD_ARG_LIT("-m");
    ADD_ARG_LIT(memory);
    ADD_ARG_LIT("-smp");
    ADD_ARG_LIT(vcpus);
D
Daniel P. Berrange 已提交
971

972
    if (qemuCmdFlags & QEMUD_CMD_FLAG_NAME) {
973 974
        ADD_ARG_LIT("-name");
        ADD_ARG_LIT(vm->def->name);
975
    }
976 977 978 979 980 981 982 983 984
    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);
    }

985 986 987 988 989 990 991
    /*
     * 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...
     */
992
    if (!vm->def->graphics)
993
        ADD_ARG_LIT("-nographic");
994

995 996
    ADD_ARG_LIT("-monitor");
    ADD_ARG_LIT("pty");
D
Daniel P. Berrange 已提交
997

998 999 1000
    ADD_ARG_LIT("-pidfile");
    ADD_ARG(pidfile);

1001 1002
    if (vm->def->localtime)
        ADD_ARG_LIT("-localtime");
1003

1004 1005
    if ((qemuCmdFlags & QEMUD_CMD_FLAG_NO_REBOOT) &&
        vm->def->onReboot != VIR_DOMAIN_LIFECYCLE_RESTART)
1006
        ADD_ARG_LIT("-no-reboot");
D
Daniel P. Berrange 已提交
1007

1008
    if (!(vm->def->features & (1 << VIR_DOMAIN_FEATURE_ACPI)))
1009
        ADD_ARG_LIT("-no-acpi");
D
Daniel P. Berrange 已提交
1010

1011
    if (!vm->def->os.bootloader) {
D
Daniel P. Berrange 已提交
1012 1013
        for (i = 0 ; i < vm->def->os.nBootDevs ; i++) {
            switch (vm->def->os.bootDevs[i]) {
1014
            case VIR_DOMAIN_BOOT_CDROM:
D
Daniel P. Berrange 已提交
1015 1016
                boot[i] = 'd';
                break;
1017
            case VIR_DOMAIN_BOOT_FLOPPY:
D
Daniel P. Berrange 已提交
1018 1019
                boot[i] = 'a';
                break;
1020
            case VIR_DOMAIN_BOOT_DISK:
D
Daniel P. Berrange 已提交
1021 1022
                boot[i] = 'c';
                break;
1023
            case VIR_DOMAIN_BOOT_NET:
D
Daniel P. Berrange 已提交
1024 1025 1026 1027 1028 1029 1030 1031
                boot[i] = 'n';
                break;
            default:
                boot[i] = 'c';
                break;
            }
        }
        boot[vm->def->os.nBootDevs] = '\0';
1032 1033
        ADD_ARG_LIT("-boot");
        ADD_ARG_LIT(boot);
D
Daniel P. Berrange 已提交
1034

1035
        if (vm->def->os.kernel) {
1036 1037
            ADD_ARG_LIT("-kernel");
            ADD_ARG_LIT(vm->def->os.kernel);
D
Daniel P. Berrange 已提交
1038
        }
1039
        if (vm->def->os.initrd) {
1040 1041
            ADD_ARG_LIT("-initrd");
            ADD_ARG_LIT(vm->def->os.initrd);
D
Daniel P. Berrange 已提交
1042
        }
1043
        if (vm->def->os.cmdline) {
1044 1045
            ADD_ARG_LIT("-append");
            ADD_ARG_LIT(vm->def->os.cmdline);
D
Daniel P. Berrange 已提交
1046 1047
        }
    } else {
1048 1049
        ADD_ARG_LIT("-bootloader");
        ADD_ARG_LIT(vm->def->os.bootloader);
D
Daniel P. Berrange 已提交
1050 1051
    }

1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063
    for (i = 0 ; i < vm->def->ndisks ; i++) {
        virDomainDiskDefPtr disk = vm->def->disks[i];

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

1064
    /* If QEMU supports -drive param instead of old -hda, -hdb, -cdrom .. */
1065
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DRIVE) {
1066 1067 1068
        int bootCD = 0, bootFloppy = 0, bootDisk = 0;

        /* If QEMU supports boot=on for -drive param... */
1069
        if (qemuCmdFlags & QEMUD_CMD_FLAG_DRIVE_BOOT) {
1070 1071
            for (i = 0 ; i < vm->def->os.nBootDevs ; i++) {
                switch (vm->def->os.bootDevs[i]) {
1072
                case VIR_DOMAIN_BOOT_CDROM:
1073 1074
                    bootCD = 1;
                    break;
1075
                case VIR_DOMAIN_BOOT_FLOPPY:
1076 1077
                    bootFloppy = 1;
                    break;
1078
                case VIR_DOMAIN_BOOT_DISK:
1079 1080 1081
                    bootDisk = 1;
                    break;
                }
1082
            }
1083
        }
D
Daniel P. Berrange 已提交
1084

1085
        for (i = 0 ; i < vm->def->ndisks ; i++) {
1086 1087
            virBuffer opt = VIR_BUFFER_INITIALIZER;
            char *optstr;
1088
            int bootable = 0;
1089
            virDomainDiskDefPtr disk = vm->def->disks[i];
1090
            int idx = virDiskNameToIndex(disk->dst);
1091
            const char *bus = virDomainDiskQEMUBusTypeToString(disk->bus);
D
Daniel P. Berrange 已提交
1092

1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103
            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;
            }

1104 1105 1106 1107 1108 1109 1110
            if (idx < 0) {
                qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                                 _("unsupported disk type '%s'"), disk->dst);
                goto error;
            }

            switch (disk->device) {
1111
            case VIR_DOMAIN_DISK_DEVICE_CDROM:
1112 1113 1114
                bootable = bootCD;
                bootCD = 0;
                break;
1115
            case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
1116 1117 1118
                bootable = bootFloppy;
                bootFloppy = 0;
                break;
1119
            case VIR_DOMAIN_DISK_DEVICE_DISK:
1120 1121 1122 1123 1124
                bootable = bootDisk;
                bootDisk = 0;
                break;
            }

1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135
            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)
                virBufferVSprintf(&opt, ",fmt=%s", disk->driverType);

1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146
            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");
            }

1147 1148 1149 1150 1151 1152
            if (virBufferError(&opt)) {
                virReportOOMError(conn);
                goto error;
            }

            optstr = virBufferContentAndReset(&opt);
1153

1154
            ADD_ARG_LIT("-drive");
1155
            ADD_ARG(optstr);
1156 1157
        }
    } else {
1158
        for (i = 0 ; i < vm->def->ndisks ; i++) {
1159 1160
            char dev[NAME_MAX];
            char file[PATH_MAX];
1161
            virDomainDiskDefPtr disk = vm->def->disks[i];
1162

1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173
            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;
            }

1174
            if (STREQ(disk->dst, "hdc") &&
1175 1176
                disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
                if (disk->src) {
1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193
                    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);

1194 1195
            ADD_ARG_LIT(dev);
            ADD_ARG_LIT(file);
1196
        }
D
Daniel P. Berrange 已提交
1197 1198
    }

1199
    if (!vm->def->nnets) {
1200 1201
        ADD_ARG_LIT("-net");
        ADD_ARG_LIT("none");
D
Daniel P. Berrange 已提交
1202
    } else {
1203
        int vlan = 0;
1204
        for (i = 0 ; i < vm->def->nnets ; i++) {
1205
            char nic[100];
1206
            virDomainNetDefPtr net = vm->def->nets[i];
1207

1208 1209
            if (snprintf(nic, sizeof(nic),
                         "nic,macaddr=%02x:%02x:%02x:%02x:%02x:%02x,vlan=%d%s%s",
1210 1211 1212
                         net->mac[0], net->mac[1],
                         net->mac[2], net->mac[3],
                         net->mac[4], net->mac[5],
1213
                         vlan,
1214 1215
                         (net->model ? ",model=" : ""),
                         (net->model ? net->model : "")) >= sizeof(nic))
1216
                goto error;
D
Daniel P. Berrange 已提交
1217

1218 1219 1220
            ADD_ARG_LIT("-net");
            ADD_ARG_LIT(nic);
            ADD_ARG_LIT("-net");
1221

1222
            switch (net->type) {
1223 1224
            case VIR_DOMAIN_NET_TYPE_NETWORK:
            case VIR_DOMAIN_NET_TYPE_BRIDGE:
1225
                {
1226 1227 1228 1229 1230 1231 1232 1233 1234 1235
                    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);
1236 1237 1238 1239 1240
                    if (tap == NULL)
                        goto error;
                    ADD_ARG(tap);
                    break;
                }
1241

1242
            case VIR_DOMAIN_NET_TYPE_ETHERNET:
1243 1244
                {
                    char arg[PATH_MAX];
1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256
                    if (net->ifname) {
                        if (snprintf(arg, PATH_MAX-1, "tap,ifname=%s,script=%s,vlan=%d",
                                     net->ifname,
                                     net->data.ethernet.script,
                                     vlan) >= (PATH_MAX-1))
                            goto error;
                    } else {
                        if (snprintf(arg, PATH_MAX-1, "tap,script=%s,vlan=%d",
                                     net->data.ethernet.script,
                                     vlan) >= (PATH_MAX-1))
                            goto error;
                    }
1257

1258
                    ADD_ARG_LIT(arg);
1259 1260 1261
                }
                break;

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

1286
                    ADD_ARG_LIT(arg);
1287 1288 1289
                }
                break;

1290
            case VIR_DOMAIN_NET_TYPE_USER:
1291 1292 1293 1294 1295 1296
            default:
                {
                    char arg[PATH_MAX];
                    if (snprintf(arg, PATH_MAX-1, "user,vlan=%d", vlan) >= (PATH_MAX-1))
                        goto error;

1297
                    ADD_ARG_LIT(arg);
1298
                }
1299
            }
D
Daniel P. Berrange 已提交
1300

1301
            vlan++;
D
Daniel P. Berrange 已提交
1302 1303 1304
        }
    }

1305
    if (!vm->def->nserials) {
1306 1307
        ADD_ARG_LIT("-serial");
        ADD_ARG_LIT("none");
1308
    } else {
1309
        for (i = 0 ; i < vm->def->nserials ; i++) {
1310
            char buf[4096];
1311
            virDomainChrDefPtr serial = vm->def->serials[i];
1312 1313 1314 1315

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

1316 1317
            ADD_ARG_LIT("-serial");
            ADD_ARG_LIT(buf);
1318 1319 1320
        }
    }

1321
    if (!vm->def->nparallels) {
1322 1323
        ADD_ARG_LIT("-parallel");
        ADD_ARG_LIT("none");
1324
    } else {
1325
        for (i = 0 ; i < vm->def->nparallels ; i++) {
1326
            char buf[4096];
1327
            virDomainChrDefPtr parallel = vm->def->parallels[i];
1328 1329 1330 1331

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

1332 1333
            ADD_ARG_LIT("-parallel");
            ADD_ARG_LIT(buf);
1334 1335 1336
        }
    }

1337
    ADD_ARG_LIT("-usb");
1338 1339 1340
    for (i = 0 ; i < vm->def->ninputs ; i++) {
        virDomainInputDefPtr input = vm->def->inputs[i];

1341
        if (input->bus == VIR_DOMAIN_INPUT_BUS_USB) {
1342
            ADD_ARG_LIT("-usbdevice");
1343
            ADD_ARG_LIT(input->type == VIR_DOMAIN_INPUT_TYPE_MOUSE ? "mouse" : "tablet");
1344 1345 1346
        }
    }

1347 1348
    if (vm->def->graphics &&
        vm->def->graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
1349 1350
        virBuffer opt = VIR_BUFFER_INITIALIZER;
        char *optstr;
D
Daniel P. Berrange 已提交
1351

1352
        if (qemuCmdFlags & QEMUD_CMD_FLAG_VNC_COLON) {
1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364
            if (vm->def->graphics->data.vnc.listenAddr)
                virBufferAdd(&opt, vm->def->graphics->data.vnc.listenAddr, -1);
            else if (driver->vncListen)
                virBufferAdd(&opt, driver->vncListen, -1);

            virBufferVSprintf(&opt, ":%d",
                              vm->def->graphics->data.vnc.port - 5900);

            if (vm->def->graphics->data.vnc.passwd ||
                driver->vncPassword)
                virBufferAddLit(&opt, ",password");

D
Daniel P. Berrange 已提交
1365
            if (driver->vncTLS) {
1366
                virBufferAddLit(&opt, ",tls");
D
Daniel P. Berrange 已提交
1367
                if (driver->vncTLSx509verify) {
1368 1369
                    virBufferVSprintf(&opt, ",x509verify=%s",
                                      driver->vncTLSx509certdir);
D
Daniel P. Berrange 已提交
1370
                } else {
1371 1372
                    virBufferVSprintf(&opt, ",x509=%s",
                                      driver->vncTLSx509certdir);
D
Daniel P. Berrange 已提交
1373 1374
                }
            }
1375 1376 1377 1378 1379 1380 1381 1382 1383

            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 已提交
1384
        } else {
1385 1386
            virBufferVSprintf(&opt, "%d",
                              vm->def->graphics->data.vnc.port - 5900);
D
Daniel P. Berrange 已提交
1387
        }
1388 1389 1390 1391
        if (virBufferError(&opt))
            goto no_memory;

        optstr = virBufferContentAndReset(&opt);
1392

1393
        ADD_ARG_LIT("-vnc");
1394
        ADD_ARG(optstr);
1395
        if (vm->def->graphics->data.vnc.keymap) {
1396
            ADD_ARG_LIT("-k");
1397
            ADD_ARG_LIT(vm->def->graphics->data.vnc.keymap);
1398
        }
1399 1400
    } else if (vm->def->graphics &&
               vm->def->graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) {
1401 1402 1403 1404
        char *xauth = NULL;
        char *display = NULL;

        if (vm->def->graphics->data.sdl.xauth &&
1405 1406
            virAsprintf(&xauth, "XAUTHORITY=%s",
                        vm->def->graphics->data.sdl.xauth) < 0)
1407 1408
            goto no_memory;
        if (vm->def->graphics->data.sdl.display &&
1409 1410
            virAsprintf(&display, "DISPLAY=%s",
                        vm->def->graphics->data.sdl.display) < 0) {
1411 1412 1413 1414 1415 1416 1417 1418
            VIR_FREE(xauth);
            goto no_memory;
        }

        if (xauth)
            ADD_ENV(xauth);
        if (display)
            ADD_ENV(display);
1419 1420
        if (vm->def->graphics->data.sdl.fullscreen)
            ADD_ARG_LIT("-full-screen");
D
Daniel P. Berrange 已提交
1421 1422
    }

D
Daniel Veillard 已提交
1423
    /* Add sound hardware */
1424
    if (vm->def->nsounds) {
D
Daniel Veillard 已提交
1425
        int size = 100;
1426 1427
        char *modstr;
        if (VIR_ALLOC_N(modstr, size+1) < 0)
D
Daniel Veillard 已提交
1428 1429
            goto no_memory;

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

1448
    /* Add host passthrough hardware */
1449
    for (i = 0 ; i < vm->def->nhostdevs ; i++) {
1450 1451
        int ret;
        char* usbdev;
1452
        char* pcidev;
1453
        virDomainHostdevDefPtr hostdev = vm->def->hostdevs[i];
1454

1455
        /* USB */
1456 1457
        if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
            hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {
1458
            if(hostdev->source.subsys.u.usb.vendor) {
1459
                    ret = virAsprintf(&usbdev, "host:%.4x:%.4x",
1460 1461
                               hostdev->source.subsys.u.usb.vendor,
                               hostdev->source.subsys.u.usb.product);
1462 1463

            } else {
1464
                    ret = virAsprintf(&usbdev, "host:%.3d.%.3d",
1465 1466
                               hostdev->source.subsys.u.usb.bus,
                               hostdev->source.subsys.u.usb.device);
1467
            }
1468
            if (ret < 0)
1469
                goto error;
1470

1471 1472 1473 1474
            ADD_ARG_LIT("-usbdevice");
            ADD_ARG_LIT(usbdev);
            VIR_FREE(usbdev);
        }
1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490

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

1493
    if (migrateFrom) {
1494
        ADD_ARG_LIT("-incoming");
1495
        ADD_ARG_LIT(migrateFrom);
1496 1497
    }

1498
    ADD_ARG(NULL);
1499
    ADD_ENV(NULL);
D
Daniel P. Berrange 已提交
1500

1501
    *retargv = qargv;
1502
    *retenv = qenv;
D
Daniel P. Berrange 已提交
1503 1504 1505
    return 0;

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

#undef ADD_ARG
#undef ADD_ARG_LIT
#undef ADD_ARG_SPACE
1530 1531 1532 1533 1534
#undef ADD_USBDISK
#undef ADD_ENV
#undef ADD_ENV_COPY
#undef ADD_ENV_LIT
#undef ADD_ENV_SPACE
D
Daniel P. Berrange 已提交
1535
}
1536 1537 1538 1539 1540 1541 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


/* 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) {
1580
        virReportOOMError(conn);
1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609
        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) {
1610
        virReportOOMError(conn);
1611 1612 1613 1614 1615 1616 1617 1618 1619 1620
        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;
1621
    if(!(tmp = virXPathString(conn, "string(./@state)", ctxt))) {
1622 1623 1624
        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                             "%s", _("invalid domain state"));
        goto error;
1625 1626 1627 1628
    } else {
        status->state = virDomainStateTypeFromString(tmp);
        VIR_FREE(tmp);
    }
1629 1630 1631 1632 1633 1634 1635 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

    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;

1681 1682 1683
    virBufferVSprintf(&buf, "<domstatus state='%s' pid='%d'>\n",
                      virDomainStateTypeToString(vm->state),
                      vm->pid);
1684 1685 1686 1687 1688 1689 1690 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
    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;
}