qemu_conf.c 55.4 KB
Newer Older
D
Daniel P. Berrange 已提交
1 2 3
/*
 * config.c: VM configuration management
 *
4
 * Copyright (C) 2006, 2007, 2008, 2009 Red Hat, Inc.
D
Daniel P. Berrange 已提交
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 * Copyright (C) 2006 Daniel P. Berrange
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
 *
 * Author: Daniel P. Berrange <berrange@redhat.com>
 */

24
#include <config.h>
25

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

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

52 53
#define VIR_FROM_THIS VIR_FROM_QEMU

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

64

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

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

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


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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

298 299

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

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

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

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

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

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

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

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

369 370 371 372 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
    char *help = NULL;
434
    enum { MAX_HELP_OUTPUT_SIZE = 1024*64 };
435
    int len = virFileReadLimFD(newstdout, MAX_HELP_OUTPUT_SIZE, &help);
436 437 438
    if (len < 0) {
        virReportSystemError(NULL, errno, "%s",
                             _("Unable to read QEMU help output"));
439
        goto cleanup2;
440
    }
441

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

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

457
    version = (major * 1000 * 1000) + (minor * 1000) + micro;
458

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

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

504 505 506 507
    if (retversion)
        *retversion = version;
    if (retflags)
        *retflags = flags;
508

509
    ret = 0;
510

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

516
cleanup2:
517
    VIR_FREE(help);
518 519
    if (close(newstdout) < 0)
        ret = -1;
520

521 522 523 524 525
rewait:
    if (waitpid(child, &status, 0) != child) {
        if (errno == EINTR)
            goto rewait;

526 527
        VIR_ERROR(_("Unexpected exit status from qemu %d pid %lu"),
                  WEXITSTATUS(status), (unsigned long)child);
528 529 530 531 532 533
        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) {
534
        VIR_WARN(_("Unexpected exit status '%d', qemu probably failed"),
535
                 WEXITSTATUS(status));
536
    }
537 538

    return ret;
539 540
}

541 542 543 544 545 546 547 548 549 550 551 552 553 554
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';
}

555
int qemudExtractVersion(virConnectPtr conn,
556 557
                        struct qemud_driver *driver) {
    const char *binary;
558
    struct stat sb;
559
    struct utsname ut;
560

561
    if (driver->qemuVersion > 0)
562 563
        return 0;

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

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

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

583
    return 0;
D
Daniel P. Berrange 已提交
584 585 586
}


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

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

        virNetworkFree(network);

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

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

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

644
    if ((err = brAddTap(driver->brctl, brname,
645
                        &net->ifname, vnet_hdr, &tapfd))) {
646 647 648 649 650 651 652 653 654
        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"),
655
                             net->ifname, brname, virStrerror(err, ebuf, sizeof ebuf));
656
        }
657 658 659
        goto error;
    }

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

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

667
    if (VIR_REALLOC_N(*tapfds, (*ntapfds)+1) < 0)
668 669
        goto no_memory;

670
    (*tapfds)[(*ntapfds)++] = tapfd;
671 672 673 674

    return retval;

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

683

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

694
    case VIR_DOMAIN_CHR_TYPE_VC:
695 696 697 698
        strncpy(buf, "vc", buflen);
        buf[buflen-1] = '\0';
        break;

699
    case VIR_DOMAIN_CHR_TYPE_PTY:
700 701 702 703
        strncpy(buf, "pty", buflen);
        buf[buflen-1] = '\0';
        break;

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

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

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

722
    case VIR_DOMAIN_CHR_TYPE_STDIO:
723 724 725 726
        strncpy(buf, "stdio", buflen);
        buf[buflen-1] = '\0';
        break;

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

736
    case VIR_DOMAIN_CHR_TYPE_TCP:
737 738 739 740
        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,
741
                         dev->data.tcp.listen ? ",server,nowait" : "") >= buflen)
742 743 744 745 746
                return -1;
        } else {
            if (snprintf(buf, buflen, "tcp:%s:%s%s",
                         dev->data.tcp.host,
                         dev->data.tcp.service,
747
                         dev->data.tcp.listen ? ",server,nowait" : "") >= buflen)
748 749
                return -1;
        }
750 751
        break;

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

    return 0;
}

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

792
    uname_normalize(&ut);
793

794
    virUUIDFormat(def->uuid, uuid);
795

796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822
    /* 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;
            }
        }
    }

823
    emulator = def->emulator;
824
    if (!emulator)
825
        emulator = virDomainDefDefaultEmulator(conn, def, driver->caps);
826 827 828 829
    if (!emulator)
        return -1;


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

840 841 842 843 844 845
    /* 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) &&
846 847
        STREQ(ut.machine, def->os.arch) &&
        def->virtType == VIR_DOMAIN_VIRT_QEMU)
848 849 850 851 852 853 854 855 856 857 858 859 860 861
        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
     */
862
    if (STREQ(def->os.arch, "i686") &&
863 864 865 866 867
        ((STREQ(ut.machine, "x86_64") &&
          strstr(emulator, "kvm")) ||
         strstr(emulator, "x86_64")))
        cpu = "qemu32";

868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888
#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 已提交
889

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

900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921
#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)

922
#define ADD_ENV_PAIR(envname, val)                                      \
923 924 925
    do {                                                                \
        char *envval;                                                   \
        ADD_ENV_SPACE;                                                  \
926 927 928 929 930 931 932 933
        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);                                    \
934
        if (val != NULL) {                                              \
935
            ADD_ENV_PAIR(envname, val);                                 \
936 937 938
        }                                                               \
    } while (0)

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

947 948 949 950 951 952 953 954 955 956
    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");

957
    ADD_ARG_LIT(emulator);
958
    ADD_ARG_LIT("-S");
959 960 961 962 963

    /* 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 */
964
    if (def->os.machine) {
965
        ADD_ARG_LIT("-M");
966
        ADD_ARG_LIT(def->os.machine);
967
    }
968 969 970 971
    if (cpu) {
        ADD_ARG_LIT("-cpu");
        ADD_ARG_LIT(cpu);
    }
972

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

982
    if (qemuCmdFlags & QEMUD_CMD_FLAG_NAME) {
983
        ADD_ARG_LIT("-name");
984
        ADD_ARG_LIT(def->name);
985
    }
986 987 988 989 990 991 992 993 994
    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);
    }

995 996 997 998 999 1000 1001
    /*
     * 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...
     */
1002
    if (!def->graphics)
1003
        ADD_ARG_LIT("-nographic");
1004

1005 1006
    ADD_ARG_LIT("-monitor");
    ADD_ARG_LIT("pty");
D
Daniel P. Berrange 已提交
1007

1008
    if (def->localtime)
1009
        ADD_ARG_LIT("-localtime");
1010

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

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

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

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

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

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

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

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

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

1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110
            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;
            }

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

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

1132 1133 1134 1135 1136 1137 1138 1139 1140
            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)
1141
                virBufferVSprintf(&opt, ",format=%s", disk->driverType);
1142

1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153
            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");
            }

1154 1155 1156 1157 1158 1159
            if (virBufferError(&opt)) {
                virReportOOMError(conn);
                goto error;
            }

            optstr = virBufferContentAndReset(&opt);
1160

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

1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180
            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;
            }

1181
            if (STREQ(disk->dst, "hdc") &&
1182 1183
                disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
                if (disk->src) {
1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200
                    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);

1201 1202
            ADD_ARG_LIT(dev);
            ADD_ARG_LIT(file);
1203
        }
D
Daniel P. Berrange 已提交
1204 1205
    }

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

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

1225 1226 1227
            ADD_ARG_LIT("-net");
            ADD_ARG_LIT(nic);
            ADD_ARG_LIT("-net");
1228

1229
            switch (net->type) {
1230 1231
            case VIR_DOMAIN_NET_TYPE_NETWORK:
            case VIR_DOMAIN_NET_TYPE_BRIDGE:
1232
                {
1233 1234 1235 1236 1237 1238 1239 1240 1241 1242
                    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);
1243 1244 1245 1246 1247
                    if (tap == NULL)
                        goto error;
                    ADD_ARG(tap);
                    break;
                }
1248

1249
            case VIR_DOMAIN_NET_TYPE_ETHERNET:
1250 1251
                {
                    char arg[PATH_MAX];
1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263
                    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;
                    }
1264

1265
                    ADD_ARG_LIT(arg);
1266 1267 1268
                }
                break;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        optstr = virBufferContentAndReset(&opt);
1399

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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


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

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

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

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