qemu_conf.c 39.8 KB
Newer Older
D
Daniel P. Berrange 已提交
1 2 3
/*
 * config.c: VM configuration management
 *
4
 * Copyright (C) 2006, 2007, 2008 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 31 32 33
#include <dirent.h>
#include <string.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
34
#include <sys/wait.h>
35
#include <arpa/inet.h>
36
#include <sys/utsname.h>
D
Daniel P. Berrange 已提交
37

38 39 40 41
#if HAVE_NUMACTL
#include <numa.h>
#endif

42
#include "qemu_conf.h"
43
#include "uuid.h"
44
#include "buf.h"
D
Daniel P. Berrange 已提交
45
#include "conf.h"
46
#include "util.h"
47
#include "memory.h"
J
Jim Meyering 已提交
48
#include "verify.h"
49 50 51 52 53 54 55

VIR_ENUM_DECL(virDomainDiskQEMUBus)
VIR_ENUM_IMPL(virDomainDiskQEMUBus, VIR_DOMAIN_DISK_BUS_LAST,
              "ide",
              "floppy",
              "scsi",
              "virtio",
56 57
              "xen",
              "usb")
58

59

60 61
#define qemudLog(level, msg...) fprintf(stderr, msg)

62 63 64 65 66
void qemudReportError(virConnectPtr conn,
                      virDomainPtr dom,
                      virNetworkPtr net,
                      int code, const char *fmt, ...) {
    va_list args;
67
    char errorMessage[1024];
D
Daniel Veillard 已提交
68
    const char *virerr;
69 70 71

    if (fmt) {
        va_start(args, fmt);
72
        vsnprintf(errorMessage, sizeof(errorMessage)-1, fmt, args);
73 74 75 76
        va_end(args);
    } else {
        errorMessage[0] = '\0';
    }
D
Daniel Veillard 已提交
77

78
    virerr = __virErrorMsg(code, (errorMessage[0] ? errorMessage : NULL));
79
    __virRaiseError(conn, dom, net, VIR_FROM_QEMU, code, VIR_ERR_ERROR,
D
Daniel Veillard 已提交
80
                    virerr, errorMessage, NULL, -1, -1, virerr, errorMessage);
81 82
}

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

    /* Setup 2 critical defaults */
89 90 91 92 93
    if (!(driver->vncListen = strdup("127.0.0.1"))) {
        qemudReportError(NULL, NULL, NULL, VIR_ERR_NO_MEMORY,
                         "%s", _("failed to allocate vncListen"));
        return -1;
    }
D
Daniel P. Berrange 已提交
94 95
    if (!(driver->vncTLSx509certdir = strdup(SYSCONF_DIR "/pki/libvirt-vnc"))) {
        qemudReportError(NULL, NULL, NULL, VIR_ERR_NO_MEMORY,
96
                         "%s", _("failed to allocate vncTLSx509certdir"));
D
Daniel P. Berrange 已提交
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 124 125 126 127
        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) {
128
        VIR_FREE(driver->vncTLSx509certdir);
D
Daniel P. Berrange 已提交
129 130
        if (!(driver->vncTLSx509certdir = strdup(p->str))) {
            qemudReportError(NULL, NULL, NULL, VIR_ERR_NO_MEMORY,
131
                             "%s", _("failed to allocate vncTLSx509certdir"));
D
Daniel P. Berrange 已提交
132 133 134 135 136 137 138 139
            virConfFree(conf);
            return -1;
        }
    }

    p = virConfGetValue (conf, "vnc_listen");
    CHECK_TYPE ("vnc_listen", VIR_CONF_STRING);
    if (p && p->str) {
140 141 142 143 144 145
        if (!(driver->vncListen = strdup(p->str))) {
            qemudReportError(NULL, NULL, NULL, VIR_ERR_NO_MEMORY,
                             "%s", _("failed to allocate vncTLSx509certdir"));
            virConfFree(conf);
            return -1;
        }
D
Daniel P. Berrange 已提交
146 147 148 149 150 151
    }

    virConfFree (conf);
    return 0;
}

D
Daniel P. Berrange 已提交
152 153
/* The list of possible machine types for various architectures,
   as supported by QEMU - taken from 'qemu -M ?' for each arch */
154 155
static const char *const arch_info_hvm_x86_machines[] = {
    "pc", "isapc"
D
Daniel P. Berrange 已提交
156
};
157 158
static const char *const arch_info_hvm_mips_machines[] = {
    "mips"
D
Daniel P. Berrange 已提交
159
};
160 161
static const char *const arch_info_hvm_sparc_machines[] = {
    "sun4m"
D
Daniel P. Berrange 已提交
162
};
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
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;
    const struct qemu_feature_flags *flags;
    int nflags;
D
Daniel P. Berrange 已提交
185 186
};

187
/* Feature flags for the architecture info */
J
Jim Meyering 已提交
188
static const struct qemu_feature_flags const arch_info_i686_flags [] = {
189 190
    { "pae",  1, 0 },
    { "nonpae",  1, 0 },
191 192 193 194
    { "acpi", 1, 1 },
    { "apic", 1, 0 },
};

J
Jim Meyering 已提交
195
static const struct qemu_feature_flags const arch_info_x86_64_flags [] = {
196 197 198 199
    { "acpi", 1, 1 },
    { "apic", 1, 0 },
};

D
Daniel P. Berrange 已提交
200
/* The archicture tables for supported QEMU archs */
201 202 203 204 205 206 207 208 209 210 211 212 213
static const struct qemu_arch_info const arch_info_hvm[] = {
    {  "i686", 32, arch_info_hvm_x86_machines, 2,
       "/usr/bin/qemu", arch_info_i686_flags, 4 },
    {  "x86_64", 64, arch_info_hvm_x86_machines, 2,
       "/usr/bin/qemu-system-x86_64", arch_info_x86_64_flags, 2 },
    {  "mips", 32, arch_info_hvm_mips_machines, 1,
       "/usr/bin/qemu-system-mips", NULL, 0 },
    {  "mipsel", 32, arch_info_hvm_mips_machines, 1,
       "/usr/bin/qemu-system-mipsel", NULL, 0 },
    {  "sparc", 32, arch_info_hvm_sparc_machines, 1,
       "/usr/bin/qemu-system-sparc", NULL, 0 },
    {  "ppc", 32, arch_info_hvm_ppc_machines, 3,
       "/usr/bin/qemu-system-ppc", NULL, 0 },
D
Daniel P. Berrange 已提交
214 215
};

216 217 218 219 220 221
static const struct qemu_arch_info const arch_info_xen[] = {
    {  "i686", 32, arch_info_xen_x86_machines, 1,
       "/usr/bin/xenner", arch_info_i686_flags, 4 },
    {  "x86_64", 64, arch_info_xen_x86_machines, 1,
       "/usr/bin/xenner", arch_info_x86_64_flags, 2 },
};
D
Daniel P. Berrange 已提交
222

223 224 225 226 227 228
static int
qemudCapsInitGuest(virCapsPtr caps,
                   const char *hostmachine,
                   const struct qemu_arch_info *info,
                   int hvm) {
    virCapsGuestPtr guest;
D
Daniel P. Berrange 已提交
229 230
    int i;

231 232 233 234 235 236 237 238 239
    if ((guest = virCapabilitiesAddGuest(caps,
                                         hvm ? "hvm" : "xen",
                                         info->arch,
                                         info->wordsize,
                                         info->binary,
                                         NULL,
                                         info->nmachines,
                                         info->machines)) == NULL)
        return -1;
D
Daniel P. Berrange 已提交
240

241 242 243 244 245 246 247 248 249 250
    if (hvm) {
        /* Check for existance of base emulator */
        if (access(info->binary, X_OK) == 0 &&
            virCapabilitiesAddGuestDomain(guest,
                                          "qemu",
                                          NULL,
                                          NULL,
                                          0,
                                          NULL) == NULL)
            return -1;
D
Daniel P. Berrange 已提交
251

252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280
        /* If guest & host match, then we can accelerate */
        if (STREQ(info->arch, hostmachine)) {
            if (access("/dev/kqemu", F_OK) == 0 &&
                virCapabilitiesAddGuestDomain(guest,
                                              "kqemu",
                                              NULL,
                                              NULL,
                                              0,
                                              NULL) == NULL)
                return -1;

            if (access("/dev/kvm", F_OK) == 0 &&
                virCapabilitiesAddGuestDomain(guest,
                                              "kvm",
                                              "/usr/bin/qemu-kvm",
                                              NULL,
                                              0,
                                              NULL) == NULL)
                return -1;
        }
    } else {
        if (virCapabilitiesAddGuestDomain(guest,
                                          "kvm",
                                          NULL,
                                          NULL,
                                          0,
                                          NULL) == NULL)
            return -1;
    }
D
Daniel P. Berrange 已提交
281

282 283 284 285 286 287 288
    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 已提交
289 290 291
        }
    }

292
    return 0;
D
Daniel P. Berrange 已提交
293 294
}

295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353
#if HAVE_NUMACTL
#define MAX_CPUS 4096
#define MAX_CPUS_MASK_SIZE (sizeof(unsigned long))
#define MAX_CPUS_MASK_LEN (MAX_CPUS / MAX_CPUS_MASK_SIZE)
#define MAX_CPUS_MASK_BYTES (MAX_CPUS / 8)

#define MASK_CPU_ISSET(mask, cpu) \
    (((mask)[((cpu) / MAX_CPUS_MASK_SIZE)] >> ((cpu) % MAX_CPUS_MASK_SIZE)) & 1)

static int
qemudCapsInitNUMA(virCapsPtr caps)
{
    int n, i;
    unsigned long *mask = NULL;
    int ncpus;
    int *cpus = NULL;
    int ret = -1;

    if (numa_available() < 0)
        return 0;

    if (VIR_ALLOC_N(mask, MAX_CPUS_MASK_LEN) < 0)
        goto cleanup;

    for (n = 0 ; n <= numa_max_node() ; n++) {
        if (numa_node_to_cpus(n, mask, MAX_CPUS_MASK_BYTES) < 0)
            goto cleanup;

        for (ncpus = 0, i = 0 ; i < MAX_CPUS ; i++)
            if (MASK_CPU_ISSET(mask, i))
                ncpus++;

        if (VIR_ALLOC_N(cpus, ncpus) < 0)
            goto cleanup;

        for (ncpus = 0, i = 0 ; i < MAX_CPUS ; i++)
            if (MASK_CPU_ISSET(mask, i))
                cpus[ncpus++] = i;

        if (virCapabilitiesAddHostNUMACell(caps,
                                           n,
                                           ncpus,
                                           cpus) < 0)
            goto cleanup;

        VIR_FREE(cpus);
    }

    ret = 0;

cleanup:
    VIR_FREE(cpus);
    VIR_FREE(mask);
    return ret;
}
#else
static int qemudCapsInitNUMA(virCapsPtr caps ATTRIBUTE_UNUSED) { return 0; }
#endif

354 355 356 357
virCapsPtr qemudCapsInit(void) {
    struct utsname utsname;
    virCapsPtr caps;
    int i;
D
Daniel P. Berrange 已提交
358

359 360 361 362 363 364 365
    /* Really, this never fails - look at the man-page. */
    uname (&utsname);

    if ((caps = virCapabilitiesNew(utsname.machine,
                                   0, 0)) == NULL)
        goto no_memory;

366 367 368
    if (qemudCapsInitNUMA(caps) < 0)
        goto no_memory;

369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386
    for (i = 0 ; i < (sizeof(arch_info_hvm)/sizeof(arch_info_hvm[0])) ; i++)
        if (qemudCapsInitGuest(caps,
                               utsname.machine,
                               &arch_info_hvm[i], 1) < 0)
            goto no_memory;

    if (access("/usr/bin/xenner", X_OK) == 0 &&
        access("/dev/kvm", F_OK) == 0) {
        for (i = 0 ; i < (sizeof(arch_info_xen)/sizeof(arch_info_xen[0])) ; i++)
            /* 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 已提交
387 388
    }

389 390 391 392 393
    return caps;

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

396

397
int qemudExtractVersionInfo(const char *qemu, int *version, int *flags) {
398 399 400
    pid_t child;
    int newstdout[2];

401 402 403 404
    if (flags)
        *flags = 0;
    if (version)
        *version = 0;
405 406 407 408 409 410 411 412 413 414 415 416

    if (pipe(newstdout) < 0) {
        return -1;
    }

    if ((child = fork()) < 0) {
        close(newstdout[0]);
        close(newstdout[1]);
        return -1;
    }

    if (child == 0) { /* Kid */
417 418 419
        /* Just in case QEMU is translated someday we force to C locale.. */
        const char *const qemuenv[] = { "LANG=C", NULL };

420 421 422 423 424 425 426 427 428
        if (close(STDIN_FILENO) < 0)
            goto cleanup1;
        if (close(STDERR_FILENO) < 0)
            goto cleanup1;
        if (close(newstdout[0]) < 0)
            goto cleanup1;
        if (dup2(newstdout[1], STDOUT_FILENO) < 0)
            goto cleanup1;

429 430 431
        /* Passing -help, rather than relying on no-args which doesn't
           always work */
        execle(qemu, qemu, "-help", (char*)NULL, qemuenv);
432 433 434 435

    cleanup1:
        _exit(-1); /* Just in case */
    } else { /* Parent */
D
Daniel P. Berrange 已提交
436
        char help[8192]; /* Ought to be enough to hold QEMU help screen */
437
        int got = 0, ret = -1;
438
        int major, minor, micro;
439
        int ver;
440 441 442 443

        if (close(newstdout[1]) < 0)
            goto cleanup2;

D
Daniel P. Berrange 已提交
444 445 446 447 448 449 450 451 452 453
        while (got < (sizeof(help)-1)) {
            int len;
            if ((len = read(newstdout[0], help+got, sizeof(help)-got-1)) <= 0) {
                if (!len)
                    break;
                if (errno == EINTR)
                    continue;
                goto cleanup2;
            }
            got += len;
454 455 456 457 458 459 460
        }
        help[got] = '\0';

        if (sscanf(help, "QEMU PC emulator version %d.%d.%d", &major,&minor, &micro) != 3) {
            goto cleanup2;
        }

461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477
        ver = (major * 1000 * 1000) + (minor * 1000) + micro;
        if (version)
            *version = ver;
        if (flags) {
            if (strstr(help, "-no-kqemu"))
                *flags |= QEMUD_CMD_FLAG_KQEMU;
            if (strstr(help, "-no-reboot"))
                *flags |= QEMUD_CMD_FLAG_NO_REBOOT;
            if (strstr(help, "-name"))
                *flags |= QEMUD_CMD_FLAG_NAME;
            if (strstr(help, "-drive"))
                *flags |= QEMUD_CMD_FLAG_DRIVE;
            if (strstr(help, "boot=on"))
                *flags |= QEMUD_CMD_FLAG_DRIVE_BOOT;
            if (ver >= 9000)
                *flags |= QEMUD_CMD_FLAG_VNC_COLON;
        }
478 479 480 481 482 483 484 485 486 487 488 489 490 491
        ret = 0;

        qemudDebug("Version %d %d %d  Cooked version: %d, with flags ? %d",
                   major, minor, micro, *version, *flags);

    cleanup2:
        if (close(newstdout[0]) < 0)
            ret = -1;

    rewait:
        if (waitpid(child, &got, 0) != child) {
            if (errno == EINTR) {
                goto rewait;
            }
492 493 494
            qemudLog(QEMUD_ERR,
                     _("Unexpected exit status from qemu %d pid %lu"),
                     got, (unsigned long)child);
495 496 497 498 499
            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 */
500
        if (WEXITSTATUS(got) != 0) {
501 502 503
            qemudLog(QEMUD_WARN,
                     _("Unexpected exit status '%d', qemu probably failed"),
                     got);
504 505 506 507 508 509
        }

        return ret;
    }
}

510
int qemudExtractVersion(virConnectPtr conn,
511 512
                        struct qemud_driver *driver) {
    const char *binary;
513
    struct stat sb;
514
    int ignored;
515

516
    if (driver->qemuVersion > 0)
517 518
        return 0;

519 520
    if ((binary = virCapabilitiesDefaultGuestEmulator(driver->caps,
                                                      "hvm",
521 522 523
                                                      "i686",
                                                      "qemu")) == NULL)
        return -1;
524

525 526 527 528 529
    if (stat(binary, &sb) < 0) {
        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                         _("Cannot find QEMU binary %s: %s"), binary,
                         strerror(errno));
        return -1;
530 531
    }

532 533 534
    if (qemudExtractVersionInfo(binary, &driver->qemuVersion, &ignored) < 0) {
        return -1;
    }
D
Daniel P. Berrange 已提交
535

536
    return 0;
D
Daniel P. Berrange 已提交
537 538 539
}


540
static char *
541 542
qemudNetworkIfaceConnect(virConnectPtr conn,
                         struct qemud_driver *driver,
543 544 545
                         int **tapfds,
                         int *ntapfds,
                         virDomainNetDefPtr net,
546
                         int vlan)
547
{
548
    virNetworkObjPtr network = NULL;
549
    char *brname;
550 551 552 553 554
    char tapfdstr[4+3+32+7];
    char *retval = NULL;
    int err;
    int tapfd = -1;

555 556
    if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
        if (!(network = virNetworkFindByName(driver->networks, net->data.network.name))) {
557
            qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
558
                             _("Network '%s' not found"),
559
                             net->data.network.name);
560
            goto error;
561
        } else if (network->def->bridge == NULL) {
562
            qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
563
                             _("Network '%s' not active"),
564
                             net->data.network.name);
565 566
            goto error;
        }
567
        brname = network->def->bridge;
568 569
    } else if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
        brname = net->data.bridge.brname;
570
    } else {
571
        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
572
                         _("Network type %d is not supported"), net->type);
573 574 575
        goto error;
    }

576 577 578 579 580 581 582 583 584 585
    if (!net->ifname ||
        STRPREFIX(net->ifname, "vnet") ||
        strchr(net->ifname, '%')) {
        VIR_FREE(net->ifname);
        if (!(net->ifname = strdup("vnet%d"))) {
            qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, NULL);
            goto error;
        }
    }

586
    if (!driver->brctl && (err = brInit(&driver->brctl))) {
587
        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
588 589
                         _("cannot initialize bridge support: %s"),
                         strerror(err));
590 591 592
        goto error;
    }

593
    if ((err = brAddTap(driver->brctl, brname,
594
                        &net->ifname, &tapfd))) {
595 596 597 598 599 600 601 602 603
        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"),
604
                             net->ifname, brname, strerror(err));
605
        }
606 607 608
        goto error;
    }

609 610
    snprintf(tapfdstr, sizeof(tapfdstr),
             "tap,fd=%d,script=,vlan=%d,ifname=%s",
611
             tapfd, vlan, net->ifname);
612 613 614 615

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

616
    if (VIR_REALLOC_N(*tapfds, (*ntapfds)+1) < 0)
617 618
        goto no_memory;

619
    (*tapfds)[(*ntapfds)++] = tapfd;
620 621 622 623

    return retval;

 no_memory:
624 625
    qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY,
                     "%s", _("failed to allocate space for tapfds string"));
626
 error:
627
    VIR_FREE(retval);
628 629 630 631 632
    if (tapfd != -1)
        close(tapfd);
    return NULL;
}

633
static int qemudBuildCommandLineChrDevStr(virDomainChrDefPtr dev,
634 635 636
                                          char *buf,
                                          int buflen)
{
637 638
    switch (dev->type) {
    case VIR_DOMAIN_CHR_TYPE_NULL:
639 640 641 642
        strncpy(buf, "null", buflen);
        buf[buflen-1] = '\0';
        break;

643
    case VIR_DOMAIN_CHR_TYPE_VC:
644 645 646 647
        strncpy(buf, "vc", buflen);
        buf[buflen-1] = '\0';
        break;

648
    case VIR_DOMAIN_CHR_TYPE_PTY:
649 650 651 652
        strncpy(buf, "pty", buflen);
        buf[buflen-1] = '\0';
        break;

653
    case VIR_DOMAIN_CHR_TYPE_DEV:
654
        if (snprintf(buf, buflen, "%s",
655
                     dev->data.file.path) >= buflen)
656 657 658
            return -1;
        break;

659
    case VIR_DOMAIN_CHR_TYPE_FILE:
660
        if (snprintf(buf, buflen, "file:%s",
661
                     dev->data.file.path) >= buflen)
662 663 664
            return -1;
        break;

665
    case VIR_DOMAIN_CHR_TYPE_PIPE:
666
        if (snprintf(buf, buflen, "pipe:%s",
667
                     dev->data.file.path) >= buflen)
668 669 670
            return -1;
        break;

671
    case VIR_DOMAIN_CHR_TYPE_STDIO:
672 673 674 675
        strncpy(buf, "stdio", buflen);
        buf[buflen-1] = '\0';
        break;

676
    case VIR_DOMAIN_CHR_TYPE_UDP:
677
        if (snprintf(buf, buflen, "udp:%s:%s@%s:%s",
678 679 680 681
                     dev->data.udp.connectHost,
                     dev->data.udp.connectService,
                     dev->data.udp.bindHost,
                     dev->data.udp.bindService) >= buflen)
682 683 684
            return -1;
        break;

685
    case VIR_DOMAIN_CHR_TYPE_TCP:
686 687 688 689 690 691 692 693 694 695 696 697 698
        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,
                         dev->data.tcp.listen ? ",server" : "") >= buflen)
                return -1;
        } else {
            if (snprintf(buf, buflen, "tcp:%s:%s%s",
                         dev->data.tcp.host,
                         dev->data.tcp.service,
                         dev->data.tcp.listen ? ",listen" : "") >= buflen)
                return -1;
        }
699 700
        break;

701
    case VIR_DOMAIN_CHR_TYPE_UNIX:
702
        if (snprintf(buf, buflen, "unix:%s%s",
703 704
                     dev->data.nix.path,
                     dev->data.nix.listen ? ",listen" : "") >= buflen)
705 706 707 708 709 710 711
            return -1;
        break;
    }

    return 0;
}

D
Daniel P. Berrange 已提交
712 713 714 715
/*
 * Constructs a argv suitable for launching qemu with config defined
 * for a given virtual machine.
 */
716 717
int qemudBuildCommandLine(virConnectPtr conn,
                          struct qemud_driver *driver,
718 719
                          virDomainObjPtr vm,
                          int qemuCmdFlags,
720
                          const char ***retargv,
721 722 723
                          int **tapfds,
                          int *ntapfds,
                          const char *migrateFrom) {
724
    int i;
D
Daniel P. Berrange 已提交
725 726
    char memory[50];
    char vcpus[50];
727 728 729 730 731
    char boot[VIR_DOMAIN_BOOT_LAST];
    virDomainDiskDefPtr disk = vm->def->disks;
    virDomainNetDefPtr net = vm->def->nets;
    virDomainInputDefPtr input = vm->def->inputs;
    virDomainSoundDefPtr sound = vm->def->sounds;
732
    virDomainHostdevDefPtr hostdev = vm->def->hostdevs;
733 734
    virDomainChrDefPtr serial = vm->def->serials;
    virDomainChrDefPtr parallel = vm->def->parallels;
735 736
    struct utsname ut;
    int disableKQEMU = 0;
737
    int qargc = 0, qarga = 0;
738
    const char **qargv = NULL;
D
Daniel P. Berrange 已提交
739

740 741
    uname(&ut);

D
Daniel P. Berrange 已提交
742
    /* Nasty hack make i?86 look like i686 to simplify next comparison */
743 744 745 746
    if (ut.machine[0] == 'i' &&
        ut.machine[2] == '8' &&
        ut.machine[3] == '6' &&
        !ut.machine[4])
D
Daniel P. Berrange 已提交
747
        ut.machine[1] = '6';
748 749 750 751 752 753

    /* Need to explicitly disable KQEMU if
     * 1. Arch matches host arch
     * 2. Guest is 'qemu'
     * 3. The qemu binary has the -no-kqemu flag
     */
754
    if ((qemuCmdFlags & QEMUD_CMD_FLAG_KQEMU) &&
755
        STREQ(ut.machine, vm->def->os.arch) &&
756
        vm->def->virtType == VIR_DOMAIN_VIRT_QEMU)
757 758
        disableKQEMU = 1;

759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779
#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 已提交
780

781 782 783 784
#define ADD_USBDISK(thisarg)                                            \
    do {                                                                \
        ADD_ARG_LIT("-usbdevice");                                      \
        ADD_ARG_SPACE;                                                  \
785
        if ((asprintf((char **)&(qargv[qargc++]), "disk:%s", thisarg)) == -1) {    \
786 787 788 789 790
            qargv[qargc-1] = NULL;                                      \
            goto no_memory;                                             \
        }                                                               \
    } while (0)

791
    snprintf(memory, sizeof(memory), "%lu", vm->def->memory/1024);
792
    snprintf(vcpus, sizeof(vcpus), "%lu", vm->def->vcpus);
D
Daniel P. Berrange 已提交
793

794

795
    ADD_ARG_LIT(vm->def->emulator);
796 797 798 799 800 801 802 803 804
    ADD_ARG_LIT("-S");
    ADD_ARG_LIT("-M");
    ADD_ARG_LIT(vm->def->os.machine);
    if (disableKQEMU)
        ADD_ARG_LIT("-no-kqemu");
    ADD_ARG_LIT("-m");
    ADD_ARG_LIT(memory);
    ADD_ARG_LIT("-smp");
    ADD_ARG_LIT(vcpus);
D
Daniel P. Berrange 已提交
805

806
    if (qemuCmdFlags & QEMUD_CMD_FLAG_NAME) {
807 808
        ADD_ARG_LIT("-name");
        ADD_ARG_LIT(vm->def->name);
809
    }
810 811 812 813 814 815 816
    /*
     * 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...
     */
817
    if (!vm->def->graphics)
818
        ADD_ARG_LIT("-nographic");
819

820 821
    ADD_ARG_LIT("-monitor");
    ADD_ARG_LIT("pty");
D
Daniel P. Berrange 已提交
822

823 824
    if (vm->def->localtime)
        ADD_ARG_LIT("-localtime");
825

826 827
    if ((qemuCmdFlags & QEMUD_CMD_FLAG_NO_REBOOT) &&
        vm->def->onReboot != VIR_DOMAIN_LIFECYCLE_RESTART)
828
        ADD_ARG_LIT("-no-reboot");
D
Daniel P. Berrange 已提交
829

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

833
    if (!vm->def->os.bootloader) {
D
Daniel P. Berrange 已提交
834 835
        for (i = 0 ; i < vm->def->os.nBootDevs ; i++) {
            switch (vm->def->os.bootDevs[i]) {
836
            case VIR_DOMAIN_BOOT_CDROM:
D
Daniel P. Berrange 已提交
837 838
                boot[i] = 'd';
                break;
839
            case VIR_DOMAIN_BOOT_FLOPPY:
D
Daniel P. Berrange 已提交
840 841
                boot[i] = 'a';
                break;
842
            case VIR_DOMAIN_BOOT_DISK:
D
Daniel P. Berrange 已提交
843 844
                boot[i] = 'c';
                break;
845
            case VIR_DOMAIN_BOOT_NET:
D
Daniel P. Berrange 已提交
846 847 848 849 850 851 852 853
                boot[i] = 'n';
                break;
            default:
                boot[i] = 'c';
                break;
            }
        }
        boot[vm->def->os.nBootDevs] = '\0';
854 855
        ADD_ARG_LIT("-boot");
        ADD_ARG_LIT(boot);
D
Daniel P. Berrange 已提交
856

857
        if (vm->def->os.kernel) {
858 859
            ADD_ARG_LIT("-kernel");
            ADD_ARG_LIT(vm->def->os.kernel);
D
Daniel P. Berrange 已提交
860
        }
861
        if (vm->def->os.initrd) {
862 863
            ADD_ARG_LIT("-initrd");
            ADD_ARG_LIT(vm->def->os.initrd);
D
Daniel P. Berrange 已提交
864
        }
865
        if (vm->def->os.cmdline) {
866 867
            ADD_ARG_LIT("-append");
            ADD_ARG_LIT(vm->def->os.cmdline);
D
Daniel P. Berrange 已提交
868 869
        }
    } else {
870 871
        ADD_ARG_LIT("-bootloader");
        ADD_ARG_LIT(vm->def->os.bootloader);
D
Daniel P. Berrange 已提交
872 873
    }

874
    /* If QEMU supports -drive param instead of old -hda, -hdb, -cdrom .. */
875
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DRIVE) {
876 877 878
        int bootCD = 0, bootFloppy = 0, bootDisk = 0;

        /* If QEMU supports boot=on for -drive param... */
879
        if (qemuCmdFlags & QEMUD_CMD_FLAG_DRIVE_BOOT) {
880 881
            for (i = 0 ; i < vm->def->os.nBootDevs ; i++) {
                switch (vm->def->os.bootDevs[i]) {
882
                case VIR_DOMAIN_BOOT_CDROM:
883 884
                    bootCD = 1;
                    break;
885
                case VIR_DOMAIN_BOOT_FLOPPY:
886 887
                    bootFloppy = 1;
                    break;
888
                case VIR_DOMAIN_BOOT_DISK:
889 890 891
                    bootDisk = 1;
                    break;
                }
892
            }
893
        }
D
Daniel P. Berrange 已提交
894

895 896 897 898 899
        while (disk) {
            char opt[PATH_MAX];
            const char *media = NULL;
            int bootable = 0;
            int idx = virDiskNameToIndex(disk->dst);
900
            const char *bus = virDomainDiskQEMUBusTypeToString(disk->bus);
D
Daniel P. Berrange 已提交
901

902 903 904 905 906 907 908 909 910 911 912 913
            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;
                }
                disk = disk->next;
                continue;
            }

914 915 916 917 918 919 920
            if (idx < 0) {
                qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                                 _("unsupported disk type '%s'"), disk->dst);
                goto error;
            }

            switch (disk->device) {
921
            case VIR_DOMAIN_DISK_DEVICE_CDROM:
922 923
                bootable = bootCD;
                bootCD = 0;
924
                media = "media=cdrom,";
925
                break;
926
            case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
927 928 929
                bootable = bootFloppy;
                bootFloppy = 0;
                break;
930
            case VIR_DOMAIN_DISK_DEVICE_DISK:
931 932 933 934 935 936
                bootable = bootDisk;
                bootDisk = 0;
                break;
            }

            snprintf(opt, PATH_MAX, "file=%s,if=%s,%sindex=%d%s",
937
                     disk->src ? disk->src : "", bus,
938 939
                     media ? media : "",
                     idx,
940 941
                     bootable &&
                     disk->device == VIR_DOMAIN_DISK_DEVICE_DISK
942
                     ? ",boot=on" : "");
943

944 945
            ADD_ARG_LIT("-drive");
            ADD_ARG_LIT(opt);
946 947 948 949 950 951 952
            disk = disk->next;
        }
    } else {
        while (disk) {
            char dev[NAME_MAX];
            char file[PATH_MAX];

953 954 955 956 957 958 959 960 961 962 963 964
            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;
                }
                disk = disk->next;
                continue;
            }

965
            if (STREQ(disk->dst, "hdc") &&
966 967
                disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
                if (disk->src) {
968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985
                    snprintf(dev, NAME_MAX, "-%s", "cdrom");
                } else {
                    disk = disk->next;
                    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);

986 987
            ADD_ARG_LIT(dev);
            ADD_ARG_LIT(file);
988 989 990

            disk = disk->next;
        }
D
Daniel P. Berrange 已提交
991 992 993
    }

    if (!net) {
994 995
        ADD_ARG_LIT("-net");
        ADD_ARG_LIT("none");
D
Daniel P. Berrange 已提交
996
    } else {
997
        int vlan = 0;
D
Daniel P. Berrange 已提交
998
        while (net) {
999
            char nic[100];
1000

1001 1002
            if (snprintf(nic, sizeof(nic),
                         "nic,macaddr=%02x:%02x:%02x:%02x:%02x:%02x,vlan=%d%s%s",
1003 1004 1005
                         net->mac[0], net->mac[1],
                         net->mac[2], net->mac[3],
                         net->mac[4], net->mac[5],
1006
                         vlan,
1007 1008
                         (net->model ? ",model=" : ""),
                         (net->model ? net->model : "")) >= sizeof(nic))
1009
                goto error;
D
Daniel P. Berrange 已提交
1010

1011 1012 1013
            ADD_ARG_LIT("-net");
            ADD_ARG_LIT(nic);
            ADD_ARG_LIT("-net");
1014

1015
            switch (net->type) {
1016 1017
            case VIR_DOMAIN_NET_TYPE_NETWORK:
            case VIR_DOMAIN_NET_TYPE_BRIDGE:
1018
                {
1019 1020 1021
                    char *tap = qemudNetworkIfaceConnect(conn, driver,
                                                         tapfds, ntapfds,
                                                         net, vlan);
1022 1023 1024 1025 1026
                    if (tap == NULL)
                        goto error;
                    ADD_ARG(tap);
                    break;
                }
1027

1028
            case VIR_DOMAIN_NET_TYPE_ETHERNET:
1029 1030 1031
                {
                    char arg[PATH_MAX];
                    if (snprintf(arg, PATH_MAX-1, "tap,ifname=%s,script=%s,vlan=%d",
1032 1033
                                 net->ifname,
                                 net->data.ethernet.script,
1034 1035 1036
                                 vlan) >= (PATH_MAX-1))
                        goto error;

1037
                    ADD_ARG_LIT(arg);
1038 1039 1040
                }
                break;

1041 1042 1043
            case VIR_DOMAIN_NET_TYPE_CLIENT:
            case VIR_DOMAIN_NET_TYPE_SERVER:
            case VIR_DOMAIN_NET_TYPE_MCAST:
1044 1045 1046 1047
                {
                    char arg[PATH_MAX];
                    const char *mode = NULL;
                    switch (net->type) {
1048
                    case VIR_DOMAIN_NET_TYPE_CLIENT:
1049 1050
                        mode = "connect";
                        break;
1051
                    case VIR_DOMAIN_NET_TYPE_SERVER:
1052 1053
                        mode = "listen";
                        break;
1054
                    case VIR_DOMAIN_NET_TYPE_MCAST:
1055 1056 1057 1058 1059
                        mode = "mcast";
                        break;
                    }
                    if (snprintf(arg, PATH_MAX-1, "socket,%s=%s:%d,vlan=%d",
                                 mode,
1060 1061
                                 net->data.socket.address,
                                 net->data.socket.port,
1062 1063 1064
                                 vlan) >= (PATH_MAX-1))
                        goto error;

1065
                    ADD_ARG_LIT(arg);
1066 1067 1068
                }
                break;

1069
            case VIR_DOMAIN_NET_TYPE_USER:
1070 1071 1072 1073 1074 1075
            default:
                {
                    char arg[PATH_MAX];
                    if (snprintf(arg, PATH_MAX-1, "user,vlan=%d", vlan) >= (PATH_MAX-1))
                        goto error;

1076
                    ADD_ARG_LIT(arg);
1077
                }
1078
            }
D
Daniel P. Berrange 已提交
1079 1080

            net = net->next;
1081
            vlan++;
D
Daniel P. Berrange 已提交
1082 1083 1084
        }
    }

1085
    if (!serial) {
1086 1087
        ADD_ARG_LIT("-serial");
        ADD_ARG_LIT("none");
1088 1089 1090 1091 1092 1093 1094
    } else {
        while (serial) {
            char buf[4096];

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

1095 1096
            ADD_ARG_LIT("-serial");
            ADD_ARG_LIT(buf);
1097 1098 1099 1100 1101 1102

            serial = serial->next;
        }
    }

    if (!parallel) {
1103 1104
        ADD_ARG_LIT("-parallel");
        ADD_ARG_LIT("none");
1105 1106 1107 1108 1109 1110 1111
    } else {
        while (parallel) {
            char buf[4096];

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

1112 1113
            ADD_ARG_LIT("-parallel");
            ADD_ARG_LIT(buf);
1114 1115 1116 1117 1118

            parallel = parallel->next;
        }
    }

1119
    ADD_ARG_LIT("-usb");
1120
    while (input) {
1121
        if (input->bus == VIR_DOMAIN_INPUT_BUS_USB) {
1122
            ADD_ARG_LIT("-usbdevice");
1123
            ADD_ARG_LIT(input->type == VIR_DOMAIN_INPUT_TYPE_MOUSE ? "mouse" : "tablet");
1124 1125 1126 1127 1128
        }

        input = input->next;
    }

1129 1130
    if (vm->def->graphics &&
        vm->def->graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
D
Daniel P. Berrange 已提交
1131
        char vncdisplay[PATH_MAX];
1132
        int ret;
D
Daniel P. Berrange 已提交
1133

1134
        if (qemuCmdFlags & QEMUD_CMD_FLAG_VNC_COLON) {
D
Daniel P. Berrange 已提交
1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147
            char options[PATH_MAX] = "";
            if (driver->vncTLS) {
                strcat(options, ",tls");
                if (driver->vncTLSx509verify) {
                    strcat(options, ",x509verify=");
                } else {
                    strcat(options, ",x509=");
                }
                strncat(options, driver->vncTLSx509certdir,
                        sizeof(options) - (strlen(driver->vncTLSx509certdir)-1));
                options[sizeof(options)-1] = '\0';
            }
            ret = snprintf(vncdisplay, sizeof(vncdisplay), "%s:%d%s",
D
Daniel P. Berrange 已提交
1148 1149 1150
                           (vm->def->graphics->data.vnc.listenAddr ?
                            vm->def->graphics->data.vnc.listenAddr :
                            (driver->vncListen ? driver->vncListen : "")),
1151
                           vm->def->graphics->data.vnc.port - 5900,
D
Daniel P. Berrange 已提交
1152 1153
                           options);
        } else {
1154
            ret = snprintf(vncdisplay, sizeof(vncdisplay), "%d",
1155
                           vm->def->graphics->data.vnc.port - 5900);
D
Daniel P. Berrange 已提交
1156
        }
1157
        if (ret < 0 || ret >= (int)sizeof(vncdisplay))
1158 1159
            goto error;

1160 1161
        ADD_ARG_LIT("-vnc");
        ADD_ARG_LIT(vncdisplay);
1162
        if (vm->def->graphics->data.vnc.keymap) {
1163
            ADD_ARG_LIT("-k");
1164
            ADD_ARG_LIT(vm->def->graphics->data.vnc.keymap);
1165
        }
1166 1167
    } else if (vm->def->graphics &&
               vm->def->graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) {
D
Daniel P. Berrange 已提交
1168 1169 1170
        /* SDL is the default. no args needed */
    }

D
Daniel Veillard 已提交
1171 1172 1173
    /* Add sound hardware */
    if (sound) {
        int size = 100;
1174 1175
        char *modstr;
        if (VIR_ALLOC_N(modstr, size+1) < 0)
D
Daniel Veillard 已提交
1176 1177 1178
            goto no_memory;

        while(sound && size > 0) {
1179
            const char *model = virDomainSoundModelTypeToString(sound->model);
D
Daniel Veillard 已提交
1180
            if (!model) {
1181
                VIR_FREE(modstr);
1182 1183 1184
                qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                                 "%s", _("invalid sound model"));
                goto error;
D
Daniel Veillard 已提交
1185 1186 1187 1188 1189 1190 1191
            }
            strncat(modstr, model, size);
            size -= strlen(model);
            sound = sound->next;
            if (sound)
               strncat(modstr, ",", size--);
        }
1192 1193
        ADD_ARG_LIT("-soundhw");
        ADD_ARG(modstr);
D
Daniel Veillard 已提交
1194 1195
    }

1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223
    /* Add host passthrough hardware */
    while (hostdev) {
        int ret;
        char* usbdev;

        if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
            hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {
            if(hostdev->source.subsys.usb.vendor) {
                    ret = asprintf(&usbdev, "host:%.4x:%.4x",
                               hostdev->source.subsys.usb.vendor,
                               hostdev->source.subsys.usb.product);

            } else {
                    ret = asprintf(&usbdev, "host:%.3d.%.3d",
                               hostdev->source.subsys.usb.bus,
                               hostdev->source.subsys.usb.device);
            }
            if (ret < 0) {
                usbdev = NULL;
                goto error;
            }
            ADD_ARG_LIT("-usbdevice");
            ADD_ARG_LIT(usbdev);
            VIR_FREE(usbdev);
        }
        hostdev = hostdev->next;
    }

1224
    if (migrateFrom) {
1225
        ADD_ARG_LIT("-incoming");
1226
        ADD_ARG_LIT(migrateFrom);
1227 1228
    }

1229
    ADD_ARG(NULL);
D
Daniel P. Berrange 已提交
1230

1231
    *retargv = qargv;
D
Daniel P. Berrange 已提交
1232 1233 1234
    return 0;

 no_memory:
1235 1236
    qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY,
                     "%s", _("failed to allocate space for argv string"));
1237
 error:
1238 1239 1240 1241 1242 1243
    if (tapfds &&
        *tapfds) {
        for (i = 0; ntapfds; i++)
            close((*tapfds)[i]);
        VIR_FREE(*tapfds);
        *ntapfds = 0;
1244
    }
1245 1246
    if (qargv) {
        for (i = 0 ; i < qargc ; i++)
1247 1248
            VIR_FREE((qargv)[i]);
        VIR_FREE(qargv);
D
Daniel P. Berrange 已提交
1249 1250
    }
    return -1;
1251 1252 1253 1254

#undef ADD_ARG
#undef ADD_ARG_LIT
#undef ADD_ARG_SPACE
D
Daniel P. Berrange 已提交
1255 1256
}