domain_conf.c 299.2 KB
Newer Older
1 2 3
/*
 * domain_conf.c: domain XML processing
 *
4
 * Copyright (C) 2006-2011 Red Hat, Inc.
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
 * Copyright (C) 2006-2008 Daniel P. Berrange
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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>
 */

#include <config.h>

#include <sys/types.h>
A
Atsushi SAKAI 已提交
27
#include <sys/stat.h>
28 29 30
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
C
Chris Lalancette 已提交
31
#include <sys/time.h>
32

33
#include "virterror_internal.h"
34
#include "datatypes.h"
35 36 37 38 39 40 41 42
#include "domain_conf.h"
#include "memory.h"
#include "verify.h"
#include "xml.h"
#include "uuid.h"
#include "util.h"
#include "buf.h"
#include "c-ctype.h"
43
#include "logging.h"
44
#include "network.h"
45
#include "nwfilter_conf.h"
C
Chris Lalancette 已提交
46
#include "ignore-value.h"
47
#include "storage_file.h"
48
#include "files.h"
49
#include "bitmap.h"
50

51 52
#define VIR_FROM_THIS VIR_FROM_DOMAIN

53 54 55 56 57 58 59
VIR_ENUM_IMPL(virDomainTaint, VIR_DOMAIN_TAINT_LAST,
              "custom-argv",
              "custom-monitor",
              "high-privileges",
              "shell-scripts",
              "disk-probing");

60 61 62 63 64 65 66 67 68 69 70 71
VIR_ENUM_IMPL(virDomainVirt, VIR_DOMAIN_VIRT_LAST,
              "qemu",
              "kqemu",
              "kvm",
              "xen",
              "lxc",
              "uml",
              "openvz",
              "vserver",
              "ldom",
              "test",
              "vmware",
72
              "hyperv",
D
Daniel Veillard 已提交
73
              "vbox",
74 75
              "one",
              "phyp")
76 77 78 79 80 81 82 83 84 85

VIR_ENUM_IMPL(virDomainBoot, VIR_DOMAIN_BOOT_LAST,
              "fd",
              "cdrom",
              "hd",
              "network")

VIR_ENUM_IMPL(virDomainFeature, VIR_DOMAIN_FEATURE_LAST,
              "acpi",
              "apic",
J
Jim Fehlig 已提交
86 87
              "pae",
              "hap")
88 89 90 91 92 93 94

VIR_ENUM_IMPL(virDomainLifecycle, VIR_DOMAIN_LIFECYCLE_LAST,
              "destroy",
              "restart",
              "rename-restart",
              "preserve")

95 96 97 98 99 100 101 102
VIR_ENUM_IMPL(virDomainLifecycleCrash, VIR_DOMAIN_LIFECYCLE_CRASH_LAST,
              "destroy",
              "restart",
              "rename-restart",
              "preserve",
              "coredump-destroy",
              "coredump-restart")

103 104 105 106 107 108
VIR_ENUM_IMPL(virDomainDevice, VIR_DOMAIN_DEVICE_LAST,
              "disk",
              "filesystem",
              "interface",
              "input",
              "sound",
109
              "video",
R
Richard Jones 已提交
110
              "hostdev",
111
              "watchdog",
112 113
              "controller",
              "graphics")
114

115 116
VIR_ENUM_IMPL(virDomainDeviceAddress, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST,
              "none",
117
              "pci",
118
              "drive",
E
Eric Blake 已提交
119 120
              "virtio-serial",
              "ccid")
121

122 123
VIR_ENUM_IMPL(virDomainDisk, VIR_DOMAIN_DISK_TYPE_LAST,
              "block",
124
              "file",
M
MORITA Kazutaka 已提交
125 126
              "dir",
              "network")
127 128 129 130 131 132 133 134 135 136 137

VIR_ENUM_IMPL(virDomainDiskDevice, VIR_DOMAIN_DISK_DEVICE_LAST,
              "disk",
              "cdrom",
              "floppy")

VIR_ENUM_IMPL(virDomainDiskBus, VIR_DOMAIN_DISK_BUS_LAST,
              "ide",
              "fdc",
              "scsi",
              "virtio",
138
              "xen",
139
              "usb",
140 141
              "uml",
              "sata")
142

143 144 145 146
VIR_ENUM_IMPL(virDomainDiskCache, VIR_DOMAIN_DISK_CACHE_LAST,
              "default",
              "none",
              "writethrough",
147
              "writeback")
148

149 150 151
VIR_ENUM_IMPL(virDomainDiskErrorPolicy, VIR_DOMAIN_DISK_ERROR_POLICY_LAST,
              "default",
              "stop",
152 153
              "ignore",
              "enospace")
154

M
MORITA Kazutaka 已提交
155 156 157 158 159
VIR_ENUM_IMPL(virDomainDiskProtocol, VIR_DOMAIN_DISK_PROTOCOL_LAST,
              "nbd",
              "rbd",
              "sheepdog")

M
Matthias Dahl 已提交
160 161 162 163 164
VIR_ENUM_IMPL(virDomainDiskIo, VIR_DOMAIN_DISK_IO_LAST,
              "default",
              "native",
              "threads")

165 166 167 168
VIR_ENUM_IMPL(virDomainController, VIR_DOMAIN_CONTROLLER_TYPE_LAST,
              "ide",
              "fdc",
              "scsi",
169
              "sata",
E
Eric Blake 已提交
170 171
              "virtio-serial",
              "ccid")
172

173
VIR_ENUM_IMPL(virDomainControllerModel, VIR_DOMAIN_CONTROLLER_MODEL_LAST,
174
              "auto",
175 176
              "buslogic",
              "lsilogic",
177 178
              "lsisas1068",
              "vmpvscsi")
179

180 181 182 183 184 185
VIR_ENUM_IMPL(virDomainFS, VIR_DOMAIN_FS_TYPE_LAST,
              "mount",
              "block",
              "file",
              "template")

186 187 188 189 190 191
VIR_ENUM_IMPL(virDomainFSAccessMode, VIR_DOMAIN_FS_ACCESSMODE_LAST,
              "passthrough",
              "mapped",
              "squash")


192 193 194 195 196 197 198
VIR_ENUM_IMPL(virDomainNet, VIR_DOMAIN_NET_TYPE_LAST,
              "user",
              "ethernet",
              "server",
              "client",
              "mcast",
              "network",
D
Daniel Veillard 已提交
199
              "bridge",
200 201
              "internal",
              "direct")
202

203 204 205 206 207
VIR_ENUM_IMPL(virDomainNetBackend, VIR_DOMAIN_NET_BACKEND_TYPE_LAST,
              "default",
              "qemu",
              "vhost")

208 209 210 211 212
VIR_ENUM_IMPL(virDomainNetVirtioTxMode, VIR_DOMAIN_NET_VIRTIO_TX_MODE_LAST,
              "default",
              "iothread",
              "timer")

213 214 215 216 217
VIR_ENUM_IMPL(virDomainChrChannelTarget,
              VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_LAST,
              "guestfwd",
              "virtio")

218 219 220 221
VIR_ENUM_IMPL(virDomainChrConsoleTarget,
              VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_LAST,
              "serial",
              "xen",
C
Cole Robinson 已提交
222 223
              "uml",
              "virtio")
224

225
VIR_ENUM_IMPL(virDomainChrDevice, VIR_DOMAIN_CHR_DEVICE_TYPE_LAST,
226 227
              "parallel",
              "serial",
228
              "console",
229
              "channel")
230

231 232 233 234 235 236 237 238 239 240
VIR_ENUM_IMPL(virDomainChr, VIR_DOMAIN_CHR_TYPE_LAST,
              "null",
              "vc",
              "pty",
              "dev",
              "file",
              "pipe",
              "stdio",
              "udp",
              "tcp",
241 242
              "unix",
              "spicevmc")
243

244 245 246 247 248 249
VIR_ENUM_IMPL(virDomainChrTcpProtocol, VIR_DOMAIN_CHR_TCP_PROTOCOL_LAST,
              "raw",
              "telnet",
              "telnets",
              "tls")

E
Eric Blake 已提交
250 251 252 253
VIR_ENUM_IMPL(virDomainChrSpicevmc, VIR_DOMAIN_CHR_SPICEVMC_LAST,
              "vdagent",
              "smartcard")

E
Eric Blake 已提交
254 255 256 257 258
VIR_ENUM_IMPL(virDomainSmartcard, VIR_DOMAIN_SMARTCARD_TYPE_LAST,
              "host",
              "host-certificates",
              "passthrough")

259 260 261
VIR_ENUM_IMPL(virDomainSoundModel, VIR_DOMAIN_SOUND_MODEL_LAST,
              "sb16",
              "es1370",
262
              "pcspk",
263 264
              "ac97",
              "ich6")
265

266 267
VIR_ENUM_IMPL(virDomainMemballoonModel, VIR_DOMAIN_MEMBALLOON_MODEL_LAST,
              "virtio",
268
              "xen",
269 270 271 272
              "none")

VIR_ENUM_IMPL(virDomainSysinfo, VIR_DOMAIN_SYSINFO_LAST,
              "smbios")
273

274 275 276 277 278 279
VIR_ENUM_IMPL(virDomainSmbiosMode, VIR_DOMAIN_SMBIOS_LAST,
              "none",
              "emulate",
              "host",
              "sysinfo")

R
Richard Jones 已提交
280 281 282 283 284 285 286 287 288
VIR_ENUM_IMPL(virDomainWatchdogModel, VIR_DOMAIN_WATCHDOG_MODEL_LAST,
              "i6300esb",
              "ib700")

VIR_ENUM_IMPL(virDomainWatchdogAction, VIR_DOMAIN_WATCHDOG_ACTION_LAST,
              "reset",
              "shutdown",
              "poweroff",
              "pause",
H
Hu Tao 已提交
289
              "dump",
R
Richard Jones 已提交
290 291
              "none")

292 293 294 295 296
VIR_ENUM_IMPL(virDomainVideo, VIR_DOMAIN_VIDEO_TYPE_LAST,
              "vga",
              "cirrus",
              "vmvga",
              "xen",
297 298
              "vbox",
              "qxl")
299

300 301 302 303 304 305 306 307 308 309 310
VIR_ENUM_IMPL(virDomainInput, VIR_DOMAIN_INPUT_TYPE_LAST,
              "mouse",
              "tablet")

VIR_ENUM_IMPL(virDomainInputBus, VIR_DOMAIN_INPUT_BUS_LAST,
              "ps2",
              "usb",
              "xen")

VIR_ENUM_IMPL(virDomainGraphics, VIR_DOMAIN_GRAPHICS_TYPE_LAST,
              "sdl",
311 312
              "vnc",
              "rdp",
313 314
              "desktop",
              "spice")
315

316 317 318 319 320 321 322
VIR_ENUM_IMPL(virDomainGraphicsSpiceChannelName,
              VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_LAST,
              "main",
              "display",
              "inputs",
              "cursor",
              "playback",
E
Eric Blake 已提交
323 324
              "record",
              "smartcard");
325 326 327 328 329 330 331

VIR_ENUM_IMPL(virDomainGraphicsSpiceChannelMode,
              VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_LAST,
              "any",
              "secure",
              "insecure");

332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361
VIR_ENUM_IMPL(virDomainGraphicsSpiceImageCompression,
              VIR_DOMAIN_GRAPHICS_SPICE_IMAGE_COMPRESSION_LAST,
              "default",
              "auto_glz",
              "auto_lz",
              "quic",
              "glz",
              "lz",
              "off");

VIR_ENUM_IMPL(virDomainGraphicsSpiceJpegCompression,
              VIR_DOMAIN_GRAPHICS_SPICE_JPEG_COMPRESSION_LAST,
              "default",
              "auto",
              "never",
              "always");

VIR_ENUM_IMPL(virDomainGraphicsSpiceZlibCompression,
              VIR_DOMAIN_GRAPHICS_SPICE_ZLIB_COMPRESSION_LAST,
              "default",
              "auto",
              "never",
              "always");

VIR_ENUM_IMPL(virDomainGraphicsSpicePlaybackCompression,
              VIR_DOMAIN_GRAPHICS_SPICE_PLAYBACK_COMPRESSION_LAST,
              "default",
              "on",
              "off");

362 363 364 365 366 367 368
VIR_ENUM_IMPL(virDomainGraphicsSpiceStreamingMode,
              VIR_DOMAIN_GRAPHICS_SPICE_STREAMING_MODE_LAST,
              "default",
              "filter",
              "all",
              "off");

369 370 371 372 373 374 375
VIR_ENUM_IMPL(virDomainHostdevMode, VIR_DOMAIN_HOSTDEV_MODE_LAST,
              "subsystem",
              "capabilities")

VIR_ENUM_IMPL(virDomainHostdevSubsys, VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST,
              "usb",
              "pci")
376

377 378 379 380 381 382 383 384 385
VIR_ENUM_IMPL(virDomainState, VIR_DOMAIN_CRASHED+1,
              "nostate",
              "running",
              "blocked",
              "paused",
              "shutdown",
              "shutoff",
              "crashed")

J
Jiri Denemark 已提交
386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435
#define VIR_DOMAIN_NOSTATE_LAST (VIR_DOMAIN_NOSTATE_UNKNOWN + 1)
VIR_ENUM_IMPL(virDomainNostateReason, VIR_DOMAIN_NOSTATE_LAST,
              "unknown")

#define VIR_DOMAIN_RUNNING_LAST (VIR_DOMAIN_RUNNING_SAVE_CANCELED + 1)
VIR_ENUM_IMPL(virDomainRunningReason, VIR_DOMAIN_RUNNING_LAST,
              "unknown",
              "booted",
              "migrated",
              "restored",
              "from snapshot",
              "unpaused",
              "migration canceled",
              "save canceled")

#define VIR_DOMAIN_BLOCKED_LAST (VIR_DOMAIN_BLOCKED_UNKNOWN + 1)
VIR_ENUM_IMPL(virDomainBlockedReason, VIR_DOMAIN_BLOCKED_LAST,
              "unknown")

#define VIR_DOMAIN_PAUSED_LAST (VIR_DOMAIN_PAUSED_FROM_SNAPSHOT + 1)
VIR_ENUM_IMPL(virDomainPausedReason, VIR_DOMAIN_PAUSED_LAST,
              "unknown",
              "user",
              "migration",
              "save",
              "dump",
              "ioerror",
              "watchdog",
              "from snapshot")

#define VIR_DOMAIN_SHUTDOWN_LAST (VIR_DOMAIN_SHUTDOWN_USER + 1)
VIR_ENUM_IMPL(virDomainShutdownReason, VIR_DOMAIN_SHUTDOWN_LAST,
              "unknown",
              "user")

#define VIR_DOMAIN_SHUTOFF_LAST (VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT + 1)
VIR_ENUM_IMPL(virDomainShutoffReason, VIR_DOMAIN_SHUTOFF_LAST,
              "unknown",
              "shutdown",
              "destroyed",
              "crashed",
              "migrated",
              "saved",
              "failed",
              "from snapshot")

#define VIR_DOMAIN_CRASHED_LAST (VIR_DOMAIN_CRASHED_UNKNOWN + 1)
VIR_ENUM_IMPL(virDomainCrashedReason, VIR_DOMAIN_CRASHED_LAST,
              "unknown")

436 437 438 439
VIR_ENUM_IMPL(virDomainSeclabel, VIR_DOMAIN_SECLABEL_LAST,
              "dynamic",
              "static")

440 441 442
VIR_ENUM_IMPL(virDomainNetdevMacvtap, VIR_DOMAIN_NETDEV_MACVTAP_MODE_LAST,
              "vepa",
              "private",
443 444
              "bridge",
              "passthrough")
445

446 447 448 449 450
VIR_ENUM_IMPL(virVirtualPort, VIR_VIRTUALPORT_TYPE_LAST,
              "none",
              "802.1Qbg",
              "802.1Qbh")

451 452
VIR_ENUM_IMPL(virDomainClockOffset, VIR_DOMAIN_CLOCK_OFFSET_LAST,
              "utc",
453
              "localtime",
454 455
              "variable",
              "timezone");
456

457 458 459 460 461 462 463
VIR_ENUM_IMPL(virDomainTimerName, VIR_DOMAIN_TIMER_NAME_LAST,
              "platform",
              "pit",
              "rtc",
              "hpet",
              "tsc");

464 465 466 467
VIR_ENUM_IMPL(virDomainTimerTrack, VIR_DOMAIN_TIMER_TRACK_LAST,
              "boot",
              "guest",
              "wall");
468 469 470 471 472 473 474 475 476 477 478

VIR_ENUM_IMPL(virDomainTimerTickpolicy, VIR_DOMAIN_TIMER_TICKPOLICY_LAST,
              "delay",
              "catchup",
              "merge",
              "discard");

VIR_ENUM_IMPL(virDomainTimerMode, VIR_DOMAIN_TIMER_MODE_LAST,
              "auto",
              "native",
              "emulate",
479 480
              "paravirt",
              "smpsafe");
481

482
#define virDomainReportError(code, ...)                              \
483
    virReportErrorHelper(VIR_FROM_DOMAIN, code, __FILE__,            \
484
                         __FUNCTION__, __LINE__, __VA_ARGS__)
485

486 487 488
#define VIR_DOMAIN_XML_WRITE_FLAGS  VIR_DOMAIN_XML_SECURE
#define VIR_DOMAIN_XML_READ_FLAGS   VIR_DOMAIN_XML_INACTIVE

489
static void
490
virDomainObjListDataFree(void *payload, const void *name ATTRIBUTE_UNUSED)
491 492 493 494 495 496 497
{
    virDomainObjPtr obj = payload;
    virDomainObjLock(obj);
    if (virDomainObjUnref(obj) > 0)
        virDomainObjUnlock(obj);
}

498
int virDomainObjListInit(virDomainObjListPtr doms)
499
{
500
    doms->objs = virHashCreate(50, virDomainObjListDataFree);
501
    if (!doms->objs)
502 503 504
        return -1;
    return 0;
}
505

506 507 508

void virDomainObjListDeinit(virDomainObjListPtr doms)
{
509
    virHashFree(doms->objs);
510 511 512 513
}


static int virDomainObjListSearchID(const void *payload,
514
                                    const void *name ATTRIBUTE_UNUSED,
515 516 517 518 519 520 521
                                    const void *data)
{
    virDomainObjPtr obj = (virDomainObjPtr)payload;
    const int *id = data;
    int want = 0;

    virDomainObjLock(obj);
D
Daniel P. Berrange 已提交
522
    if (virDomainObjIsActive(obj) &&
523 524 525 526 527 528 529 530 531 532 533 534 535 536
        obj->def->id == *id)
        want = 1;
    virDomainObjUnlock(obj);
    return want;
}

virDomainObjPtr virDomainFindByID(const virDomainObjListPtr doms,
                                  int id)
{
    virDomainObjPtr obj;
    obj = virHashSearch(doms->objs, virDomainObjListSearchID, &id);
    if (obj)
        virDomainObjLock(obj);
    return obj;
537 538 539
}


540
virDomainObjPtr virDomainFindByUUID(const virDomainObjListPtr doms,
541 542
                                    const unsigned char *uuid)
{
543 544
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    virDomainObjPtr obj;
545

546
    virUUIDFormat(uuid, uuidstr);
547

548 549 550 551 552 553 554
    obj = virHashLookup(doms->objs, uuidstr);
    if (obj)
        virDomainObjLock(obj);
    return obj;
}

static int virDomainObjListSearchName(const void *payload,
555
                                      const void *name ATTRIBUTE_UNUSED,
556 557 558 559 560 561 562 563 564 565
                                      const void *data)
{
    virDomainObjPtr obj = (virDomainObjPtr)payload;
    int want = 0;

    virDomainObjLock(obj);
    if (STREQ(obj->def->name, (const char *)data))
        want = 1;
    virDomainObjUnlock(obj);
    return want;
566 567
}

568
virDomainObjPtr virDomainFindByName(const virDomainObjListPtr doms,
569 570
                                    const char *name)
{
571 572 573 574 575
    virDomainObjPtr obj;
    obj = virHashSearch(doms->objs, virDomainObjListSearchName, name);
    if (obj)
        virDomainObjLock(obj);
    return obj;
576 577
}

578 579 580 581 582 583 584 585 586 587 588 589 590 591

bool virDomainObjTaint(virDomainObjPtr obj,
                       enum virDomainTaintFlags taint)
{
    int flag = (1 << taint);

    if (obj->taint & flag)
        return false;

    obj->taint |= flag;
    return true;
}


592 593 594 595 596 597 598 599 600 601 602
static void
virDomainGraphicsAuthDefClear(virDomainGraphicsAuthDefPtr def)
{
    if (!def)
        return;

    VIR_FREE(def->passwd);

    /* Don't free def */
}

603 604 605 606 607 608 609 610
void virDomainGraphicsDefFree(virDomainGraphicsDefPtr def)
{
    if (!def)
        return;

    switch (def->type) {
    case VIR_DOMAIN_GRAPHICS_TYPE_VNC:
        VIR_FREE(def->data.vnc.listenAddr);
611
        VIR_FREE(def->data.vnc.socket);
612
        VIR_FREE(def->data.vnc.keymap);
613
        virDomainGraphicsAuthDefClear(&def->data.vnc.auth);
614 615 616 617 618 619
        break;

    case VIR_DOMAIN_GRAPHICS_TYPE_SDL:
        VIR_FREE(def->data.sdl.display);
        VIR_FREE(def->data.sdl.xauth);
        break;
620 621 622 623 624 625 626 627

    case VIR_DOMAIN_GRAPHICS_TYPE_RDP:
        VIR_FREE(def->data.rdp.listenAddr);
        break;

    case VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP:
        VIR_FREE(def->data.desktop.display);
        break;
628 629 630 631

    case VIR_DOMAIN_GRAPHICS_TYPE_SPICE:
        VIR_FREE(def->data.spice.listenAddr);
        VIR_FREE(def->data.spice.keymap);
632
        virDomainGraphicsAuthDefClear(&def->data.spice.auth);
633
        break;
634 635 636 637 638 639 640 641 642 643
    }

    VIR_FREE(def);
}

void virDomainInputDefFree(virDomainInputDefPtr def)
{
    if (!def)
        return;

644
    virDomainDeviceInfoClear(&def->info);
645 646 647 648 649
    VIR_FREE(def);
}

void virDomainDiskDefFree(virDomainDiskDefPtr def)
{
650 651
    unsigned int i;

652 653 654
    if (!def)
        return;

655
    VIR_FREE(def->serial);
656 657 658 659
    VIR_FREE(def->src);
    VIR_FREE(def->dst);
    VIR_FREE(def->driverName);
    VIR_FREE(def->driverType);
660
    virStorageEncryptionFree(def->encryption);
661
    virDomainDeviceInfoClear(&def->info);
662

663 664
    for (i = 0 ; i < def->nhosts ; i++)
        virDomainDiskHostDefFree(&def->hosts[i]);
E
Eric Blake 已提交
665
    VIR_FREE(def->hosts);
666

667 668 669
    VIR_FREE(def);
}

670 671 672 673 674 675 676 677 678
void virDomainDiskHostDefFree(virDomainDiskHostDefPtr def)
{
    if (!def)
        return;

    VIR_FREE(def->name);
    VIR_FREE(def->port);
}

679 680 681 682 683 684 685 686 687 688
void virDomainControllerDefFree(virDomainControllerDefPtr def)
{
    if (!def)
        return;

    virDomainDeviceInfoClear(&def->info);

    VIR_FREE(def);
}

689 690 691 692 693 694 695
void virDomainFSDefFree(virDomainFSDefPtr def)
{
    if (!def)
        return;

    VIR_FREE(def->src);
    VIR_FREE(def->dst);
696
    virDomainDeviceInfoClear(&def->info);
697 698 699 700

    VIR_FREE(def);
}

701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726
void virDomainNetDefFree(virDomainNetDefPtr def)
{
    if (!def)
        return;

    VIR_FREE(def->model);

    switch (def->type) {
    case VIR_DOMAIN_NET_TYPE_ETHERNET:
        VIR_FREE(def->data.ethernet.dev);
        VIR_FREE(def->data.ethernet.script);
        VIR_FREE(def->data.ethernet.ipaddr);
        break;

    case VIR_DOMAIN_NET_TYPE_SERVER:
    case VIR_DOMAIN_NET_TYPE_CLIENT:
    case VIR_DOMAIN_NET_TYPE_MCAST:
        VIR_FREE(def->data.socket.address);
        break;

    case VIR_DOMAIN_NET_TYPE_NETWORK:
        VIR_FREE(def->data.network.name);
        break;

    case VIR_DOMAIN_NET_TYPE_BRIDGE:
        VIR_FREE(def->data.bridge.brname);
727
        VIR_FREE(def->data.bridge.script);
728
        VIR_FREE(def->data.bridge.ipaddr);
729
        break;
D
Daniel Veillard 已提交
730 731 732 733

    case VIR_DOMAIN_NET_TYPE_INTERNAL:
        VIR_FREE(def->data.internal.name);
        break;
734 735 736 737

    case VIR_DOMAIN_NET_TYPE_DIRECT:
        VIR_FREE(def->data.direct.linkdev);
        break;
S
Stefan Berger 已提交
738 739 740 741

    case VIR_DOMAIN_NET_TYPE_USER:
    case VIR_DOMAIN_NET_TYPE_LAST:
        break;
742 743 744
    }

    VIR_FREE(def->ifname);
745 746 747

    virDomainDeviceInfoClear(&def->info);

748 749 750
    VIR_FREE(def->filter);
    virNWFilterHashTableFree(def->filterparams);

751 752 753
    VIR_FREE(def);
}

754 755
static void ATTRIBUTE_NONNULL(1)
virDomainChrSourceDefClear(virDomainChrSourceDefPtr def)
756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780
{
    switch (def->type) {
    case VIR_DOMAIN_CHR_TYPE_PTY:
    case VIR_DOMAIN_CHR_TYPE_DEV:
    case VIR_DOMAIN_CHR_TYPE_FILE:
    case VIR_DOMAIN_CHR_TYPE_PIPE:
        VIR_FREE(def->data.file.path);
        break;

    case VIR_DOMAIN_CHR_TYPE_UDP:
        VIR_FREE(def->data.udp.bindHost);
        VIR_FREE(def->data.udp.bindService);
        VIR_FREE(def->data.udp.connectHost);
        VIR_FREE(def->data.udp.connectService);
        break;

    case VIR_DOMAIN_CHR_TYPE_TCP:
        VIR_FREE(def->data.tcp.host);
        VIR_FREE(def->data.tcp.service);
        break;

    case VIR_DOMAIN_CHR_TYPE_UNIX:
        VIR_FREE(def->data.nix.path);
        break;
    }
781 782 783 784 785 786 787 788 789 790 791
}

void virDomainChrSourceDefFree(virDomainChrSourceDefPtr def)
{
    if (!def)
        return;

    virDomainChrSourceDefClear(def);

    VIR_FREE(def);
}
792

793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815
void virDomainChrDefFree(virDomainChrDefPtr def)
{
    if (!def)
        return;

    switch (def->deviceType) {
    case VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL:
        switch (def->targetType) {
        case VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_GUESTFWD:
            VIR_FREE(def->target.addr);
            break;

        case VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO:
            VIR_FREE(def->target.name);
            break;
        }
        break;

    default:
        break;
    }

    virDomainChrSourceDefClear(&def->source);
816 817
    virDomainDeviceInfoClear(&def->info);

818 819 820
    VIR_FREE(def);
}

E
Eric Blake 已提交
821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849
void virDomainSmartcardDefFree(virDomainSmartcardDefPtr def)
{
    size_t i;
    if (!def)
        return;

    switch (def->type) {
    case VIR_DOMAIN_SMARTCARD_TYPE_HOST:
        break;

    case VIR_DOMAIN_SMARTCARD_TYPE_HOST_CERTIFICATES:
        for (i = 0; i < VIR_DOMAIN_SMARTCARD_NUM_CERTIFICATES; i++)
            VIR_FREE(def->data.cert.file[i]);
        VIR_FREE(def->data.cert.database);
        break;

    case VIR_DOMAIN_SMARTCARD_TYPE_PASSTHROUGH:
        virDomainChrSourceDefClear(&def->data.passthru);
        break;

    default:
        break;
    }

    virDomainDeviceInfoClear(&def->info);

    VIR_FREE(def);
}

850 851 852 853 854
void virDomainSoundDefFree(virDomainSoundDefPtr def)
{
    if (!def)
        return;

855 856
    virDomainDeviceInfoClear(&def->info);

857 858 859
    VIR_FREE(def);
}

860 861 862 863 864 865 866 867 868 869
void virDomainMemballoonDefFree(virDomainMemballoonDefPtr def)
{
    if (!def)
        return;

    virDomainDeviceInfoClear(&def->info);

    VIR_FREE(def);
}

R
Richard Jones 已提交
870 871 872 873 874
void virDomainWatchdogDefFree(virDomainWatchdogDefPtr def)
{
    if (!def)
        return;

875 876
    virDomainDeviceInfoClear(&def->info);

R
Richard Jones 已提交
877 878 879
    VIR_FREE(def);
}

880 881 882 883 884
void virDomainVideoDefFree(virDomainVideoDefPtr def)
{
    if (!def)
        return;

885 886
    virDomainDeviceInfoClear(&def->info);

887
    VIR_FREE(def->accel);
888 889 890
    VIR_FREE(def);
}

891 892 893 894 895
void virDomainHostdevDefFree(virDomainHostdevDefPtr def)
{
    if (!def)
        return;

896
    virDomainDeviceInfoClear(&def->info);
897 898 899
    VIR_FREE(def);
}

900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917
void virDomainDeviceDefFree(virDomainDeviceDefPtr def)
{
    if (!def)
        return;

    switch (def->type) {
    case VIR_DOMAIN_DEVICE_DISK:
        virDomainDiskDefFree(def->data.disk);
        break;
    case VIR_DOMAIN_DEVICE_NET:
        virDomainNetDefFree(def->data.net);
        break;
    case VIR_DOMAIN_DEVICE_INPUT:
        virDomainInputDefFree(def->data.input);
        break;
    case VIR_DOMAIN_DEVICE_SOUND:
        virDomainSoundDefFree(def->data.sound);
        break;
918 919 920
    case VIR_DOMAIN_DEVICE_VIDEO:
        virDomainVideoDefFree(def->data.video);
        break;
921 922 923
    case VIR_DOMAIN_DEVICE_HOSTDEV:
        virDomainHostdevDefFree(def->data.hostdev);
        break;
R
Richard Jones 已提交
924 925 926
    case VIR_DOMAIN_DEVICE_WATCHDOG:
        virDomainWatchdogDefFree(def->data.watchdog);
        break;
927 928 929
    case VIR_DOMAIN_DEVICE_CONTROLLER:
        virDomainControllerDefFree(def->data.controller);
        break;
930 931 932
    case VIR_DOMAIN_DEVICE_GRAPHICS:
        virDomainGraphicsDefFree(def->data.graphics);
        break;
933 934 935 936 937
    }

    VIR_FREE(def);
}

938 939 940 941 942 943 944 945 946
void virSecurityLabelDefFree(virDomainDefPtr def);

void virSecurityLabelDefFree(virDomainDefPtr def)
{
    VIR_FREE(def->seclabel.model);
    VIR_FREE(def->seclabel.label);
    VIR_FREE(def->seclabel.imagelabel);
}

947 948 949 950 951 952 953 954 955 956 957 958
static void
virDomainClockDefClear(virDomainClockDefPtr def)
{
    if (def->offset == VIR_DOMAIN_CLOCK_OFFSET_TIMEZONE)
        VIR_FREE(def->data.timezone);

    int i;
    for (i = 0; i < def->ntimers; i++)
        VIR_FREE(def->timers[i]);
    VIR_FREE(def->timers);
}

959 960 961 962 963 964 965 966 967 968
static void
virDomainVcpupinDefFree(virDomainVcpupinDefPtr *def,
                        int nvcpupin)
{
    int i;

    if (!def || !nvcpupin)
        return;

    for(i = 0; i < nvcpupin; i++) {
H
Hu Tao 已提交
969
        VIR_FREE(def[i]->cpumask);
970 971 972 973 974 975
        VIR_FREE(def[i]);
    }

    VIR_FREE(def);
}

976 977
void virDomainDefFree(virDomainDefPtr def)
{
978 979
    unsigned int i;

980 981 982
    if (!def)
        return;

983 984 985
    for (i = 0 ; i < def->ngraphics ; i++)
        virDomainGraphicsDefFree(def->graphics[i]);
    VIR_FREE(def->graphics);
986 987 988 989 990 991 992 993 994

    for (i = 0 ; i < def->ninputs ; i++)
        virDomainInputDefFree(def->inputs[i]);
    VIR_FREE(def->inputs);

    for (i = 0 ; i < def->ndisks ; i++)
        virDomainDiskDefFree(def->disks[i]);
    VIR_FREE(def->disks);

995 996 997 998
    for (i = 0 ; i < def->ncontrollers ; i++)
        virDomainControllerDefFree(def->controllers[i]);
    VIR_FREE(def->controllers);

999 1000 1001 1002 1003 1004 1005
    for (i = 0 ; i < def->nfss ; i++)
        virDomainFSDefFree(def->fss[i]);
    VIR_FREE(def->fss);

    for (i = 0 ; i < def->nnets ; i++)
        virDomainNetDefFree(def->nets[i]);
    VIR_FREE(def->nets);
1006

E
Eric Blake 已提交
1007 1008 1009 1010
    for (i = 0 ; i < def->nsmartcards ; i++)
        virDomainSmartcardDefFree(def->smartcards[i]);
    VIR_FREE(def->smartcards);

1011 1012 1013 1014 1015 1016 1017 1018
    for (i = 0 ; i < def->nserials ; i++)
        virDomainChrDefFree(def->serials[i]);
    VIR_FREE(def->serials);

    for (i = 0 ; i < def->nparallels ; i++)
        virDomainChrDefFree(def->parallels[i]);
    VIR_FREE(def->parallels);

1019 1020 1021 1022
    for (i = 0 ; i < def->nchannels ; i++)
        virDomainChrDefFree(def->channels[i]);
    VIR_FREE(def->channels);

1023
    virDomainChrDefFree(def->console);
1024 1025 1026 1027 1028

    for (i = 0 ; i < def->nsounds ; i++)
        virDomainSoundDefFree(def->sounds[i]);
    VIR_FREE(def->sounds);

1029 1030 1031 1032
    for (i = 0 ; i < def->nvideos ; i++)
        virDomainVideoDefFree(def->videos[i]);
    VIR_FREE(def->videos);

1033 1034 1035
    for (i = 0 ; i < def->nhostdevs ; i++)
        virDomainHostdevDefFree(def->hostdevs[i]);
    VIR_FREE(def->hostdevs);
1036 1037 1038 1039

    VIR_FREE(def->os.type);
    VIR_FREE(def->os.arch);
    VIR_FREE(def->os.machine);
1040
    VIR_FREE(def->os.init);
1041 1042 1043 1044 1045 1046 1047 1048
    VIR_FREE(def->os.kernel);
    VIR_FREE(def->os.initrd);
    VIR_FREE(def->os.cmdline);
    VIR_FREE(def->os.root);
    VIR_FREE(def->os.loader);
    VIR_FREE(def->os.bootloader);
    VIR_FREE(def->os.bootloaderArgs);

1049
    virDomainClockDefClear(&def->clock);
1050

1051 1052 1053
    VIR_FREE(def->name);
    VIR_FREE(def->cpumask);
    VIR_FREE(def->emulator);
1054
    VIR_FREE(def->description);
1055

R
Richard Jones 已提交
1056 1057
    virDomainWatchdogDefFree(def->watchdog);

C
Chris Lalancette 已提交
1058 1059
    virDomainMemballoonDefFree(def->memballoon);

1060 1061
    virSecurityLabelDefFree(def);

1062 1063
    virCPUDefFree(def->cpu);

1064 1065
    virDomainVcpupinDefFree(def->cputune.vcpupin, def->cputune.nvcpupin);

1066 1067
    virSysinfoDefFree(def->sysinfo);

1068 1069 1070
    if (def->namespaceData && def->ns.free)
        (def->ns.free)(def->namespaceData);

1071 1072 1073
    VIR_FREE(def);
}

1074
static void virDomainSnapshotObjListDeinit(virDomainSnapshotObjListPtr snapshots);
1075
static void virDomainObjFree(virDomainObjPtr dom)
1076 1077 1078 1079
{
    if (!dom)
        return;

1080
    VIR_DEBUG("obj=%p", dom);
1081 1082 1083
    virDomainDefFree(dom->def);
    virDomainDefFree(dom->newDef);

1084 1085 1086
    if (dom->privateDataFreeFunc)
        (dom->privateDataFreeFunc)(dom->privateData);

1087 1088
    virMutexDestroy(&dom->lock);

C
Chris Lalancette 已提交
1089 1090
    virDomainSnapshotObjListDeinit(&dom->snapshots);

1091 1092 1093
    VIR_FREE(dom);
}

1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107
void virDomainObjRef(virDomainObjPtr dom)
{
    dom->refs++;
    VIR_DEBUG("obj=%p refs=%d", dom, dom->refs);
}


int virDomainObjUnref(virDomainObjPtr dom)
{
    dom->refs--;
    VIR_DEBUG("obj=%p refs=%d", dom, dom->refs);
    if (dom->refs == 0) {
        virDomainObjUnlock(dom);
        virDomainObjFree(dom);
1108
        return 0;
1109
    }
1110
    return dom->refs;
1111 1112
}

1113
static virDomainObjPtr virDomainObjNew(virCapsPtr caps)
1114 1115 1116 1117
{
    virDomainObjPtr domain;

    if (VIR_ALLOC(domain) < 0) {
1118
        virReportOOMError();
1119 1120 1121
        return NULL;
    }

1122 1123
    if (caps->privateDataAllocFunc &&
        !(domain->privateData = (caps->privateDataAllocFunc)())) {
1124
        virReportOOMError();
1125 1126 1127 1128 1129
        VIR_FREE(domain);
        return NULL;
    }
    domain->privateDataFreeFunc = caps->privateDataFreeFunc;

1130
    if (virMutexInit(&domain->lock) < 0) {
1131
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
1132
                             "%s", _("cannot initialize mutex"));
1133 1134
        if (domain->privateDataFreeFunc)
            (domain->privateDataFreeFunc)(domain->privateData);
1135 1136 1137 1138 1139
        VIR_FREE(domain);
        return NULL;
    }

    virDomainObjLock(domain);
J
Jiri Denemark 已提交
1140 1141
    virDomainObjSetState(domain, VIR_DOMAIN_SHUTOFF,
                                 VIR_DOMAIN_SHUTOFF_UNKNOWN);
1142
    domain->refs = 1;
1143

C
Chris Lalancette 已提交
1144 1145
    virDomainSnapshotObjListInit(&domain->snapshots);

1146
    VIR_DEBUG("obj=%p", domain);
1147 1148 1149
    return domain;
}

1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169
void virDomainObjAssignDef(virDomainObjPtr domain,
                           const virDomainDefPtr def,
                           bool live)
{
    if (!virDomainObjIsActive(domain)) {
        if (live) {
            /* save current configuration to be restored on domain shutdown */
            if (!domain->newDef)
                domain->newDef = domain->def;
            domain->def = def;
        } else {
            virDomainDefFree(domain->def);
            domain->def = def;
        }
    } else {
        virDomainDefFree(domain->newDef);
        domain->newDef = def;
    }
}

1170
virDomainObjPtr virDomainAssignDef(virCapsPtr caps,
1171
                                   virDomainObjListPtr doms,
1172 1173
                                   const virDomainDefPtr def,
                                   bool live)
1174 1175
{
    virDomainObjPtr domain;
1176
    char uuidstr[VIR_UUID_STRING_BUFLEN];
1177

1178
    if ((domain = virDomainFindByUUID(doms, def->uuid))) {
1179
        virDomainObjAssignDef(domain, def, live);
1180 1181 1182
        return domain;
    }

1183
    if (!(domain = virDomainObjNew(caps)))
1184
        return NULL;
1185
    domain->def = def;
1186

1187 1188 1189 1190 1191
    virUUIDFormat(def->uuid, uuidstr);
    if (virHashAddEntry(doms->objs, uuidstr, domain) < 0) {
        VIR_FREE(domain);
        return NULL;
    }
1192 1193 1194 1195

    return domain;
}

1196 1197 1198 1199 1200 1201
/*
 * Mark the running VM config as transient. Ensures transient hotplug
 * operations do not persist past shutdown.
 *
 * @param caps pointer to capabilities info
 * @param domain domain object pointer
1202 1203 1204 1205
 * @param live if true, run this operation even for an inactive domain.
 *   this allows freely updated domain->def with runtime defaults before
 *   starting the VM, which will be discarded on VM shutdown. Any cleanup
 *   paths need to be sure to handle newDef if the domain is never started.
1206 1207 1208 1209
 * @return 0 on success, -1 on failure
 */
int
virDomainObjSetDefTransient(virCapsPtr caps,
1210 1211
                            virDomainObjPtr domain,
                            bool live)
1212 1213 1214 1215 1216
{
    int ret = -1;
    char *xml = NULL;
    virDomainDefPtr newDef = NULL;

1217
    if (!virDomainObjIsActive(domain) && !live)
1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239
        return 0;

    if (!domain->persistent)
        return 0;

    if (domain->newDef)
        return 0;

    if (!(xml = virDomainDefFormat(domain->def, VIR_DOMAIN_XML_WRITE_FLAGS)))
        goto out;

    if (!(newDef = virDomainDefParseString(caps, xml,
                                           VIR_DOMAIN_XML_READ_FLAGS)))
        goto out;

    domain->newDef = newDef;
    ret = 0;
out:
    VIR_FREE(xml);
    return ret;
}

1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251
/*
 * Return the persistent domain configuration. If domain is transient,
 * return the running config.
 *
 * @param caps pointer to capabilities info
 * @param domain domain object pointer
 * @return NULL on error, virDOmainDefPtr on success
 */
virDomainDefPtr
virDomainObjGetPersistentDef(virCapsPtr caps,
                             virDomainObjPtr domain)
{
1252
    if (virDomainObjSetDefTransient(caps, domain, false) < 0)
1253 1254 1255 1256 1257 1258 1259 1260
        return NULL;

    if (domain->newDef)
        return domain->newDef;
    else
        return domain->def;
}

1261 1262 1263 1264 1265
/*
 * The caller must hold a lock  on the driver owning 'doms',
 * and must also have locked 'dom', to ensure no one else
 * is either waiting for 'dom' or still usingn it
 */
1266
void virDomainRemoveInactive(virDomainObjListPtr doms,
1267 1268
                             virDomainObjPtr dom)
{
1269 1270
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    virUUIDFormat(dom->def->uuid, uuidstr);
1271

1272 1273
    virDomainObjUnlock(dom);

1274
    virHashRemoveEntry(doms->objs, uuidstr);
1275
}
D
Daniel P. Berrange 已提交
1276

1277

1278 1279 1280 1281 1282 1283 1284 1285 1286
int virDomainDeviceAddressIsValid(virDomainDeviceInfoPtr info,
                                  int type)
{
    if (info->type != type)
        return 0;

    switch (info->type) {
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI:
        return virDomainDevicePCIAddressIsValid(&info->addr.pci);
1287 1288 1289

    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE:
        return virDomainDeviceDriveAddressIsValid(&info->addr.drive);
1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301
    }

    return 0;
}


int virDomainDevicePCIAddressIsValid(virDomainDevicePCIAddressPtr addr)
{
    return addr->domain || addr->bus || addr->slot;
}


1302 1303 1304 1305 1306
int virDomainDeviceDriveAddressIsValid(virDomainDeviceDriveAddressPtr addr ATTRIBUTE_UNUSED)
{
    /*return addr->controller || addr->bus || addr->unit;*/
    return 1; /* 0 is valid for all fields, so any successfully parsed addr is valid */
}
1307 1308 1309 1310 1311 1312 1313


int virDomainDeviceVirtioSerialAddressIsValid(
    virDomainDeviceVirtioSerialAddressPtr addr ATTRIBUTE_UNUSED)
{
    return 1; /* 0 is valid for all fields, so any successfully parsed addr is valid */
}
1314 1315


1316 1317 1318 1319
int virDomainDeviceInfoIsSet(virDomainDeviceInfoPtr info)
{
    if (info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
        return 1;
D
Daniel P. Berrange 已提交
1320 1321
    if (info->alias)
        return 1;
1322 1323 1324 1325 1326 1327
    return 0;
}


void virDomainDeviceInfoClear(virDomainDeviceInfoPtr info)
{
D
Daniel P. Berrange 已提交
1328
    VIR_FREE(info->alias);
1329 1330 1331 1332 1333
    memset(&info->addr, 0, sizeof(info->addr));
    info->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE;
}


1334 1335 1336
static int virDomainDeviceInfoClearAlias(virDomainDefPtr def ATTRIBUTE_UNUSED,
                                         virDomainDeviceInfoPtr info,
                                         void *opaque ATTRIBUTE_UNUSED)
1337
{
1338 1339 1340 1341 1342 1343 1344 1345 1346
    VIR_FREE(info->alias);
    return 0;
}

static int virDomainDeviceInfoClearPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED,
                                              virDomainDeviceInfoPtr info,
                                              void *opaque ATTRIBUTE_UNUSED)
{
    if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
1347 1348 1349
        memset(&info->addr, 0, sizeof(info->addr));
        info->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE;
    }
1350
    return 0;
1351 1352
}

1353 1354 1355
int virDomainDeviceInfoIterate(virDomainDefPtr def,
                               virDomainDeviceInfoCallback cb,
                               void *opaque)
1356 1357 1358 1359
{
    int i;

    for (i = 0; i < def->ndisks ; i++)
1360 1361
        if (cb(def, &def->disks[i]->info, opaque) < 0)
            return -1;
1362
    for (i = 0; i < def->nnets ; i++)
1363 1364
        if (cb(def, &def->nets[i]->info, opaque) < 0)
            return -1;
1365
    for (i = 0; i < def->nsounds ; i++)
1366 1367
        if (cb(def, &def->sounds[i]->info, opaque) < 0)
            return -1;
1368
    for (i = 0; i < def->nhostdevs ; i++)
1369 1370
        if (cb(def, &def->hostdevs[i]->info, opaque) < 0)
            return -1;
1371
    for (i = 0; i < def->nvideos ; i++)
1372 1373
        if (cb(def, &def->videos[i]->info, opaque) < 0)
            return -1;
1374
    for (i = 0; i < def->ncontrollers ; i++)
1375 1376
        if (cb(def, &def->controllers[i]->info, opaque) < 0)
            return -1;
E
Eric Blake 已提交
1377 1378 1379
    for (i = 0; i < def->nsmartcards ; i++)
        if (cb(def, &def->smartcards[i]->info, opaque) < 0)
            return -1;
1380
    for (i = 0; i < def->nserials ; i++)
1381 1382
        if (cb(def, &def->serials[i]->info, opaque) < 0)
            return -1;
1383
    for (i = 0; i < def->nparallels ; i++)
1384 1385
        if (cb(def, &def->parallels[i]->info, opaque) < 0)
            return -1;
1386
    for (i = 0; i < def->nchannels ; i++)
1387 1388
        if (cb(def, &def->channels[i]->info, opaque) < 0)
            return -1;
1389
    for (i = 0; i < def->ninputs ; i++)
1390 1391
        if (cb(def, &def->inputs[i]->info, opaque) < 0)
            return -1;
1392
    for (i = 0; i < def->nfss ; i++)
1393 1394
        if (cb(def, &def->fss[i]->info, opaque) < 0)
            return -1;
1395
    if (def->watchdog)
1396 1397
        if (cb(def, &def->watchdog->info, opaque) < 0)
            return -1;
1398 1399 1400
    if (def->memballoon)
        if (cb(def, &def->memballoon->info, opaque) < 0)
            return -1;
1401
    if (def->console)
1402 1403 1404
        if (cb(def, &def->console->info, opaque) < 0)
            return -1;
    return 0;
1405 1406 1407 1408 1409
}


void virDomainDefClearPCIAddresses(virDomainDefPtr def)
{
1410
    virDomainDeviceInfoIterate(def, virDomainDeviceInfoClearPCIAddress, NULL);
D
Daniel P. Berrange 已提交
1411 1412 1413 1414
}

void virDomainDefClearDeviceAliases(virDomainDefPtr def)
{
1415
    virDomainDeviceInfoIterate(def, virDomainDeviceInfoClearAlias, NULL);
1416 1417 1418
}


1419 1420 1421
/* Generate a string representation of a device address
 * @param address Device address to stringify
 */
E
Eric Blake 已提交
1422 1423 1424 1425
static int ATTRIBUTE_NONNULL(2)
virDomainDeviceInfoFormat(virBufferPtr buf,
                          virDomainDeviceInfoPtr info,
                          int flags)
1426
{
D
Daniel P. Berrange 已提交
1427 1428
    if (info->alias &&
        !(flags & VIR_DOMAIN_XML_INACTIVE)) {
1429
        virBufferAsprintf(buf, "      <alias name='%s'/>\n", info->alias);
D
Daniel P. Berrange 已提交
1430 1431
    }

1432 1433 1434 1435
    if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
        return 0;

    /* We'll be in domain/devices/[device type]/ so 3 level indent */
1436
    virBufferAsprintf(buf, "      <address type='%s'",
1437 1438 1439 1440
                      virDomainDeviceAddressTypeToString(info->type));

    switch (info->type) {
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI:
1441
        virBufferAsprintf(buf, " domain='0x%.4x' bus='0x%.2x' slot='0x%.2x' function='0x%.1x'",
1442 1443 1444 1445 1446 1447
                          info->addr.pci.domain,
                          info->addr.pci.bus,
                          info->addr.pci.slot,
                          info->addr.pci.function);
        break;

1448
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE:
1449
        virBufferAsprintf(buf, " controller='%d' bus='%d' unit='%d'",
1450 1451 1452 1453 1454
                          info->addr.drive.controller,
                          info->addr.drive.bus,
                          info->addr.drive.unit);
        break;

1455
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL:
1456
        virBufferAsprintf(buf, " controller='%d' bus='%d' port='%d'",
1457
                          info->addr.vioserial.controller,
1458 1459
                          info->addr.vioserial.bus,
                          info->addr.vioserial.port);
1460 1461
        break;

E
Eric Blake 已提交
1462
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCID:
1463
        virBufferAsprintf(buf, " controller='%d' slot='%d'",
E
Eric Blake 已提交
1464 1465 1466 1467
                          info->addr.ccid.controller,
                          info->addr.ccid.slot);
        break;

1468
    default:
1469
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480
                             _("unknown address type '%d'"), info->type);
        return -1;
    }

    virBufferAddLit(buf, "/>\n");

    return 0;
}


static int
1481
virDomainDevicePCIAddressParseXML(xmlNodePtr node,
1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494
                                  virDomainDevicePCIAddressPtr addr)
{
    char *domain, *slot, *bus, *function;
    int ret = -1;

    memset(addr, 0, sizeof(*addr));

    domain   = virXMLPropString(node, "domain");
    bus      = virXMLPropString(node, "bus");
    slot     = virXMLPropString(node, "slot");
    function = virXMLPropString(node, "function");

    if (domain &&
1495
        virStrToLong_ui(domain, NULL, 0, &addr->domain) < 0) {
1496
        virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1497 1498 1499 1500 1501
                             _("Cannot parse <address> 'domain' attribute"));
        goto cleanup;
    }

    if (bus &&
1502
        virStrToLong_ui(bus, NULL, 0, &addr->bus) < 0) {
1503
        virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1504 1505 1506 1507 1508
                             _("Cannot parse <address> 'bus' attribute"));
        goto cleanup;
    }

    if (slot &&
1509
        virStrToLong_ui(slot, NULL, 0, &addr->slot) < 0) {
1510
        virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1511 1512 1513 1514 1515
                             _("Cannot parse <address> 'slot' attribute"));
        goto cleanup;
    }

    if (function &&
1516
        virStrToLong_ui(function, NULL, 0, &addr->function) < 0) {
1517
        virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1518 1519 1520 1521 1522
                             _("Cannot parse <address> 'function' attribute"));
        goto cleanup;
    }

    if (!virDomainDevicePCIAddressIsValid(addr)) {
1523
        virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538
                             _("Insufficient specification for PCI address"));
        goto cleanup;
    }

    ret = 0;

cleanup:
    VIR_FREE(domain);
    VIR_FREE(bus);
    VIR_FREE(slot);
    VIR_FREE(function);
    return ret;
}


1539
static int
1540
virDomainDeviceDriveAddressParseXML(xmlNodePtr node,
1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553
                                    virDomainDeviceDriveAddressPtr addr)
{
    char *bus, *unit, *controller;
    int ret = -1;

    memset(addr, 0, sizeof(*addr));

    controller = virXMLPropString(node, "controller");
    bus = virXMLPropString(node, "bus");
    unit = virXMLPropString(node, "unit");

    if (controller &&
        virStrToLong_ui(controller, NULL, 10, &addr->controller) < 0) {
1554
        virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1555 1556 1557 1558 1559 1560
                             _("Cannot parse <address> 'controller' attribute"));
        goto cleanup;
    }

    if (bus &&
        virStrToLong_ui(bus, NULL, 10, &addr->bus) < 0) {
1561
        virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1562 1563 1564 1565 1566 1567
                             _("Cannot parse <address> 'bus' attribute"));
        goto cleanup;
    }

    if (unit &&
        virStrToLong_ui(unit, NULL, 10, &addr->unit) < 0) {
1568
        virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1569 1570 1571 1572 1573
                             _("Cannot parse <address> 'unit' attribute"));
        goto cleanup;
    }

    if (!virDomainDeviceDriveAddressIsValid(addr)) {
1574
        virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587
                             _("Insufficient specification for drive address"));
        goto cleanup;
    }

    ret = 0;

cleanup:
    VIR_FREE(controller);
    VIR_FREE(bus);
    VIR_FREE(unit);
    return ret;
}

1588 1589 1590 1591 1592 1593 1594

static int
virDomainDeviceVirtioSerialAddressParseXML(
    xmlNodePtr node,
    virDomainDeviceVirtioSerialAddressPtr addr
)
{
1595
    char *controller, *bus, *port;
1596 1597 1598 1599 1600 1601
    int ret = -1;

    memset(addr, 0, sizeof(*addr));

    controller = virXMLPropString(node, "controller");
    bus = virXMLPropString(node, "bus");
1602
    port = virXMLPropString(node, "port");
1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617

    if (controller &&
        virStrToLong_ui(controller, NULL, 10, &addr->controller) < 0) {
        virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                             _("Cannot parse <address> 'controller' attribute"));
        goto cleanup;
    }

    if (bus &&
        virStrToLong_ui(bus, NULL, 10, &addr->bus) < 0) {
        virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                             _("Cannot parse <address> 'bus' attribute"));
        goto cleanup;
    }

1618 1619 1620 1621 1622 1623 1624
    if (port &&
        virStrToLong_ui(port, NULL, 10, &addr->port) < 0) {
        virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                             _("Cannot parse <address> 'port' attribute"));
        goto cleanup;
    }

1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636
    if (!virDomainDeviceVirtioSerialAddressIsValid(addr)) {
        virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                             _("Insufficient specification for "
                               "virtio serial address"));
        goto cleanup;
    }

    ret = 0;

cleanup:
    VIR_FREE(controller);
    VIR_FREE(bus);
E
Eric Blake 已提交
1637
    VIR_FREE(port);
1638 1639 1640
    return ret;
}

E
Eric Blake 已提交
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
static int
virDomainDeviceCcidAddressParseXML(xmlNodePtr node,
                                   virDomainDeviceCcidAddressPtr addr)
{
    char *controller, *slot;
    int ret = -1;

    memset(addr, 0, sizeof(*addr));

    controller = virXMLPropString(node, "controller");
    slot = virXMLPropString(node, "slot");

    if (controller &&
        virStrToLong_ui(controller, NULL, 10, &addr->controller) < 0) {
        virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                             _("Cannot parse <address> 'controller' attribute"));
        goto cleanup;
    }

    if (slot &&
        virStrToLong_ui(slot, NULL, 10, &addr->slot) < 0) {
        virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                             _("Cannot parse <address> 'slot' attribute"));
        goto cleanup;
    }

    ret = 0;

cleanup:
    VIR_FREE(controller);
    VIR_FREE(slot);
    return ret;
}

1675 1676 1677 1678
/* Parse the XML definition for a device address
 * @param node XML nodeset to parse for device address definition
 */
static int
1679
virDomainDeviceInfoParseXML(xmlNodePtr node,
1680
                            virDomainDeviceInfoPtr info,
D
Daniel P. Berrange 已提交
1681
                            int flags)
1682 1683 1684
{
    xmlNodePtr cur;
    xmlNodePtr address = NULL;
D
Daniel P. Berrange 已提交
1685
    xmlNodePtr alias = NULL;
1686 1687 1688 1689 1690 1691 1692 1693
    char *type = NULL;
    int ret = -1;

    virDomainDeviceInfoClear(info);

    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
D
Daniel P. Berrange 已提交
1694 1695 1696 1697 1698 1699
            if (alias == NULL &&
                !(flags & VIR_DOMAIN_XML_INACTIVE) &&
                xmlStrEqual(cur->name, BAD_CAST "alias")) {
                alias = cur;
            } else if (address == NULL &&
                       xmlStrEqual(cur->name, BAD_CAST "address")) {
1700 1701 1702 1703 1704 1705
                address = cur;
            }
        }
        cur = cur->next;
    }

D
Daniel P. Berrange 已提交
1706 1707 1708
    if (alias)
        info->alias = virXMLPropString(alias, "name");

1709 1710 1711 1712 1713 1714 1715
    if (!address)
        return 0;

    type = virXMLPropString(address, "type");

    if (type) {
        if ((info->type = virDomainDeviceAddressTypeFromString(type)) < 0) {
1716
            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
1717 1718 1719 1720
                                 _("unknown address type '%s'"), type);
            goto cleanup;
        }
    } else {
1721
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
1722
                             "%s", _("No type specified for device address"));
1723 1724 1725 1726 1727
        goto cleanup;
    }

    switch (info->type) {
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI:
1728
        if (virDomainDevicePCIAddressParseXML(address, &info->addr.pci) < 0)
1729 1730 1731
            goto cleanup;
        break;

1732
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE:
1733
        if (virDomainDeviceDriveAddressParseXML(address, &info->addr.drive) < 0)
1734 1735 1736
            goto cleanup;
        break;

1737 1738 1739 1740 1741 1742
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL:
        if (virDomainDeviceVirtioSerialAddressParseXML
                (address, &info->addr.vioserial) < 0)
            goto cleanup;
        break;

E
Eric Blake 已提交
1743 1744 1745 1746 1747
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCID:
        if (virDomainDeviceCcidAddressParseXML(address, &info->addr.ccid) < 0)
            goto cleanup;
        break;

1748 1749
    default:
        /* Should not happen */
1750
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
1751
                             "%s", _("Unknown device address type"));
1752 1753 1754 1755 1756 1757
        goto cleanup;
    }

    ret = 0;

cleanup:
D
Daniel P. Berrange 已提交
1758 1759
    if (ret == -1)
        VIR_FREE(info->alias);
1760 1761 1762 1763
    VIR_FREE(type);
    return ret;
}

1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807
static int
virDomainDeviceBootParseXML(xmlNodePtr node,
                            int *bootIndex,
                            virBitmapPtr bootMap)
{
    char *order;
    int boot;
    int ret = -1;

    order = virXMLPropString(node, "order");
    if (!order) {
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                            "%s", _("missing boot order attribute"));
        goto cleanup;
    } else if (virStrToLong_i(order, NULL, 10, &boot) < 0 ||
               boot <= 0) {
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                _("incorrect boot order '%s', expecting positive integer"),
                order);
        goto cleanup;
    }

    if (bootMap) {
        bool set;
        if (virBitmapGetBit(bootMap, boot - 1, &set) < 0) {
            virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                    _("boot orders have to be contiguous and starting from 1"));
            goto cleanup;
        } else if (set) {
            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                    _("boot order %d used for more than one device"), boot);
            goto cleanup;
        }
        ignore_value(virBitmapSetBit(bootMap, boot - 1));
    }

    *bootIndex = boot;
    ret = 0;

cleanup:
    VIR_FREE(order);
    return ret;
}

1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824
static int
virDomainParseLegacyDeviceAddress(char *devaddr,
                                  virDomainDevicePCIAddressPtr pci)
{
    char *tmp;

    /* expected format: <domain>:<bus>:<slot> */
    if (/* domain */
        virStrToLong_ui(devaddr, &tmp, 16, &pci->domain) < 0 || *tmp != ':' ||
        /* bus */
        virStrToLong_ui(tmp + 1, &tmp, 16, &pci->bus) < 0 || *tmp != ':' ||
        /* slot */
        virStrToLong_ui(tmp + 1, NULL, 16, &pci->slot) < 0)
        return -1;

    return 0;
}
1825

1826
int
1827
virDomainDiskDefAssignAddress(virCapsPtr caps, virDomainDiskDefPtr def)
1828 1829
{
    int idx = virDiskNameToIndex(def->dst);
1830 1831
    if (idx < 0)
        return -1;
1832 1833 1834 1835

    switch (def->bus) {
    case VIR_DOMAIN_DISK_BUS_SCSI:
        def->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE;
1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858

        if (caps->hasWideScsiBus) {
            /* For a wide SCSI bus we define the default mapping to be
             * 16 units per bus, 1 bus per controller, many controllers.
             * Unit 7 is the SCSI controller itself. Therefore unit 7
             * cannot be assigned to disks and is skipped.
             */
            def->info.addr.drive.controller = idx / 15;
            def->info.addr.drive.bus = 0;
            def->info.addr.drive.unit = idx % 15;

            /* Skip the SCSI controller at unit 7 */
            if (def->info.addr.drive.unit >= 7) {
                ++def->info.addr.drive.unit;
            }
        } else {
            /* For a narrow SCSI bus we define the default mapping to be
             * 7 units per bus, 1 bus per controller, many controllers */
            def->info.addr.drive.controller = idx / 7;
            def->info.addr.drive.bus = 0;
            def->info.addr.drive.unit = idx % 7;
        }

1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882
        break;

    case VIR_DOMAIN_DISK_BUS_IDE:
        /* For IDE we define the default mapping to be 2 units
         * per bus, 2 bus per controller, many controllers */
        def->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE;
        def->info.addr.drive.controller = idx / 4;
        def->info.addr.drive.bus = (idx % 4) / 2;
        def->info.addr.drive.unit = (idx % 2);
        break;

    case VIR_DOMAIN_DISK_BUS_FDC:
        /* For FDC we define the default mapping to be 2 units
         * per bus, 1 bus per controller, many controllers */
        def->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE;
        def->info.addr.drive.controller = idx / 2;
        def->info.addr.drive.bus = 0;
        def->info.addr.drive.unit = idx % 2;
        break;

    default:
        /* Other disk bus's aren't controller based */
        break;
    }
1883 1884

    return 0;
1885 1886
}

1887 1888 1889 1890
/* Parse the XML definition for a disk
 * @param node XML nodeset to parse for disk definition
 */
static virDomainDiskDefPtr
1891 1892
virDomainDiskDefParseXML(virCapsPtr caps,
                         xmlNodePtr node,
1893 1894 1895
                         virBitmapPtr bootMap,
                         int flags)
{
1896
    virDomainDiskDefPtr def;
M
MORITA Kazutaka 已提交
1897
    xmlNodePtr cur, host;
1898 1899 1900 1901 1902 1903
    char *type = NULL;
    char *device = NULL;
    char *driverName = NULL;
    char *driverType = NULL;
    char *source = NULL;
    char *target = NULL;
M
MORITA Kazutaka 已提交
1904 1905 1906
    char *protocol = NULL;
    virDomainDiskHostDefPtr hosts = NULL;
    int nhosts = 0;
1907
    char *bus = NULL;
1908
    char *cachetag = NULL;
1909
    char *error_policy = NULL;
M
Matthias Dahl 已提交
1910
    char *iotag = NULL;
1911
    char *devaddr = NULL;
1912
    virStorageEncryptionPtr encryption = NULL;
1913
    char *serial = NULL;
1914 1915

    if (VIR_ALLOC(def) < 0) {
1916
        virReportOOMError();
1917 1918 1919 1920 1921 1922
        return NULL;
    }

    type = virXMLPropString(node, "type");
    if (type) {
        if ((def->type = virDomainDiskTypeFromString(type)) < 0) {
1923
            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
1924 1925 1926 1927 1928 1929 1930 1931 1932 1933
                                 _("unknown disk type '%s'"), type);
            goto error;
        }
    } else {
        def->type = VIR_DOMAIN_DISK_TYPE_FILE;
    }

    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
M
MORITA Kazutaka 已提交
1934
            if ((source == NULL && hosts == NULL) &&
1935 1936
                (xmlStrEqual(cur->name, BAD_CAST "source"))) {

1937 1938
                switch (def->type) {
                case VIR_DOMAIN_DISK_TYPE_FILE:
1939
                    source = virXMLPropString(cur, "file");
1940 1941
                    break;
                case VIR_DOMAIN_DISK_TYPE_BLOCK:
1942
                    source = virXMLPropString(cur, "dev");
1943 1944 1945 1946
                    break;
                case VIR_DOMAIN_DISK_TYPE_DIR:
                    source = virXMLPropString(cur, "dir");
                    break;
M
MORITA Kazutaka 已提交
1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960
                case VIR_DOMAIN_DISK_TYPE_NETWORK:
                    protocol = virXMLPropString(cur, "protocol");
                    if (protocol == NULL) {
                        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                                             "%s", _("missing protocol type"));
                        goto error;
                    }
                    def->protocol = virDomainDiskProtocolTypeFromString(protocol);
                    if (def->protocol < 0) {
                        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                                             _("unknown protocol type '%s'"),
                                             protocol);
                        goto error;
                    }
1961 1962 1963 1964 1965 1966
                    if (!(source = virXMLPropString(cur, "name")) &&
                        def->protocol != VIR_DOMAIN_DISK_PROTOCOL_NBD) {
                        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                                             _("missing name for disk source"));
                        goto error;
                    }
M
MORITA Kazutaka 已提交
1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994
                    host = cur->children;
                    while (host != NULL) {
                        if (host->type == XML_ELEMENT_NODE &&
                            xmlStrEqual(host->name, BAD_CAST "host")) {
                            if (VIR_REALLOC_N(hosts, nhosts + 1) < 0) {
                                virReportOOMError();
                                goto error;
                            }
                            hosts[nhosts].name = NULL;
                            hosts[nhosts].port = NULL;
                            nhosts++;

                            hosts[nhosts - 1].name = virXMLPropString(host, "name");
                            if (!hosts[nhosts - 1].name) {
                                virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                                                     "%s", _("missing name for host"));
                                goto error;
                            }
                            hosts[nhosts - 1].port = virXMLPropString(host, "port");
                            if (!hosts[nhosts - 1].port) {
                                virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                                                     "%s", _("missing port for host"));
                                goto error;
                            }
                        }
                        host = host->next;
                    }
                    break;
1995
                default:
1996
                    virDomainReportError(VIR_ERR_INTERNAL_ERROR,
1997 1998 1999 2000
                                         _("unexpected disk type %s"),
                                         virDomainDiskTypeToString(def->type));
                    goto error;
                }
2001 2002 2003 2004 2005 2006 2007 2008

                /* People sometimes pass a bogus '' source path
                   when they mean to omit the source element
                   completely. eg CDROM without media. This is
                   just a little compatability check to help
                   those broken apps */
                if (source && STREQ(source, ""))
                    VIR_FREE(source);
2009 2010 2011 2012
            } else if ((target == NULL) &&
                       (xmlStrEqual(cur->name, BAD_CAST "target"))) {
                target = virXMLPropString(cur, "dev");
                bus = virXMLPropString(cur, "bus");
2013 2014 2015 2016 2017 2018

                /* HACK: Work around for compat with Xen
                 * driver in previous libvirt releases */
                if (target &&
                    STRPREFIX(target, "ioemu:"))
                    memmove(target, target+6, strlen(target)-5);
2019 2020 2021 2022
            } else if ((driverName == NULL) &&
                       (xmlStrEqual(cur->name, BAD_CAST "driver"))) {
                driverName = virXMLPropString(cur, "name");
                driverType = virXMLPropString(cur, "type");
2023
                cachetag = virXMLPropString(cur, "cache");
2024
                error_policy = virXMLPropString(cur, "error_policy");
M
Matthias Dahl 已提交
2025
                iotag = virXMLPropString(cur, "io");
2026 2027 2028 2029
            } else if (xmlStrEqual(cur->name, BAD_CAST "readonly")) {
                def->readonly = 1;
            } else if (xmlStrEqual(cur->name, BAD_CAST "shareable")) {
                def->shared = 1;
2030 2031
            } else if ((flags & VIR_DOMAIN_XML_INTERNAL_STATUS) &&
                       xmlStrEqual(cur->name, BAD_CAST "state")) {
2032
                /* Legacy back-compat. Don't add any more attributes here */
2033
                devaddr = virXMLPropString(cur, "devaddr");
2034 2035
            } else if (encryption == NULL &&
                       xmlStrEqual(cur->name, BAD_CAST "encryption")) {
2036
                encryption = virStorageEncryptionParseNode(node->doc,
2037 2038 2039
                                                           cur);
                if (encryption == NULL)
                    goto error;
2040 2041 2042
            } else if ((serial == NULL) &&
                       (xmlStrEqual(cur->name, BAD_CAST "serial"))) {
                serial = (char *)xmlNodeGetContent(cur);
2043 2044 2045 2046
            } else if (xmlStrEqual(cur->name, BAD_CAST "boot")) {
                if (virDomainDeviceBootParseXML(cur, &def->bootIndex,
                                                bootMap))
                    goto error;
2047 2048 2049 2050 2051 2052 2053 2054
            }
        }
        cur = cur->next;
    }

    device = virXMLPropString(node, "device");
    if (device) {
        if ((def->device = virDomainDiskDeviceTypeFromString(device)) < 0) {
2055
            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
2056 2057 2058 2059 2060 2061 2062 2063 2064
                                 _("unknown disk device '%s'"), device);
            goto error;
        }
    } else {
        def->device = VIR_DOMAIN_DISK_DEVICE_DISK;
    }

    /* Only CDROM and Floppy devices are allowed missing source path
     * to indicate no media present */
M
MORITA Kazutaka 已提交
2065
    if (source == NULL && hosts == NULL &&
2066 2067
        def->device != VIR_DOMAIN_DISK_DEVICE_CDROM &&
        def->device != VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
2068
        virDomainReportError(VIR_ERR_NO_SOURCE,
2069 2070 2071 2072 2073
                             target ? "%s" : NULL, target);
        goto error;
    }

    if (target == NULL) {
2074
        virDomainReportError(VIR_ERR_NO_TARGET,
2075 2076 2077 2078 2079 2080
                             source ? "%s" : NULL, source);
        goto error;
    }

    if (def->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY &&
        !STRPREFIX(target, "fd")) {
2081
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093
                             _("Invalid floppy device name: %s"), target);
        goto error;
    }

    /* Force CDROM to be listed as read only */
    if (def->device == VIR_DOMAIN_DISK_DEVICE_CDROM)
        def->readonly = 1;

    if (def->device == VIR_DOMAIN_DISK_DEVICE_DISK &&
        !STRPREFIX((const char *)target, "hd") &&
        !STRPREFIX((const char *)target, "sd") &&
        !STRPREFIX((const char *)target, "vd") &&
2094 2095
        !STRPREFIX((const char *)target, "xvd") &&
        !STRPREFIX((const char *)target, "ubd")) {
2096
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
2097 2098 2099 2100 2101 2102
                             _("Invalid harddisk device name: %s"), target);
        goto error;
    }

    if (bus) {
        if ((def->bus = virDomainDiskBusTypeFromString(bus)) < 0) {
2103
            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118
                                 _("unknown disk bus type '%s'"), bus);
            goto error;
        }
    } else {
        if (def->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
            def->bus = VIR_DOMAIN_DISK_BUS_FDC;
        } else {
            if (STRPREFIX(target, "hd"))
                def->bus = VIR_DOMAIN_DISK_BUS_IDE;
            else if (STRPREFIX(target, "sd"))
                def->bus = VIR_DOMAIN_DISK_BUS_SCSI;
            else if (STRPREFIX(target, "vd"))
                def->bus = VIR_DOMAIN_DISK_BUS_VIRTIO;
            else if (STRPREFIX(target, "xvd"))
                def->bus = VIR_DOMAIN_DISK_BUS_XEN;
2119 2120
            else if (STRPREFIX(target, "ubd"))
                def->bus = VIR_DOMAIN_DISK_BUS_UML;
2121 2122 2123 2124 2125 2126 2127
            else
                def->bus = VIR_DOMAIN_DISK_BUS_IDE;
        }
    }

    if (def->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY &&
        def->bus != VIR_DOMAIN_DISK_BUS_FDC) {
2128
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
2129 2130 2131 2132 2133
                             _("Invalid bus type '%s' for floppy disk"), bus);
        goto error;
    }
    if (def->device != VIR_DOMAIN_DISK_DEVICE_FLOPPY &&
        def->bus == VIR_DOMAIN_DISK_BUS_FDC) {
2134
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
2135 2136 2137 2138
                             _("Invalid bus type '%s' for disk"), bus);
        goto error;
    }

2139 2140
    if (cachetag &&
        (def->cachemode = virDomainDiskCacheTypeFromString(cachetag)) < 0) {
2141
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
2142 2143 2144 2145
                             _("unknown disk cache mode '%s'"), cachetag);
        goto error;
    }

2146 2147 2148 2149 2150 2151 2152
    if (error_policy &&
        (def->error_policy = virDomainDiskErrorPolicyTypeFromString(error_policy)) < 0) {
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                             _("unknown disk error policy '%s'"), error_policy);
        goto error;
    }

M
Matthias Dahl 已提交
2153 2154 2155 2156 2157 2158 2159 2160 2161
    if (iotag) {
        if ((def->iomode = virDomainDiskIoTypeFromString(iotag)) < 0 ||
            def->iomode == VIR_DOMAIN_DISK_IO_DEFAULT) {
            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                                 _("unknown disk io mode '%s'"), iotag);
            goto error;
        }
    }

2162
    if (devaddr) {
2163 2164
        if (virDomainParseLegacyDeviceAddress(devaddr,
                                              &def->info.addr.pci) < 0) {
2165
            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
2166 2167 2168 2169 2170 2171
                                 _("Unable to parse devaddr parameter '%s'"),
                                 devaddr);
            goto error;
        }
        def->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
    } else {
2172
        if (virDomainDeviceInfoParseXML(node, &def->info, flags) < 0)
2173
            goto error;
2174 2175
    }

2176 2177 2178 2179
    def->src = source;
    source = NULL;
    def->dst = target;
    target = NULL;
M
MORITA Kazutaka 已提交
2180 2181 2182 2183
    def->hosts = hosts;
    hosts = NULL;
    def->nhosts = nhosts;
    nhosts = 0;
2184 2185 2186 2187
    def->driverName = driverName;
    driverName = NULL;
    def->driverType = driverType;
    driverType = NULL;
2188 2189
    def->encryption = encryption;
    encryption = NULL;
2190 2191
    def->serial = serial;
    serial = NULL;
2192

2193 2194 2195 2196 2197 2198 2199 2200 2201 2202
    if (!def->driverType &&
        caps->defaultDiskDriverType &&
        !(def->driverType = strdup(caps->defaultDiskDriverType)))
        goto no_memory;

    if (!def->driverName &&
        caps->defaultDiskDriverName &&
        !(def->driverName = strdup(caps->defaultDiskDriverName)))
        goto no_memory;

2203
    if (def->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE
2204
        && virDomainDiskDefAssignAddress(caps, def) < 0)
2205
        goto error;
2206

2207 2208 2209 2210 2211
cleanup:
    VIR_FREE(bus);
    VIR_FREE(type);
    VIR_FREE(target);
    VIR_FREE(source);
M
MORITA Kazutaka 已提交
2212
    while (nhosts > 0) {
2213
        virDomainDiskHostDefFree(&hosts[nhosts - 1]);
M
MORITA Kazutaka 已提交
2214 2215 2216 2217
        nhosts--;
    }
    VIR_FREE(hosts);
    VIR_FREE(protocol);
2218 2219 2220
    VIR_FREE(device);
    VIR_FREE(driverType);
    VIR_FREE(driverName);
2221
    VIR_FREE(cachetag);
2222
    VIR_FREE(error_policy);
M
Matthias Dahl 已提交
2223
    VIR_FREE(iotag);
2224
    VIR_FREE(devaddr);
2225
    VIR_FREE(serial);
2226
    virStorageEncryptionFree(encryption);
2227 2228 2229

    return def;

2230 2231 2232
no_memory:
    virReportOOMError();

2233 2234 2235 2236 2237 2238 2239
 error:
    virDomainDiskDefFree(def);
    def = NULL;
    goto cleanup;
}


2240 2241 2242 2243
/* Parse the XML definition for a controller
 * @param node XML nodeset to parse for controller definition
 */
static virDomainControllerDefPtr
2244
virDomainControllerDefParseXML(xmlNodePtr node,
2245 2246 2247 2248 2249
                               int flags)
{
    virDomainControllerDefPtr def;
    char *type = NULL;
    char *idx = NULL;
2250
    char *model = NULL;
2251 2252

    if (VIR_ALLOC(def) < 0) {
2253
        virReportOOMError();
2254 2255 2256 2257 2258
        return NULL;
    }

    type = virXMLPropString(node, "type");
    if (type) {
2259
        if ((def->type = virDomainControllerTypeFromString(type)) < 0) {
2260
            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
2261
                                 _("Unknown controller type '%s'"), type);
2262 2263 2264 2265 2266 2267 2268
            goto error;
        }
    }

    idx = virXMLPropString(node, "index");
    if (idx) {
        if (virStrToLong_i(idx, NULL, 10, &def->idx) < 0) {
2269
            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
2270
                                 _("Cannot parse controller index %s"), idx);
2271 2272 2273 2274
            goto error;
        }
    }

2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285
    model = virXMLPropString(node, "model");
    if (model) {
        if ((def->model = virDomainControllerModelTypeFromString(model)) < 0) {
            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                                 _("Unknown model type '%s'"), model);
            goto error;
        }
    } else {
        def->model = -1;
    }

2286
    if (virDomainDeviceInfoParseXML(node, &def->info, flags) < 0)
2287 2288
        goto error;

2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326
    switch (def->type) {
    case VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL: {
        char *ports = virXMLPropString(node, "ports");
        if (ports) {
            int r = virStrToLong_i(ports, NULL, 10,
                                   &def->opts.vioserial.ports);
            if (r != 0 || def->opts.vioserial.ports < 0) {
                virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                                     _("Invalid ports: %s"), ports);
                VIR_FREE(ports);
                goto error;
            }
        } else {
            def->opts.vioserial.ports = -1;
        }
        VIR_FREE(ports);

        char *vectors = virXMLPropString(node, "vectors");
        if (vectors) {
            int r = virStrToLong_i(vectors, NULL, 10,
                                   &def->opts.vioserial.vectors);
            if (r != 0 || def->opts.vioserial.vectors < 0) {
                virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                                     _("Invalid vectors: %s"), vectors);
                VIR_FREE(vectors);
                goto error;
            }
        } else {
            def->opts.vioserial.vectors = -1;
        }
        VIR_FREE(vectors);
        break;
    }

    default:
        break;
    }

2327 2328
    if (def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
2329
        virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2330
                             _("Controllers must use the 'pci' address type"));
2331 2332 2333 2334 2335 2336
        goto error;
    }

cleanup:
    VIR_FREE(type);
    VIR_FREE(idx);
2337
    VIR_FREE(model);
2338 2339 2340 2341 2342 2343 2344 2345 2346

    return def;

 error:
    virDomainControllerDefFree(def);
    def = NULL;
    goto cleanup;
}

2347 2348 2349 2350
/* Parse the XML definition for a disk
 * @param node XML nodeset to parse for disk definition
 */
static virDomainFSDefPtr
2351
virDomainFSDefParseXML(xmlNodePtr node,
2352
                       int flags) {
2353 2354 2355 2356 2357
    virDomainFSDefPtr def;
    xmlNodePtr cur;
    char *type = NULL;
    char *source = NULL;
    char *target = NULL;
2358
    char *accessmode = NULL;
2359 2360

    if (VIR_ALLOC(def) < 0) {
2361
        virReportOOMError();
2362 2363 2364 2365 2366 2367
        return NULL;
    }

    type = virXMLPropString(node, "type");
    if (type) {
        if ((def->type = virDomainFSTypeFromString(type)) < 0) {
2368
            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
2369 2370 2371 2372 2373 2374 2375
                                 _("unknown filesystem type '%s'"), type);
            goto error;
        }
    } else {
        def->type = VIR_DOMAIN_FS_TYPE_MOUNT;
    }

2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386
    accessmode = virXMLPropString(node, "accessmode");
    if (accessmode) {
        if ((def->accessmode = virDomainFSAccessModeTypeFromString(accessmode)) < 0) {
            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                                 _("unknown accessmode '%s'"), accessmode);
            goto error;
        }
    } else {
        def->accessmode = VIR_DOMAIN_FS_ACCESSMODE_PASSTHROUGH;
    }

2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411
    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
            if ((source == NULL) &&
                (xmlStrEqual(cur->name, BAD_CAST "source"))) {

                if (def->type == VIR_DOMAIN_FS_TYPE_MOUNT)
                    source = virXMLPropString(cur, "dir");
                else if (def->type == VIR_DOMAIN_FS_TYPE_FILE)
                    source = virXMLPropString(cur, "file");
                else if (def->type == VIR_DOMAIN_FS_TYPE_BLOCK)
                    source = virXMLPropString(cur, "dev");
                else if (def->type == VIR_DOMAIN_FS_TYPE_TEMPLATE)
                    source = virXMLPropString(cur, "name");
            } else if ((target == NULL) &&
                       (xmlStrEqual(cur->name, BAD_CAST "target"))) {
                target = virXMLPropString(cur, "dir");
            } else if (xmlStrEqual(cur->name, BAD_CAST "readonly")) {
                def->readonly = 1;
            }
        }
        cur = cur->next;
    }

    if (source == NULL) {
2412
        virDomainReportError(VIR_ERR_NO_SOURCE,
2413 2414 2415 2416 2417
                             target ? "%s" : NULL, target);
        goto error;
    }

    if (target == NULL) {
2418
        virDomainReportError(VIR_ERR_NO_TARGET,
2419 2420 2421 2422 2423 2424 2425 2426 2427
                             source ? "%s" : NULL, source);
        goto error;
    }

    def->src = source;
    source = NULL;
    def->dst = target;
    target = NULL;

2428
    if (virDomainDeviceInfoParseXML(node, &def->info, flags) < 0)
2429 2430
        goto error;

2431 2432 2433 2434
cleanup:
    VIR_FREE(type);
    VIR_FREE(target);
    VIR_FREE(source);
2435
    VIR_FREE(accessmode);
2436 2437 2438 2439 2440 2441 2442 2443 2444 2445

    return def;

 error:
    virDomainFSDefFree(def);
    def = NULL;
    goto cleanup;
}


2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585
static int
virVirtualPortProfileParamsParseXML(xmlNodePtr node,
                                    virVirtualPortProfileParamsPtr virtPort)
{
    int ret = -1;
    char *virtPortType;
    char *virtPortManagerID = NULL;
    char *virtPortTypeID = NULL;
    char *virtPortTypeIDVersion = NULL;
    char *virtPortInstanceID = NULL;
    char *virtPortProfileID = NULL;
    xmlNodePtr cur = node->children;
    const char *msg = NULL;

    virtPortType = virXMLPropString(node, "type");
    if (!virtPortType)
        return -1;

    while (cur != NULL) {
        if (xmlStrEqual(cur->name, BAD_CAST "parameters")) {

            virtPortManagerID = virXMLPropString(cur, "managerid");
            virtPortTypeID = virXMLPropString(cur, "typeid");
            virtPortTypeIDVersion = virXMLPropString(cur, "typeidversion");
            virtPortInstanceID = virXMLPropString(cur, "instanceid");
            virtPortProfileID = virXMLPropString(cur, "profileid");

            break;
        }

        cur = cur->next;
    }

    virtPort->virtPortType = VIR_VIRTUALPORT_NONE;

    switch (virVirtualPortTypeFromString(virtPortType)) {

    case VIR_VIRTUALPORT_8021QBG:
        if (virtPortManagerID     != NULL && virtPortTypeID     != NULL &&
            virtPortTypeIDVersion != NULL) {
            unsigned int val;

            if (virStrToLong_ui(virtPortManagerID, NULL, 0, &val)) {
                msg = _("cannot parse value of managerid parameter");
                goto err_exit;
            }

            if (val > 0xff) {
                msg = _("value of managerid out of range");
                goto err_exit;
            }

            virtPort->u.virtPort8021Qbg.managerID = (uint8_t)val;

            if (virStrToLong_ui(virtPortTypeID, NULL, 0, &val)) {
                msg = _("cannot parse value of typeid parameter");
                goto err_exit;
            }

            if (val > 0xffffff) {
                msg = _("value for typeid out of range");
                goto err_exit;
            }

            virtPort->u.virtPort8021Qbg.typeID = (uint32_t)val;

            if (virStrToLong_ui(virtPortTypeIDVersion, NULL, 0, &val)) {
                msg = _("cannot parse value of typeidversion parameter");
                goto err_exit;
            }

            if (val > 0xff) {
                msg = _("value of typeidversion out of range");
                goto err_exit;
            }

            virtPort->u.virtPort8021Qbg.typeIDVersion = (uint8_t)val;

            if (virtPortInstanceID != NULL) {
                if (virUUIDParse(virtPortInstanceID,
                                 virtPort->u.virtPort8021Qbg.instanceID)) {
                    msg = _("cannot parse instanceid parameter as a uuid");
                    goto err_exit;
                }
            } else {
                if (virUUIDGenerate(virtPort->u.virtPort8021Qbg.instanceID)) {
                    msg = _("cannot generate a random uuid for instanceid");
                    goto err_exit;
                }
            }

            virtPort->virtPortType = VIR_VIRTUALPORT_8021QBG;
            ret = 0;
        } else {
            msg = _("a parameter is missing for 802.1Qbg description");
            goto err_exit;
        }
    break;

    case VIR_VIRTUALPORT_8021QBH:
        if (virtPortProfileID != NULL) {
            if (virStrcpyStatic(virtPort->u.virtPort8021Qbh.profileID,
                                virtPortProfileID) != NULL) {
                virtPort->virtPortType = VIR_VIRTUALPORT_8021QBH;
                ret = 0;
            } else {
                msg = _("profileid parameter too long");
                goto err_exit;
            }
        } else {
            msg = _("profileid parameter is missing for 802.1Qbh descripion");
            goto err_exit;
        }
    break;


    default:
    case VIR_VIRTUALPORT_NONE:
    case VIR_VIRTUALPORT_TYPE_LAST:
        msg = _("unknown virtualport type");
        goto err_exit;
    break;
    }

err_exit:

    if (msg)
        virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s", msg);

    VIR_FREE(virtPortManagerID);
    VIR_FREE(virtPortTypeID);
    VIR_FREE(virtPortTypeIDVersion);
    VIR_FREE(virtPortInstanceID);
    VIR_FREE(virtPortProfileID);
    VIR_FREE(virtPortType);

    return ret;
}


2586 2587 2588 2589
/* Parse the XML definition for a network interface
 * @param node XML nodeset to parse for net definition
 * @return 0 on success, -1 on failure
 */
2590
static virDomainNetDefPtr
2591
virDomainNetDefParseXML(virCapsPtr caps,
2592
                        xmlNodePtr node,
2593
                        xmlXPathContextPtr ctxt,
2594 2595 2596
                        virBitmapPtr bootMap,
                        int flags ATTRIBUTE_UNUSED)
{
2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608
    virDomainNetDefPtr def;
    xmlNodePtr cur;
    char *macaddr = NULL;
    char *type = NULL;
    char *network = NULL;
    char *bridge = NULL;
    char *dev = NULL;
    char *ifname = NULL;
    char *script = NULL;
    char *address = NULL;
    char *port = NULL;
    char *model = NULL;
2609
    char *backend = NULL;
2610
    char *txmode = NULL;
2611
    char *filter = NULL;
D
Daniel Veillard 已提交
2612
    char *internal = NULL;
2613
    char *devaddr = NULL;
2614
    char *mode = NULL;
2615
    virNWFilterHashTablePtr filterparams = NULL;
2616 2617
    virVirtualPortProfileParams virtPort;
    bool virtPortParsed = false;
2618 2619
    xmlNodePtr oldnode = ctxt->node;
    int ret;
2620 2621

    if (VIR_ALLOC(def) < 0) {
2622
        virReportOOMError();
2623 2624 2625
        return NULL;
    }

2626 2627
    ctxt->node = node;

2628 2629
    type = virXMLPropString(node, "type");
    if (type != NULL) {
S
Stefan Berger 已提交
2630
        if ((int)(def->type = virDomainNetTypeFromString(type)) < 0) {
2631
            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648
                                 _("unknown interface type '%s'"), type);
            goto error;
        }
    } else {
        def->type = VIR_DOMAIN_NET_TYPE_USER;
    }

    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
            if ((macaddr == NULL) &&
                (xmlStrEqual(cur->name, BAD_CAST "mac"))) {
                macaddr = virXMLPropString(cur, "address");
            } else if ((network == NULL) &&
                       (def->type == VIR_DOMAIN_NET_TYPE_NETWORK) &&
                       (xmlStrEqual(cur->name, BAD_CAST "source"))) {
                network = virXMLPropString(cur, "network");
D
Daniel Veillard 已提交
2649 2650 2651 2652
            } else if ((internal == NULL) &&
                       (def->type == VIR_DOMAIN_NET_TYPE_INTERNAL) &&
                       (xmlStrEqual(cur->name, BAD_CAST "source"))) {
                internal = virXMLPropString(cur, "name");
2653 2654 2655 2656 2657
            } else if ((network == NULL) &&
                       (def->type == VIR_DOMAIN_NET_TYPE_BRIDGE) &&
                       (xmlStrEqual(cur->name, BAD_CAST "source"))) {
                bridge = virXMLPropString(cur, "bridge");
            } else if ((dev == NULL) &&
2658 2659
                       (def->type == VIR_DOMAIN_NET_TYPE_ETHERNET ||
                        def->type == VIR_DOMAIN_NET_TYPE_DIRECT) &&
2660
                       xmlStrEqual(cur->name, BAD_CAST "source")) {
2661 2662
                dev  = virXMLPropString(cur, "dev");
                mode = virXMLPropString(cur, "mode");
2663
            } else if (!virtPortParsed &&
2664 2665 2666 2667 2668
                       (def->type == VIR_DOMAIN_NET_TYPE_DIRECT) &&
                       xmlStrEqual(cur->name, BAD_CAST "virtualport")) {
                if (virVirtualPortProfileParamsParseXML(cur, &virtPort))
                    goto error;
                virtPortParsed = true;
2669 2670 2671 2672 2673 2674 2675 2676
            } else if ((network == NULL) &&
                       ((def->type == VIR_DOMAIN_NET_TYPE_SERVER) ||
                        (def->type == VIR_DOMAIN_NET_TYPE_CLIENT) ||
                        (def->type == VIR_DOMAIN_NET_TYPE_MCAST)) &&
                       (xmlStrEqual(cur->name, BAD_CAST "source"))) {
                address = virXMLPropString(cur, "address");
                port = virXMLPropString(cur, "port");
            } else if ((address == NULL) &&
2677 2678
                       (def->type == VIR_DOMAIN_NET_TYPE_ETHERNET ||
                        def->type == VIR_DOMAIN_NET_TYPE_BRIDGE) &&
2679 2680 2681 2682 2683
                       (xmlStrEqual(cur->name, BAD_CAST "ip"))) {
                address = virXMLPropString(cur, "address");
            } else if ((ifname == NULL) &&
                       xmlStrEqual(cur->name, BAD_CAST "target")) {
                ifname = virXMLPropString(cur, "dev");
2684
                if ((ifname != NULL) &&
C
Chris Lalancette 已提交
2685 2686
                    ((flags & VIR_DOMAIN_XML_INACTIVE) &&
                      (STRPREFIX((const char*)ifname, "vnet")))) {
2687 2688 2689 2690
                    /* An auto-generated target name, blank it out */
                    VIR_FREE(ifname);
                }
            } else if ((script == NULL) &&
2691 2692
                       (def->type == VIR_DOMAIN_NET_TYPE_ETHERNET ||
                        def->type == VIR_DOMAIN_NET_TYPE_BRIDGE) &&
2693 2694 2695 2696
                       xmlStrEqual(cur->name, BAD_CAST "script")) {
                script = virXMLPropString(cur, "path");
            } else if (xmlStrEqual (cur->name, BAD_CAST "model")) {
                model = virXMLPropString(cur, "type");
2697 2698
            } else if (xmlStrEqual (cur->name, BAD_CAST "driver")) {
                backend = virXMLPropString(cur, "name");
2699
                txmode = virXMLPropString(cur, "txmode");
2700 2701
            } else if (xmlStrEqual (cur->name, BAD_CAST "filterref")) {
                filter = virXMLPropString(cur, "filter");
2702
                VIR_FREE(filterparams);
2703
                filterparams = virNWFilterParseParamAttributes(cur);
2704 2705
            } else if ((flags & VIR_DOMAIN_XML_INTERNAL_STATUS) &&
                       xmlStrEqual(cur->name, BAD_CAST "state")) {
2706
                /* Legacy back-compat. Don't add any more attributes here */
2707
                devaddr = virXMLPropString(cur, "devaddr");
2708 2709 2710 2711
            } else if (xmlStrEqual(cur->name, BAD_CAST "boot")) {
                if (virDomainDeviceBootParseXML(cur, &def->bootIndex,
                                                bootMap))
                    goto error;
2712 2713 2714 2715 2716 2717
            }
        }
        cur = cur->next;
    }

    if (macaddr) {
2718
        if (virParseMacAddr((const char *)macaddr, def->mac) < 0) {
2719
            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
2720 2721 2722 2723
                                 _("unable to parse mac address '%s'"),
                                 (const char *)macaddr);
            goto error;
        }
2724
    } else {
2725
        virCapabilitiesGenerateMac(caps, def->mac);
2726 2727
    }

2728
    if (devaddr) {
2729 2730
        if (virDomainParseLegacyDeviceAddress(devaddr,
                                              &def->info.addr.pci) < 0) {
2731
            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
2732 2733 2734 2735 2736 2737
                                 _("Unable to parse devaddr parameter '%s'"),
                                 devaddr);
            goto error;
        }
        def->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
    } else {
2738
        if (virDomainDeviceInfoParseXML(node, &def->info, flags) < 0)
2739 2740 2741 2742 2743 2744 2745
            goto error;
    }

    /* XXX what about ISA/USB based NIC models - once we support
     * them we should make sure address type is correct */
    if (def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
2746
        virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2747
                             _("Network interfaces must use 'pci' address type"));
2748 2749 2750
        goto error;
    }

2751 2752 2753
    switch (def->type) {
    case VIR_DOMAIN_NET_TYPE_NETWORK:
        if (network == NULL) {
2754
            virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2755
    _("No <source> 'network' attribute specified with <interface type='network'/>"));
2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779
            goto error;
        }
        def->data.network.name = network;
        network = NULL;
        break;

    case VIR_DOMAIN_NET_TYPE_ETHERNET:

        if (script != NULL) {
            def->data.ethernet.script = script;
            script = NULL;
        }
        if (dev != NULL) {
            def->data.ethernet.dev = dev;
            dev = NULL;
        }
        if (address != NULL) {
            def->data.ethernet.ipaddr = address;
            address = NULL;
        }
        break;

    case VIR_DOMAIN_NET_TYPE_BRIDGE:
        if (bridge == NULL) {
2780
            virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2781
    _("No <source> 'bridge' attribute specified with <interface type='bridge'/>"));
2782 2783 2784 2785
            goto error;
        }
        def->data.bridge.brname = bridge;
        bridge = NULL;
2786 2787 2788 2789
        if (script != NULL) {
            def->data.bridge.script = script;
            script = NULL;
        }
2790 2791 2792 2793
        if (address != NULL) {
            def->data.bridge.ipaddr = address;
            address = NULL;
        }
2794 2795 2796 2797 2798 2799
        break;

    case VIR_DOMAIN_NET_TYPE_CLIENT:
    case VIR_DOMAIN_NET_TYPE_SERVER:
    case VIR_DOMAIN_NET_TYPE_MCAST:
        if (port == NULL) {
2800
            virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2801
            _("No <source> 'port' attribute specified with socket interface"));
2802 2803 2804
            goto error;
        }
        if (virStrToLong_i(port, NULL, 10, &def->data.socket.port) < 0) {
2805
            virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2806
            _("Cannot parse <source> 'port' attribute with socket interface"));
2807 2808 2809 2810 2811 2812
            goto error;
        }

        if (address == NULL) {
            if (def->type == VIR_DOMAIN_NET_TYPE_CLIENT ||
                def->type == VIR_DOMAIN_NET_TYPE_MCAST) {
2813
                virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2814
        _("No <source> 'address' attribute specified with socket interface"));
2815 2816 2817 2818 2819 2820
                goto error;
            }
        } else {
            def->data.socket.address = address;
            address = NULL;
        }
2821 2822
        break;

D
Daniel Veillard 已提交
2823 2824
    case VIR_DOMAIN_NET_TYPE_INTERNAL:
        if (internal == NULL) {
2825
            virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
D
Daniel Veillard 已提交
2826 2827 2828 2829 2830 2831
        _("No <source> 'name' attribute specified with <interface type='internal'/>"));
            goto error;
        }
        def->data.internal.name = internal;
        internal = NULL;
        break;
2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850

    case VIR_DOMAIN_NET_TYPE_DIRECT:
        if (dev == NULL) {
            virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
        _("No <source> 'dev' attribute specified with <interface type='direct'/>"));
            goto error;
        }

        if (mode != NULL) {
            int m;
            if ((m = virDomainNetdevMacvtapTypeFromString(mode)) < 0) {
                virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                     _("Unkown mode has been specified"));
                goto error;
            }
            def->data.direct.mode = m;
        } else
            def->data.direct.mode = VIR_DOMAIN_NETDEV_MACVTAP_MODE_VEPA;

2851 2852 2853
        if (virtPortParsed)
            def->data.direct.virtPortProfile = virtPort;

2854 2855 2856
        def->data.direct.linkdev = dev;
        dev = NULL;

2857 2858
        if ((flags & VIR_DOMAIN_XML_INACTIVE))
            VIR_FREE(ifname);
2859

2860
        break;
S
Stefan Berger 已提交
2861 2862 2863 2864

    case VIR_DOMAIN_NET_TYPE_USER:
    case VIR_DOMAIN_NET_TYPE_LAST:
        break;
2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881
    }

    if (ifname != NULL) {
        def->ifname = ifname;
        ifname = NULL;
    }

    /* NIC model (see -net nic,model=?).  We only check that it looks
     * reasonable, not that it is a supported NIC type.  FWIW kvm
     * supports these types as of April 2008:
     * i82551 i82557b i82559er ne2k_pci pcnet rtl8139 e1000 virtio
     */
    if (model != NULL) {
        int i;
        for (i = 0 ; i < strlen(model) ; i++) {
            int char_ok = c_isalnum(model[i]) || model[i] == '_';
            if (!char_ok) {
2882 2883
                virDomainReportError(VIR_ERR_INVALID_ARG, "%s",
                                     _("Model name contains invalid characters"));
2884 2885 2886 2887 2888 2889 2890
                goto error;
            }
        }
        def->model = model;
        model = NULL;
    }

2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902
    if (def->model && STREQ(def->model, "virtio")) {
        if (backend != NULL) {
            int name;
            if (((name = virDomainNetBackendTypeFromString(backend)) < 0) ||
                (name == VIR_DOMAIN_NET_BACKEND_TYPE_DEFAULT)) {
                virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                                     _("Unknown interface <driver name='%s'> "
                                       "has been specified"),
                                     backend);
                goto error;
            }
            def->driver.virtio.name = name;
2903
        }
2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915
        if (txmode != NULL) {
            int m;
            if (((m = virDomainNetVirtioTxModeTypeFromString(txmode)) < 0) ||
                (m == VIR_DOMAIN_NET_VIRTIO_TX_MODE_DEFAULT)) {
                virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                                     _("Unknown interface <driver txmode='%s'> "
                                       "has been specified"),
                                     txmode);
                goto error;
            }
            def->driver.virtio.txmode = m;
        }
2916
    }
2917

2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932
    if (filter != NULL) {
        switch (def->type) {
        case VIR_DOMAIN_NET_TYPE_ETHERNET:
        case VIR_DOMAIN_NET_TYPE_NETWORK:
        case VIR_DOMAIN_NET_TYPE_BRIDGE:
            def->filter = filter;
            filter = NULL;
            def->filterparams = filterparams;
            filterparams = NULL;
        break;
        default:
        break;
        }
    }

2933 2934 2935 2936 2937 2938 2939 2940 2941
    ret = virXPathULong("string(./tune/sndbuf)", ctxt, &def->tune.sndbuf);
    if (ret >= 0) {
        def->tune.sndbuf_specified = true;
    } else if (ret == -2) {
        virDomainReportError(VIR_ERR_XML_ERROR, "%s",
                             _("sndbuf must be a positive integer"));
        goto error;
    }

2942
cleanup:
2943
    ctxt->node = oldnode;
2944 2945 2946 2947 2948 2949 2950 2951 2952
    VIR_FREE(macaddr);
    VIR_FREE(network);
    VIR_FREE(address);
    VIR_FREE(port);
    VIR_FREE(ifname);
    VIR_FREE(dev);
    VIR_FREE(script);
    VIR_FREE(bridge);
    VIR_FREE(model);
2953
    VIR_FREE(backend);
2954
    VIR_FREE(txmode);
2955
    VIR_FREE(filter);
2956
    VIR_FREE(type);
D
Daniel Veillard 已提交
2957
    VIR_FREE(internal);
2958
    VIR_FREE(devaddr);
S
Stefan Berger 已提交
2959
    VIR_FREE(mode);
2960
    virNWFilterHashTableFree(filterparams);
2961 2962 2963 2964 2965 2966 2967 2968 2969

    return def;

error:
    virDomainNetDefFree(def);
    def = NULL;
    goto cleanup;
}

2970
static int
2971
virDomainChrDefaultTargetType(virCapsPtr caps, int devtype) {
2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982

    int target = -1;

    switch (devtype) {
    case VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL:
        virDomainReportError(VIR_ERR_XML_ERROR,
                             _("target type must be specified for %s device"),
                             virDomainChrDeviceTypeToString(devtype));
        break;

    case VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE:
2983 2984 2985
        target = caps->defaultConsoleTargetType;
        break;

2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997
    case VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL:
    case VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL:
    default:
        /* No target type yet*/
        target = 0;
        break;
    }

    return target;
}

static int
2998 2999
virDomainChrTargetTypeFromString(virCapsPtr caps,
                                 int devtype,
3000 3001 3002 3003 3004 3005
                                 const char *targetType)
{
    int ret = -1;
    int target = 0;

    if (!targetType) {
3006
        target = virDomainChrDefaultTargetType(caps, devtype);
3007 3008 3009 3010 3011 3012 3013 3014
        goto out;
    }

    switch (devtype) {
    case VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL:
        target = virDomainChrChannelTargetTypeFromString(targetType);
        break;

3015 3016
    case VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE:
        target = virDomainChrConsoleTargetTypeFromString(targetType);
C
Cole Robinson 已提交
3017
        break;
3018

3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031
    case VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL:
    case VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL:
    default:
        /* No target type yet*/
        break;
    }

out:
    ret = target;
    return ret;
}

static int
3032 3033
virDomainChrDefParseTargetXML(virCapsPtr caps,
                              virDomainChrDefPtr def,
3034 3035 3036 3037 3038 3039 3040 3041 3042 3043
                              xmlNodePtr cur,
                              int flags ATTRIBUTE_UNUSED)
{
    int ret = -1;
    unsigned int port;
    const char *targetType = virXMLPropString(cur, "type");
    const char *addrStr = NULL;
    const char *portStr = NULL;

    if ((def->targetType =
3044 3045
        virDomainChrTargetTypeFromString(caps,
                                         def->deviceType, targetType)) < 0) {
3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067
        goto error;
    }

    switch (def->deviceType) {
    case VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL:
        switch (def->targetType) {
        case VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_GUESTFWD:
            addrStr = virXMLPropString(cur, "address");
            portStr = virXMLPropString(cur, "port");

            if (addrStr == NULL) {
                virDomainReportError(VIR_ERR_XML_ERROR, "%s",
                                     _("guestfwd channel does not "
                                       "define a target address"));
                goto error;
            }

            if (VIR_ALLOC(def->target.addr) < 0) {
                virReportOOMError();
                goto error;
            }

3068
            if (virSocketParseAddr(addrStr, def->target.addr, AF_UNSPEC) < 0)
3069 3070
                goto error;

3071
            if (def->target.addr->data.stor.ss_family != AF_INET) {
3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103
                virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                     "%s", _("guestfwd channel only supports "
                                             "IPv4 addresses"));
                goto error;
            }

            if (portStr == NULL) {
                virDomainReportError(VIR_ERR_XML_ERROR, "%s",
                                     _("guestfwd channel does "
                                       "not define a target port"));
                goto error;
            }

            if (virStrToLong_ui(portStr, NULL, 10, &port) < 0) {
                virDomainReportError(VIR_ERR_XML_ERROR,
                                     _("Invalid port number: %s"),
                                     portStr);
                goto error;
            }

            virSocketSetPort(def->target.addr, port);
            break;

        case VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO:
            def->target.name = virXMLPropString(cur, "name");
            break;
        }
        break;

    default:
        portStr = virXMLPropString(cur, "port");
        if (portStr == NULL) {
3104 3105
            /* Set to negative value to indicate we should set it later */
            def->target.port = -1;
3106 3107 3108 3109 3110 3111 3112 3113 3114
            break;
        }

        if (virStrToLong_ui(portStr, NULL, 10, &port) < 0) {
            virDomainReportError(VIR_ERR_XML_ERROR,
                                 _("Invalid port number: %s"),
                                 portStr);
            goto error;
        }
3115
        def->target.port = port;
3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128
        break;
    }


    ret = 0;
error:
    VIR_FREE(targetType);
    VIR_FREE(addrStr);
    VIR_FREE(portStr);

    return ret;
}

3129 3130 3131 3132 3133 3134 3135 3136 3137
/* Parse the source half of the XML definition for a character device,
 * where node is the first element of node->children of the parent
 * element.  def->type must already be valid.  Return -1 on failure,
 * otherwise the number of ignored children (this intentionally skips
 * <target>, which is used by <serial> but not <smartcard>). */
static int
virDomainChrSourceDefParseXML(virDomainChrSourceDefPtr def,
                              xmlNodePtr cur)
{
3138 3139 3140 3141 3142 3143 3144
    char *bindHost = NULL;
    char *bindService = NULL;
    char *connectHost = NULL;
    char *connectService = NULL;
    char *path = NULL;
    char *mode = NULL;
    char *protocol = NULL;
3145
    int remaining = 0;
3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172

    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
            if (xmlStrEqual(cur->name, BAD_CAST "source")) {
                if (mode == NULL)
                    mode = virXMLPropString(cur, "mode");

                switch (def->type) {
                case VIR_DOMAIN_CHR_TYPE_PTY:
                case VIR_DOMAIN_CHR_TYPE_DEV:
                case VIR_DOMAIN_CHR_TYPE_FILE:
                case VIR_DOMAIN_CHR_TYPE_PIPE:
                case VIR_DOMAIN_CHR_TYPE_UNIX:
                    if (path == NULL)
                        path = virXMLPropString(cur, "path");

                    break;

                case VIR_DOMAIN_CHR_TYPE_UDP:
                case VIR_DOMAIN_CHR_TYPE_TCP:
                    if (mode == NULL ||
                        STREQ((const char *)mode, "connect")) {

                        if (connectHost == NULL)
                            connectHost = virXMLPropString(cur, "host");
                        if (connectService == NULL)
                            connectService = virXMLPropString(cur, "service");
3173
                    } else if (STREQ((const char *)mode, "bind")) {
3174 3175 3176 3177
                        if (bindHost == NULL)
                            bindHost = virXMLPropString(cur, "host");
                        if (bindService == NULL)
                            bindService = virXMLPropString(cur, "service");
3178
                    } else {
3179
                        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
3180 3181 3182
                                             _("Unknown source mode '%s'"),
                                             mode);
                        goto error;
3183 3184
                    }

3185
                    if (def->type == VIR_DOMAIN_CHR_TYPE_UDP)
3186 3187 3188 3189 3190
                        VIR_FREE(mode);
                }
            } else if (xmlStrEqual(cur->name, BAD_CAST "protocol")) {
                if (protocol == NULL)
                    protocol = virXMLPropString(cur, "type");
3191 3192
            } else {
                remaining++;
3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209
            }
        }
        cur = cur->next;
    }

    switch (def->type) {
    case VIR_DOMAIN_CHR_TYPE_NULL:
        /* Nada */
        break;

    case VIR_DOMAIN_CHR_TYPE_VC:
        break;

    case VIR_DOMAIN_CHR_TYPE_PTY:
    case VIR_DOMAIN_CHR_TYPE_DEV:
    case VIR_DOMAIN_CHR_TYPE_FILE:
    case VIR_DOMAIN_CHR_TYPE_PIPE:
3210 3211
        if (path == NULL &&
            def->type != VIR_DOMAIN_CHR_TYPE_PTY) {
3212
            virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3213
                       _("Missing source path attribute for char device"));
3214 3215 3216 3217 3218 3219 3220 3221
            goto error;
        }

        def->data.file.path = path;
        path = NULL;
        break;

    case VIR_DOMAIN_CHR_TYPE_STDIO:
3222
    case VIR_DOMAIN_CHR_TYPE_SPICEVMC:
3223 3224 3225 3226 3227 3228 3229
        /* Nada */
        break;

    case VIR_DOMAIN_CHR_TYPE_TCP:
        if (mode == NULL ||
            STREQ(mode, "connect")) {
            if (connectHost == NULL) {
3230
                virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3231
                        _("Missing source host attribute for char device"));
3232 3233 3234
                goto error;
            }
            if (connectService == NULL) {
3235
                virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3236
                     _("Missing source service attribute for char device"));
3237 3238 3239 3240 3241 3242 3243
                goto error;
            }

            def->data.tcp.host = connectHost;
            connectHost = NULL;
            def->data.tcp.service = connectService;
            connectService = NULL;
3244
            def->data.tcp.listen = false;
3245 3246
        } else {
            if (bindHost == NULL) {
3247
                virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3248
                        _("Missing source host attribute for char device"));
3249 3250 3251
                goto error;
            }
            if (bindService == NULL) {
3252
                virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3253
                     _("Missing source service attribute for char device"));
3254 3255 3256 3257 3258 3259 3260
                goto error;
            }

            def->data.tcp.host = bindHost;
            bindHost = NULL;
            def->data.tcp.service = bindService;
            bindService = NULL;
3261
            def->data.tcp.listen = true;
3262
        }
3263

3264
        if (protocol == NULL)
3265
            def->data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_RAW;
3266 3267
        else if ((def->data.tcp.protocol =
                  virDomainChrTcpProtocolTypeFromString(protocol)) < 0) {
3268
            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
3269 3270 3271 3272
                                 _("Unknown protocol '%s'"), protocol);
            goto error;
        }

3273 3274 3275 3276
        break;

    case VIR_DOMAIN_CHR_TYPE_UDP:
        if (connectService == NULL) {
3277
            virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3278
                   _("Missing source service attribute for char device"));
3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294
            goto error;
        }

        def->data.udp.connectHost = connectHost;
        connectHost = NULL;
        def->data.udp.connectService = connectService;
        connectService = NULL;

        def->data.udp.bindHost = bindHost;
        bindHost = NULL;
        def->data.udp.bindService = bindService;
        bindService = NULL;
        break;

    case VIR_DOMAIN_CHR_TYPE_UNIX:
        if (path == NULL) {
3295
            virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3296
                         _("Missing source path attribute for char device"));
3297 3298 3299
            goto error;
        }

3300
        def->data.nix.listen = mode != NULL && STRNEQ(mode, "connect");
3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315

        def->data.nix.path = path;
        path = NULL;
        break;
    }

cleanup:
    VIR_FREE(mode);
    VIR_FREE(protocol);
    VIR_FREE(bindHost);
    VIR_FREE(bindService);
    VIR_FREE(connectHost);
    VIR_FREE(connectService);
    VIR_FREE(path);

3316 3317 3318 3319 3320 3321 3322 3323
    return remaining;

error:
    virDomainChrSourceDefClear(def);
    remaining = -1;
    goto cleanup;
}

M
Michal Novotny 已提交
3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339
/* Create a new character device definition and set
 * default port.
 */
virDomainChrDefPtr
virDomainChrDefNew(void) {
    virDomainChrDefPtr def = NULL;

    if (VIR_ALLOC(def) < 0) {
        virReportOOMError();
        return NULL;
    }

    def->target.port = -1;
    return def;
}

3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387
/* Parse the XML definition for a character device
 * @param node XML nodeset to parse for net definition
 *
 * The XML we're dealing with looks like
 *
 * <serial type="pty">
 *   <source path="/dev/pts/3"/>
 *   <target port="1"/>
 * </serial>
 *
 * <serial type="dev">
 *   <source path="/dev/ttyS0"/>
 *   <target port="1"/>
 * </serial>
 *
 * <serial type="tcp">
 *   <source mode="connect" host="0.0.0.0" service="2445"/>
 *   <target port="1"/>
 * </serial>
 *
 * <serial type="tcp">
 *   <source mode="bind" host="0.0.0.0" service="2445"/>
 *   <target port="1"/>
 *   <protocol type='raw'/>
 * </serial>
 *
 * <serial type="udp">
 *   <source mode="bind" host="0.0.0.0" service="2445"/>
 *   <source mode="connect" host="0.0.0.0" service="2445"/>
 *   <target port="1"/>
 * </serial>
 *
 * <serial type="unix">
 *   <source mode="bind" path="/tmp/foo"/>
 *   <target port="1"/>
 * </serial>
 *
 */
static virDomainChrDefPtr
virDomainChrDefParseXML(virCapsPtr caps,
                        xmlNodePtr node,
                        int flags) {
    xmlNodePtr cur;
    char *type = NULL;
    const char *nodeName;
    virDomainChrDefPtr def;
    int remaining;

M
Michal Novotny 已提交
3388
    if (!(def = virDomainChrDefNew()))
3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425
        return NULL;

    type = virXMLPropString(node, "type");
    if (type == NULL) {
        def->source.type = VIR_DOMAIN_CHR_TYPE_PTY;
    } else if ((def->source.type = virDomainChrTypeFromString(type)) < 0) {
        virDomainReportError(VIR_ERR_XML_ERROR,
                             _("unknown type presented to host for character device: %s"),
                             type);
        goto error;
    }

    nodeName = (const char *) node->name;
    if ((def->deviceType = virDomainChrDeviceTypeFromString(nodeName)) < 0) {
        virDomainReportError(VIR_ERR_XML_ERROR,
                             _("unknown character device type: %s"),
                             nodeName);
    }

    cur = node->children;
    remaining = virDomainChrSourceDefParseXML(&def->source, cur);
    if (remaining < 0)
        goto error;
    if (remaining) {
        while (cur != NULL) {
            if (cur->type == XML_ELEMENT_NODE) {
                if (xmlStrEqual(cur->name, BAD_CAST "target")) {
                    if (virDomainChrDefParseTargetXML(caps, def, cur,
                                                      flags) < 0) {
                        goto error;
                    }
                }
            }
            cur = cur->next;
        }
    }

E
Eric Blake 已提交
3426 3427 3428 3429 3430 3431 3432 3433 3434
    if (def->source.type == VIR_DOMAIN_CHR_TYPE_SPICEVMC) {
        if (def->targetType != VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO) {
            virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                                 _("spicevmc device type only supports "
                                   "virtio"));
            goto error;
        } else {
            def->source.data.spicevmc = VIR_DOMAIN_CHR_SPICEVMC_VDAGENT;
        }
3435 3436
    }

3437 3438 3439 3440 3441 3442
    if (virDomainDeviceInfoParseXML(node, &def->info, flags) < 0)
        goto error;

cleanup:
    VIR_FREE(type);

3443 3444 3445 3446 3447 3448 3449 3450
    return def;

error:
    virDomainChrDefFree(def);
    def = NULL;
    goto cleanup;
}

E
Eric Blake 已提交
3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543
static virDomainSmartcardDefPtr
virDomainSmartcardDefParseXML(xmlNodePtr node,
                              int flags)
{
    xmlNodePtr cur;
    char *mode = NULL;
    char *type = NULL;
    virDomainSmartcardDefPtr def;
    int i;

    if (VIR_ALLOC(def) < 0) {
        virReportOOMError();
        return NULL;
    }

    mode = virXMLPropString(node, "mode");
    if (mode == NULL) {
        virDomainReportError(VIR_ERR_XML_ERROR, "%s",
                             _("missing smartcard device mode"));
        goto error;
    }
    if ((def->type = virDomainSmartcardTypeFromString(mode)) < 0) {
        virDomainReportError(VIR_ERR_XML_ERROR,
                             _("unknown smartcard device mode: %s"),
                             mode);
        goto error;
    }

    switch (def->type) {
    case VIR_DOMAIN_SMARTCARD_TYPE_HOST:
        break;

    case VIR_DOMAIN_SMARTCARD_TYPE_HOST_CERTIFICATES:
        i = 0;
        cur = node->children;
        while (cur) {
            if (cur->type == XML_ELEMENT_NODE &&
                xmlStrEqual(cur->name, BAD_CAST "certificate")) {
                if (i == 3) {
                    virDomainReportError(VIR_ERR_XML_ERROR, "%s",
                                         _("host-certificates mode needs "
                                           "exactly three certificates"));
                    goto error;
                }
                def->data.cert.file[i] = (char *)xmlNodeGetContent(cur);
                if (!def->data.cert.file[i]) {
                    virReportOOMError();
                    goto error;
                }
                i++;
            } else if (cur->type == XML_ELEMENT_NODE &&
                       xmlStrEqual(cur->name, BAD_CAST "database") &&
                       !def->data.cert.database) {
                def->data.cert.database = (char *)xmlNodeGetContent(cur);
                if (!def->data.cert.database) {
                    virReportOOMError();
                    goto error;
                }
                if (*def->data.cert.database != '/') {
                    virDomainReportError(VIR_ERR_XML_ERROR,
                                         _("expecting absolute path: %s"),
                                         def->data.cert.database);
                    goto error;
                }
            }
            cur = cur->next;
        }
        if (i < 3) {
            virDomainReportError(VIR_ERR_XML_ERROR, "%s",
                                 _("host-certificates mode needs "
                                   "exactly three certificates"));
            goto error;
        }
        break;

    case VIR_DOMAIN_SMARTCARD_TYPE_PASSTHROUGH:
        type = virXMLPropString(node, "type");
        if (type == NULL) {
            virDomainReportError(VIR_ERR_XML_ERROR, "%s",
                                 _("passthrough mode requires a character "
                                   "device type attribute"));
            goto error;
        }
        if ((def->data.passthru.type = virDomainChrTypeFromString(type)) < 0) {
            virDomainReportError(VIR_ERR_XML_ERROR,
                                 _("unknown type presented to host for "
                                   "character device: %s"), type);
            goto error;
        }

        cur = node->children;
        if (virDomainChrSourceDefParseXML(&def->data.passthru, cur) < 0)
            goto error;
3544 3545

        if (def->data.passthru.type == VIR_DOMAIN_CHR_TYPE_SPICEVMC) {
E
Eric Blake 已提交
3546 3547
            def->data.passthru.data.spicevmc
                = VIR_DOMAIN_CHR_SPICEVMC_SMARTCARD;
3548
        }
E
Eric Blake 已提交
3549

E
Eric Blake 已提交
3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578
        break;

    default:
        virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                             _("unknown smartcard mode"));
        goto error;
    }

    if (virDomainDeviceInfoParseXML(node, &def->info, flags) < 0)
        goto error;
    if (def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCID) {
        virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                             _("Controllers must use the 'ccid' address type"));
        goto error;
    }

cleanup:
    VIR_FREE(mode);
    VIR_FREE(type);

    return def;

error:
    virDomainSmartcardDefFree(def);
    def = NULL;
    goto cleanup;
}

3579 3580
/* Parse the XML definition for a network interface */
static virDomainInputDefPtr
3581
virDomainInputDefParseXML(const char *ostype,
3582
                          xmlNodePtr node,
3583
                          int flags) {
3584 3585 3586 3587 3588
    virDomainInputDefPtr def;
    char *type = NULL;
    char *bus = NULL;

    if (VIR_ALLOC(def) < 0) {
3589
        virReportOOMError();
3590 3591 3592 3593 3594 3595 3596
        return NULL;
    }

    type = virXMLPropString(node, "type");
    bus = virXMLPropString(node, "bus");

    if (!type) {
3597
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
3598 3599 3600 3601 3602
                             "%s", _("missing input device type"));
        goto error;
    }

    if ((def->type = virDomainInputTypeFromString(type)) < 0) {
3603
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
3604 3605 3606 3607 3608 3609
                             _("unknown input device type '%s'"), type);
        goto error;
    }

    if (bus) {
        if ((def->bus = virDomainInputBusTypeFromString(bus)) < 0) {
3610
            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
3611 3612 3613 3614 3615 3616 3617
                                 _("unknown input bus type '%s'"), bus);
            goto error;
        }

        if (STREQ(ostype, "hvm")) {
            if (def->bus == VIR_DOMAIN_INPUT_BUS_PS2 && /* Only allow mouse for ps2 */
                def->type != VIR_DOMAIN_INPUT_TYPE_MOUSE) {
3618
                virDomainReportError(VIR_ERR_INTERNAL_ERROR,
3619
                                 _("ps2 bus does not support %s input device"),
3620 3621 3622 3623
                                     type);
                goto error;
            }
            if (def->bus == VIR_DOMAIN_INPUT_BUS_XEN) {
3624
                virDomainReportError(VIR_ERR_INTERNAL_ERROR,
3625 3626 3627 3628 3629 3630
                                     _("unsupported input bus %s"),
                                     bus);
                goto error;
            }
        } else {
            if (def->bus != VIR_DOMAIN_INPUT_BUS_XEN) {
3631
                virDomainReportError(VIR_ERR_INTERNAL_ERROR,
3632 3633 3634 3635
                                     _("unsupported input bus %s"),
                                     bus);
            }
            if (def->type != VIR_DOMAIN_INPUT_TYPE_MOUSE) {
3636
                virDomainReportError(VIR_ERR_INTERNAL_ERROR,
3637
                                 _("xen bus does not support %s input device"),
3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652
                                     type);
                goto error;
            }
        }
    } else {
        if (STREQ(ostype, "hvm")) {
            if (def->type == VIR_DOMAIN_INPUT_TYPE_MOUSE)
                def->bus = VIR_DOMAIN_INPUT_BUS_PS2;
            else
                def->bus = VIR_DOMAIN_INPUT_BUS_USB;
        } else {
            def->bus = VIR_DOMAIN_INPUT_BUS_XEN;
        }
    }

3653
    if (virDomainDeviceInfoParseXML(node, &def->info, flags) < 0)
3654 3655
        goto error;

3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668
cleanup:
    VIR_FREE(type);
    VIR_FREE(bus);

    return def;

error:
    virDomainInputDefFree(def);
    def = NULL;
    goto cleanup;
}


3669 3670 3671 3672 3673 3674 3675 3676 3677
/* Parse the XML definition for a clock timer */
static virDomainTimerDefPtr
virDomainTimerDefParseXML(const xmlNodePtr node,
                          xmlXPathContextPtr ctxt,
                          int flags ATTRIBUTE_UNUSED)
{
    char *name = NULL;
    char *present = NULL;
    char *tickpolicy = NULL;
3678
    char *track = NULL;
3679 3680 3681 3682
    char *mode = NULL;

    virDomainTimerDefPtr def;
    xmlNodePtr oldnode = ctxt->node;
3683 3684
    xmlNodePtr catchup;
    int ret;
3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727

    if (VIR_ALLOC(def) < 0) {
        virReportOOMError();
        return NULL;
    }

    ctxt->node = node;

    name = virXMLPropString(node, "name");
    if (name == NULL) {
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                             "%s", _("missing timer name"));
        goto error;
    }
    if ((def->name = virDomainTimerNameTypeFromString(name)) < 0) {
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                             _("unknown timer name '%s'"), name);
        goto error;
    }

    def->present = -1; /* unspecified */
    if ((present = virXMLPropString(node, "present")) != NULL) {
        if (STREQ(present, "yes")) {
            def->present = 1;
        } else if (STREQ(present, "no")) {
            def->present = 0;
        } else {
            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                                 _("unknown timer present value '%s'"), present);
            goto error;
        }
    }

    def->tickpolicy = -1;
    tickpolicy = virXMLPropString(node, "tickpolicy");
    if (tickpolicy != NULL) {
        if ((def->tickpolicy = virDomainTimerTickpolicyTypeFromString(tickpolicy)) < 0) {
            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                                 _("unknown timer tickpolicy '%s'"), tickpolicy);
            goto error;
        }
    }

3728 3729 3730 3731
    def->track = -1;
    track = virXMLPropString(node, "track");
    if (track != NULL) {
        if ((def->track = virDomainTimerTrackTypeFromString(track)) < 0) {
3732
            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
3733
                                 _("unknown timer track '%s'"), track);
3734 3735 3736 3737
            goto error;
        }
    }

3738
    ret = virXPathULong("string(./frequency)", ctxt, &def->frequency);
3739 3740
    if (ret == -1) {
        def->frequency = 0;
3741
    } else if (ret < 0) {
3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                             "%s", _("invalid timer frequency"));
        goto error;
    }

    def->mode = -1;
    mode = virXMLPropString(node, "mode");
    if (mode != NULL) {
        if ((def->mode = virDomainTimerModeTypeFromString(mode)) < 0) {
            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                                 _("unknown timer mode '%s'"), mode);
            goto error;
        }
    }

3757
    catchup = virXPathNode("./catchup", ctxt);
3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787
    if (catchup != NULL) {
        ret = virXPathULong("string(./catchup/@threshold)", ctxt,
                            &def->catchup.threshold);
        if (ret == -1) {
            def->catchup.threshold = 0;
        } else if (ret < 0) {
            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                                 "%s", _("invalid catchup threshold"));
            goto error;
        }

        ret = virXPathULong("string(./catchup/@slew)", ctxt, &def->catchup.slew);
        if (ret == -1) {
            def->catchup.slew = 0;
        } else if (ret < 0) {
            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                                 "%s", _("invalid catchup slew"));
            goto error;
        }

        ret = virXPathULong("string(./catchup/@limit)", ctxt, &def->catchup.limit);
        if (ret == -1) {
            def->catchup.limit = 0;
        } else if (ret < 0) {
            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                                 "%s", _("invalid catchup limit"));
            goto error;
        }
    }

3788 3789 3790 3791
cleanup:
    VIR_FREE(name);
    VIR_FREE(present);
    VIR_FREE(tickpolicy);
3792
    VIR_FREE(track);
3793 3794 3795 3796 3797 3798 3799 3800 3801 3802
    VIR_FREE(mode);
    ctxt->node = oldnode;

    return def;

error:
    VIR_FREE(def);
    goto cleanup;
}

3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851

static int
virDomainGraphicsAuthDefParseXML(xmlNodePtr node, virDomainGraphicsAuthDefPtr def)
{
    char *validTo = NULL;

    def->passwd = virXMLPropString(node, "passwd");

    if (!def->passwd)
        return 0;

    validTo = virXMLPropString(node, "passwdValidTo");
    if (validTo) {
        char *tmp;
        struct tm tm;
        memset(&tm, 0, sizeof(tm));
        /* Expect: YYYY-MM-DDTHH:MM:SS (%d-%d-%dT%d:%d:%d)  eg 2010-11-28T14:29:01 */
        if (/* year */
            virStrToLong_i(validTo, &tmp, 10, &tm.tm_year) < 0 || *tmp != '-' ||
            /* month */
            virStrToLong_i(tmp+1, &tmp, 10, &tm.tm_mon) < 0 || *tmp != '-' ||
            /* day */
            virStrToLong_i(tmp+1, &tmp, 10, &tm.tm_mday) < 0 || *tmp != 'T' ||
            /* hour */
            virStrToLong_i(tmp+1, &tmp, 10, &tm.tm_hour) < 0 || *tmp != ':' ||
            /* minute */
            virStrToLong_i(tmp+1, &tmp, 10, &tm.tm_min) < 0 || *tmp != ':' ||
            /* second */
            virStrToLong_i(tmp+1, &tmp, 10, &tm.tm_sec) < 0 || *tmp != '\0') {
            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                                 _("cannot parse password validity time '%s', expect YYYY-MM-DDTHH:MM:SS"),
                                 validTo);
            VIR_FREE(validTo);
            VIR_FREE(def->passwd);
            return -1;
        }
        VIR_FREE(validTo);

        tm.tm_year -= 1900; /* Human epoch starts at 0 BC, not 1900BC */
        tm.tm_mon--; /* Humans start months at 1, computers at 0 */

        def->validTo = timegm(&tm);
        def->expires = 1;
    }

    return 0;
}


3852 3853
/* Parse the XML definition for a graphics device */
static virDomainGraphicsDefPtr
3854
virDomainGraphicsDefParseXML(xmlNodePtr node, int flags) {
3855 3856 3857 3858
    virDomainGraphicsDefPtr def;
    char *type = NULL;

    if (VIR_ALLOC(def) < 0) {
3859
        virReportOOMError();
3860 3861 3862 3863 3864 3865
        return NULL;
    }

    type = virXMLPropString(node, "type");

    if (!type) {
3866
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
3867 3868 3869 3870 3871
                             "%s", _("missing graphics device type"));
        goto error;
    }

    if ((def->type = virDomainGraphicsTypeFromString(type)) < 0) {
3872
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
3873 3874 3875 3876 3877 3878 3879 3880 3881 3882
                             _("unknown graphics device type '%s'"), type);
        goto error;
    }

    if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
        char *port = virXMLPropString(node, "port");
        char *autoport;

        if (port) {
            if (virStrToLong_i(port, NULL, 10, &def->data.vnc.port) < 0) {
3883
                virDomainReportError(VIR_ERR_INTERNAL_ERROR,
3884 3885 3886 3887 3888 3889 3890
                                     _("cannot parse vnc port %s"), port);
                VIR_FREE(port);
                goto error;
            }
            VIR_FREE(port);
            /* Legacy compat syntax, used -1 for auto-port */
            if (def->data.vnc.port == -1) {
3891 3892
                if (flags & VIR_DOMAIN_XML_INACTIVE)
                    def->data.vnc.port = 0;
3893 3894 3895 3896 3897 3898 3899 3900 3901
                def->data.vnc.autoport = 1;
            }
        } else {
            def->data.vnc.port = 0;
            def->data.vnc.autoport = 1;
        }

        if ((autoport = virXMLPropString(node, "autoport")) != NULL) {
            if (STREQ(autoport, "yes")) {
3902 3903
                if (flags & VIR_DOMAIN_XML_INACTIVE)
                    def->data.vnc.port = 0;
3904 3905 3906 3907 3908 3909
                def->data.vnc.autoport = 1;
            }
            VIR_FREE(autoport);
        }

        def->data.vnc.listenAddr = virXMLPropString(node, "listen");
3910
        def->data.vnc.socket = virXMLPropString(node, "socket");
3911
        def->data.vnc.keymap = virXMLPropString(node, "keymap");
3912

3913 3914 3915 3916
        if (def->data.vnc.listenAddr &&
            !def->data.vnc.listenAddr[0])
            VIR_FREE(def->data.vnc.listenAddr);

3917 3918
        if (virDomainGraphicsAuthDefParseXML(node, &def->data.vnc.auth) < 0)
            goto error;
3919
    } else if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) {
3920 3921 3922 3923 3924 3925 3926 3927
        char *fullscreen = virXMLPropString(node, "fullscreen");

        if (fullscreen != NULL) {
            if (STREQ(fullscreen, "yes")) {
                def->data.sdl.fullscreen = 1;
            } else if (STREQ(fullscreen, "no")) {
                def->data.sdl.fullscreen = 0;
            } else {
3928
                virDomainReportError(VIR_ERR_INTERNAL_ERROR,
3929 3930 3931 3932 3933 3934 3935
                             _("unknown fullscreen value '%s'"), fullscreen);
                VIR_FREE(fullscreen);
                goto error;
            }
            VIR_FREE(fullscreen);
        } else
            def->data.sdl.fullscreen = 0;
3936 3937
        def->data.sdl.xauth = virXMLPropString(node, "xauth");
        def->data.sdl.display = virXMLPropString(node, "display");
3938 3939 3940 3941 3942 3943 3944 3945
    } else if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_RDP) {
        char *port = virXMLPropString(node, "port");
        char *autoport;
        char *replaceUser;
        char *multiUser;

        if (port) {
            if (virStrToLong_i(port, NULL, 10, &def->data.rdp.port) < 0) {
3946
                virDomainReportError(VIR_ERR_INTERNAL_ERROR,
3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980
                                     _("cannot parse rdp port %s"), port);
                VIR_FREE(port);
                goto error;
            }
            VIR_FREE(port);
        } else {
            def->data.rdp.port = 0;
            def->data.rdp.autoport = 1;
        }

        if ((autoport = virXMLPropString(node, "autoport")) != NULL) {
            if (STREQ(autoport, "yes")) {
                if (flags & VIR_DOMAIN_XML_INACTIVE)
                    def->data.rdp.port = 0;
                def->data.rdp.autoport = 1;
            }
            VIR_FREE(autoport);
        }

        if ((replaceUser = virXMLPropString(node, "replaceUser")) != NULL) {
            if (STREQ(replaceUser, "yes")) {
                def->data.rdp.replaceUser = 1;
            }
            VIR_FREE(replaceUser);
        }

        if ((multiUser = virXMLPropString(node, "multiUser")) != NULL) {
            if (STREQ(multiUser, "yes")) {
                def->data.rdp.multiUser = 1;
            }
            VIR_FREE(multiUser);
        }

        def->data.rdp.listenAddr = virXMLPropString(node, "listen");
3981 3982 3983 3984

        if (def->data.rdp.listenAddr &&
            !def->data.rdp.listenAddr[0])
            VIR_FREE(def->data.rdp.listenAddr);
3985 3986 3987 3988 3989 3990 3991 3992 3993
    } else if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP) {
        char *fullscreen = virXMLPropString(node, "fullscreen");

        if (fullscreen != NULL) {
            if (STREQ(fullscreen, "yes")) {
                def->data.desktop.fullscreen = 1;
            } else if (STREQ(fullscreen, "no")) {
                def->data.desktop.fullscreen = 0;
            } else {
3994
                virDomainReportError(VIR_ERR_INTERNAL_ERROR,
3995 3996 3997 3998 3999 4000 4001 4002 4003
                             _("unknown fullscreen value '%s'"), fullscreen);
                VIR_FREE(fullscreen);
                goto error;
            }
            VIR_FREE(fullscreen);
        } else
            def->data.desktop.fullscreen = 0;

        def->data.desktop.display = virXMLPropString(node, "display");
4004
    } else if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) {
4005
        xmlNodePtr cur;
4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047
        char *port = virXMLPropString(node, "port");
        char *tlsPort;
        char *autoport;

        if (port) {
            if (virStrToLong_i(port, NULL, 10, &def->data.spice.port) < 0) {
                virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                                     _("cannot parse spice port %s"), port);
                VIR_FREE(port);
                goto error;
            }
            VIR_FREE(port);
        } else {
            def->data.spice.port = 5900;
        }

        tlsPort = virXMLPropString(node, "tlsPort");
        if (tlsPort) {
            if (virStrToLong_i(tlsPort, NULL, 10, &def->data.spice.tlsPort) < 0) {
                virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                                     _("cannot parse spice tlsPort %s"), tlsPort);
                VIR_FREE(tlsPort);
                goto error;
            }
            VIR_FREE(tlsPort);
        } else {
            def->data.spice.tlsPort = 0;
        }

        if ((autoport = virXMLPropString(node, "autoport")) != NULL) {
            if (STREQ(autoport, "yes")) {
                if (flags & VIR_DOMAIN_XML_INACTIVE) {
                    def->data.spice.port = 0;
                    def->data.spice.tlsPort = 0;
                }
                def->data.spice.autoport = 1;
            }
            VIR_FREE(autoport);
        }

        def->data.spice.listenAddr = virXMLPropString(node, "listen");
        def->data.spice.keymap = virXMLPropString(node, "keymap");
4048 4049 4050 4051 4052

        if (def->data.spice.listenAddr &&
            !def->data.spice.listenAddr[0])
            VIR_FREE(def->data.spice.listenAddr);

4053
        if (virDomainGraphicsAuthDefParseXML(node, &def->data.spice.auth) < 0)
4054
            goto error;
4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067

        cur = node->children;
        while (cur != NULL) {
            if (cur->type == XML_ELEMENT_NODE) {
                if (xmlStrEqual(cur->name, BAD_CAST "channel")) {
                    const char *name, *mode;
                    int nameval, modeval;
                    name = virXMLPropString(cur, "name");
                    mode = virXMLPropString(cur, "mode");

                    if (!name || !mode) {
                        virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                             _("spice channel missing name/mode"));
E
Eric Blake 已提交
4068 4069
                        VIR_FREE(name);
                        VIR_FREE(mode);
4070 4071 4072 4073 4074 4075 4076
                        goto error;
                    }

                    if ((nameval = virDomainGraphicsSpiceChannelNameTypeFromString(name)) < 0) {
                        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                                             _("unknown spice channel name %s"),
                                             name);
E
Eric Blake 已提交
4077 4078
                        VIR_FREE(name);
                        VIR_FREE(mode);
4079 4080 4081 4082 4083 4084
                        goto error;
                    }
                    if ((modeval = virDomainGraphicsSpiceChannelModeTypeFromString(mode)) < 0) {
                        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                                             _("unknown spice channel mode %s"),
                                             mode);
E
Eric Blake 已提交
4085 4086
                        VIR_FREE(name);
                        VIR_FREE(mode);
4087 4088
                        goto error;
                    }
E
Eric Blake 已提交
4089 4090
                    VIR_FREE(name);
                    VIR_FREE(mode);
4091 4092

                    def->data.spice.channels[nameval] = modeval;
4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152
                } else if (xmlStrEqual(cur->name, BAD_CAST "image")) {
                    const char *compression = virXMLPropString(cur, "compression");
                    int compressionVal;

                    if (!compression) {
                        virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                             _("spice image missing compression"));
                        goto error;
                    }

                    if ((compressionVal =
                         virDomainGraphicsSpiceImageCompressionTypeFromString(compression)) <= 0) {
                        virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                             _("unknown spice image compression %s"),
                                             compression);
                        VIR_FREE(compression);
                        goto error;
                    }
                    VIR_FREE(compression);

                    def->data.spice.image = compressionVal;
                } else if (xmlStrEqual(cur->name, BAD_CAST "jpeg")) {
                    const char *compression = virXMLPropString(cur, "compression");
                    int compressionVal;

                    if (!compression) {
                        virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                             _("spice jpeg missing compression"));
                        goto error;
                    }

                    if ((compressionVal =
                         virDomainGraphicsSpiceJpegCompressionTypeFromString(compression)) <= 0) {
                        virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                             _("unknown spice jpeg compression %s"),
                                             compression);
                        VIR_FREE(compression);
                        goto error;
                    }
                    VIR_FREE(compression);

                    def->data.spice.jpeg = compressionVal;
                } else if (xmlStrEqual(cur->name, BAD_CAST "zlib")) {
                    const char *compression = virXMLPropString(cur, "compression");
                    int compressionVal;

                    if (!compression) {
                        virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                             _("spice zlib missing compression"));
                        goto error;
                    }

                    if ((compressionVal =
                         virDomainGraphicsSpiceZlibCompressionTypeFromString(compression)) <= 0) {
                        virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                             _("unknown spice zlib compression %s"),
                                             compression);
                        VIR_FREE(compression);
                        goto error;
                    }
4153
                    VIR_FREE(compression);
4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176

                    def->data.spice.zlib = compressionVal;
                } else if (xmlStrEqual(cur->name, BAD_CAST "playback")) {
                    const char *compression = virXMLPropString(cur, "compression");
                    int compressionVal;

                    if (!compression) {
                        virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                             _("spice playback missing compression"));
                        goto error;
                    }

                    if ((compressionVal =
                         virDomainGraphicsSpicePlaybackCompressionTypeFromString(compression)) <= 0) {
                        virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                             _("unknown spice playback compression"));
                        VIR_FREE(compression);
                        goto error;

                    }
                    VIR_FREE(compression);

                    def->data.spice.playback = compressionVal;
4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196
                } else if (xmlStrEqual(cur->name, BAD_CAST "streaming")) {
                    const char *mode = virXMLPropString(cur, "mode");
                    int modeVal;

                    if (!mode) {
                        virDomainReportError(VIR_ERR_XML_ERROR, "%s",
                                             _("spice streaming missing mode"));
                        goto error;
                    }
                    if ((modeVal =
                         virDomainGraphicsSpiceStreamingModeTypeFromString(mode)) <= 0) {
                        virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                             _("unknown spice streaming mode"));
                        VIR_FREE(mode);
                        goto error;

                    }
                    VIR_FREE(mode);

                    def->data.spice.streaming = modeVal;
4197 4198 4199 4200
                }
            }
            cur = cur->next;
        }
4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215
    }

cleanup:
    VIR_FREE(type);

    return def;

error:
    virDomainGraphicsDefFree(def);
    def = NULL;
    goto cleanup;
}


static virDomainSoundDefPtr
4216
virDomainSoundDefParseXML(const xmlNodePtr node,
4217 4218
                          int flags)
{
4219 4220 4221 4222
    char *model;
    virDomainSoundDefPtr def;

    if (VIR_ALLOC(def) < 0) {
4223
        virReportOOMError();
4224 4225 4226 4227 4228
        return NULL;
    }

    model = virXMLPropString(node, "model");
    if ((def->model = virDomainSoundModelTypeFromString(model)) < 0) {
4229
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
4230 4231 4232 4233
                             _("unknown sound model '%s'"), model);
        goto error;
    }

4234
    if (virDomainDeviceInfoParseXML(node, &def->info, flags) < 0)
4235 4236
        goto error;

4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247
cleanup:
    VIR_FREE(model);

    return def;

error:
    virDomainSoundDefFree(def);
    def = NULL;
    goto cleanup;
}

4248

R
Richard Jones 已提交
4249
static virDomainWatchdogDefPtr
4250
virDomainWatchdogDefParseXML(const xmlNodePtr node,
4251 4252
                             int flags)
{
R
Richard Jones 已提交
4253 4254 4255 4256 4257 4258

    char *model = NULL;
    char *action = NULL;
    virDomainWatchdogDefPtr def;

    if (VIR_ALLOC (def) < 0) {
4259
        virReportOOMError();
R
Richard Jones 已提交
4260 4261 4262 4263 4264
        return NULL;
    }

    model = virXMLPropString (node, "model");
    if (model == NULL) {
4265 4266
        virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                             _("watchdog must contain model name"));
R
Richard Jones 已提交
4267 4268 4269 4270
        goto error;
    }
    def->model = virDomainWatchdogModelTypeFromString (model);
    if (def->model < 0) {
4271 4272
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                             _("unknown watchdog model '%s'"), model);
R
Richard Jones 已提交
4273 4274 4275 4276 4277 4278 4279 4280 4281
        goto error;
    }

    action = virXMLPropString (node, "action");
    if (action == NULL)
        def->action = VIR_DOMAIN_WATCHDOG_ACTION_RESET;
    else {
        def->action = virDomainWatchdogActionTypeFromString (action);
        if (def->action < 0) {
4282 4283
            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                                 _("unknown watchdog action '%s'"), action);
R
Richard Jones 已提交
4284 4285 4286 4287
            goto error;
        }
    }

4288
    if (virDomainDeviceInfoParseXML(node, &def->info, flags) < 0)
4289 4290
        goto error;

R
Richard Jones 已提交
4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303
cleanup:
    VIR_FREE (action);
    VIR_FREE (model);

    return def;

error:
    virDomainWatchdogDefFree (def);
    def = NULL;
    goto cleanup;
}


4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316
static virDomainMemballoonDefPtr
virDomainMemballoonDefParseXML(const xmlNodePtr node,
                               int flags)
{
    char *model;
    virDomainMemballoonDefPtr def;

    if (VIR_ALLOC(def) < 0) {
        virReportOOMError();
        return NULL;
    }

    model = virXMLPropString(node, "model");
4317 4318 4319 4320 4321
    if (model == NULL) {
        virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                             _("balloon memory must contain model name"));
        goto error;
    }
4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341
    if ((def->model = virDomainMemballoonModelTypeFromString(model)) < 0) {
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                             _("unknown memory balloon model '%s'"), model);
        goto error;
    }

    if (virDomainDeviceInfoParseXML(node, &def->info, flags) < 0)
        goto error;

cleanup:
    VIR_FREE(model);

    return def;

error:
    virDomainMemballoonDefFree(def);
    def = NULL;
    goto cleanup;
}

4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395
static virSysinfoDefPtr
virSysinfoParseXML(const xmlNodePtr node,
                  xmlXPathContextPtr ctxt)
{
    virSysinfoDefPtr def;
    char *type;

    if (!xmlStrEqual(node->name, BAD_CAST "sysinfo")) {
        virDomainReportError(VIR_ERR_XML_ERROR, "%s",
                        _("XML does not contain expected 'sysinfo' element"));
        return(NULL);
    }

    if (VIR_ALLOC(def) < 0) {
        virReportOOMError();
        return(NULL);
    }

    type = virXMLPropString(node, "type");
    if (type == NULL) {
        virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                             _("sysinfo must contain a type attribute"));
        goto error;
    }
    if ((def->type = virDomainSysinfoTypeFromString(type)) < 0) {
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                             _("unknown sysinfo type '%s'"), type);
        goto error;
    }


    /* Extract BIOS related metadata */
    def->bios_vendor =
        virXPathString("string(bios/entry[@name='vendor'])", ctxt);
    def->bios_version =
        virXPathString("string(bios/entry[@name='version'])", ctxt);
    def->bios_date =
        virXPathString("string(bios/entry[@name='date'])", ctxt);
    def->bios_release =
        virXPathString("string(bios/entry[@name='release'])", ctxt);

    /* Extract system related metadata */
    def->system_manufacturer =
        virXPathString("string(system/entry[@name='manufacturer'])", ctxt);
    def->system_product =
        virXPathString("string(system/entry[@name='product'])", ctxt);
    def->system_version =
        virXPathString("string(system/entry[@name='version'])", ctxt);
    def->system_serial =
        virXPathString("string(system/entry[@name='serial'])", ctxt);
    def->system_uuid =
        virXPathString("string(system/entry[@name='uuid'])", ctxt);
    def->system_sku =
        virXPathString("string(system/entry[@name='sku'])", ctxt);
E
Eric Blake 已提交
4396 4397
    def->system_family =
        virXPathString("string(system/entry[@name='family'])", ctxt);
4398 4399 4400 4401 4402 4403 4404 4405 4406 4407

cleanup:
    VIR_FREE(type);
    return(def);

error:
    virSysinfoDefFree(def);
    def = NULL;
    goto cleanup;
}
4408

4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419
int
virDomainVideoDefaultRAM(virDomainDefPtr def,
                         int type)
{
    switch (type) {
        /* Wierd, QEMU defaults to 9 MB ??! */
    case VIR_DOMAIN_VIDEO_TYPE_VGA:
    case VIR_DOMAIN_VIDEO_TYPE_CIRRUS:
    case VIR_DOMAIN_VIDEO_TYPE_VMVGA:
        if (def->virtType == VIR_DOMAIN_VIRT_VBOX)
            return 8 * 1024;
M
Matthias Bolte 已提交
4420 4421
        else if (def->virtType == VIR_DOMAIN_VIRT_VMWARE)
            return 4 * 1024;
4422 4423 4424 4425 4426 4427 4428 4429
        else
            return 9 * 1024;
        break;

    case VIR_DOMAIN_VIDEO_TYPE_XEN:
        /* Original Xen PVFB hardcoded to 4 MB */
        return 4 * 1024;

4430 4431 4432 4433
    case VIR_DOMAIN_VIDEO_TYPE_QXL:
        /* QEMU use 64M as the minimal video video memory for qxl device */
        return 64 * 1024;

4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458
    default:
        return 0;
    }
}


int
virDomainVideoDefaultType(virDomainDefPtr def)
{
    switch (def->virtType) {
    case VIR_DOMAIN_VIRT_TEST:
    case VIR_DOMAIN_VIRT_QEMU:
    case VIR_DOMAIN_VIRT_KQEMU:
    case VIR_DOMAIN_VIRT_KVM:
    case VIR_DOMAIN_VIRT_XEN:
        if (def->os.type &&
            (STREQ(def->os.type, "xen") ||
             STREQ(def->os.type, "linux")))
            return VIR_DOMAIN_VIDEO_TYPE_XEN;
        else
            return VIR_DOMAIN_VIDEO_TYPE_CIRRUS;

    case VIR_DOMAIN_VIRT_VBOX:
        return VIR_DOMAIN_VIDEO_TYPE_VBOX;

M
Matthias Bolte 已提交
4459 4460 4461
    case VIR_DOMAIN_VIRT_VMWARE:
        return VIR_DOMAIN_VIDEO_TYPE_VMVGA;

4462 4463 4464 4465 4466
    default:
        return -1;
    }
}

4467
static virDomainVideoAccelDefPtr
4468
virDomainVideoAccelDefParseXML(const xmlNodePtr node) {
4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489
    xmlNodePtr cur;
    virDomainVideoAccelDefPtr def;
    char *support3d = NULL;
    char *support2d = NULL;

    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
            if ((support3d == NULL) && (support2d == NULL) &&
                xmlStrEqual(cur->name, BAD_CAST "acceleration")) {
                support3d = virXMLPropString(cur, "accel3d");
                support2d = virXMLPropString(cur, "accel2d");
            }
        }
        cur = cur->next;
    }

    if ((support3d == NULL) && (support2d == NULL))
        return(NULL);

    if (VIR_ALLOC(def) < 0) {
4490
        virReportOOMError();
4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512
        return NULL;
    }

    if (support3d) {
        if (STREQ(support3d, "yes"))
            def->support3d = 1;
        else
            def->support3d = 0;
        VIR_FREE(support3d);
    }

    if (support2d) {
        if (STREQ(support2d, "yes"))
            def->support2d = 1;
        else
            def->support2d = 0;
        VIR_FREE(support2d);
    }

    return def;
}

4513
static virDomainVideoDefPtr
4514
virDomainVideoDefParseXML(const xmlNodePtr node,
4515
                          virDomainDefPtr dom,
4516
                          int flags) {
4517 4518 4519 4520 4521 4522 4523
    virDomainVideoDefPtr def;
    xmlNodePtr cur;
    char *type = NULL;
    char *heads = NULL;
    char *vram = NULL;

    if (VIR_ALLOC(def) < 0) {
4524
        virReportOOMError();
4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535
        return NULL;
    }

    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
            if ((type == NULL) && (vram == NULL) && (heads == NULL) &&
                xmlStrEqual(cur->name, BAD_CAST "model")) {
                type = virXMLPropString(cur, "type");
                vram = virXMLPropString(cur, "vram");
                heads = virXMLPropString(cur, "heads");
4536
                def->accel = virDomainVideoAccelDefParseXML(cur);
4537 4538 4539 4540 4541 4542 4543
            }
        }
        cur = cur->next;
    }

    if (type) {
        if ((def->type = virDomainVideoTypeFromString(type)) < 0) {
4544
            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
4545 4546 4547 4548 4549
                                 _("unknown video model '%s'"), type);
            goto error;
        }
    } else {
        if ((def->type = virDomainVideoDefaultType(dom)) < 0) {
4550
            virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4551 4552 4553 4554 4555 4556 4557
                                 _("missing video model and cannot determine default"));
            goto error;
        }
    }

    if (vram) {
        if (virStrToLong_ui(vram, NULL, 10, &def->vram) < 0) {
4558
            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
4559 4560 4561 4562 4563 4564 4565 4566 4567
                                 _("cannot parse video ram '%s'"), vram);
            goto error;
        }
    } else {
        def->vram = virDomainVideoDefaultRAM(dom, def->type);
    }

    if (heads) {
        if (virStrToLong_ui(heads, NULL, 10, &def->heads) < 0) {
4568
            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
4569 4570 4571 4572 4573 4574 4575
                                 _("cannot parse video heads '%s'"), heads);
            goto error;
        }
    } else {
        def->heads = 1;
    }

4576
    if (virDomainDeviceInfoParseXML(node, &def->info, flags) < 0)
4577 4578
        goto error;

4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592
    VIR_FREE(type);
    VIR_FREE(vram);
    VIR_FREE(heads);

    return def;

error:
    virDomainVideoDefFree(def);
    VIR_FREE(type);
    VIR_FREE(vram);
    VIR_FREE(heads);
    return NULL;
}

4593
static int
4594
virDomainHostdevSubsysUsbDefParseXML(const xmlNodePtr node,
4595 4596
                                     virDomainHostdevDefPtr def,
                                     int flags ATTRIBUTE_UNUSED) {
4597 4598

    int ret = -1;
4599
    int got_product, got_vendor;
4600 4601
    xmlNodePtr cur;

4602 4603 4604 4605 4606
    /* Product can validly be 0, so we need some extra help to determine
     * if it is uninitialized*/
    got_product = 0;
    got_vendor = 0;

4607 4608 4609 4610 4611 4612 4613
    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
            if (xmlStrEqual(cur->name, BAD_CAST "vendor")) {
                char *vendor = virXMLPropString(cur, "id");

                if (vendor) {
4614
                    got_vendor = 1;
4615
                    if (virStrToLong_ui(vendor, NULL, 0,
4616
                                    &def->source.subsys.u.usb.vendor) < 0) {
4617
                        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
4618 4619 4620 4621 4622 4623
                                 _("cannot parse vendor id %s"), vendor);
                        VIR_FREE(vendor);
                        goto out;
                    }
                    VIR_FREE(vendor);
                } else {
4624
                    virDomainReportError(VIR_ERR_INTERNAL_ERROR,
4625 4626 4627 4628 4629 4630 4631
                                         "%s", _("usb vendor needs id"));
                    goto out;
                }
            } else if (xmlStrEqual(cur->name, BAD_CAST "product")) {
                char* product = virXMLPropString(cur, "id");

                if (product) {
4632
                    got_product = 1;
4633
                    if (virStrToLong_ui(product, NULL, 0,
4634
                                        &def->source.subsys.u.usb.product) < 0) {
4635
                        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
4636 4637
                                             _("cannot parse product %s"),
                                             product);
4638 4639 4640 4641 4642
                        VIR_FREE(product);
                        goto out;
                    }
                    VIR_FREE(product);
                } else {
4643
                    virDomainReportError(VIR_ERR_INTERNAL_ERROR,
4644 4645 4646 4647 4648 4649 4650 4651 4652
                                         "%s", _("usb product needs id"));
                    goto out;
                }
            } else if (xmlStrEqual(cur->name, BAD_CAST "address")) {
                char *bus, *device;

                bus = virXMLPropString(cur, "bus");
                if (bus) {
                    if (virStrToLong_ui(bus, NULL, 0,
4653
                                        &def->source.subsys.u.usb.bus) < 0) {
4654
                        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
4655 4656 4657 4658 4659 4660
                                             _("cannot parse bus %s"), bus);
                        VIR_FREE(bus);
                        goto out;
                    }
                    VIR_FREE(bus);
                } else {
4661
                    virDomainReportError(VIR_ERR_INTERNAL_ERROR,
4662 4663 4664 4665 4666 4667 4668
                                         "%s", _("usb address needs bus id"));
                    goto out;
                }

                device = virXMLPropString(cur, "device");
                if (device) {
                    if (virStrToLong_ui(device, NULL, 0,
4669
                                        &def->source.subsys.u.usb.device) < 0)  {
4670
                        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
4671 4672 4673 4674 4675 4676 4677
                                             _("cannot parse device %s"),
                                             device);
                        VIR_FREE(device);
                        goto out;
                    }
                    VIR_FREE(device);
                } else {
4678
                    virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4679
                                         _("usb address needs device id"));
4680 4681 4682
                    goto out;
                }
            } else {
4683
                virDomainReportError(VIR_ERR_INTERNAL_ERROR,
4684 4685
                                     _("unknown usb source type '%s'"),
                                     cur->name);
4686 4687 4688 4689 4690 4691
                goto out;
            }
        }
        cur = cur->next;
    }

4692
    if (got_vendor && def->source.subsys.u.usb.vendor == 0) {
4693
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
4694 4695 4696 4697 4698
            "%s", _("vendor cannot be 0."));
        goto out;
    }

    if (!got_vendor && got_product) {
4699
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
4700
            "%s", _("missing vendor"));
4701 4702
        goto out;
    }
4703
    if (got_vendor && !got_product) {
4704
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
4705
            "%s", _("missing product"));
4706 4707 4708 4709 4710 4711 4712 4713 4714
        goto out;
    }

    ret = 0;
out:
    return ret;
}


4715
static int
4716
virDomainHostdevSubsysPciDefParseXML(const xmlNodePtr node,
4717
                                     virDomainHostdevDefPtr def,
4718
                                     int flags) {
4719 4720 4721 4722 4723 4724 4725 4726

    int ret = -1;
    xmlNodePtr cur;

    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
            if (xmlStrEqual(cur->name, BAD_CAST "address")) {
4727 4728
                virDomainDevicePCIAddressPtr addr =
                    &def->source.subsys.u.pci;
4729

4730
                if (virDomainDevicePCIAddressParseXML(cur, addr) < 0)
4731
                    goto out;
4732 4733
            } else if ((flags & VIR_DOMAIN_XML_INTERNAL_STATUS) &&
                       xmlStrEqual(cur->name, BAD_CAST "state")) {
4734
                /* Legacy back-compat. Don't add any more attributes here */
4735 4736
                char *devaddr = virXMLPropString(cur, "devaddr");
                if (devaddr &&
4737 4738
                    virDomainParseLegacyDeviceAddress(devaddr,
                                                      &def->info.addr.pci) < 0) {
4739
                    virDomainReportError(VIR_ERR_INTERNAL_ERROR,
4740 4741 4742 4743 4744
                                         _("Unable to parse devaddr parameter '%s'"),
                                         devaddr);
                    VIR_FREE(devaddr);
                    goto out;
                }
4745
                def->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
4746
            } else {
4747
                virDomainReportError(VIR_ERR_INTERNAL_ERROR,
4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761
                                     _("unknown pci source type '%s'"),
                                     cur->name);
                goto out;
            }
        }
        cur = cur->next;
    }

    ret = 0;
out:
    return ret;
}


4762
static virDomainHostdevDefPtr
4763
virDomainHostdevDefParseXML(const xmlNodePtr node,
4764 4765 4766
                            virBitmapPtr bootMap,
                            int flags)
{
4767 4768 4769

    xmlNodePtr cur;
    virDomainHostdevDefPtr def;
4770
    char *mode, *type = NULL, *managed = NULL;
4771 4772

    if (VIR_ALLOC(def) < 0) {
4773
        virReportOOMError();
4774 4775 4776 4777 4778 4779
        return NULL;
    }

    mode = virXMLPropString(node, "mode");
    if (mode) {
        if ((def->mode=virDomainHostdevModeTypeFromString(mode)) < 0) {
4780
             virDomainReportError(VIR_ERR_INTERNAL_ERROR,
4781 4782 4783 4784 4785 4786 4787 4788 4789 4790
                                  _("unknown hostdev mode '%s'"), mode);
            goto error;
        }
    } else {
        def->mode = VIR_DOMAIN_HOSTDEV_MODE_SUBSYS;
    }

    type = virXMLPropString(node, "type");
    if (type) {
        if ((def->source.subsys.type = virDomainHostdevSubsysTypeFromString(type)) < 0) {
4791
            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
4792 4793 4794 4795
                                 _("unknown host device type '%s'"), type);
            goto error;
        }
    } else {
4796
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
4797 4798 4799 4800
                             "%s", _("missing type in hostdev"));
        goto error;
    }

4801 4802 4803 4804 4805 4806 4807
    managed = virXMLPropString(node, "managed");
    if (managed != NULL) {
        if (STREQ(managed, "yes"))
            def->managed = 1;
        VIR_FREE(managed);
    }

4808 4809 4810 4811 4812 4813
    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
            if (xmlStrEqual(cur->name, BAD_CAST "source")) {
                if (def->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
                    def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {
4814
                        if (virDomainHostdevSubsysUsbDefParseXML(cur, def, flags) < 0)
4815 4816
                            goto error;
                }
4817 4818
                if (def->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
                    def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) {
4819
                        if (virDomainHostdevSubsysPciDefParseXML(cur, def, flags) < 0)
4820 4821
                            goto error;
                }
D
Daniel P. Berrange 已提交
4822
            } else if (xmlStrEqual(cur->name, BAD_CAST "address")) {
4823 4824 4825
                /* address is parsed as part of virDomainDeviceInfoParseXML */
            } else if (xmlStrEqual(cur->name, BAD_CAST "alias")) {
                /* alias is parsed as part of virDomainDeviceInfoParseXML */
4826 4827 4828 4829
            } else if (xmlStrEqual(cur->name, BAD_CAST "boot")) {
                if (virDomainDeviceBootParseXML(cur, &def->bootIndex,
                                                bootMap))
                    goto error;
D
Daniel P. Berrange 已提交
4830
            } else {
4831
                virDomainReportError(VIR_ERR_INTERNAL_ERROR,
D
Daniel P. Berrange 已提交
4832
                                     _("unknown node %s"), cur->name);
4833 4834 4835 4836 4837
            }
        }
        cur = cur->next;
    }

4838
    if (def->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
4839
        if (virDomainDeviceInfoParseXML(node, &def->info, flags) < 0)
4840 4841 4842 4843 4844 4845 4846 4847
            goto error;
    }

    if (def->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
        switch (def->source.subsys.type) {
        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
            if (def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
                def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
4848
                virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4849 4850 4851 4852 4853 4854 4855
                                     _("PCI host devices must use 'pci' address type"));
                goto error;
            }
            break;
        }
    }

4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866
cleanup:
    VIR_FREE(type);
    VIR_FREE(mode);
    return def;

error:
    virDomainHostdevDefFree(def);
    def = NULL;
    goto cleanup;
}

4867

4868
static int virDomainLifecycleParseXML(xmlXPathContextPtr ctxt,
4869 4870
                                      const char *xpath,
                                      int *val,
4871 4872
                                      int defaultVal,
                                      virLifecycleFromStringFunc convFunc)
4873
{
4874
    char *tmp = virXPathString(xpath, ctxt);
4875 4876 4877
    if (tmp == NULL) {
        *val = defaultVal;
    } else {
4878
        *val = convFunc(tmp);
4879
        if (*val < 0) {
4880
            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
4881 4882 4883 4884 4885 4886 4887 4888 4889
                                 _("unknown lifecycle action %s"), tmp);
            VIR_FREE(tmp);
            return -1;
        }
        VIR_FREE(tmp);
    }
    return 0;
}

4890
static int
4891
virSecurityLabelDefParseXML(const virDomainDefPtr def,
4892 4893
                            xmlXPathContextPtr ctxt,
                            int flags)
4894 4895 4896
{
    char *p;

4897
    if (virXPathNode("./seclabel", ctxt) == NULL)
4898 4899
        return 0;

4900
    p = virXPathStringLimit("string(./seclabel/@type)",
4901
                            VIR_SECURITY_LABEL_BUFLEN-1, ctxt);
4902
    if (p == NULL) {
4903
        virDomainReportError(VIR_ERR_XML_ERROR,
4904
                             "%s", _("missing security type"));
4905
        goto error;
4906 4907
    }
    def->seclabel.type = virDomainSeclabelTypeFromString(p);
4908
    VIR_FREE(p);
4909
    if (def->seclabel.type < 0) {
4910
        virDomainReportError(VIR_ERR_XML_ERROR,
4911
                             "%s", _("invalid security type"));
4912 4913
        goto error;
    }
4914 4915 4916 4917 4918 4919

    /* Only parse details, if using static labels, or
     * if the 'live' VM XML is requested
     */
    if (def->seclabel.type == VIR_DOMAIN_SECLABEL_STATIC ||
        !(flags & VIR_DOMAIN_XML_INACTIVE)) {
4920
        p = virXPathStringLimit("string(./seclabel/@model)",
4921 4922
                                VIR_SECURITY_MODEL_BUFLEN-1, ctxt);
        if (p == NULL) {
4923
            virDomainReportError(VIR_ERR_XML_ERROR,
4924 4925 4926 4927
                                 "%s", _("missing security model"));
            goto error;
        }
        def->seclabel.model = p;
4928

4929
        p = virXPathStringLimit("string(./seclabel/label[1])",
4930
                                VIR_SECURITY_LABEL_BUFLEN-1, ctxt);
4931
        if (p == NULL) {
4932
            virDomainReportError(VIR_ERR_XML_ERROR,
4933
                                 "%s", _("security label is missing"));
4934
            goto error;
4935 4936
        }

4937 4938 4939 4940 4941 4942
        def->seclabel.label = p;
    }

    /* Only parse imagelabel, if requested live XML for dynamic label */
    if (def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC &&
        !(flags & VIR_DOMAIN_XML_INACTIVE)) {
4943
        p = virXPathStringLimit("string(./seclabel/imagelabel[1])",
4944
                                VIR_SECURITY_LABEL_BUFLEN-1, ctxt);
4945
        if (p == NULL) {
4946
            virDomainReportError(VIR_ERR_XML_ERROR,
4947
                                 "%s", _("security imagelabel is missing"));
4948
            goto error;
4949
        }
4950 4951
        def->seclabel.imagelabel = p;
    }
4952 4953 4954 4955 4956 4957 4958

    return 0;

error:
    virSecurityLabelDefFree(def);
    return -1;
}
4959

4960
virDomainDeviceDefPtr virDomainDeviceDefParse(virCapsPtr caps,
4961
                                              const virDomainDefPtr def,
4962 4963
                                              const char *xmlStr,
                                              int flags)
4964 4965 4966
{
    xmlDocPtr xml;
    xmlNodePtr node;
4967
    xmlXPathContextPtr ctxt = NULL;
4968 4969
    virDomainDeviceDefPtr dev = NULL;

4970
    if (!(xml = virXMLParseString(xmlStr, "device.xml"))) {
4971 4972 4973 4974
        goto error;
    }
    node = xmlDocGetRootElement(xml);

4975 4976 4977 4978 4979
    ctxt = xmlXPathNewContext(xml);
    if (ctxt == NULL) {
        virReportOOMError();
        goto error;
    }
4980
    ctxt->node = xmlDocGetRootElement(xml);
4981

4982
    if (VIR_ALLOC(dev) < 0) {
4983
        virReportOOMError();
4984 4985 4986 4987 4988
        goto error;
    }

    if (xmlStrEqual(node->name, BAD_CAST "disk")) {
        dev->type = VIR_DOMAIN_DEVICE_DISK;
4989 4990
        if (!(dev->data.disk = virDomainDiskDefParseXML(caps, node,
                                                        NULL, flags)))
4991
            goto error;
4992 4993
    } else if (xmlStrEqual(node->name, BAD_CAST "filesystem")) {
        dev->type = VIR_DOMAIN_DEVICE_FS;
4994
        if (!(dev->data.fs = virDomainFSDefParseXML(node, flags)))
4995
            goto error;
4996 4997
    } else if (xmlStrEqual(node->name, BAD_CAST "interface")) {
        dev->type = VIR_DOMAIN_DEVICE_NET;
4998 4999
        if (!(dev->data.net = virDomainNetDefParseXML(caps, node, ctxt,
                                                      NULL, flags)))
5000 5001
            goto error;
    } else if (xmlStrEqual(node->name, BAD_CAST "input")) {
5002
        dev->type = VIR_DOMAIN_DEVICE_INPUT;
5003
        if (!(dev->data.input = virDomainInputDefParseXML(def->os.type,
5004
                                                          node, flags)))
5005 5006 5007
            goto error;
    } else if (xmlStrEqual(node->name, BAD_CAST "sound")) {
        dev->type = VIR_DOMAIN_DEVICE_SOUND;
5008
        if (!(dev->data.sound = virDomainSoundDefParseXML(node, flags)))
5009
            goto error;
R
Richard Jones 已提交
5010 5011
    } else if (xmlStrEqual(node->name, BAD_CAST "watchdog")) {
        dev->type = VIR_DOMAIN_DEVICE_WATCHDOG;
5012
        if (!(dev->data.watchdog = virDomainWatchdogDefParseXML(node, flags)))
R
Richard Jones 已提交
5013
            goto error;
5014 5015
    } else if (xmlStrEqual(node->name, BAD_CAST "video")) {
        dev->type = VIR_DOMAIN_DEVICE_VIDEO;
5016
        if (!(dev->data.video = virDomainVideoDefParseXML(node, def, flags)))
5017
            goto error;
5018 5019
    } else if (xmlStrEqual(node->name, BAD_CAST "hostdev")) {
        dev->type = VIR_DOMAIN_DEVICE_HOSTDEV;
5020 5021
        if (!(dev->data.hostdev = virDomainHostdevDefParseXML(node, NULL,
                                                              flags)))
5022
            goto error;
5023 5024
    } else if (xmlStrEqual(node->name, BAD_CAST "controller")) {
        dev->type = VIR_DOMAIN_DEVICE_CONTROLLER;
5025
        if (!(dev->data.controller = virDomainControllerDefParseXML(node, flags)))
5026
            goto error;
5027 5028 5029 5030
    } else if (xmlStrEqual(node->name, BAD_CAST "graphics")) {
        dev->type = VIR_DOMAIN_DEVICE_GRAPHICS;
        if (!(dev->data.graphics = virDomainGraphicsDefParseXML(node, flags)))
            goto error;
5031
    } else {
5032
        virDomainReportError(VIR_ERR_XML_ERROR,
5033 5034 5035 5036 5037
                             "%s", _("unknown device type"));
        goto error;
    }

    xmlFreeDoc(xml);
5038
    xmlXPathFreeContext(ctxt);
5039 5040 5041 5042
    return dev;

  error:
    xmlFreeDoc(xml);
5043
    xmlXPathFreeContext(ctxt);
5044 5045 5046
    VIR_FREE(dev);
    return NULL;
}
M
Matthias Bolte 已提交
5047 5048


5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 5068
static const char *
virDomainChrTargetTypeToString(int deviceType,
                               int targetType)
{
    const char *type = NULL;

    switch (deviceType) {
    case VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL:
        type = virDomainChrChannelTargetTypeToString(targetType);
        break;
    case VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE:
        type = virDomainChrConsoleTargetTypeToString(targetType);
        break;
    default:
        break;
    }

    return type;
}

M
Matthias Bolte 已提交
5069 5070 5071 5072 5073 5074 5075 5076 5077 5078
static void
virVirtualPortProfileFormat(virBufferPtr buf,
                            virVirtualPortProfileParamsPtr virtPort,
                            const char *indent)
{
    char uuidstr[VIR_UUID_STRING_BUFLEN];

    if (virtPort->virtPortType == VIR_VIRTUALPORT_NONE)
        return;

5079
    virBufferAsprintf(buf, "%s<virtualport type='%s'>\n",
M
Matthias Bolte 已提交
5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090
                      indent,
                      virVirtualPortTypeToString(virtPort->virtPortType));

    switch (virtPort->virtPortType) {
    case VIR_VIRTUALPORT_NONE:
    case VIR_VIRTUALPORT_TYPE_LAST:
        break;

    case VIR_VIRTUALPORT_8021QBG:
        virUUIDFormat(virtPort->u.virtPort8021Qbg.instanceID,
                      uuidstr);
5091
        virBufferAsprintf(buf,
M
Matthias Bolte 已提交
5092 5093 5094 5095 5096 5097 5098 5099
                          "%s  <parameters managerid='%d' typeid='%d' "
                          "typeidversion='%d' instanceid='%s'/>\n",
                          indent,
                          virtPort->u.virtPort8021Qbg.managerID,
                          virtPort->u.virtPort8021Qbg.typeID,
                          virtPort->u.virtPort8021Qbg.typeIDVersion,
                          uuidstr);
        break;
5100

M
Matthias Bolte 已提交
5101
    case VIR_VIRTUALPORT_8021QBH:
5102
        virBufferAsprintf(buf,
M
Matthias Bolte 已提交
5103 5104 5105 5106 5107 5108
                          "%s  <parameters profileid='%s'/>\n",
                          indent,
                          virtPort->u.virtPort8021Qbh.profileID);
        break;
    }

5109
    virBufferAsprintf(buf, "%s</virtualport>\n", indent);
M
Matthias Bolte 已提交
5110
}
5111

5112 5113 5114 5115 5116 5117 5118 5119 5120 5121 5122 5123 5124
int virDomainDiskIndexByName(virDomainDefPtr def, const char *name)
{
    virDomainDiskDefPtr vdisk;
    int i;

    for (i = 0; i < def->ndisks; i++) {
        vdisk = def->disks[i];
        if (STREQ(vdisk->dst, name))
            return i;
    }
    return -1;
}

5125 5126
int virDomainDiskInsert(virDomainDefPtr def,
                        virDomainDiskDefPtr disk)
5127 5128
{

5129 5130 5131 5132 5133 5134
    if (VIR_REALLOC_N(def->disks, def->ndisks+1) < 0)
        return -1;

    virDomainDiskInsertPreAlloced(def, disk);

    return 0;
5135 5136
}

5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 5161 5162 5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174 5175 5176 5177 5178
void virDomainDiskInsertPreAlloced(virDomainDefPtr def,
                                   virDomainDiskDefPtr disk)
{
    int i;
    /* Tenatively plan to insert disk at the end. */
    int insertAt = -1;

    /* Then work backwards looking for disks on
     * the same bus. If we find a disk with a drive
     * index greater than the new one, insert at
     * that position
     */
    for (i = (def->ndisks - 1) ; i >= 0 ; i--) {
        /* If bus matches and current disk is after
         * new disk, then new disk should go here */
        if (def->disks[i]->bus == disk->bus &&
            (virDiskNameToIndex(def->disks[i]->dst) >
             virDiskNameToIndex(disk->dst))) {
            insertAt = i;
        } else if (def->disks[i]->bus == disk->bus &&
                   insertAt == -1) {
            /* Last disk with match bus is before the
             * new disk, then put new disk just after
             */
            insertAt = i + 1;
        }
    }

    /* No disks with this bus yet, so put at end of list */
    if (insertAt == -1)
        insertAt = def->ndisks;

    if (insertAt < def->ndisks)
        memmove(def->disks + insertAt + 1,
                def->disks + insertAt,
                (sizeof(def->disks[0]) * (def->ndisks-insertAt)));

    def->disks[insertAt] = disk;
    def->ndisks++;
}


5179 5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194 5195
void virDomainDiskRemove(virDomainDefPtr def, size_t i)
{
    if (def->ndisks > 1) {
        memmove(def->disks + i,
                def->disks + i + 1,
                sizeof(*def->disks) *
                (def->ndisks - (i + 1)));
        def->ndisks--;
        if (VIR_REALLOC_N(def->disks, def->ndisks) < 0) {
            /* ignore, harmless */
        }
    } else {
        VIR_FREE(def->disks);
        def->ndisks = 0;
    }
}

5196 5197 5198 5199 5200 5201 5202 5203 5204
int virDomainDiskRemoveByName(virDomainDefPtr def, const char *name)
{
    int i = virDomainDiskIndexByName(def, name);
    if (i < 0)
        return -1;
    virDomainDiskRemove(def, i);
    return 0;
}

5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228 5229 5230 5231 5232 5233 5234 5235 5236 5237 5238 5239 5240 5241 5242 5243 5244 5245 5246 5247 5248 5249
int virDomainNetInsert(virDomainDefPtr def, virDomainNetDefPtr net)
{
    if (VIR_REALLOC_N(def->nets, def->nnets + 1) < 0)
        return -1;
    def->nets[def->nnets]  = net;
    def->nnets++;
    return 0;
}

int virDomainNetIndexByMac(virDomainDefPtr def, const unsigned char *mac)
{
    int i;

    for (i = 0; i < def->nnets; i++)
        if (!memcmp(def->nets[i]->mac, mac, VIR_MAC_BUFLEN))
            return i;
    return -1;
}

static void virDomainNetRemove(virDomainDefPtr def, size_t i)
{
    if (def->nnets > 1) {
        memmove(def->nets + i,
                def->nets + i + 1,
                sizeof(*def->nets) * (def->nnets - (i + 1)));
        def->nnets--;
        if (VIR_REALLOC_N(def->nets, def->nnets) < 0) {
            /* ignore harmless */
        }
    } else {
        VIR_FREE(def->nets);
        def->nnets = 0;
    }
}

int virDomainNetRemoveByMac(virDomainDefPtr def, const unsigned char *mac)
{
    int i = virDomainNetIndexByMac(def, mac);

    if (i < 0)
        return -1;
    virDomainNetRemove(def, i);
    return 0;
}

5250

5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264 5265 5266 5267 5268 5269 5270 5271 5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303
int virDomainControllerInsert(virDomainDefPtr def,
                              virDomainControllerDefPtr controller)
{

    if (VIR_REALLOC_N(def->controllers, def->ncontrollers+1) < 0)
        return -1;

    virDomainControllerInsertPreAlloced(def, controller);

    return 0;
}

void virDomainControllerInsertPreAlloced(virDomainDefPtr def,
                                         virDomainControllerDefPtr controller)
{
    int i;
    /* Tenatively plan to insert controller at the end. */
    int insertAt = -1;

    /* Then work backwards looking for controllers of
     * the same type. If we find a controller with a
     * index greater than the new one, insert at
     * that position
     */
    for (i = (def->ncontrollers - 1) ; i >= 0 ; i--) {
        /* If bus matches and current controller is after
         * new controller, then new controller should go here */
        if ((def->controllers[i]->type == controller->type) &&
            (def->controllers[i]->idx > controller->idx)) {
            insertAt = i;
        } else if (def->controllers[i]->type == controller->type &&
                   insertAt == -1) {
            /* Last controller with match bus is before the
             * new controller, then put new controller just after
             */
            insertAt = i + 1;
        }
    }

    /* No controllers with this bus yet, so put at end of list */
    if (insertAt == -1)
        insertAt = def->ncontrollers;

    if (insertAt < def->ncontrollers)
        memmove(def->controllers + insertAt + 1,
                def->controllers + insertAt,
                (sizeof(def->controllers[0]) * (def->ncontrollers-insertAt)));

    def->controllers[insertAt] = controller;
    def->ncontrollers++;
}


5304
static char *virDomainDefDefaultEmulator(virDomainDefPtr def,
5305 5306 5307 5308 5309 5310 5311
                                         virCapsPtr caps) {
    const char *type;
    const char *emulator;
    char *retemu;

    type = virDomainVirtTypeToString(def->virtType);
    if (!type) {
5312
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
5313 5314 5315 5316 5317 5318 5319 5320 5321 5322
                             "%s", _("unknown virt type"));
        return NULL;
    }

    emulator = virCapabilitiesDefaultGuestEmulator(caps,
                                                   def->os.type,
                                                   def->os.arch,
                                                   type);

    if (!emulator) {
5323
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
5324 5325 5326 5327 5328 5329 5330
                             _("no emulator for domain %s os type %s on architecture %s"),
                             type, def->os.type, def->os.arch);
        return NULL;
    }

    retemu = strdup(emulator);
    if (!retemu)
5331
        virReportOOMError();
5332 5333 5334 5335

    return retemu;
}

5336 5337
static int
virDomainDefParseBootXML(xmlXPathContextPtr ctxt,
5338 5339
                         virDomainDefPtr def,
                         unsigned long *bootCount)
5340 5341 5342 5343 5344
{
    xmlNodePtr *nodes = NULL;
    int i, n;
    char *bootstr;
    int ret = -1;
5345 5346 5347
    unsigned long deviceBoot;

    if (virXPathULong("count(./devices/disk[boot]"
5348 5349
                      "|./devices/interface[boot]"
                      "|./devices/hostdev[boot])", ctxt, &deviceBoot) < 0) {
5350 5351 5352 5353
        virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                             _("cannot count boot devices"));
        goto cleanup;
    }
5354 5355 5356 5357 5358 5359

    /* analysis of the boot devices */
    if ((n = virXPathNodeSet("./os/boot", ctxt, &nodes)) < 0) {
        goto cleanup;
    }

5360 5361 5362 5363 5364 5365 5366
    if (n > 0 && deviceBoot) {
        virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                             _("per-device boot elements cannot be used"
                               " together with os/boot elements"));
        goto cleanup;
    }

5367 5368 5369 5370 5371 5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384
    for (i = 0 ; i < n && i < VIR_DOMAIN_BOOT_LAST ; i++) {
        int val;
        char *dev = virXMLPropString(nodes[i], "dev");
        if (!dev) {
            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                                 "%s", _("missing boot device"));
            goto cleanup;
        }
        if ((val = virDomainBootTypeFromString(dev)) < 0) {
            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                                 _("unknown boot device '%s'"),
                                 dev);
            VIR_FREE(dev);
            goto cleanup;
        }
        VIR_FREE(dev);
        def->os.bootDevs[def->os.nBootDevs++] = val;
    }
5385
    if (def->os.nBootDevs == 0 && !deviceBoot) {
5386 5387 5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398
        def->os.nBootDevs = 1;
        def->os.bootDevs[0] = VIR_DOMAIN_BOOT_DISK;
    }

    bootstr = virXPathString("string(./os/bootmenu[1]/@enable)", ctxt);
    if (bootstr) {
        if (STREQ(bootstr, "yes"))
            def->os.bootmenu = VIR_DOMAIN_BOOT_MENU_ENABLED;
        else
            def->os.bootmenu = VIR_DOMAIN_BOOT_MENU_DISABLED;
        VIR_FREE(bootstr);
    }

5399
    *bootCount = deviceBoot;
5400 5401 5402 5403 5404 5405 5406
    ret = 0;

cleanup:
    VIR_FREE(nodes);
    return ret;
}

5407 5408 5409 5410 5411 5412 5413 5414 5415 5416 5417 5418 5419 5420 5421 5422 5423 5424 5425 5426 5427 5428 5429 5430 5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454 5455 5456 5457 5458 5459 5460 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 5474 5475 5476
/* Parse the XML definition for a vcpupin */
static virDomainVcpupinDefPtr
virDomainVcpupinDefParseXML(const xmlNodePtr node,
                            xmlXPathContextPtr ctxt,
                            int maxvcpus,
                            int flags ATTRIBUTE_UNUSED)
{
    virDomainVcpupinDefPtr def;
    xmlNodePtr oldnode = ctxt->node;
    unsigned int vcpuid;
    char *tmp = NULL;
    int ret;

    if (VIR_ALLOC(def) < 0) {
        virReportOOMError();
        return NULL;
    }

    ctxt->node = node;

    ret = virXPathUInt("string(./@vcpu)", ctxt, &vcpuid);
    if (ret == -2) {
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                             "%s", _("vcpu id must be an unsigned integer"));
        goto error;
    } else if (ret == -1) {
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                             "%s", _("can't parse vcpupin node"));
        goto error;
    }

    if (vcpuid >= maxvcpus) {
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                             "%s", _("vcpu id must be less than maxvcpus"));
        goto error;
    }

    def->vcpuid = vcpuid;

    tmp = virXMLPropString(node, "cpuset");

    if (tmp) {
        char *set = tmp;
        int cpumasklen = VIR_DOMAIN_CPUMASK_LEN;

        if (VIR_ALLOC_N(def->cpumask, cpumasklen) < 0) {
            virReportOOMError();
            goto error;
        }
        if (virDomainCpuSetParse((const char **)&set,
                                 0, def->cpumask,
                                 cpumasklen) < 0)
           goto error;
        VIR_FREE(tmp);
    } else {
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                             "%s", _("missing cpuset for vcpupin"));
        goto error;
    }

cleanup:
    ctxt->node = oldnode;
    return def;

error:
    VIR_FREE(def);
    goto cleanup;
}


5477
static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
5478 5479 5480 5481
                                            xmlDocPtr xml,
                                            xmlNodePtr root,
                                            xmlXPathContextPtr ctxt,
                                            int flags)
5482 5483 5484 5485
{
    xmlNodePtr *nodes = NULL, node = NULL;
    char *tmp = NULL;
    int i, n;
5486
    long id = -1;
5487
    virDomainDefPtr def;
E
Eric Blake 已提交
5488
    unsigned long count;
5489
    bool uuid_generated = false;
5490 5491
    virBitmapPtr bootMap = NULL;
    unsigned long bootMapSize = 0;
5492 5493

    if (VIR_ALLOC(def) < 0) {
5494
        virReportOOMError();
5495 5496
        return NULL;
    }
5497 5498

    if (!(flags & VIR_DOMAIN_XML_INACTIVE))
5499
        if ((virXPathLong("string(./@id)", ctxt, &id)) < 0)
5500 5501
            id = -1;
    def->id = (int)id;
5502

5503
    /* Find out what type of virtualization to use */
5504
    if (!(tmp = virXPathString("string(./@type)", ctxt))) {
5505
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
5506 5507 5508 5509 5510
                             "%s", _("missing domain type attribute"));
        goto error;
    }

    if ((def->virtType = virDomainVirtTypeFromString(tmp)) < 0) {
5511
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
5512 5513 5514 5515 5516 5517
                             _("invalid domain type %s"), tmp);
        goto error;
    }
    VIR_FREE(tmp);

    /* Extract domain name */
5518
    if (!(def->name = virXPathString("string(./name[1])", ctxt))) {
5519
        virDomainReportError(VIR_ERR_NO_NAME, NULL);
5520 5521 5522
        goto error;
    }

5523 5524 5525
    /* Extract domain uuid. If both uuid and sysinfo/system/entry/uuid
     * exist, they must match; and if only the latter exists, it can
     * also serve as the uuid. */
5526
    tmp = virXPathString("string(./uuid[1])", ctxt);
5527
    if (!tmp) {
5528
        if (virUUIDGenerate(def->uuid)) {
5529
            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
5530
                                 "%s", _("Failed to generate UUID"));
5531 5532
            goto error;
        }
5533
        uuid_generated = true;
5534 5535
    } else {
        if (virUUIDParse(tmp, def->uuid) < 0) {
5536
            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
5537 5538 5539 5540 5541 5542
                                 "%s", _("malformed uuid element"));
            goto error;
        }
        VIR_FREE(tmp);
    }

5543
    /* Extract documentation if present */
5544
    def->description = virXPathString("string(./description[1])", ctxt);
5545

5546
    /* Extract domain memory */
5547 5548
    if (virXPathULong("string(./memory[1])", ctxt,
                      &def->mem.max_balloon) < 0) {
5549
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
5550 5551 5552 5553
                             "%s", _("missing memory element"));
        goto error;
    }

5554 5555 5556
    if (virXPathULong("string(./currentMemory[1])", ctxt,
                      &def->mem.cur_balloon) < 0)
        def->mem.cur_balloon = def->mem.max_balloon;
5557

5558
    node = virXPathNode("./memoryBacking/hugepages", ctxt);
5559
    if (node)
5560 5561
        def->mem.hugepage_backed = 1;

5562 5563 5564 5565 5566
    /* Extract blkio cgroup tunables */
    if (virXPathUInt("string(./blkiotune/weight)", ctxt,
                     &def->blkio.weight) < 0)
        def->blkio.weight = 0;

5567 5568 5569 5570 5571 5572 5573 5574 5575 5576 5577 5578 5579 5580 5581 5582
    /* Extract other memory tunables */
    if (virXPathULong("string(./memtune/hard_limit)", ctxt,
                      &def->mem.hard_limit) < 0)
        def->mem.hard_limit = 0;

    if (virXPathULong("string(./memtune/soft_limit[1])", ctxt,
                      &def->mem.soft_limit) < 0)
        def->mem.soft_limit = 0;

    if (virXPathULong("string(./memtune/min_guarantee[1])", ctxt,
                      &def->mem.min_guarantee) < 0)
        def->mem.min_guarantee = 0;

    if (virXPathULong("string(./memtune/swap_hard_limit[1])", ctxt,
                      &def->mem.swap_hard_limit) < 0)
        def->mem.swap_hard_limit = 0;
5583

E
Eric Blake 已提交
5584 5585 5586 5587 5588 5589 5590 5591 5592
    n = virXPathULong("string(./vcpu[1])", ctxt, &count);
    if (n == -2) {
        virDomainReportError(VIR_ERR_XML_ERROR, "%s",
                             _("maximum vcpus must be an integer"));
        goto error;
    } else if (n < 0) {
        def->maxvcpus = 1;
    } else {
        def->maxvcpus = count;
5593
        if (count == 0) {
E
Eric Blake 已提交
5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608
            virDomainReportError(VIR_ERR_XML_ERROR,
                                 _("invalid maxvcpus %lu"), count);
            goto error;
        }
    }

    n = virXPathULong("string(./vcpu[1]/@current)", ctxt, &count);
    if (n == -2) {
        virDomainReportError(VIR_ERR_XML_ERROR, "%s",
                             _("current vcpus must be an integer"));
        goto error;
    } else if (n < 0) {
        def->vcpus = def->maxvcpus;
    } else {
        def->vcpus = count;
5609
        if (count == 0) {
E
Eric Blake 已提交
5610 5611 5612 5613
            virDomainReportError(VIR_ERR_XML_ERROR,
                                 _("invalid current vcpus %lu"), count);
            goto error;
        }
5614 5615 5616 5617 5618 5619 5620

        if (def->maxvcpus < count) {
            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                _("maxvcpus must not be less than current vcpus (%d < %lu)"),
                def->maxvcpus, count);
            goto error;
        }
E
Eric Blake 已提交
5621
    }
5622

5623
    tmp = virXPathString("string(./vcpu[1]/@cpuset)", ctxt);
5624 5625 5626 5627
    if (tmp) {
        char *set = tmp;
        def->cpumasklen = VIR_DOMAIN_CPUMASK_LEN;
        if (VIR_ALLOC_N(def->cpumask, def->cpumasklen) < 0) {
5628
            virReportOOMError();
5629 5630
            goto error;
        }
5631
        if (virDomainCpuSetParse((const char **)&set,
5632 5633 5634 5635 5636 5637
                                 0, def->cpumask,
                                 def->cpumasklen) < 0)
            goto error;
        VIR_FREE(tmp);
    }

5638 5639 5640 5641 5642 5643 5644 5645 5646 5647 5648 5649 5650 5651 5652 5653 5654 5655 5656 5657 5658 5659 5660 5661 5662 5663 5664 5665 5666 5667 5668 5669 5670 5671 5672 5673 5674 5675
    /* Extract cpu tunables. */
    if (virXPathULong("string(./cputune/shares[1])", ctxt,
                      &def->cputune.shares) < 0)
        def->cputune.shares = 0;

    if ((n = virXPathNodeSet("./cputune/vcpupin", ctxt, &nodes)) < 0) {
        goto error;
    }

    if (n && VIR_ALLOC_N(def->cputune.vcpupin, n) < 0)
        goto no_memory;

    if (n > def->maxvcpus) {
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                             "%s", _("vcpupin nodes must be less than maxvcpus"));
        goto error;
    }

    for (i = 0 ; i < n ; i++) {
        virDomainVcpupinDefPtr vcpupin = NULL;
        vcpupin = virDomainVcpupinDefParseXML(nodes[i], ctxt, def->maxvcpus, 0);

        if (!vcpupin)
            goto error;

        if (virDomainVcpupinIsDuplicate(def->cputune.vcpupin,
                                        def->cputune.nvcpupin,
                                        vcpupin->vcpuid)) {
            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                                 "%s", _("duplicate vcpupin for same vcpu"));
            VIR_FREE(vcpupin);
            goto error;
        }

        def->cputune.vcpupin[def->cputune.nvcpupin++] = vcpupin;
    }
    VIR_FREE(nodes);

5676
    n = virXPathNodeSet("./features/*", ctxt, &nodes);
5677 5678 5679
    if (n < 0)
        goto error;
    if (n) {
5680 5681 5682
        for (i = 0 ; i < n ; i++) {
            int val = virDomainFeatureTypeFromString((const char *)nodes[i]->name);
            if (val < 0) {
5683
                virDomainReportError(VIR_ERR_INTERNAL_ERROR,
5684 5685 5686 5687 5688 5689
                                     _("unexpected feature %s"),
                                     nodes[i]->name);
                goto error;
            }
            def->features |= (1 << val);
        }
5690
        VIR_FREE(nodes);
5691 5692
    }

5693
    if (virDomainLifecycleParseXML(ctxt, "string(./on_reboot[1])",
5694 5695
                                   &def->onReboot, VIR_DOMAIN_LIFECYCLE_RESTART,
                                   virDomainLifecycleTypeFromString) < 0)
5696 5697
        goto error;

5698
    if (virDomainLifecycleParseXML(ctxt, "string(./on_poweroff[1])",
5699 5700
                                   &def->onPoweroff, VIR_DOMAIN_LIFECYCLE_DESTROY,
                                   virDomainLifecycleTypeFromString) < 0)
5701 5702
        goto error;

5703
    if (virDomainLifecycleParseXML(ctxt, "string(./on_crash[1])",
5704 5705 5706
                                        &def->onCrash,
                                   VIR_DOMAIN_LIFECYCLE_CRASH_DESTROY,
                                   virDomainLifecycleCrashTypeFromString) < 0)
5707 5708
        goto error;

5709
    tmp = virXPathString("string(./clock/@offset)", ctxt);
5710 5711 5712 5713 5714 5715 5716 5717 5718 5719
    if (tmp) {
        if ((def->clock.offset = virDomainClockOffsetTypeFromString(tmp)) < 0) {
            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                                 _("unknown clock offset '%s'"), tmp);
            goto error;
        }
        VIR_FREE(tmp);
    } else {
        def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_UTC;
    }
5720 5721 5722
    switch (def->clock.offset) {
    case VIR_DOMAIN_CLOCK_OFFSET_VARIABLE:
        if (virXPathLongLong("number(./clock/@adjustment)", ctxt,
5723 5724 5725 5726 5727 5728 5729 5730 5731 5732 5733
                             &def->clock.data.adjustment) < 0)
            def->clock.data.adjustment = 0;
        break;

    case VIR_DOMAIN_CLOCK_OFFSET_TIMEZONE:
        def->clock.data.timezone = virXPathString("string(./clock/@timezone)", ctxt);
        if (!def->clock.data.timezone) {
            virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                 _("missing 'timezone' attribute for clock with offset='timezone'"));
            goto error;
        }
5734 5735
        break;
    }
5736

5737 5738 5739 5740 5741 5742 5743 5744 5745 5746 5747 5748 5749 5750 5751 5752
    if ((n = virXPathNodeSet("./clock/timer", ctxt, &nodes)) < 0) {
        goto error;
    }
    if (n && VIR_ALLOC_N(def->clock.timers, n) < 0)
        goto no_memory;
    for (i = 0 ; i < n ; i++) {
        virDomainTimerDefPtr timer = virDomainTimerDefParseXML(nodes[i],
                                                               ctxt,
                                                               flags);
        if (!timer)
            goto error;

        def->clock.timers[def->clock.ntimers++] = timer;
    }
    VIR_FREE(nodes);

5753 5754
    def->os.bootloader = virXPathString("string(./bootloader)", ctxt);
    def->os.bootloaderArgs = virXPathString("string(./bootloader_args)", ctxt);
5755

5756
    def->os.type = virXPathString("string(./os/type[1])", ctxt);
5757 5758 5759 5760
    if (!def->os.type) {
        if (def->os.bootloader) {
            def->os.type = strdup("xen");
            if (!def->os.type) {
5761
                virReportOOMError();
5762 5763 5764
                goto error;
            }
        } else {
5765
            virDomainReportError(VIR_ERR_OS_TYPE,
5766 5767 5768 5769 5770 5771 5772 5773 5774 5775 5776 5777 5778
                                 "%s", _("no OS type"));
            goto error;
        }
    }
    /*
     * HACK: For xen driver we previously used bogus 'linux' as the
     * os type for paravirt, whereas capabilities declare it to
     * be 'xen'. So we accept the former and convert
     */
    if (STREQ(def->os.type, "linux") &&
        def->virtType == VIR_DOMAIN_VIRT_XEN) {
        VIR_FREE(def->os.type);
        if (!(def->os.type = strdup("xen"))) {
5779
            virReportOOMError();
5780 5781 5782 5783 5784
            goto error;
        }
    }

    if (!virCapabilitiesSupportsGuestOSType(caps, def->os.type)) {
5785
        virDomainReportError(VIR_ERR_OS_TYPE,
5786 5787 5788 5789
                             "%s", def->os.type);
        goto error;
    }

5790
    def->os.arch = virXPathString("string(./os/type[1]/@arch)", ctxt);
5791 5792
    if (def->os.arch) {
        if (!virCapabilitiesSupportsGuestArch(caps, def->os.type, def->os.arch)) {
5793
            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
5794 5795 5796 5797 5798
                                 _("os type '%s' & arch '%s' combination is not supported"),
                                 def->os.type, def->os.arch);
            goto error;
        }
    } else {
5799
        const char *defaultArch = virCapabilitiesDefaultGuestArch(caps, def->os.type, virDomainVirtTypeToString(def->virtType));
5800
        if (defaultArch == NULL) {
5801
            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
5802 5803 5804 5805 5806
                                 _("no supported architecture for os type '%s'"),
                                 def->os.type);
            goto error;
        }
        if (!(def->os.arch = strdup(defaultArch))) {
5807
            virReportOOMError();
5808 5809 5810 5811
            goto error;
        }
    }

5812
    def->os.machine = virXPathString("string(./os/type[1]/@machine)", ctxt);
5813 5814 5815
    if (!def->os.machine) {
        const char *defaultMachine = virCapabilitiesDefaultGuestMachine(caps,
                                                                        def->os.type,
5816 5817
                                                                        def->os.arch,
                                                                        virDomainVirtTypeToString(def->virtType));
5818 5819
        if (defaultMachine != NULL) {
            if (!(def->os.machine = strdup(defaultMachine))) {
5820
                virReportOOMError();
5821 5822 5823 5824 5825
                goto error;
            }
        }
    }

5826 5827 5828 5829 5830 5831 5832 5833 5834 5835
    /*
     * Booting options for different OS types....
     *
     *   - A bootloader (and optional kernel+initrd)  (xen)
     *   - A kernel + initrd                          (xen)
     *   - A boot device (and optional kernel+initrd) (hvm)
     *   - An init script                             (exe)
     */

    if (STREQ(def->os.type, "exe")) {
5836
        def->os.init = virXPathString("string(./os/init[1])", ctxt);
5837 5838 5839 5840 5841 5842 5843 5844 5845 5846 5847 5848
        if (!def->os.init) {
            if (caps->defaultInitPath) {
                def->os.init = strdup(caps->defaultInitPath);
                if (!def->os.init) {
                    goto no_memory;
                }
            } else {
                virDomainReportError(VIR_ERR_XML_ERROR, "%s",
                                     _("init binary must be specified"));
                goto error;
            }
        }
5849 5850 5851
    }

    if (STREQ(def->os.type, "xen") ||
5852 5853
        STREQ(def->os.type, "hvm") ||
        STREQ(def->os.type, "uml")) {
5854 5855 5856 5857 5858
        def->os.kernel = virXPathString("string(./os/kernel[1])", ctxt);
        def->os.initrd = virXPathString("string(./os/initrd[1])", ctxt);
        def->os.cmdline = virXPathString("string(./os/cmdline[1])", ctxt);
        def->os.root = virXPathString("string(./os/root[1])", ctxt);
        def->os.loader = virXPathString("string(./os/loader[1])", ctxt);
5859
    }
5860

5861 5862 5863 5864 5865
    if (STREQ(def->os.type, "hvm")) {
        if (virDomainDefParseBootXML(ctxt, def, &bootMapSize) < 0)
            goto error;
        if (bootMapSize && !(bootMap = virBitmapAlloc(bootMapSize)))
            goto no_memory;
5866 5867
    }

5868
    def->emulator = virXPathString("string(./devices/emulator[1])", ctxt);
5869
    if (!def->emulator && virCapabilitiesIsEmulatorRequired(caps)) {
5870
        def->emulator = virDomainDefDefaultEmulator(def, caps);
5871 5872 5873
        if (!def->emulator)
            goto error;
    }
5874 5875

    /* analysis of the disk devices */
5876
    if ((n = virXPathNodeSet("./devices/disk", ctxt, &nodes)) < 0) {
5877 5878
        goto error;
    }
5879 5880
    if (n && VIR_ALLOC_N(def->disks, n) < 0)
        goto no_memory;
5881
    for (i = 0 ; i < n ; i++) {
5882 5883
        virDomainDiskDefPtr disk = virDomainDiskDefParseXML(caps,
                                                            nodes[i],
5884
                                                            bootMap,
5885
                                                            flags);
5886 5887 5888
        if (!disk)
            goto error;

5889
        def->disks[def->ndisks++] = disk;
5890 5891 5892
    }
    VIR_FREE(nodes);

5893
    /* analysis of the controller devices */
5894
    if ((n = virXPathNodeSet("./devices/controller", ctxt, &nodes)) < 0) {
5895 5896 5897 5898 5899
        goto error;
    }
    if (n && VIR_ALLOC_N(def->controllers, n) < 0)
        goto no_memory;
    for (i = 0 ; i < n ; i++) {
5900
        virDomainControllerDefPtr controller = virDomainControllerDefParseXML(nodes[i],
5901 5902 5903 5904 5905 5906 5907 5908
                                                                              flags);
        if (!controller)
            goto error;

        def->controllers[def->ncontrollers++] = controller;
    }
    VIR_FREE(nodes);

5909
    /* analysis of the filesystems */
5910
    if ((n = virXPathNodeSet("./devices/filesystem", ctxt, &nodes)) < 0) {
5911 5912
        goto error;
    }
5913 5914 5915
    if (n && VIR_ALLOC_N(def->fss, n) < 0)
        goto no_memory;
    for (i = 0 ; i < n ; i++) {
5916
        virDomainFSDefPtr fs = virDomainFSDefParseXML(nodes[i],
5917
                                                      flags);
5918 5919 5920
        if (!fs)
            goto error;

5921
        def->fss[def->nfss++] = fs;
5922 5923 5924
    }
    VIR_FREE(nodes);

5925
    /* analysis of the network devices */
5926
    if ((n = virXPathNodeSet("./devices/interface", ctxt, &nodes)) < 0) {
5927 5928
        goto error;
    }
5929 5930 5931
    if (n && VIR_ALLOC_N(def->nets, n) < 0)
        goto no_memory;
    for (i = 0 ; i < n ; i++) {
5932
        virDomainNetDefPtr net = virDomainNetDefParseXML(caps,
5933
                                                         nodes[i],
5934
                                                         ctxt,
5935
                                                         bootMap,
5936
                                                         flags);
5937 5938 5939
        if (!net)
            goto error;

5940
        def->nets[def->nnets++] = net;
5941 5942 5943 5944
    }
    VIR_FREE(nodes);


E
Eric Blake 已提交
5945 5946 5947 5948 5949 5950 5951 5952 5953 5954 5955 5956 5957 5958 5959 5960 5961 5962
    /* analysis of the smartcard devices */
    if ((n = virXPathNodeSet("./devices/smartcard", ctxt, &nodes)) < 0) {
        goto error;
    }
    if (n && VIR_ALLOC_N(def->smartcards, n) < 0)
        goto no_memory;

    for (i = 0 ; i < n ; i++) {
        virDomainSmartcardDefPtr card = virDomainSmartcardDefParseXML(nodes[i],
                                                                      flags);
        if (!card)
            goto error;

        def->smartcards[def->nsmartcards++] = card;
    }
    VIR_FREE(nodes);


5963
    /* analysis of the character devices */
5964
    if ((n = virXPathNodeSet("./devices/parallel", ctxt, &nodes)) < 0) {
5965 5966
        goto error;
    }
5967 5968 5969 5970
    if (n && VIR_ALLOC_N(def->parallels, n) < 0)
        goto no_memory;

    for (i = 0 ; i < n ; i++) {
5971 5972
        virDomainChrDefPtr chr = virDomainChrDefParseXML(caps,
                                                         nodes[i],
5973
                                                         flags);
5974 5975 5976
        if (!chr)
            goto error;

5977 5978 5979 5980 5981 5982 5983 5984 5985
        if (chr->target.port == -1) {
            int maxport = -1;
            int j;
            for (j = 0 ; j < i ; j++) {
                if (def->parallels[j]->target.port > maxport)
                    maxport = def->parallels[j]->target.port;
            }
            chr->target.port = maxport + 1;
        }
5986
        def->parallels[def->nparallels++] = chr;
5987 5988 5989
    }
    VIR_FREE(nodes);

5990
    if ((n = virXPathNodeSet("./devices/serial", ctxt, &nodes)) < 0) {
5991 5992
        goto error;
    }
5993 5994 5995 5996
    if (n && VIR_ALLOC_N(def->serials, n) < 0)
        goto no_memory;

    for (i = 0 ; i < n ; i++) {
5997 5998
        virDomainChrDefPtr chr = virDomainChrDefParseXML(caps,
                                                         nodes[i],
5999
                                                         flags);
6000 6001 6002
        if (!chr)
            goto error;

6003 6004 6005 6006 6007 6008 6009 6010 6011
        if (chr->target.port == -1) {
            int maxport = -1;
            int j;
            for (j = 0 ; j < i ; j++) {
                if (def->serials[j]->target.port > maxport)
                    maxport = def->serials[j]->target.port;
            }
            chr->target.port = maxport + 1;
        }
6012
        def->serials[def->nserials++] = chr;
6013 6014 6015
    }
    VIR_FREE(nodes);

6016
    if ((node = virXPathNode("./devices/console[1]", ctxt)) != NULL) {
6017 6018
        virDomainChrDefPtr chr = virDomainChrDefParseXML(caps,
                                                         node,
6019
                                                         flags);
6020 6021
        if (!chr)
            goto error;
6022

6023
        chr->target.port = 0;
6024 6025 6026 6027
        /*
         * For HVM console actually created a serial device
         * while for non-HVM it was a parvirt console
         */
C
Cole Robinson 已提交
6028 6029
        if (STREQ(def->os.type, "hvm") &&
            chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL) {
6030 6031 6032
            if (def->nserials != 0) {
                virDomainChrDefFree(chr);
            } else {
6033 6034 6035 6036 6037 6038
                if (VIR_ALLOC_N(def->serials, 1) < 0) {
                    virDomainChrDefFree(chr);
                    goto no_memory;
                }
                def->nserials = 1;
                def->serials[0] = chr;
6039
                chr->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL;
6040
            }
6041 6042
        } else {
            def->console = chr;
6043 6044 6045
        }
    }

6046
    if ((n = virXPathNodeSet("./devices/channel", ctxt, &nodes)) < 0) {
6047 6048 6049 6050 6051 6052
        goto error;
    }
    if (n && VIR_ALLOC_N(def->channels, n) < 0)
        goto no_memory;

    for (i = 0 ; i < n ; i++) {
6053 6054
        virDomainChrDefPtr chr = virDomainChrDefParseXML(caps,
                                                         nodes[i],
6055 6056 6057 6058 6059
                                                         flags);
        if (!chr)
            goto error;

        def->channels[def->nchannels++] = chr;
6060

6061 6062
        if (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL &&
            chr->targetType == VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO &&
6063 6064 6065
            chr->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
            chr->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL;

6066 6067
        if (chr->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL &&
            chr->info.addr.vioserial.port == 0) {
6068
            int maxport = 0;
6069 6070 6071 6072 6073 6074 6075 6076 6077 6078 6079
            int j;
            for (j = 0 ; j < i ; j++) {
                virDomainChrDefPtr thischr = def->channels[j];
                if (thischr->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL &&
                    thischr->info.addr.vioserial.controller == chr->info.addr.vioserial.controller &&
                    thischr->info.addr.vioserial.bus == chr->info.addr.vioserial.bus &&
                    (int)thischr->info.addr.vioserial.port > maxport)
                    maxport = thischr->info.addr.vioserial.port;
            }
            chr->info.addr.vioserial.port = maxport + 1;
        }
6080 6081 6082
    }
    VIR_FREE(nodes);

6083 6084

    /* analysis of the input devices */
6085
    if ((n = virXPathNodeSet("./devices/input", ctxt, &nodes)) < 0) {
6086 6087
        goto error;
    }
6088 6089 6090 6091
    if (n && VIR_ALLOC_N(def->inputs, n) < 0)
        goto no_memory;

    for (i = 0 ; i < n ; i++) {
6092
        virDomainInputDefPtr input = virDomainInputDefParseXML(def->os.type,
6093 6094
                                                               nodes[i],
                                                               flags);
6095 6096 6097 6098 6099 6100 6101 6102 6103 6104 6105 6106 6107 6108 6109 6110 6111
        if (!input)
            goto error;


        /* With QEMU / KVM / Xen graphics, mouse + PS/2 is implicit
         * with graphics, so don't store it.
         * XXX will this be true for other virt types ? */
        if ((STREQ(def->os.type, "hvm") &&
             input->bus == VIR_DOMAIN_INPUT_BUS_PS2 &&
             input->type == VIR_DOMAIN_INPUT_TYPE_MOUSE) ||
            (STRNEQ(def->os.type, "hvm") &&
             input->bus == VIR_DOMAIN_INPUT_BUS_XEN &&
             input->type == VIR_DOMAIN_INPUT_TYPE_MOUSE)) {
            virDomainInputDefFree(input);
            continue;
        }

6112
        def->inputs[def->ninputs++] = input;
6113 6114 6115
    }
    VIR_FREE(nodes);

6116
    /* analysis of the graphics devices */
6117
    if ((n = virXPathNodeSet("./devices/graphics", ctxt, &nodes)) < 0) {
6118 6119
        goto error;
    }
6120 6121 6122
    if (n && VIR_ALLOC_N(def->graphics, n) < 0)
        goto no_memory;
    for (i = 0 ; i < n ; i++) {
6123
        virDomainGraphicsDefPtr graphics = virDomainGraphicsDefParseXML(nodes[i],
6124
                                                                        flags);
6125 6126 6127
        if (!graphics)
            goto error;

6128
        def->graphics[def->ngraphics++] = graphics;
6129 6130 6131 6132
    }
    VIR_FREE(nodes);

    /* If graphics are enabled, there's an implicit PS2 mouse */
6133
    if (def->ngraphics > 0) {
6134 6135 6136
        virDomainInputDefPtr input;

        if (VIR_ALLOC(input) < 0) {
6137
            virReportOOMError();
6138 6139 6140 6141 6142 6143 6144 6145 6146
            goto error;
        }
        if (STREQ(def->os.type, "hvm")) {
            input->type = VIR_DOMAIN_INPUT_TYPE_MOUSE;
            input->bus = VIR_DOMAIN_INPUT_BUS_PS2;
        } else {
            input->type = VIR_DOMAIN_INPUT_TYPE_MOUSE;
            input->bus = VIR_DOMAIN_INPUT_BUS_XEN;
        }
6147 6148 6149 6150 6151 6152 6153

        if (VIR_REALLOC_N(def->inputs, def->ninputs + 1) < 0) {
            virDomainInputDefFree(input);
            goto no_memory;
        }
        def->inputs[def->ninputs] = input;
        def->ninputs++;
6154 6155 6156 6157
    }


    /* analysis of the sound devices */
6158
    if ((n = virXPathNodeSet("./devices/sound", ctxt, &nodes)) < 0) {
6159 6160
        goto error;
    }
6161 6162 6163
    if (n && VIR_ALLOC_N(def->sounds, n) < 0)
        goto no_memory;
    for (i = 0 ; i < n ; i++) {
6164
        virDomainSoundDefPtr sound = virDomainSoundDefParseXML(nodes[i],
6165
                                                               flags);
6166 6167 6168
        if (!sound)
            goto error;

6169
        def->sounds[def->nsounds++] = sound;
6170 6171 6172
    }
    VIR_FREE(nodes);

6173
    /* analysis of the video devices */
6174
    if ((n = virXPathNodeSet("./devices/video", ctxt, &nodes)) < 0) {
6175 6176 6177 6178 6179
        goto error;
    }
    if (n && VIR_ALLOC_N(def->videos, n) < 0)
        goto no_memory;
    for (i = 0 ; i < n ; i++) {
6180
        virDomainVideoDefPtr video = virDomainVideoDefParseXML(nodes[i],
6181 6182 6183 6184 6185 6186 6187 6188 6189 6190 6191 6192 6193 6194 6195 6196
                                                               def,
                                                               flags);
        if (!video)
            goto error;
        def->videos[def->nvideos++] = video;
    }
    VIR_FREE(nodes);

    /* For backwards compatability, if no <video> tag is set but there
     * is a <graphics> tag, then we add a single video tag */
    if (def->ngraphics && !def->nvideos) {
        virDomainVideoDefPtr video;
        if (VIR_ALLOC(video) < 0)
            goto no_memory;
        video->type = virDomainVideoDefaultType(def);
        if (video->type < 0) {
6197
            virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6198 6199 6200 6201 6202 6203 6204 6205 6206 6207 6208 6209 6210
                                 _("cannot determine default video type"));
            VIR_FREE(video);
            goto error;
        }
        video->vram = virDomainVideoDefaultRAM(def, video->type);
        video->heads = 1;
        if (VIR_ALLOC_N(def->videos, 1) < 0) {
            virDomainVideoDefFree(video);
            goto no_memory;
        }
        def->videos[def->nvideos++] = video;
    }

6211
    /* analysis of the host devices */
6212
    if ((n = virXPathNodeSet("./devices/hostdev", ctxt, &nodes)) < 0) {
6213 6214
        goto error;
    }
6215 6216
    if (n && VIR_ALLOC_N(def->hostdevs, n) < 0)
        goto no_memory;
6217
    for (i = 0 ; i < n ; i++) {
6218
        virDomainHostdevDefPtr hostdev = virDomainHostdevDefParseXML(nodes[i],
6219
                                                                     bootMap,
6220
                                                                     flags);
6221 6222 6223
        if (!hostdev)
            goto error;

6224
        def->hostdevs[def->nhostdevs++] = hostdev;
6225 6226 6227
    }
    VIR_FREE(nodes);

R
Richard Jones 已提交
6228 6229
    /* analysis of the watchdog devices */
    def->watchdog = NULL;
6230
    if ((n = virXPathNodeSet("./devices/watchdog", ctxt, &nodes)) < 0) {
R
Richard Jones 已提交
6231 6232 6233
        goto error;
    }
    if (n > 1) {
6234
        virDomainReportError (VIR_ERR_INTERNAL_ERROR,
R
Richard Jones 已提交
6235 6236 6237 6238 6239
                              "%s", _("only a single watchdog device is supported"));
        goto error;
    }
    if (n > 0) {
        virDomainWatchdogDefPtr watchdog =
6240
            virDomainWatchdogDefParseXML(nodes[0], flags);
R
Richard Jones 已提交
6241 6242 6243 6244 6245 6246 6247
        if (!watchdog)
            goto error;

        def->watchdog = watchdog;
        VIR_FREE(nodes);
    }

6248 6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 6264 6265 6266 6267 6268 6269 6270 6271 6272 6273 6274 6275 6276 6277 6278 6279 6280
    /* analysis of the memballoon devices */
    def->memballoon = NULL;
    if ((n = virXPathNodeSet("./devices/memballoon", ctxt, &nodes)) < 0) {
        goto error;
    }
    if (n > 1) {
        virDomainReportError (VIR_ERR_INTERNAL_ERROR,
                              "%s", _("only a single memory balloon device is supported"));
        goto error;
    }
    if (n > 0) {
        virDomainMemballoonDefPtr memballoon =
            virDomainMemballoonDefParseXML(nodes[0], flags);
        if (!memballoon)
            goto error;

        def->memballoon = memballoon;
        VIR_FREE(nodes);
    } else {
        if (def->virtType == VIR_DOMAIN_VIRT_XEN ||
            def->virtType == VIR_DOMAIN_VIRT_QEMU ||
            def->virtType == VIR_DOMAIN_VIRT_KQEMU ||
            def->virtType == VIR_DOMAIN_VIRT_KVM) {
            virDomainMemballoonDefPtr memballoon;
            if (VIR_ALLOC(memballoon) < 0)
                goto no_memory;
            memballoon->model = def->virtType == VIR_DOMAIN_VIRT_XEN ?
                VIR_DOMAIN_MEMBALLOON_MODEL_XEN :
                VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO;
            def->memballoon = memballoon;
        }
    }

6281
    /* analysis of security label */
6282
    if (virSecurityLabelDefParseXML(def, ctxt, flags) == -1)
6283 6284
        goto error;

6285
    if ((node = virXPathNode("./cpu[1]", ctxt)) != NULL) {
6286 6287
        xmlNodePtr oldnode = ctxt->node;
        ctxt->node = node;
6288
        def->cpu = virCPUDefParseXML(node, ctxt, VIR_CPU_TYPE_GUEST);
6289 6290 6291 6292 6293 6294
        ctxt->node = oldnode;

        if (def->cpu == NULL)
            goto error;
    }

6295 6296 6297 6298 6299 6300 6301 6302
    if ((node = virXPathNode("./sysinfo[1]", ctxt)) != NULL) {
        xmlNodePtr oldnode = ctxt->node;
        ctxt->node = node;
        def->sysinfo = virSysinfoParseXML(node, ctxt);
        ctxt->node = oldnode;

        if (def->sysinfo == NULL)
            goto error;
6303 6304 6305 6306 6307 6308 6309 6310 6311 6312 6313 6314 6315 6316 6317 6318
        if (def->sysinfo->system_uuid != NULL) {
            unsigned char uuidbuf[VIR_UUID_BUFLEN];
            if (virUUIDParse(def->sysinfo->system_uuid, uuidbuf) < 0) {
                virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                                     "%s", _("malformed uuid element"));
                goto error;
            }
            if (uuid_generated)
                memcpy(def->uuid, uuidbuf, VIR_UUID_BUFLEN);
            else if (memcmp(def->uuid, uuidbuf, VIR_UUID_BUFLEN) != 0) {
                virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                     _("UUID mismatch between <uuid> and "
                                       "<sysinfo>"));
                goto error;
            }
        }
6319
    }
6320 6321 6322 6323 6324 6325 6326 6327 6328 6329 6330 6331 6332 6333
    tmp = virXPathString("string(./os/smbios/@mode)", ctxt);
    if (tmp) {
        int mode;

        if ((mode = virDomainSmbiosModeTypeFromString(tmp)) < 0) {
            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                                 _("unknown smbios mode '%s'"), tmp);
            goto error;
        }
        def->os.smbios_mode = mode;
        VIR_FREE(tmp);
    } else {
        def->os.smbios_mode = VIR_DOMAIN_SMBIOS_NONE; /* not present */
    }
6334

6335 6336 6337 6338 6339 6340 6341 6342 6343 6344
    /* we have to make a copy of all of the callback pointers here since
     * we won't have the virCaps structure available during free
     */
    def->ns = caps->ns;

    if (def->ns.parse) {
        if ((def->ns.parse)(xml, root, ctxt, &def->namespaceData) < 0)
            goto error;
    }

6345 6346 6347 6348 6349
    /* Auto-add any implied controllers which aren't present
     */
    if (virDomainDefAddImplicitControllers(def) < 0)
        goto error;

6350 6351
    virBitmapFree(bootMap);

6352 6353
    return def;

6354
no_memory:
6355
    virReportOOMError();
6356 6357
    /* fallthrough */

6358 6359 6360
 error:
    VIR_FREE(tmp);
    VIR_FREE(nodes);
6361
    virBitmapFree(bootMap);
6362 6363 6364 6365
    virDomainDefFree(def);
    return NULL;
}

6366

6367
static virDomainObjPtr virDomainObjParseXML(virCapsPtr caps,
6368
                                            xmlDocPtr xml,
6369 6370 6371 6372 6373 6374 6375
                                            xmlXPathContextPtr ctxt)
{
    char *tmp = NULL;
    long val;
    xmlNodePtr config;
    xmlNodePtr oldnode;
    virDomainObjPtr obj;
6376 6377
    xmlNodePtr *nodes = NULL;
    int i, n;
J
Jiri Denemark 已提交
6378 6379
    int state;
    int reason = 0;
6380

6381
    if (!(obj = virDomainObjNew(caps)))
6382 6383
        return NULL;

6384
    if (!(config = virXPathNode("./domain", ctxt))) {
6385
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
6386 6387 6388 6389 6390 6391
                             "%s", _("no domain config"));
        goto error;
    }

    oldnode = ctxt->node;
    ctxt->node = config;
6392
    obj->def = virDomainDefParseXML(caps, xml, config, ctxt,
6393
                                    VIR_DOMAIN_XML_INTERNAL_STATUS);
6394 6395 6396 6397
    ctxt->node = oldnode;
    if (!obj->def)
        goto error;

6398
    if (!(tmp = virXPathString("string(./@state)", ctxt))) {
6399
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
6400 6401 6402
                             "%s", _("missing domain state"));
        goto error;
    }
J
Jiri Denemark 已提交
6403
    if ((state = virDomainStateTypeFromString(tmp)) < 0) {
6404
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
6405 6406 6407 6408 6409 6410
                             _("invalid domain state '%s'"), tmp);
        VIR_FREE(tmp);
        goto error;
    }
    VIR_FREE(tmp);

J
Jiri Denemark 已提交
6411 6412 6413 6414 6415 6416 6417 6418 6419 6420 6421 6422
    if ((tmp = virXPathString("string(./@reason)", ctxt))) {
        if ((reason = virDomainStateReasonFromString(state, tmp)) < 0) {
            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                                 _("invalid domain state reason '%s'"), tmp);
            VIR_FREE(tmp);
            goto error;
        }
        VIR_FREE(tmp);
    }

    virDomainObjSetState(obj, state, reason);

6423
    if ((virXPathLong("string(./@pid)", ctxt, &val)) < 0) {
6424
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
6425 6426 6427 6428 6429
                             "%s", _("invalid pid"));
        goto error;
    }
    obj->pid = (pid_t)val;

6430 6431 6432 6433 6434 6435 6436 6437 6438 6439 6440 6441 6442 6443 6444 6445 6446 6447
    if ((n = virXPathNodeSet("./taint", ctxt, &nodes)) < 0) {
        goto error;
    }
    for (i = 0 ; i < n ; i++) {
        char *str = virXMLPropString(nodes[i], "flag");
        if (str) {
            int flag = virDomainTaintTypeFromString(str);
            VIR_FREE(str);
            if (flag < 0) {
                virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                                     _("Unknown taint flag %s"), str);
                goto error;
            }
            virDomainObjTaint(obj, flag);
        }
    }
    VIR_FREE(nodes);

6448 6449
    if (caps->privateDataXMLParse &&
        ((caps->privateDataXMLParse)(ctxt, obj->privateData)) < 0)
6450
        goto error;
6451

6452 6453 6454
    return obj;

error:
6455 6456
    /* obj was never shared, so unref should return 0 */
    ignore_value(virDomainObjUnref(obj));
6457
    VIR_FREE(nodes);
6458 6459 6460 6461
    return NULL;
}


J
Jiri Denemark 已提交
6462 6463 6464 6465 6466
static virDomainDefPtr
virDomainDefParse(const char *xmlStr,
                  const char *filename,
                  virCapsPtr caps,
                  int flags)
6467
{
J
Jiri Denemark 已提交
6468 6469 6470 6471 6472 6473
    xmlDocPtr xml;
    virDomainDefPtr def = NULL;

    if ((xml = virXMLParse(filename, xmlStr, "domain.xml"))) {
        def = virDomainDefParseNode(caps, xml, xmlDocGetRootElement(xml), flags);
        xmlFreeDoc(xml);
6474
    }
J
Jiri Denemark 已提交
6475 6476

    return def;
6477
}
6478

6479
virDomainDefPtr virDomainDefParseString(virCapsPtr caps,
6480 6481
                                        const char *xmlStr,
                                        int flags)
6482
{
J
Jiri Denemark 已提交
6483
    return virDomainDefParse(xmlStr, NULL, caps, flags);
6484 6485
}

6486
virDomainDefPtr virDomainDefParseFile(virCapsPtr caps,
J
Jiri Denemark 已提交
6487 6488
                                      const char *filename,
                                      int flags)
6489
{
J
Jiri Denemark 已提交
6490
    return virDomainDefParse(NULL, filename, caps, flags);
6491 6492 6493
}


6494
virDomainDefPtr virDomainDefParseNode(virCapsPtr caps,
6495
                                      xmlDocPtr xml,
6496 6497
                                      xmlNodePtr root,
                                      int flags)
6498 6499 6500 6501 6502
{
    xmlXPathContextPtr ctxt = NULL;
    virDomainDefPtr def = NULL;

    if (!xmlStrEqual(root->name, BAD_CAST "domain")) {
6503
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
6504 6505 6506 6507 6508 6509
                              "%s", _("incorrect root element"));
        goto cleanup;
    }

    ctxt = xmlXPathNewContext(xml);
    if (ctxt == NULL) {
6510
        virReportOOMError();
6511 6512 6513 6514
        goto cleanup;
    }

    ctxt->node = root;
6515
    def = virDomainDefParseXML(caps, xml, root, ctxt, flags);
6516 6517 6518 6519 6520

cleanup:
    xmlXPathFreeContext(ctxt);
    return def;
}
6521 6522


H
Hu Tao 已提交
6523 6524 6525 6526
static virDomainObjPtr
virDomainObjParseNode(virCapsPtr caps,
                      xmlDocPtr xml,
                      xmlNodePtr root)
6527 6528 6529 6530 6531
{
    xmlXPathContextPtr ctxt = NULL;
    virDomainObjPtr obj = NULL;

    if (!xmlStrEqual(root->name, BAD_CAST "domstatus")) {
6532
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
6533 6534 6535 6536 6537 6538
                             "%s", _("incorrect root element"));
        goto cleanup;
    }

    ctxt = xmlXPathNewContext(xml);
    if (ctxt == NULL) {
6539
        virReportOOMError();
6540 6541 6542 6543
        goto cleanup;
    }

    ctxt->node = root;
6544
    obj = virDomainObjParseXML(caps, xml, ctxt);
6545 6546 6547 6548 6549 6550

cleanup:
    xmlXPathFreeContext(ctxt);
    return obj;
}

H
Hu Tao 已提交
6551 6552 6553 6554 6555 6556 6557 6558 6559 6560 6561 6562 6563 6564 6565 6566

virDomainObjPtr virDomainObjParseFile(virCapsPtr caps,
                                      const char *filename)
{
    xmlDocPtr xml;
    virDomainObjPtr obj = NULL;

    if ((xml = virXMLParseFile(filename))) {
        obj = virDomainObjParseNode(caps, xml, xmlDocGetRootElement(xml));
        xmlFreeDoc(xml);
    }

    return obj;
}


6567 6568 6569
static int virDomainDefMaybeAddController(virDomainDefPtr def,
                                          int type,
                                          int idx)
6570 6571 6572 6573 6574 6575 6576 6577 6578 6579 6580 6581 6582 6583 6584
{
    int found = 0;
    int i;
    virDomainControllerDefPtr cont;

    for (i = 0 ; (i < def->ncontrollers) && !found; i++) {
        if (def->controllers[i]->type == type &&
            def->controllers[i]->idx == idx)
            found = 1;
    }

    if (found)
        return 0;

    if (VIR_ALLOC(cont) < 0) {
6585
        virReportOOMError();
6586 6587 6588 6589 6590
        return -1;
    }

    cont->type = type;
    cont->idx = idx;
6591
    cont->model = -1;
6592

6593 6594 6595 6596 6597 6598
    if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL) {
        cont->opts.vioserial.ports = -1;
        cont->opts.vioserial.vectors = -1;
    }


6599 6600
    if (VIR_REALLOC_N(def->controllers, def->ncontrollers+1) < 0) {
        VIR_FREE(cont);
6601
        virReportOOMError();
6602 6603 6604 6605 6606 6607 6608 6609 6610 6611 6612 6613 6614 6615 6616 6617 6618 6619 6620 6621 6622 6623 6624 6625 6626 6627 6628
        return -1;
    }
    def->controllers[def->ncontrollers] = cont;
    def->ncontrollers++;

    return 0;
}

static int virDomainDefAddDiskControllersForType(virDomainDefPtr def,
                                                 int controllerType,
                                                 int diskBus)
{
    int i;
    int maxController = -1;

    for (i = 0 ; i < def->ndisks ; i++) {
        if (def->disks[i]->bus != diskBus)
            continue;

        if (def->disks[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE)
            continue;

        if ((int)def->disks[i]->info.addr.drive.controller > maxController)
            maxController = def->disks[i]->info.addr.drive.controller;
    }

    for (i = 0 ; i <= maxController ; i++) {
6629
        if (virDomainDefMaybeAddController(def, controllerType, i) < 0)
6630 6631 6632 6633 6634 6635 6636
            return -1;
    }

    return 0;
}


6637 6638
static int virDomainDefMaybeAddVirtioSerialController(virDomainDefPtr def)
{
C
Cole Robinson 已提交
6639
    /* Look for any virtio serial or virtio console devs */
6640
    int i;
6641

6642 6643 6644
    for (i = 0 ; i < def->nchannels ; i++) {
        virDomainChrDefPtr channel = def->channels[i];

6645
        if (channel->targetType == VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO) {
6646 6647 6648 6649
            int idx = 0;
            if (channel->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL)
                idx = channel->info.addr.vioserial.controller;

6650
            if (virDomainDefMaybeAddController(def,
6651
                VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL, idx) < 0)
6652 6653 6654 6655
                return -1;
        }
    }

C
Cole Robinson 已提交
6656 6657 6658 6659 6660 6661 6662 6663 6664 6665 6666 6667 6668 6669 6670
    if (def->console) {
        virDomainChrDefPtr console = def->console;

        if (console->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_VIRTIO) {
            int idx = 0;
            if (console->info.type ==
                VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL)
                idx = console->info.addr.vioserial.controller;

            if (virDomainDefMaybeAddController(def,
                VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL, idx) < 0)
                return -1;
        }
    }

6671 6672 6673 6674
    return 0;
}


E
Eric Blake 已提交
6675 6676 6677 6678 6679 6680 6681 6682 6683 6684 6685 6686 6687 6688 6689 6690 6691 6692 6693 6694 6695 6696 6697 6698 6699 6700 6701 6702 6703 6704 6705 6706 6707 6708 6709 6710 6711 6712 6713
static int
virDomainDefMaybeAddSmartcardController(virDomainDefPtr def)
{
    /* Look for any smartcard devs */
    int i;

    for (i = 0 ; i < def->nsmartcards ; i++) {
        virDomainSmartcardDefPtr smartcard = def->smartcards[i];
        int idx = 0;

        if (smartcard->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCID) {
            idx = smartcard->info.addr.ccid.controller;
        } else if (smartcard->info.type
                   == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
            int j;
            int max = -1;

            for (j = 0; j < def->nsmartcards; j++) {
                virDomainDeviceInfoPtr info = &def->smartcards[j]->info;
                if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCID &&
                    info->addr.ccid.controller == 0 &&
                    (int) info->addr.ccid.slot > max)
                    max = info->addr.ccid.slot;
            }
            smartcard->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCID;
            smartcard->info.addr.ccid.controller = 0;
            smartcard->info.addr.ccid.slot = max + 1;
        }

        if (virDomainDefMaybeAddController(def,
                                           VIR_DOMAIN_CONTROLLER_TYPE_CCID,
                                           idx) < 0)
            return -1;
    }

    return 0;
}


6714
/*
6715
 * Based on the declared <address/> info for any devices,
6716 6717 6718 6719
 * add neccessary drive controllers which are not already present
 * in the XML. This is for compat with existing apps which will
 * not know/care about <controller> info in the XML
 */
6720
int virDomainDefAddImplicitControllers(virDomainDefPtr def)
6721 6722 6723 6724 6725 6726 6727 6728 6729 6730 6731 6732 6733 6734 6735 6736
{
    if (virDomainDefAddDiskControllersForType(def,
                                              VIR_DOMAIN_CONTROLLER_TYPE_SCSI,
                                              VIR_DOMAIN_DISK_BUS_SCSI) < 0)
        return -1;

    if (virDomainDefAddDiskControllersForType(def,
                                              VIR_DOMAIN_CONTROLLER_TYPE_FDC,
                                              VIR_DOMAIN_DISK_BUS_FDC) < 0)
        return -1;

    if (virDomainDefAddDiskControllersForType(def,
                                              VIR_DOMAIN_CONTROLLER_TYPE_IDE,
                                              VIR_DOMAIN_DISK_BUS_IDE) < 0)
        return -1;

6737 6738 6739
    if (virDomainDefMaybeAddVirtioSerialController(def) < 0)
        return -1;

E
Eric Blake 已提交
6740 6741 6742
    if (virDomainDefMaybeAddSmartcardController(def) < 0)
        return -1;

6743 6744 6745 6746
    return 0;
}


6747
/************************************************************************
6748 6749 6750
 *                                                                        *
 * Parser and converter for the CPUset strings used in libvirt                *
 *                                                                        *
6751 6752 6753 6754 6755 6756 6757 6758 6759 6760 6761 6762 6763 6764 6765 6766 6767 6768 6769 6770 6771 6772 6773 6774 6775 6776 6777 6778 6779 6780 6781 6782 6783 6784 6785 6786 6787 6788
 ************************************************************************/
/**
 * virDomainCpuNumberParse
 * @str: pointer to the char pointer used
 * @maxcpu: maximum CPU number allowed
 *
 * Parse a CPU number
 *
 * Returns the CPU number or -1 in case of error. @str will be
 *         updated to skip the number.
 */
static int
virDomainCpuNumberParse(const char **str, int maxcpu)
{
    int ret = 0;
    const char *cur = *str;

    if (!c_isdigit(*cur))
        return (-1);

    while (c_isdigit(*cur)) {
        ret = ret * 10 + (*cur - '0');
        if (ret >= maxcpu)
            return (-1);
        cur++;
    }
    *str = cur;
    return (ret);
}

/**
 * virDomainCpuSetFormat:
 * @conn: connection
 * @cpuset: pointer to a char array for the CPU set
 * @maxcpu: number of elements available in @cpuset
 *
 * Serialize the cpuset to a string
 *
E
Eric Blake 已提交
6789
 * Returns the new string NULL in case of error. The string needs to be
6790 6791 6792
 *         freed by the caller.
 */
char *
6793
virDomainCpuSetFormat(char *cpuset, int maxcpu)
6794 6795 6796 6797 6798 6799 6800 6801 6802 6803 6804 6805 6806 6807 6808 6809 6810 6811 6812 6813
{
    virBuffer buf = VIR_BUFFER_INITIALIZER;
    int start, cur;
    int first = 1;

    if ((cpuset == NULL) || (maxcpu <= 0) || (maxcpu > 100000))
        return (NULL);

    cur = 0;
    start = -1;
    while (cur < maxcpu) {
        if (cpuset[cur]) {
            if (start == -1)
                start = cur;
        } else if (start != -1) {
            if (!first)
                virBufferAddLit(&buf, ",");
            else
                first = 0;
            if (cur == start + 1)
6814
                virBufferAsprintf(&buf, "%d", start);
6815
            else
6816
                virBufferAsprintf(&buf, "%d-%d", start, cur - 1);
6817 6818 6819 6820 6821 6822 6823 6824
            start = -1;
        }
        cur++;
    }
    if (start != -1) {
        if (!first)
            virBufferAddLit(&buf, ",");
        if (maxcpu == start + 1)
6825
            virBufferAsprintf(&buf, "%d", start);
6826
        else
6827
            virBufferAsprintf(&buf, "%d-%d", start, maxcpu - 1);
6828 6829 6830
    }

    if (virBufferError(&buf)) {
6831
        virBufferFreeAndReset(&buf);
6832
        virReportOOMError();
6833 6834 6835 6836 6837 6838 6839 6840 6841 6842 6843 6844 6845 6846 6847
        return NULL;
    }

    return virBufferContentAndReset(&buf);
}

/**
 * virDomainCpuSetParse:
 * @conn: connection
 * @str: pointer to a CPU set string pointer
 * @sep: potential character used to mark the end of string if not 0
 * @cpuset: pointer to a char array for the CPU set
 * @maxcpu: number of elements available in @cpuset
 *
 * Parse the cpu set, it will set the value for enabled CPUs in the @cpuset
E
Eric Blake 已提交
6848 6849
 * to 1, and 0 otherwise. The syntax allows comma separated entries; each
 * can be either a CPU number, ^N to unset that CPU, or N-M for ranges.
6850 6851 6852 6853 6854 6855
 *
 * Returns the number of CPU found in that set, or -1 in case of error.
 *         @cpuset is modified accordingly to the value parsed.
 *         @str is updated to the end of the part parsed
 */
int
6856
virDomainCpuSetParse(const char **str, char sep,
6857 6858 6859 6860 6861 6862 6863 6864 6865 6866 6867 6868 6869 6870 6871 6872 6873 6874 6875 6876 6877 6878 6879 6880 6881 6882 6883 6884 6885 6886 6887 6888 6889 6890 6891 6892 6893 6894 6895 6896 6897 6898 6899 6900 6901 6902 6903 6904 6905 6906 6907 6908 6909 6910 6911 6912 6913 6914 6915 6916 6917 6918 6919 6920 6921 6922 6923 6924 6925 6926 6927 6928 6929 6930 6931 6932 6933 6934 6935 6936
                     char *cpuset, int maxcpu)
{
    const char *cur;
    int ret = 0;
    int i, start, last;
    int neg = 0;

    if ((str == NULL) || (cpuset == NULL) || (maxcpu <= 0) ||
        (maxcpu > 100000))
        return (-1);

    cur = *str;
    virSkipSpaces(&cur);
    if (*cur == 0)
        goto parse_error;

    /* initialize cpumap to all 0s */
    for (i = 0; i < maxcpu; i++)
        cpuset[i] = 0;
    ret = 0;

    while ((*cur != 0) && (*cur != sep)) {
        /*
         * 3 constructs are allowed:
         *     - N   : a single CPU number
         *     - N-M : a range of CPU numbers with N < M
         *     - ^N  : remove a single CPU number from the current set
         */
        if (*cur == '^') {
            cur++;
            neg = 1;
        }

        if (!c_isdigit(*cur))
            goto parse_error;
        start = virDomainCpuNumberParse(&cur, maxcpu);
        if (start < 0)
            goto parse_error;
        virSkipSpaces(&cur);
        if ((*cur == ',') || (*cur == 0) || (*cur == sep)) {
            if (neg) {
                if (cpuset[start] == 1) {
                    cpuset[start] = 0;
                    ret--;
                }
            } else {
                if (cpuset[start] == 0) {
                    cpuset[start] = 1;
                    ret++;
                }
            }
        } else if (*cur == '-') {
            if (neg)
                goto parse_error;
            cur++;
            virSkipSpaces(&cur);
            last = virDomainCpuNumberParse(&cur, maxcpu);
            if (last < start)
                goto parse_error;
            for (i = start; i <= last; i++) {
                if (cpuset[i] == 0) {
                    cpuset[i] = 1;
                    ret++;
                }
            }
            virSkipSpaces(&cur);
        }
        if (*cur == ',') {
            cur++;
            virSkipSpaces(&cur);
            neg = 0;
        } else if ((*cur == 0) || (*cur == sep)) {
            break;
        } else
            goto parse_error;
    }
    *str = cur;
    return (ret);

  parse_error:
6937
    virDomainReportError(VIR_ERR_INTERNAL_ERROR,
6938 6939 6940 6941 6942
                         "%s", _("topology cpuset syntax error"));
    return (-1);
}


6943 6944 6945 6946 6947 6948 6949 6950 6951 6952 6953 6954 6955 6956 6957 6958 6959 6960 6961 6962 6963 6964 6965 6966 6967 6968 6969 6970 6971 6972 6973 6974 6975 6976 6977 6978 6979 6980 6981 6982 6983 6984 6985 6986 6987 6988 6989 6990 6991 6992 6993 6994 6995 6996 6997 6998 6999 7000 7001 7002 7003 7004 7005 7006 7007 7008 7009 7010 7011 7012 7013 7014 7015 7016 7017 7018 7019 7020 7021 7022 7023 7024 7025 7026 7027 7028 7029 7030 7031 7032 7033 7034 7035 7036 7037 7038 7039 7040 7041 7042 7043 7044 7045 7046 7047 7048 7049 7050 7051 7052 7053 7054 7055 7056 7057 7058 7059 7060 7061 7062
/* Check if vcpupin with same vcpuid already exists.
 * Return 1 if exists, 0 if not. */
int
virDomainVcpupinIsDuplicate(virDomainVcpupinDefPtr *def,
                            int nvcpupin,
                            int vcpu)
{
    int i;

    if (!def || !nvcpupin)
        return 0;

    for (i = 0; i < nvcpupin; i++) {
        if (def[i]->vcpuid == vcpu)
            return 1;
    }

    return 0;
}

virDomainVcpupinDefPtr
virDomainVcpupinFindByVcpu(virDomainVcpupinDefPtr *def,
                           int nvcpupin,
                           int vcpu)
{
    int i;

    if (!def || !nvcpupin)
        return NULL;

    for (i = 0; i < nvcpupin; i++) {
        if (def[i]->vcpuid == vcpu)
            return def[i];
    }

    return NULL;
}

int
virDomainVcpupinAdd(virDomainDefPtr def,
                    unsigned char *cpumap,
                    int maplen,
                    int vcpu)
{
    virDomainVcpupinDefPtr *vcpupin_list = NULL;
    virDomainVcpupinDefPtr vcpupin = NULL;
    char *cpumask = NULL;
    int i;

    if (VIR_ALLOC_N(cpumask, VIR_DOMAIN_CPUMASK_LEN) < 0) {
        virReportOOMError();
        goto cleanup;
    }

    /* Reset cpumask to all 0s. */
    for (i = 0; i < VIR_DOMAIN_CPUMASK_LEN; i++)
        cpumask[i] = 0;

    /* Convert bitmap (cpumap) to cpumask, which is byte map? */
    for (i = 0; i < maplen; i++) {
        int cur;

        for (cur = 0; cur < 8; cur++) {
            if (cpumap[i] & (1 << cur))
                cpumask[i * 8 + cur] = 1;
        }
    }

    /* No vcpupin exists yet. */
    if (!def->cputune.nvcpupin) {
        if (VIR_ALLOC(vcpupin) < 0) {
            virReportOOMError();
            goto cleanup;
        }

        if (VIR_ALLOC(vcpupin_list) < 0) {
            virReportOOMError();
            VIR_FREE(vcpupin);
            goto cleanup;
        }

        vcpupin->vcpuid = vcpu;
        vcpupin->cpumask = cpumask;
        vcpupin_list[def->cputune.nvcpupin++] = vcpupin;

        def->cputune.vcpupin = vcpupin_list;
    } else {
        if (virDomainVcpupinIsDuplicate(def->cputune.vcpupin,
                                        def->cputune.nvcpupin,
                                        vcpu)) {
            vcpupin = virDomainVcpupinFindByVcpu(def->cputune.vcpupin,
                                                 def->cputune.nvcpupin,
                                                 vcpu);
            vcpupin->vcpuid = vcpu;
            vcpupin->cpumask = cpumask;
        } else {
            if (VIR_ALLOC(vcpupin) < 0) {
                virReportOOMError();
                goto cleanup;
            }

            if (VIR_REALLOC_N(def->cputune.vcpupin, def->cputune.nvcpupin + 1) < 0) {
                virReportOOMError();
                VIR_FREE(vcpupin);
                goto cleanup;
            }

            vcpupin->vcpuid = vcpu;
            vcpupin->cpumask = cpumask;
            def->cputune.vcpupin[def->cputune.nvcpupin++] = vcpupin;
       }
    }

    return 0;

cleanup:
    VIR_FREE(cpumask);
    return -1;
}

7063
static int
7064
virDomainLifecycleDefFormat(virBufferPtr buf,
7065
                            int type,
7066 7067
                            const char *name,
                            virLifecycleToStringFunc convFunc)
7068
{
7069
    const char *typeStr = convFunc(type);
7070
    if (!typeStr) {
7071
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
7072 7073 7074 7075
                             _("unexpected lifecycle type %d"), type);
        return -1;
    }

7076
    virBufferAsprintf(buf, "  <%s>%s</%s>\n", name, typeStr, name);
7077 7078 7079 7080 7081 7082

    return 0;
}


static int
7083
virDomainDiskDefFormat(virBufferPtr buf,
D
Daniel P. Berrange 已提交
7084 7085
                       virDomainDiskDefPtr def,
                       int flags)
7086 7087 7088 7089
{
    const char *type = virDomainDiskTypeToString(def->type);
    const char *device = virDomainDiskDeviceTypeToString(def->device);
    const char *bus = virDomainDiskBusTypeToString(def->bus);
7090
    const char *cachemode = virDomainDiskCacheTypeToString(def->cachemode);
7091
    const char *error_policy = virDomainDiskErrorPolicyTypeToString(def->error_policy);
M
Matthias Dahl 已提交
7092
    const char *iomode = virDomainDiskIoTypeToString(def->iomode);
7093 7094

    if (!type) {
7095
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
7096 7097 7098 7099
                             _("unexpected disk type %d"), def->type);
        return -1;
    }
    if (!device) {
7100
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
7101 7102 7103 7104
                             _("unexpected disk device %d"), def->device);
        return -1;
    }
    if (!bus) {
7105
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
7106 7107 7108
                             _("unexpected disk bus %d"), def->bus);
        return -1;
    }
7109
    if (!cachemode) {
7110
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
7111 7112 7113
                             _("unexpected disk cache mode %d"), def->cachemode);
        return -1;
    }
M
Matthias Dahl 已提交
7114 7115 7116 7117 7118
    if (!iomode) {
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                             _("unexpected disk io mode %d"), def->iomode);
        return -1;
    }
7119

7120
    virBufferAsprintf(buf,
7121 7122 7123
                      "    <disk type='%s' device='%s'>\n",
                      type, device);

7124
    if (def->driverName || def->driverType || def->cachemode) {
7125
        virBufferAsprintf(buf, "      <driver");
7126
        if (def->driverName)
7127
            virBufferAsprintf(buf, " name='%s'", def->driverName);
7128
        if (def->driverType)
7129
            virBufferAsprintf(buf, " type='%s'", def->driverType);
7130
        if (def->cachemode)
7131
            virBufferAsprintf(buf, " cache='%s'", cachemode);
7132
        if (def->error_policy)
7133
            virBufferAsprintf(buf, " error_policy='%s'", error_policy);
M
Matthias Dahl 已提交
7134
        if (def->iomode)
7135 7136
            virBufferAsprintf(buf, " io='%s'", iomode);
        virBufferAsprintf(buf, "/>\n");
7137 7138
    }

M
MORITA Kazutaka 已提交
7139
    if (def->src || def->nhosts > 0) {
7140 7141
        switch (def->type) {
        case VIR_DOMAIN_DISK_TYPE_FILE:
7142 7143
            virBufferEscapeString(buf, "      <source file='%s'/>\n",
                                  def->src);
7144 7145
            break;
        case VIR_DOMAIN_DISK_TYPE_BLOCK:
7146 7147
            virBufferEscapeString(buf, "      <source dev='%s'/>\n",
                                  def->src);
7148 7149 7150 7151 7152
            break;
        case VIR_DOMAIN_DISK_TYPE_DIR:
            virBufferEscapeString(buf, "      <source dir='%s'/>\n",
                                  def->src);
            break;
M
MORITA Kazutaka 已提交
7153
        case VIR_DOMAIN_DISK_TYPE_NETWORK:
7154
            virBufferAsprintf(buf, "      <source protocol='%s'",
M
MORITA Kazutaka 已提交
7155 7156 7157 7158 7159
                              virDomainDiskProtocolTypeToString(def->protocol));
            if (def->src) {
                virBufferEscapeString(buf, " name='%s'", def->src);
            }
            if (def->nhosts == 0) {
7160
                virBufferAsprintf(buf, "/>\n");
M
MORITA Kazutaka 已提交
7161 7162 7163
            } else {
                int i;

7164
                virBufferAsprintf(buf, ">\n");
M
MORITA Kazutaka 已提交
7165 7166 7167 7168 7169 7170
                for (i = 0; i < def->nhosts; i++) {
                    virBufferEscapeString(buf, "        <host name='%s'",
                                          def->hosts[i].name);
                    virBufferEscapeString(buf, " port='%s'/>\n",
                                          def->hosts[i].port);
                }
7171
                virBufferAsprintf(buf, "      </source>\n");
M
MORITA Kazutaka 已提交
7172 7173
            }
            break;
7174
        default:
7175
            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
7176 7177 7178 7179
                                 _("unexpected disk type %s"),
                                 virDomainDiskTypeToString(def->type));
            return -1;
        }
7180 7181
    }

7182
    virBufferAsprintf(buf, "      <target dev='%s' bus='%s'/>\n",
7183 7184
                      def->dst, bus);

7185
    if (def->bootIndex)
7186
        virBufferAsprintf(buf, "      <boot order='%d'/>\n", def->bootIndex);
7187 7188 7189 7190
    if (def->readonly)
        virBufferAddLit(buf, "      <readonly/>\n");
    if (def->shared)
        virBufferAddLit(buf, "      <shareable/>\n");
7191 7192 7193
    if (def->serial)
        virBufferEscapeString(buf, "      <serial>%s</serial>\n",
                              def->serial);
7194
    if (def->encryption != NULL &&
7195
        virStorageEncryptionFormat(buf, def->encryption, 6) < 0)
7196
        return -1;
7197

D
Daniel P. Berrange 已提交
7198
    if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
7199
        return -1;
7200

7201 7202 7203 7204 7205
    virBufferAddLit(buf, "    </disk>\n");

    return 0;
}

7206
static int
7207
virDomainControllerDefFormat(virBufferPtr buf,
D
Daniel P. Berrange 已提交
7208 7209
                             virDomainControllerDefPtr def,
                             int flags)
7210 7211
{
    const char *type = virDomainControllerTypeToString(def->type);
7212
    const char *model = NULL;
7213 7214

    if (!type) {
7215
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
7216 7217 7218 7219
                             _("unexpected controller type %d"), def->type);
        return -1;
    }

7220 7221 7222 7223 7224 7225 7226 7227 7228 7229
    if (def->model != -1) {
        model = virDomainControllerModelTypeToString(def->model);

        if (!model) {
            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                                 _("unexpected model type %d"), def->model);
            return -1;
        }
    }

7230
    virBufferAsprintf(buf,
7231 7232 7233
                      "    <controller type='%s' index='%d'",
                      type, def->idx);

7234 7235 7236 7237
    if (model) {
        virBufferEscapeString(buf, " model='%s'", model);
    }

7238 7239 7240
    switch (def->type) {
    case VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL:
        if (def->opts.vioserial.ports != -1) {
7241
            virBufferAsprintf(buf, " ports='%d'",
7242 7243 7244
                              def->opts.vioserial.ports);
        }
        if (def->opts.vioserial.vectors != -1) {
7245
            virBufferAsprintf(buf, " vectors='%d'",
7246 7247 7248 7249 7250 7251 7252 7253
                              def->opts.vioserial.vectors);
        }
        break;

    default:
        break;
    }

7254 7255
    if (virDomainDeviceInfoIsSet(&def->info)) {
        virBufferAddLit(buf, ">\n");
D
Daniel P. Berrange 已提交
7256
        if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
7257 7258 7259 7260 7261 7262 7263 7264 7265
            return -1;
        virBufferAddLit(buf, "    </controller>\n");
    } else {
        virBufferAddLit(buf, "/>\n");
    }

    return 0;
}

7266
static int
7267
virDomainFSDefFormat(virBufferPtr buf,
7268 7269
                     virDomainFSDefPtr def,
                     int flags)
7270 7271
{
    const char *type = virDomainFSTypeToString(def->type);
7272
    const char *accessmode = virDomainFSAccessModeTypeToString(def->accessmode);
7273 7274

    if (!type) {
7275
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
7276 7277 7278 7279
                             _("unexpected filesystem type %d"), def->type);
        return -1;
    }

7280 7281 7282 7283 7284 7285 7286
   if (!accessmode) {
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                             _("unexpected accessmode %d"), def->accessmode);
        return -1;
    }


7287
    virBufferAsprintf(buf,
7288 7289
                      "    <filesystem type='%s' accessmode='%s'>\n",
                      type, accessmode);
7290 7291 7292 7293 7294 7295 7296 7297 7298 7299 7300 7301 7302 7303 7304 7305 7306 7307 7308 7309 7310 7311 7312 7313

    if (def->src) {
        switch (def->type) {
        case VIR_DOMAIN_FS_TYPE_MOUNT:
            virBufferEscapeString(buf, "      <source dir='%s'/>\n",
                                  def->src);
            break;

        case VIR_DOMAIN_FS_TYPE_BLOCK:
            virBufferEscapeString(buf, "      <source dev='%s'/>\n",
                                  def->src);
            break;

        case VIR_DOMAIN_FS_TYPE_FILE:
            virBufferEscapeString(buf, "      <source file='%s'/>\n",
                                  def->src);
            break;

        case VIR_DOMAIN_FS_TYPE_TEMPLATE:
            virBufferEscapeString(buf, "      <source name='%s'/>\n",
                                  def->src);
        }
    }

7314
    virBufferAsprintf(buf, "      <target dir='%s'/>\n",
7315 7316 7317 7318 7319
                      def->dst);

    if (def->readonly)
        virBufferAddLit(buf, "      <readonly/>\n");

7320 7321 7322
    if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
        return -1;

7323 7324 7325 7326 7327
    virBufferAddLit(buf, "    </filesystem>\n");

    return 0;
}

7328
static int
7329
virDomainNetDefFormat(virBufferPtr buf,
7330 7331
                      virDomainNetDefPtr def,
                      int flags)
7332 7333
{
    const char *type = virDomainNetTypeToString(def->type);
7334
    char *attrs;
7335 7336

    if (!type) {
7337
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
7338 7339 7340 7341
                             _("unexpected net type %d"), def->type);
        return -1;
    }

7342
    virBufferAsprintf(buf, "    <interface type='%s'>\n", type);
7343

7344
    virBufferAsprintf(buf,
7345 7346 7347 7348 7349 7350 7351 7352 7353 7354 7355 7356 7357 7358 7359
                      "      <mac address='%02x:%02x:%02x:%02x:%02x:%02x'/>\n",
                      def->mac[0], def->mac[1], def->mac[2],
                      def->mac[3], def->mac[4], def->mac[5]);

    switch (def->type) {
    case VIR_DOMAIN_NET_TYPE_NETWORK:
        virBufferEscapeString(buf, "      <source network='%s'/>\n",
                              def->data.network.name);
        break;

    case VIR_DOMAIN_NET_TYPE_ETHERNET:
        if (def->data.ethernet.dev)
            virBufferEscapeString(buf, "      <source dev='%s'/>\n",
                                  def->data.ethernet.dev);
        if (def->data.ethernet.ipaddr)
7360
            virBufferAsprintf(buf, "      <ip address='%s'/>\n",
7361 7362 7363 7364 7365 7366 7367 7368 7369
                              def->data.ethernet.ipaddr);
        if (def->data.ethernet.script)
            virBufferEscapeString(buf, "      <script path='%s'/>\n",
                                  def->data.ethernet.script);
        break;

    case VIR_DOMAIN_NET_TYPE_BRIDGE:
        virBufferEscapeString(buf, "      <source bridge='%s'/>\n",
                              def->data.bridge.brname);
7370
        if (def->data.bridge.ipaddr)
7371
            virBufferAsprintf(buf, "      <ip address='%s'/>\n",
7372
                              def->data.bridge.ipaddr);
7373 7374 7375
        if (def->data.bridge.script)
            virBufferEscapeString(buf, "      <script path='%s'/>\n",
                                  def->data.bridge.script);
7376 7377 7378 7379 7380 7381
        break;

    case VIR_DOMAIN_NET_TYPE_SERVER:
    case VIR_DOMAIN_NET_TYPE_CLIENT:
    case VIR_DOMAIN_NET_TYPE_MCAST:
        if (def->data.socket.address)
7382
            virBufferAsprintf(buf, "      <source address='%s' port='%d'/>\n",
7383 7384
                              def->data.socket.address, def->data.socket.port);
        else
7385
            virBufferAsprintf(buf, "      <source port='%d'/>\n",
7386
                              def->data.socket.port);
7387
        break;
D
Daniel Veillard 已提交
7388 7389 7390 7391 7392 7393

    case VIR_DOMAIN_NET_TYPE_INTERNAL:
        virBufferEscapeString(buf, "      <source name='%s'/>\n",
                              def->data.internal.name);
        break;

7394 7395 7396
    case VIR_DOMAIN_NET_TYPE_DIRECT:
        virBufferEscapeString(buf, "      <source dev='%s'",
                              def->data.direct.linkdev);
7397
        virBufferAsprintf(buf, " mode='%s'",
7398 7399
                   virDomainNetdevMacvtapTypeToString(def->data.direct.mode));
        virBufferAddLit(buf, "/>\n");
7400 7401
        virVirtualPortProfileFormat(buf, &def->data.direct.virtPortProfile,
                                    "      ");
7402
        break;
S
Stefan Berger 已提交
7403 7404 7405 7406

    case VIR_DOMAIN_NET_TYPE_USER:
    case VIR_DOMAIN_NET_TYPE_LAST:
        break;
7407 7408 7409 7410 7411
    }

    if (def->ifname)
        virBufferEscapeString(buf, "      <target dev='%s'/>\n",
                              def->ifname);
7412
    if (def->model) {
7413 7414
        virBufferEscapeString(buf, "      <model type='%s'/>\n",
                              def->model);
7415
        if (STREQ(def->model, "virtio") &&
7416
            (def->driver.virtio.name || def->driver.virtio.txmode)) {
7417 7418
            virBufferAddLit(buf, "      <driver");
            if (def->driver.virtio.name) {
7419
                virBufferAsprintf(buf, " name='%s'",
7420 7421
                                  virDomainNetBackendTypeToString(def->driver.virtio.name));
            }
7422
            if (def->driver.virtio.txmode) {
7423
                virBufferAsprintf(buf, " txmode='%s'",
7424 7425
                                  virDomainNetVirtioTxModeTypeToString(def->driver.virtio.txmode));
            }
7426
            virBufferAddLit(buf, "/>\n");
7427 7428
        }
    }
7429 7430 7431 7432 7433 7434 7435 7436
    if (def->filter) {
        virBufferEscapeString(buf, "      <filterref filter='%s'",
                              def->filter);
        attrs = virNWFilterFormatParamAttributes(def->filterparams,
                                                 "        ");
        if (!attrs || strlen(attrs) <= 1)
            virBufferAddLit(buf, "/>\n");
        else
7437
            virBufferAsprintf(buf, ">\n%s      </filterref>\n", attrs);
7438 7439
        VIR_FREE(attrs);
    }
7440
    if (def->bootIndex)
7441
        virBufferAsprintf(buf, "      <boot order='%d'/>\n", def->bootIndex);
7442

7443 7444
    if (def->tune.sndbuf_specified) {
        virBufferAddLit(buf,   "      <tune>\n");
7445
        virBufferAsprintf(buf, "        <sndbuf>%lu</sndbuf>\n", def->tune.sndbuf);
7446 7447 7448
        virBufferAddLit(buf,   "      </tune>\n");
    }

D
Daniel P. Berrange 已提交
7449
    if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
7450 7451
        return -1;

7452 7453 7454 7455 7456 7457
    virBufferAddLit(buf, "    </interface>\n");

    return 0;
}


7458 7459
/* Assumes that "<device" has already been generated, and starts
 * output at " type='type'>". */
7460
static int
7461 7462 7463 7464
virDomainChrSourceDefFormat(virBufferPtr buf,
                            virDomainChrSourceDefPtr def,
                            bool tty_compat,
                            int flags)
7465 7466
{
    const char *type = virDomainChrTypeToString(def->type);
7467

7468
    if (!type) {
7469
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
7470
                             _("unexpected char type %d"), def->type);
7471
        return -1;
7472 7473 7474
    }

    /* Compat with legacy  <console tty='/dev/pts/5'/> syntax */
7475
    virBufferAsprintf(buf, " type='%s'", type);
7476
    if (tty_compat) {
C
Cole Robinson 已提交
7477
        virBufferEscapeString(buf, " tty='%s'",
7478 7479
                              def->data.file.path);
    }
C
Cole Robinson 已提交
7480
    virBufferAddLit(buf, ">\n");
7481 7482 7483 7484 7485

    switch (def->type) {
    case VIR_DOMAIN_CHR_TYPE_NULL:
    case VIR_DOMAIN_CHR_TYPE_VC:
    case VIR_DOMAIN_CHR_TYPE_STDIO:
7486
    case VIR_DOMAIN_CHR_TYPE_SPICEVMC:
7487 7488 7489 7490 7491 7492 7493 7494
        /* nada */
        break;

    case VIR_DOMAIN_CHR_TYPE_PTY:
    case VIR_DOMAIN_CHR_TYPE_DEV:
    case VIR_DOMAIN_CHR_TYPE_FILE:
    case VIR_DOMAIN_CHR_TYPE_PIPE:
        if (def->type != VIR_DOMAIN_CHR_TYPE_PTY ||
7495 7496
            (def->data.file.path &&
             !(flags & VIR_DOMAIN_XML_INACTIVE))) {
7497 7498 7499 7500 7501 7502 7503 7504
            virBufferEscapeString(buf, "      <source path='%s'/>\n",
                                  def->data.file.path);
        }
        break;

    case VIR_DOMAIN_CHR_TYPE_UDP:
        if (def->data.udp.bindService &&
            def->data.udp.bindHost) {
7505
            virBufferAsprintf(buf,
7506 7507
                              "      <source mode='bind' host='%s' "
                              "service='%s'/>\n",
7508 7509 7510
                              def->data.udp.bindHost,
                              def->data.udp.bindService);
        } else if (def->data.udp.bindHost) {
7511
            virBufferAsprintf(buf, "      <source mode='bind' host='%s'/>\n",
7512 7513
                              def->data.udp.bindHost);
        } else if (def->data.udp.bindService) {
7514
            virBufferAsprintf(buf, "      <source mode='bind' service='%s'/>\n",
7515 7516 7517 7518 7519
                              def->data.udp.bindService);
        }

        if (def->data.udp.connectService &&
            def->data.udp.connectHost) {
7520
            virBufferAsprintf(buf,
7521 7522
                              "      <source mode='connect' host='%s' "
                              "service='%s'/>\n",
7523 7524 7525
                              def->data.udp.connectHost,
                              def->data.udp.connectService);
        } else if (def->data.udp.connectHost) {
7526
            virBufferAsprintf(buf, "      <source mode='connect' host='%s'/>\n",
7527 7528
                              def->data.udp.connectHost);
        } else if (def->data.udp.connectService) {
7529
            virBufferAsprintf(buf,
7530
                              "      <source mode='connect' service='%s'/>\n",
7531 7532 7533 7534 7535
                              def->data.udp.connectService);
        }
        break;

    case VIR_DOMAIN_CHR_TYPE_TCP:
7536
        virBufferAsprintf(buf,
7537
                          "      <source mode='%s' host='%s' service='%s'/>\n",
7538 7539 7540
                          def->data.tcp.listen ? "bind" : "connect",
                          def->data.tcp.host,
                          def->data.tcp.service);
7541
        virBufferAsprintf(buf, "      <protocol type='%s'/>\n",
7542 7543
                          virDomainChrTcpProtocolTypeToString(
                              def->data.tcp.protocol));
7544 7545 7546
        break;

    case VIR_DOMAIN_CHR_TYPE_UNIX:
7547
        virBufferAsprintf(buf, "      <source mode='%s'",
7548 7549 7550 7551 7552 7553
                          def->data.nix.listen ? "bind" : "connect");
        virBufferEscapeString(buf, " path='%s'/>\n",
                              def->data.nix.path);
        break;
    }

7554 7555 7556 7557 7558 7559 7560 7561 7562 7563 7564 7565 7566 7567 7568 7569 7570 7571 7572 7573 7574 7575
    return 0;
}

static int
virDomainChrDefFormat(virBufferPtr buf,
                      virDomainChrDefPtr def,
                      int flags)
{
    const char *elementName = virDomainChrDeviceTypeToString(def->deviceType);
    const char *targetType = virDomainChrTargetTypeToString(def->deviceType,
                                                            def->targetType);
    bool tty_compat;

    int ret = 0;

    if (!elementName) {
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                             _("unexpected char device type %d"),
                             def->deviceType);
        return -1;
    }

7576
    virBufferAsprintf(buf, "    <%s", elementName);
7577 7578 7579 7580 7581 7582 7583 7584
    tty_compat = (def->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE &&
                  def->target.port == 0 &&
                  def->source.type == VIR_DOMAIN_CHR_TYPE_PTY &&
                  !(flags & VIR_DOMAIN_XML_INACTIVE) &&
                  def->source.data.file.path);
    if (virDomainChrSourceDefFormat(buf, &def->source, tty_compat, flags) < 0)
        return -1;

7585
    /* Format <target> block */
7586
    switch (def->deviceType) {
7587 7588 7589 7590 7591 7592
    case VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL: {
        if (!targetType) {
            virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                 _("Could not format channel target type"));
            return -1;
        }
7593
        virBufferAsprintf(buf, "      <target type='%s'", targetType);
7594 7595 7596

        switch (def->targetType) {
        case VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_GUESTFWD: {
7597 7598
            int port = virSocketGetPort(def->target.addr);
            if (port < 0) {
7599
                virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
7600 7601 7602
                                     _("Unable to format guestfwd port"));
                return -1;
            }
7603

7604
            const char *addr = virSocketFormatAddr(def->target.addr);
7605
            if (addr == NULL)
7606
                return -1;
7607

7608
            virBufferAsprintf(buf, " address='%s' port='%d'",
7609 7610 7611
                              addr, port);
            VIR_FREE(addr);
            break;
7612 7613
        }

7614 7615 7616 7617 7618 7619 7620
        case VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO: {
            if (def->target.name) {
                virBufferEscapeString(buf, " name='%s'", def->target.name);
            }
            break;
        }

7621 7622 7623
        }
        virBufferAddLit(buf, "/>\n");
        break;
7624
    }
7625

7626
    case VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE:
7627
        virBufferAsprintf(buf,
7628 7629 7630 7631 7632 7633
                          "      <target type='%s' port='%d'/>\n",
                          virDomainChrTargetTypeToString(def->deviceType,
                                                         def->targetType),
                          def->target.port);
        break;

7634
    default:
7635
        virBufferAsprintf(buf, "      <target port='%d'/>\n",
7636
                          def->target.port);
7637
        break;
7638
    }
7639

7640 7641 7642 7643
    if (virDomainDeviceInfoIsSet(&def->info)) {
        if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
            return -1;
    }
7644

7645
    virBufferAsprintf(buf, "    </%s>\n",
7646
                      elementName);
7647

7648
    return ret;
7649 7650
}

E
Eric Blake 已提交
7651 7652 7653 7654 7655 7656 7657 7658 7659 7660 7661 7662 7663 7664
static int
virDomainSmartcardDefFormat(virBufferPtr buf,
                            virDomainSmartcardDefPtr def,
                            int flags)
{
    const char *mode = virDomainSmartcardTypeToString(def->type);
    size_t i;

    if (!mode) {
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                             _("unexpected smartcard type %d"), def->type);
        return -1;
    }

7665
    virBufferAsprintf(buf, "    <smartcard mode='%s'", mode);
E
Eric Blake 已提交
7666 7667 7668 7669 7670 7671
    switch (def->type) {
    case VIR_DOMAIN_SMARTCARD_TYPE_HOST:
        if (!virDomainDeviceInfoIsSet(&def->info)) {
            virBufferAddLit(buf, "/>\n");
            return 0;
        }
7672
        virBufferAddLit(buf, ">\n");
E
Eric Blake 已提交
7673 7674 7675 7676 7677 7678 7679 7680 7681 7682 7683 7684 7685 7686 7687 7688 7689 7690 7691 7692 7693 7694 7695 7696 7697 7698 7699 7700 7701
        break;

    case VIR_DOMAIN_SMARTCARD_TYPE_HOST_CERTIFICATES:
        virBufferAddLit(buf, ">\n");
        for (i = 0; i < VIR_DOMAIN_SMARTCARD_NUM_CERTIFICATES; i++)
            virBufferEscapeString(buf, "      <certificate>%s</certificate>\n",
                                  def->data.cert.file[i]);
        if (def->data.cert.database)
            virBufferEscapeString(buf, "      <database>%s</database>\n",
                                  def->data.cert.database);
        break;

    case VIR_DOMAIN_SMARTCARD_TYPE_PASSTHROUGH:
        if (virDomainChrSourceDefFormat(buf, &def->data.passthru, false,
                                        flags) < 0)
            return -1;
        break;

    default:
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                             _("unexpected smartcard type %d"), def->type);
        return -1;
    }
    if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
        return -1;
    virBufferAddLit(buf, "    </smartcard>\n");
    return 0;
}

7702
static int
7703
virDomainSoundDefFormat(virBufferPtr buf,
D
Daniel P. Berrange 已提交
7704 7705
                        virDomainSoundDefPtr def,
                        int flags)
7706 7707 7708 7709
{
    const char *model = virDomainSoundModelTypeToString(def->model);

    if (!model) {
7710
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
7711 7712 7713 7714
                             _("unexpected sound model %d"), def->model);
        return -1;
    }

7715
    virBufferAsprintf(buf, "    <sound model='%s'",
7716 7717
                      model);

7718 7719
    if (virDomainDeviceInfoIsSet(&def->info)) {
        virBufferAddLit(buf, ">\n");
D
Daniel P. Berrange 已提交
7720
        if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
7721 7722 7723 7724 7725 7726
            return -1;
        virBufferAddLit(buf, "    </sound>\n");
    } else {
        virBufferAddLit(buf, "/>\n");
    }

7727 7728 7729
    return 0;
}

7730

7731 7732 7733 7734 7735 7736 7737 7738 7739 7740 7741 7742 7743
static int
virDomainMemballoonDefFormat(virBufferPtr buf,
                             virDomainMemballoonDefPtr def,
                             int flags)
{
    const char *model = virDomainMemballoonModelTypeToString(def->model);

    if (!model) {
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                             _("unexpected memballoon model %d"), def->model);
        return -1;
    }

7744
    virBufferAsprintf(buf, "    <memballoon model='%s'",
7745 7746 7747 7748 7749 7750 7751 7752 7753 7754 7755 7756 7757 7758
                      model);

    if (virDomainDeviceInfoIsSet(&def->info)) {
        virBufferAddLit(buf, ">\n");
        if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
            return -1;
        virBufferAddLit(buf, "    </memballoon>\n");
    } else {
        virBufferAddLit(buf, "/>\n");
    }

    return 0;
}

7759 7760 7761 7762
static int
virDomainSysinfoDefFormat(virBufferPtr buf,
                          virSysinfoDefPtr def)
{
E
Eric Blake 已提交
7763
    char *format = virSysinfoFormat(def, "  ");
7764

E
Eric Blake 已提交
7765
    if (!format)
7766
        return -1;
E
Eric Blake 已提交
7767 7768
    virBufferAdd(buf, format, strlen(format));
    VIR_FREE(format);
7769 7770 7771
    return 0;
}

7772

R
Richard Jones 已提交
7773
static int
7774
virDomainWatchdogDefFormat(virBufferPtr buf,
D
Daniel P. Berrange 已提交
7775 7776
                           virDomainWatchdogDefPtr def,
                           int flags)
R
Richard Jones 已提交
7777 7778 7779 7780 7781
{
    const char *model = virDomainWatchdogModelTypeToString (def->model);
    const char *action = virDomainWatchdogActionTypeToString (def->action);

    if (!model) {
7782
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
R
Richard Jones 已提交
7783 7784 7785 7786 7787
                             _("unexpected watchdog model %d"), def->model);
        return -1;
    }

    if (!action) {
7788
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
R
Richard Jones 已提交
7789 7790 7791 7792
                             _("unexpected watchdog action %d"), def->action);
        return -1;
    }

7793
    virBufferAsprintf(buf, "    <watchdog model='%s' action='%s'",
R
Richard Jones 已提交
7794 7795
                      model, action);

7796 7797
    if (virDomainDeviceInfoIsSet(&def->info)) {
        virBufferAddLit(buf, ">\n");
D
Daniel P. Berrange 已提交
7798
        if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
7799 7800 7801 7802 7803 7804
            return -1;
        virBufferAddLit(buf, "    </watchdog>\n");
    } else {
        virBufferAddLit(buf, "/>\n");
    }

R
Richard Jones 已提交
7805 7806 7807 7808
    return 0;
}


7809 7810 7811 7812
static void
virDomainVideoAccelDefFormat(virBufferPtr buf,
                             virDomainVideoAccelDefPtr def)
{
7813
    virBufferAsprintf(buf, "        <acceleration accel3d='%s'",
7814
                      def->support3d ? "yes" : "no");
7815
    virBufferAsprintf(buf, " accel2d='%s'",
7816 7817 7818 7819 7820
                      def->support2d ? "yes" : "no");
    virBufferAddLit(buf, "/>\n");
}


7821
static int
7822
virDomainVideoDefFormat(virBufferPtr buf,
D
Daniel P. Berrange 已提交
7823 7824
                        virDomainVideoDefPtr def,
                        int flags)
7825 7826 7827 7828
{
    const char *model = virDomainVideoTypeToString(def->type);

    if (!model) {
7829
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
7830 7831 7832 7833 7834
                             _("unexpected video model %d"), def->type);
        return -1;
    }

    virBufferAddLit(buf, "    <video>\n");
7835
    virBufferAsprintf(buf, "      <model type='%s'",
7836 7837
                      model);
    if (def->vram)
7838
        virBufferAsprintf(buf, " vram='%u'", def->vram);
7839
    if (def->heads)
7840
        virBufferAsprintf(buf, " heads='%u'", def->heads);
7841 7842 7843 7844 7845 7846 7847 7848
    if (def->accel) {
        virBufferAddLit(buf, ">\n");
        virDomainVideoAccelDefFormat(buf, def->accel);
        virBufferAddLit(buf, "      </model>\n");
    } else {
        virBufferAddLit(buf, "/>\n");
    }

D
Daniel P. Berrange 已提交
7849
    if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
7850 7851
        return -1;

7852 7853 7854 7855 7856
    virBufferAddLit(buf, "    </video>\n");

    return 0;
}

7857
static int
7858
virDomainInputDefFormat(virBufferPtr buf,
7859 7860
                        virDomainInputDefPtr def,
                        int flags)
7861 7862 7863 7864 7865
{
    const char *type = virDomainInputTypeToString(def->type);
    const char *bus = virDomainInputBusTypeToString(def->bus);

    if (!type) {
7866
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
7867 7868 7869 7870
                             _("unexpected input type %d"), def->type);
        return -1;
    }
    if (!bus) {
7871
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
7872 7873 7874 7875
                             _("unexpected input bus type %d"), def->bus);
        return -1;
    }

7876
    virBufferAsprintf(buf, "    <input type='%s' bus='%s'",
7877 7878
                      type, bus);

7879 7880 7881 7882 7883 7884 7885 7886 7887
    if (virDomainDeviceInfoIsSet(&def->info)) {
        virBufferAddLit(buf, ">\n");
        if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
            return -1;
        virBufferAddLit(buf, "    </input>\n");
    } else {
        virBufferAddLit(buf, "/>\n");
    }

7888 7889 7890 7891
    return 0;
}


7892 7893 7894 7895 7896 7897 7898 7899 7900 7901 7902
static int
virDomainTimerDefFormat(virBufferPtr buf,
                        virDomainTimerDefPtr def)
{
    const char *name = virDomainTimerNameTypeToString(def->name);

    if (!name) {
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                             _("unexpected timer name %d"), def->name);
        return -1;
    }
7903
    virBufferAsprintf(buf, "    <timer name='%s'", name);
7904 7905 7906 7907 7908 7909 7910 7911 7912 7913 7914 7915 7916 7917 7918 7919

    if (def->present == 0) {
        virBufferAddLit(buf, " present='no'");
    } else if (def->present == 1) {
        virBufferAddLit(buf, " present='yes'");
    }

    if (def->tickpolicy != -1) {
        const char *tickpolicy
            = virDomainTimerTickpolicyTypeToString(def->tickpolicy);
        if (!tickpolicy) {
            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                                 _("unexpected timer tickpolicy %d"),
                                 def->tickpolicy);
            return -1;
        }
7920
        virBufferAsprintf(buf, " tickpolicy='%s'", tickpolicy);
7921 7922 7923 7924
    }

    if ((def->name == VIR_DOMAIN_TIMER_NAME_PLATFORM)
        || (def->name == VIR_DOMAIN_TIMER_NAME_RTC)) {
7925 7926 7927 7928
        if (def->track != -1) {
            const char *track
                = virDomainTimerTrackTypeToString(def->track);
            if (!track) {
7929
                virDomainReportError(VIR_ERR_INTERNAL_ERROR,
7930 7931
                                     _("unexpected timer track %d"),
                                     def->track);
7932 7933
                return -1;
            }
7934
            virBufferAsprintf(buf, " track='%s'", track);
7935 7936 7937 7938 7939
        }
    }

    if (def->name == VIR_DOMAIN_TIMER_NAME_TSC) {
        if (def->frequency > 0) {
7940
            virBufferAsprintf(buf, " frequency='%lu'", def->frequency);
7941 7942 7943 7944 7945 7946 7947 7948 7949 7950 7951
        }

        if (def->mode != -1) {
            const char *mode
                = virDomainTimerModeTypeToString(def->mode);
            if (!mode) {
                virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                                     _("unexpected timer mode %d"),
                                     def->mode);
                return -1;
            }
7952
            virBufferAsprintf(buf, " mode='%s'", mode);
7953 7954 7955
        }
    }

7956 7957 7958 7959 7960 7961 7962
    if ((def->catchup.threshold == 0)
        && (def->catchup.slew == 0)
        && (def->catchup.limit == 0)) {
        virBufferAddLit(buf, "/>\n");
    } else {
        virBufferAddLit(buf, ">\n      <catchup ");
        if (def->catchup.threshold > 0) {
7963
            virBufferAsprintf(buf, " threshold='%lu'", def->catchup.threshold);
7964 7965
        }
        if (def->catchup.slew > 0) {
7966
            virBufferAsprintf(buf, " slew='%lu'", def->catchup.slew);
7967 7968
        }
        if (def->catchup.limit > 0) {
7969
            virBufferAsprintf(buf, " limit='%lu'", def->catchup.limit);
7970 7971 7972
        }
        virBufferAddLit(buf, "/>\n    </timer>\n");
    }
7973 7974 7975 7976

    return 0;
}

7977 7978 7979 7980 7981 7982 7983 7984 7985 7986 7987 7988 7989 7990 7991 7992 7993
static void
virDomainGraphicsAuthDefFormatAttr(virBufferPtr buf,
                                   virDomainGraphicsAuthDefPtr def,
                                   unsigned int flags)
{
    if (!def->passwd)
        return;

    if (flags & VIR_DOMAIN_XML_SECURE)
        virBufferEscapeString(buf, " passwd='%s'",
                              def->passwd);

    if (def->expires) {
        char strbuf[100];
        struct tm tmbuf, *tm;
        tm = gmtime_r(&def->validTo, &tmbuf);
        strftime(strbuf, sizeof(strbuf), "%Y-%m-%dT%H:%M:%S", tm);
7994
        virBufferAsprintf(buf, " passwdValidTo='%s'", strbuf);
7995 7996 7997
    }
}

7998
static int
7999
virDomainGraphicsDefFormat(virBufferPtr buf,
8000 8001 8002 8003
                           virDomainGraphicsDefPtr def,
                           int flags)
{
    const char *type = virDomainGraphicsTypeToString(def->type);
8004 8005
    int children = 0;
    int i;
8006 8007

    if (!type) {
8008
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
8009 8010 8011 8012
                             _("unexpected net type %d"), def->type);
        return -1;
    }

8013
    virBufferAsprintf(buf, "    <graphics type='%s'", type);
8014 8015 8016

    switch (def->type) {
    case VIR_DOMAIN_GRAPHICS_TYPE_VNC:
8017 8018
        if (def->data.vnc.socket) {
            if (def->data.vnc.socket)
8019
                virBufferAsprintf(buf, " socket='%s'",
8020 8021 8022 8023
                                  def->data.vnc.socket);
        } else {
            if (def->data.vnc.port &&
                (!def->data.vnc.autoport || !(flags & VIR_DOMAIN_XML_INACTIVE)))
8024
                virBufferAsprintf(buf, " port='%d'",
8025 8026 8027
                                  def->data.vnc.port);
            else if (def->data.vnc.autoport)
                virBufferAddLit(buf, " port='-1'");
8028

8029
            virBufferAsprintf(buf, " autoport='%s'",
8030
                              def->data.vnc.autoport ? "yes" : "no");
8031

8032
            if (def->data.vnc.listenAddr)
8033
                virBufferAsprintf(buf, " listen='%s'",
8034 8035
                                  def->data.vnc.listenAddr);
        }
8036 8037 8038 8039 8040

        if (def->data.vnc.keymap)
            virBufferEscapeString(buf, " keymap='%s'",
                                  def->data.vnc.keymap);

8041
        virDomainGraphicsAuthDefFormatAttr(buf, &def->data.vnc.auth, flags);
8042 8043 8044 8045 8046 8047 8048 8049 8050 8051
        break;

    case VIR_DOMAIN_GRAPHICS_TYPE_SDL:
        if (def->data.sdl.display)
            virBufferEscapeString(buf, " display='%s'",
                                  def->data.sdl.display);

        if (def->data.sdl.xauth)
            virBufferEscapeString(buf, " xauth='%s'",
                                  def->data.sdl.xauth);
8052 8053 8054
        if (def->data.sdl.fullscreen)
            virBufferAddLit(buf, " fullscreen='yes'");

8055
        break;
8056 8057 8058

    case VIR_DOMAIN_GRAPHICS_TYPE_RDP:
        if (def->data.rdp.port)
8059
            virBufferAsprintf(buf, " port='%d'",
8060 8061 8062 8063 8064
                              def->data.rdp.port);
        else if (def->data.rdp.autoport)
            virBufferAddLit(buf, " port='0'");

        if (def->data.rdp.autoport)
8065
            virBufferAsprintf(buf, " autoport='yes'");
8066 8067

        if (def->data.rdp.replaceUser)
8068
            virBufferAsprintf(buf, " replaceUser='yes'");
8069 8070

        if (def->data.rdp.multiUser)
8071
            virBufferAsprintf(buf, " multiUser='yes'");
8072 8073

        if (def->data.rdp.listenAddr)
8074
            virBufferAsprintf(buf, " listen='%s'", def->data.rdp.listenAddr);
8075 8076 8077 8078 8079 8080 8081 8082 8083 8084 8085 8086 8087

        break;

    case VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP:
        if (def->data.desktop.display)
            virBufferEscapeString(buf, " display='%s'",
                                  def->data.desktop.display);

        if (def->data.desktop.fullscreen)
            virBufferAddLit(buf, " fullscreen='yes'");

        break;

8088 8089
    case VIR_DOMAIN_GRAPHICS_TYPE_SPICE:
        if (def->data.spice.port)
8090
            virBufferAsprintf(buf, " port='%d'",
8091 8092 8093
                              def->data.spice.port);

        if (def->data.spice.tlsPort)
8094
            virBufferAsprintf(buf, " tlsPort='%d'",
8095 8096
                              def->data.spice.tlsPort);

8097
        virBufferAsprintf(buf, " autoport='%s'",
8098 8099 8100
                          def->data.spice.autoport ? "yes" : "no");

        if (def->data.spice.listenAddr)
8101
            virBufferAsprintf(buf, " listen='%s'",
8102 8103 8104 8105 8106 8107
                              def->data.spice.listenAddr);

        if (def->data.spice.keymap)
            virBufferEscapeString(buf, " keymap='%s'",
                                  def->data.spice.keymap);

8108
        virDomainGraphicsAuthDefFormatAttr(buf, &def->data.spice.auth, flags);
8109 8110
        break;

8111 8112
    }

8113 8114 8115 8116 8117 8118 8119 8120 8121 8122 8123
    if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) {
        for (i = 0 ; i < VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_LAST ; i++) {
            int mode = def->data.spice.channels[i];
            if (mode == VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_ANY)
                continue;

            if (!children) {
                virBufferAddLit(buf, ">\n");
                children = 1;
            }

8124
            virBufferAsprintf(buf, "      <channel name='%s' mode='%s'/>\n",
8125 8126 8127
                              virDomainGraphicsSpiceChannelNameTypeToString(i),
                              virDomainGraphicsSpiceChannelModeTypeToString(mode));
        }
8128
        if (def->data.spice.image)
8129
            virBufferAsprintf(buf, "      <image compression='%s'/>\n",
8130 8131
                              virDomainGraphicsSpiceImageCompressionTypeToString(def->data.spice.image));
        if (def->data.spice.jpeg)
8132
            virBufferAsprintf(buf, "      <jpeg compression='%s'/>\n",
8133 8134
                              virDomainGraphicsSpiceJpegCompressionTypeToString(def->data.spice.jpeg));
        if (def->data.spice.zlib)
8135
            virBufferAsprintf(buf, "      <zlib compression='%s'/>\n",
8136 8137
                              virDomainGraphicsSpiceZlibCompressionTypeToString(def->data.spice.zlib));
        if (def->data.spice.playback)
8138
            virBufferAsprintf(buf, "      <playback compression='%s'/>\n",
8139
                              virDomainGraphicsSpicePlaybackCompressionTypeToString(def->data.spice.playback));
8140 8141 8142
        if (def->data.spice.streaming)
            virBufferAsprintf(buf, "      <streaming mode='%s'/>\n",
                              virDomainGraphicsSpiceStreamingModeTypeToString(def->data.spice.streaming));
8143 8144 8145 8146 8147 8148 8149
    }

    if (children) {
        virBufferAddLit(buf, "    </graphics>\n");
    } else {
        virBufferAddLit(buf, "/>\n");
    }
8150 8151 8152 8153

    return 0;
}

8154 8155

static int
8156
virDomainHostdevDefFormat(virBufferPtr buf,
D
Daniel P. Berrange 已提交
8157 8158
                          virDomainHostdevDefPtr def,
                          int flags)
8159 8160 8161 8162 8163
{
    const char *mode = virDomainHostdevModeTypeToString(def->mode);
    const char *type;

    if (!mode || def->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
8164
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
8165 8166 8167 8168 8169
                             _("unexpected hostdev mode %d"), def->mode);
        return -1;
    }

    type = virDomainHostdevSubsysTypeToString(def->source.subsys.type);
8170
    if (!type || (def->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB && def->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) ) {
8171
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
8172 8173 8174 8175 8176
                             _("unexpected hostdev type %d"),
                             def->source.subsys.type);
        return -1;
    }

8177
    virBufferAsprintf(buf, "    <hostdev mode='%s' type='%s' managed='%s'>\n",
8178
                      mode, type, def->managed ? "yes" : "no");
8179 8180
    virBufferAddLit(buf, "      <source>\n");

8181 8182
    if (def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {
        if (def->source.subsys.u.usb.vendor) {
8183
            virBufferAsprintf(buf, "        <vendor id='0x%.4x'/>\n",
8184
                              def->source.subsys.u.usb.vendor);
8185
            virBufferAsprintf(buf, "        <product id='0x%.4x'/>\n",
8186
                              def->source.subsys.u.usb.product);
8187 8188 8189
        }
        if (def->source.subsys.u.usb.bus ||
            def->source.subsys.u.usb.device)
8190
            virBufferAsprintf(buf, "        <address bus='%d' device='%d'/>\n",
8191 8192
                              def->source.subsys.u.usb.bus,
                              def->source.subsys.u.usb.device);
8193
    } else if (def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) {
8194
        virBufferAsprintf(buf, "        <address domain='0x%.4x' bus='0x%.2x' slot='0x%.2x' function='0x%.1x'/>\n",
8195 8196 8197 8198
                          def->source.subsys.u.pci.domain,
                          def->source.subsys.u.pci.bus,
                          def->source.subsys.u.pci.slot,
                          def->source.subsys.u.pci.function);
8199 8200 8201
    }

    virBufferAddLit(buf, "      </source>\n");
8202

8203
    if (def->bootIndex)
8204
        virBufferAsprintf(buf, "      <boot order='%d'/>\n", def->bootIndex);
8205

D
Daniel P. Berrange 已提交
8206
    if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
8207 8208
        return -1;

8209 8210 8211 8212 8213 8214
    virBufferAddLit(buf, "    </hostdev>\n");

    return 0;
}


8215
char *virDomainDefFormat(virDomainDefPtr def,
8216 8217 8218 8219 8220
                         int flags)
{
    virBuffer buf = VIR_BUFFER_INITIALIZER;
    unsigned char *uuid;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
8221
    const char *type = NULL;
8222 8223 8224
    int n, allones = 1;

    if (!(type = virDomainVirtTypeToString(def->virtType))) {
8225
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
8226 8227 8228 8229
                         _("unexpected domain type %d"), def->virtType);
        goto cleanup;
    }

8230 8231 8232
    if (def->id == -1)
        flags |= VIR_DOMAIN_XML_INACTIVE;

8233
    virBufferAsprintf(&buf, "<domain type='%s'", type);
8234
    if (!(flags & VIR_DOMAIN_XML_INACTIVE))
8235
        virBufferAsprintf(&buf, " id='%d'", def->id);
8236
    if (def->namespaceData && def->ns.href)
8237
        virBufferAsprintf(&buf, " %s", (def->ns.href)());
8238
    virBufferAddLit(&buf, ">\n");
8239 8240 8241 8242 8243

    virBufferEscapeString(&buf, "  <name>%s</name>\n", def->name);

    uuid = def->uuid;
    virUUIDFormat(uuid, uuidstr);
8244
    virBufferAsprintf(&buf, "  <uuid>%s</uuid>\n", uuidstr);
8245

8246 8247 8248 8249
    if (def->description)
        virBufferEscapeString(&buf, "  <description>%s</description>\n",
                              def->description);

8250 8251
    virBufferAsprintf(&buf, "  <memory>%lu</memory>\n", def->mem.max_balloon);
    virBufferAsprintf(&buf, "  <currentMemory>%lu</currentMemory>\n",
8252 8253
                      def->mem.cur_balloon);

8254 8255
    /* add blkiotune only if there are any */
    if (def->blkio.weight) {
8256 8257
        virBufferAsprintf(&buf, "  <blkiotune>\n");
        virBufferAsprintf(&buf, "    <weight>%u</weight>\n",
8258
                          def->blkio.weight);
8259
        virBufferAsprintf(&buf, "  </blkiotune>\n");
8260 8261
    }

8262
    /* add memtune only if there are any */
8263 8264
    if (def->mem.hard_limit || def->mem.soft_limit || def->mem.min_guarantee ||
        def->mem.swap_hard_limit)
8265
        virBufferAsprintf(&buf, "  <memtune>\n");
8266
    if (def->mem.hard_limit) {
8267
        virBufferAsprintf(&buf, "    <hard_limit>%lu</hard_limit>\n",
8268 8269 8270
                          def->mem.hard_limit);
    }
    if (def->mem.soft_limit) {
8271
        virBufferAsprintf(&buf, "    <soft_limit>%lu</soft_limit>\n",
8272 8273
                          def->mem.soft_limit);
    }
8274
    if (def->mem.min_guarantee) {
8275
        virBufferAsprintf(&buf, "    <min_guarantee>%lu</min_guarantee>\n",
8276 8277
                          def->mem.min_guarantee);
    }
8278
    if (def->mem.swap_hard_limit) {
8279
        virBufferAsprintf(&buf, "    <swap_hard_limit>%lu</swap_hard_limit>\n",
8280 8281
                          def->mem.swap_hard_limit);
    }
8282 8283
    if (def->mem.hard_limit || def->mem.soft_limit || def->mem.min_guarantee ||
        def->mem.swap_hard_limit)
8284
        virBufferAsprintf(&buf, "  </memtune>\n");
8285 8286

    if (def->mem.hugepage_backed) {
8287 8288 8289 8290
        virBufferAddLit(&buf, "  <memoryBacking>\n");
        virBufferAddLit(&buf, "    <hugepages/>\n");
        virBufferAddLit(&buf, "  </memoryBacking>\n");
    }
8291

8292 8293 8294 8295
    for (n = 0 ; n < def->cpumasklen ; n++)
        if (def->cpumask[n] != 1)
            allones = 0;

E
Eric Blake 已提交
8296 8297
    virBufferAddLit(&buf, "  <vcpu");
    if (!allones) {
8298 8299
        char *cpumask = NULL;
        if ((cpumask =
8300
             virDomainCpuSetFormat(def->cpumask, def->cpumasklen)) == NULL)
8301
            goto cleanup;
8302
        virBufferAsprintf(&buf, " cpuset='%s'", cpumask);
8303 8304
        VIR_FREE(cpumask);
    }
E
Eric Blake 已提交
8305
    if (def->vcpus != def->maxvcpus)
8306 8307
        virBufferAsprintf(&buf, " current='%u'", def->vcpus);
    virBufferAsprintf(&buf, ">%u</vcpu>\n", def->maxvcpus);
8308

8309 8310 8311 8312
    if (def->cputune.shares || def->cputune.vcpupin)
        virBufferAddLit(&buf, "  <cputune>\n");

    if (def->cputune.shares)
8313
        virBufferAsprintf(&buf, "    <shares>%lu</shares>\n",
8314 8315 8316 8317
                          def->cputune.shares);
    if (def->cputune.vcpupin) {
        int i;
        for (i = 0; i < def->cputune.nvcpupin; i++) {
8318
            virBufferAsprintf(&buf, "    <vcpupin vcpu='%u' ",
8319 8320 8321 8322 8323 8324 8325 8326 8327 8328 8329 8330
                              def->cputune.vcpupin[i]->vcpuid);

            char *cpumask = NULL;
            cpumask = virDomainCpuSetFormat(def->cputune.vcpupin[i]->cpumask,
                                            VIR_DOMAIN_CPUMASK_LEN);

            if (cpumask == NULL) {
                virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                                     "%s", _("failed to format cpuset for vcpupin"));
                goto cleanup;
            }

8331
            virBufferAsprintf(&buf, "cpuset='%s'/>\n", cpumask);
8332 8333 8334 8335 8336 8337 8338
            VIR_FREE(cpumask);
        }
    }

    if (def->cputune.shares || def->cputune.vcpupin)
        virBufferAddLit(&buf, "  </cputune>\n");

8339 8340 8341
    if (def->sysinfo)
        virDomainSysinfoDefFormat(&buf, def->sysinfo);

8342 8343 8344 8345 8346 8347 8348 8349 8350 8351 8352
    if (def->os.bootloader) {
        virBufferEscapeString(&buf, "  <bootloader>%s</bootloader>\n",
                              def->os.bootloader);
        if (def->os.bootloaderArgs)
            virBufferEscapeString(&buf, "  <bootloader_args>%s</bootloader_args>\n",
                                  def->os.bootloaderArgs);
    }
    virBufferAddLit(&buf, "  <os>\n");

    virBufferAddLit(&buf, "    <type");
    if (def->os.arch)
8353
        virBufferAsprintf(&buf, " arch='%s'", def->os.arch);
8354
    if (def->os.machine)
8355
        virBufferAsprintf(&buf, " machine='%s'", def->os.machine);
8356 8357 8358 8359 8360 8361 8362
    /*
     * HACK: For xen driver we previously used bogus 'linux' as the
     * os type for paravirt, whereas capabilities declare it to
     * be 'xen'. So we convert to the former for backcompat
     */
    if (def->virtType == VIR_DOMAIN_VIRT_XEN &&
        STREQ(def->os.type, "xen"))
8363
        virBufferAsprintf(&buf, ">%s</type>\n", "linux");
8364
    else
8365
        virBufferAsprintf(&buf, ">%s</type>\n", def->os.type);
8366

8367 8368 8369
    if (def->os.init)
        virBufferEscapeString(&buf, "    <init>%s</init>\n",
                              def->os.init);
8370 8371 8372 8373 8374 8375 8376 8377 8378 8379 8380 8381 8382 8383 8384 8385 8386 8387 8388 8389 8390
    if (def->os.loader)
        virBufferEscapeString(&buf, "    <loader>%s</loader>\n",
                              def->os.loader);
    if (def->os.kernel)
        virBufferEscapeString(&buf, "    <kernel>%s</kernel>\n",
                              def->os.kernel);
    if (def->os.initrd)
        virBufferEscapeString(&buf, "    <initrd>%s</initrd>\n",
                              def->os.initrd);
    if (def->os.cmdline)
        virBufferEscapeString(&buf, "    <cmdline>%s</cmdline>\n",
                              def->os.cmdline);
    if (def->os.root)
        virBufferEscapeString(&buf, "    <root>%s</root>\n",
                              def->os.root);

    if (!def->os.bootloader) {
        for (n = 0 ; n < def->os.nBootDevs ; n++) {
            const char *boottype =
                virDomainBootTypeToString(def->os.bootDevs[n]);
            if (!boottype) {
8391
                virDomainReportError(VIR_ERR_INTERNAL_ERROR,
8392 8393 8394 8395
                                     _("unexpected boot device type %d"),
                                     def->os.bootDevs[n]);
                goto cleanup;
            }
8396
            virBufferAsprintf(&buf, "    <boot dev='%s'/>\n", boottype);
8397
        }
8398 8399 8400 8401 8402

        if (def->os.bootmenu != VIR_DOMAIN_BOOT_MENU_DEFAULT) {
            const char *enabled = (def->os.bootmenu ==
                                   VIR_DOMAIN_BOOT_MENU_ENABLED ? "yes"
                                                                : "no");
8403
            virBufferAsprintf(&buf, "    <bootmenu enable='%s'/>\n", enabled);
8404
        }
8405 8406
    }

8407 8408 8409 8410 8411 8412 8413 8414 8415
    if (def->os.smbios_mode) {
        const char *mode;

        mode = virDomainSmbiosModeTypeToString(def->os.smbios_mode);
        if (mode == NULL) {
            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                         _("unexpected smbios mode %d"), def->os.smbios_mode);
            goto cleanup;
        }
8416
        virBufferAsprintf(&buf, "    <smbios mode='%s'/>\n", mode);
8417 8418
    }

8419 8420 8421 8422 8423 8424 8425 8426 8427
    virBufferAddLit(&buf, "  </os>\n");

    if (def->features) {
        int i;
        virBufferAddLit(&buf, "  <features>\n");
        for (i = 0 ; i < VIR_DOMAIN_FEATURE_LAST ; i++) {
            if (def->features & (1 << i)) {
                const char *name = virDomainFeatureTypeToString(i);
                if (!name) {
8428
                    virDomainReportError(VIR_ERR_INTERNAL_ERROR,
8429 8430 8431
                                         _("unexpected feature %d"), i);
                    goto cleanup;
                }
8432
                virBufferAsprintf(&buf, "    <%s/>\n", name);
8433 8434 8435 8436 8437
            }
        }
        virBufferAddLit(&buf, "  </features>\n");
    }

8438
    if (virCPUDefFormatBuf(&buf, def->cpu, "  ", 0) < 0)
8439 8440
        goto cleanup;

8441
    virBufferAsprintf(&buf, "  <clock offset='%s'",
8442
                      virDomainClockOffsetTypeToString(def->clock.offset));
8443 8444
    switch (def->clock.offset) {
    case VIR_DOMAIN_CLOCK_OFFSET_VARIABLE:
8445
        virBufferAsprintf(&buf, " adjustment='%lld'", def->clock.data.adjustment);
8446 8447 8448
        break;
    case VIR_DOMAIN_CLOCK_OFFSET_TIMEZONE:
        virBufferEscapeString(&buf, " timezone='%s'", def->clock.data.timezone);
8449 8450
        break;
    }
8451 8452 8453 8454 8455 8456 8457 8458 8459 8460
    if (def->clock.ntimers == 0) {
        virBufferAddLit(&buf, "/>\n");
    } else {
        virBufferAddLit(&buf, ">\n");
        for (n = 0; n < def->clock.ntimers; n++) {
            if (virDomainTimerDefFormat(&buf, def->clock.timers[n]) < 0)
                goto cleanup;
        }
        virBufferAddLit(&buf, "  </clock>\n");
    }
8461

8462
    if (virDomainLifecycleDefFormat(&buf, def->onPoweroff,
8463 8464
                                    "on_poweroff",
                                    virDomainLifecycleTypeToString) < 0)
8465
        goto cleanup;
8466
    if (virDomainLifecycleDefFormat(&buf, def->onReboot,
8467 8468
                                    "on_reboot",
                                    virDomainLifecycleTypeToString) < 0)
8469
        goto cleanup;
8470
    if (virDomainLifecycleDefFormat(&buf, def->onCrash,
8471 8472
                                    "on_crash",
                                    virDomainLifecycleCrashTypeToString) < 0)
8473 8474 8475 8476 8477 8478 8479 8480
        goto cleanup;

    virBufferAddLit(&buf, "  <devices>\n");

    if (def->emulator)
        virBufferEscapeString(&buf, "    <emulator>%s</emulator>\n",
                              def->emulator);

8481
    for (n = 0 ; n < def->ndisks ; n++)
8482
        if (virDomainDiskDefFormat(&buf, def->disks[n], flags) < 0)
8483
            goto cleanup;
8484

8485
    for (n = 0 ; n < def->ncontrollers ; n++)
8486
        if (virDomainControllerDefFormat(&buf, def->controllers[n], flags) < 0)
8487 8488
            goto cleanup;

8489
    for (n = 0 ; n < def->nfss ; n++)
8490
        if (virDomainFSDefFormat(&buf, def->fss[n], flags) < 0)
8491
            goto cleanup;
8492 8493


8494
    for (n = 0 ; n < def->nnets ; n++)
8495
        if (virDomainNetDefFormat(&buf, def->nets[n], flags) < 0)
8496
            goto cleanup;
8497

E
Eric Blake 已提交
8498 8499 8500 8501
    for (n = 0 ; n < def->nsmartcards ; n++)
        if (virDomainSmartcardDefFormat(&buf, def->smartcards[n], flags) < 0)
            goto cleanup;

8502
    for (n = 0 ; n < def->nserials ; n++)
8503
        if (virDomainChrDefFormat(&buf, def->serials[n], flags) < 0)
8504 8505
            goto cleanup;

8506
    for (n = 0 ; n < def->nparallels ; n++)
8507
        if (virDomainChrDefFormat(&buf, def->parallels[n], flags) < 0)
8508 8509 8510 8511
            goto cleanup;

    /* If there's a PV console that's preferred.. */
    if (def->console) {
8512
        if (virDomainChrDefFormat(&buf, def->console, flags) < 0)
8513
            goto cleanup;
8514
    } else if (def->nserials != 0) {
8515 8516
        /* ..else for legacy compat duplicate the first serial device as a
         * console */
8517 8518
        virDomainChrDef console;
        memcpy(&console, def->serials[0], sizeof(console));
8519
        console.deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE;
8520
        if (virDomainChrDefFormat(&buf, &console, flags) < 0)
8521 8522 8523
            goto cleanup;
    }

8524
    for (n = 0 ; n < def->nchannels ; n++)
8525
        if (virDomainChrDefFormat(&buf, def->channels[n], flags) < 0)
8526 8527
            goto cleanup;

8528 8529
    for (n = 0 ; n < def->ninputs ; n++)
        if (def->inputs[n]->bus == VIR_DOMAIN_INPUT_BUS_USB &&
8530
            virDomainInputDefFormat(&buf, def->inputs[n], flags) < 0)
8531 8532
            goto cleanup;

8533
    if (def->ngraphics > 0) {
8534 8535 8536 8537
        /* If graphics is enabled, add the implicit mouse */
        virDomainInputDef autoInput = {
            VIR_DOMAIN_INPUT_TYPE_MOUSE,
            STREQ(def->os.type, "hvm") ?
8538 8539
            VIR_DOMAIN_INPUT_BUS_PS2 : VIR_DOMAIN_INPUT_BUS_XEN,
            { .alias = NULL },
8540
        };
8541

8542
        if (virDomainInputDefFormat(&buf, &autoInput, flags) < 0)
8543 8544
            goto cleanup;

8545
        for (n = 0 ; n < def->ngraphics ; n++)
8546
            if (virDomainGraphicsDefFormat(&buf, def->graphics[n], flags) < 0)
8547
                goto cleanup;
8548 8549
    }

8550
    for (n = 0 ; n < def->nsounds ; n++)
8551
        if (virDomainSoundDefFormat(&buf, def->sounds[n], flags) < 0)
8552 8553
            goto cleanup;

8554
    for (n = 0 ; n < def->nvideos ; n++)
8555
        if (virDomainVideoDefFormat(&buf, def->videos[n], flags) < 0)
8556 8557
            goto cleanup;

8558
    for (n = 0 ; n < def->nhostdevs ; n++)
8559
        if (virDomainHostdevDefFormat(&buf, def->hostdevs[n], flags) < 0)
8560 8561
            goto cleanup;

R
Richard Jones 已提交
8562
    if (def->watchdog)
8563
        virDomainWatchdogDefFormat (&buf, def->watchdog, flags);
R
Richard Jones 已提交
8564

8565 8566 8567
    if (def->memballoon)
        virDomainMemballoonDefFormat (&buf, def->memballoon, flags);

8568
    virBufferAddLit(&buf, "  </devices>\n");
8569 8570

    if (def->seclabel.model) {
8571 8572 8573 8574 8575 8576
        const char *sectype = virDomainSeclabelTypeToString(def->seclabel.type);
        if (!sectype)
            goto cleanup;
        if (!def->seclabel.label ||
            (def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC &&
             (flags & VIR_DOMAIN_XML_INACTIVE))) {
8577
            virBufferAsprintf(&buf, "  <seclabel type='%s' model='%s'/>\n",
8578 8579
                              sectype, def->seclabel.model);
        } else {
8580
            virBufferAsprintf(&buf, "  <seclabel type='%s' model='%s'>\n",
8581 8582 8583 8584 8585 8586 8587 8588 8589
                                  sectype, def->seclabel.model);
            virBufferEscapeString(&buf, "    <label>%s</label>\n",
                                  def->seclabel.label);
            if (def->seclabel.imagelabel &&
                def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC)
                virBufferEscapeString(&buf, "    <imagelabel>%s</imagelabel>\n",
                                      def->seclabel.imagelabel);
            virBufferAddLit(&buf, "  </seclabel>\n");
        }
8590 8591
    }

8592 8593 8594 8595 8596
    if (def->namespaceData && def->ns.format) {
        if ((def->ns.format)(&buf, def->namespaceData) < 0)
            goto cleanup;
    }

8597 8598 8599 8600 8601 8602 8603 8604
    virBufferAddLit(&buf, "</domain>\n");

    if (virBufferError(&buf))
        goto no_memory;

    return virBufferContentAndReset(&buf);

 no_memory:
8605
    virReportOOMError();
8606
 cleanup:
8607
    virBufferFreeAndReset(&buf);
8608 8609 8610
    return NULL;
}

8611

8612 8613 8614
static char *virDomainObjFormat(virCapsPtr caps,
                                virDomainObjPtr obj,
                                int flags)
8615
{
8616
    char *config_xml = NULL;
8617
    virBuffer buf = VIR_BUFFER_INITIALIZER;
J
Jiri Denemark 已提交
8618 8619
    int state;
    int reason;
8620
    int i;
8621

J
Jiri Denemark 已提交
8622 8623 8624 8625
    state = virDomainObjGetState(obj, &reason);
    virBufferAsprintf(&buf, "<domstatus state='%s' reason='%s' pid='%d'>\n",
                      virDomainStateTypeToString(state),
                      virDomainStateReasonToString(state, reason),
8626
                      obj->pid);
8627

8628 8629 8630 8631 8632 8633
    for (i = 0 ; i < VIR_DOMAIN_TAINT_LAST ; i++) {
        if (obj->taint & (1 << i))
            virBufferAsprintf(&buf, "  <taint flag='%s'/>\n",
                              virDomainTaintTypeToString(i));
    }

8634 8635 8636
    if (caps->privateDataXMLFormat &&
        ((caps->privateDataXMLFormat)(&buf, obj->privateData)) < 0)
        goto error;
8637

8638
    if (!(config_xml = virDomainDefFormat(obj->def,
8639 8640 8641 8642 8643 8644 8645 8646 8647 8648 8649 8650 8651
                                          flags)))
        goto error;

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

    if (virBufferError(&buf))
        goto no_memory;

    return virBufferContentAndReset(&buf);

no_memory:
8652
    virReportOOMError();
8653
error:
8654
    virBufferFreeAndReset(&buf);
8655 8656 8657
    return NULL;
}

8658
int virDomainSaveXML(const char *configDir,
8659 8660
                     virDomainDefPtr def,
                     const char *xml)
8661
{
8662
    char *configFile = NULL;
8663 8664 8665
    int fd = -1, ret = -1;
    size_t towrite;

8666
    if ((configFile = virDomainConfigFile(configDir, def->name)) == NULL)
8667 8668
        goto cleanup;

8669
    if (virFileMakePath(configDir)) {
8670
        virReportSystemError(errno,
8671 8672
                             _("cannot create config directory '%s'"),
                             configDir);
8673 8674 8675
        goto cleanup;
    }

8676
    if ((fd = open(configFile,
8677 8678
                   O_WRONLY | O_CREAT | O_TRUNC,
                   S_IRUSR | S_IWUSR )) < 0) {
8679
        virReportSystemError(errno,
8680 8681
                             _("cannot create config file '%s'"),
                             configFile);
8682 8683 8684
        goto cleanup;
    }

8685 8686
    virEmitXMLWarning(fd, def->name, "edit");

8687 8688
    towrite = strlen(xml);
    if (safewrite(fd, xml, towrite) < 0) {
8689
        virReportSystemError(errno,
8690 8691
                             _("cannot write config file '%s'"),
                             configFile);
8692 8693 8694
        goto cleanup;
    }

8695
    if (VIR_CLOSE(fd) < 0) {
8696
        virReportSystemError(errno,
8697 8698
                             _("cannot save config file '%s'"),
                             configFile);
8699 8700 8701 8702 8703
        goto cleanup;
    }

    ret = 0;
 cleanup:
8704 8705
    VIR_FORCE_CLOSE(fd);

R
Ryota Ozaki 已提交
8706
    VIR_FREE(configFile);
8707 8708 8709
    return ret;
}

8710
int virDomainSaveConfig(const char *configDir,
8711 8712 8713 8714
                        virDomainDefPtr def)
{
    int ret = -1;
    char *xml;
8715

8716
    if (!(xml = virDomainDefFormat(def,
8717
                                   VIR_DOMAIN_XML_WRITE_FLAGS)))
8718 8719
        goto cleanup;

8720
    if (virDomainSaveXML(configDir, def, xml))
8721 8722 8723 8724 8725
        goto cleanup;

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

8729
int virDomainSaveStatus(virCapsPtr caps,
8730 8731 8732
                        const char *statusDir,
                        virDomainObjPtr obj)
{
8733
    int flags = VIR_DOMAIN_XML_SECURE|VIR_DOMAIN_XML_INTERNAL_STATUS;
8734 8735 8736
    int ret = -1;
    char *xml;

8737
    if (!(xml = virDomainObjFormat(caps, obj, flags)))
8738 8739
        goto cleanup;

8740
    if (virDomainSaveXML(statusDir, obj->def, xml))
8741 8742 8743 8744 8745 8746 8747 8748
        goto cleanup;

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

8749

8750 8751 8752 8753 8754 8755 8756
static virDomainObjPtr virDomainLoadConfig(virCapsPtr caps,
                                           virDomainObjListPtr doms,
                                           const char *configDir,
                                           const char *autostartDir,
                                           const char *name,
                                           virDomainLoadConfigNotify notify,
                                           void *opaque)
8757 8758 8759 8760 8761
{
    char *configFile = NULL, *autostartLink = NULL;
    virDomainDefPtr def = NULL;
    virDomainObjPtr dom;
    int autostart;
8762
    int newVM = 1;
8763

8764
    if ((configFile = virDomainConfigFile(configDir, name)) == NULL)
8765
        goto error;
8766
    if (!(def = virDomainDefParseFile(caps, configFile,
8767
                                      VIR_DOMAIN_XML_INACTIVE)))
8768 8769
        goto error;

8770 8771 8772 8773 8774 8775 8776
    /* if the domain is already in our hashtable, we don't need to do
     * anything further
     */
    if ((dom = virDomainFindByUUID(doms, def->uuid))) {
        VIR_FREE(configFile);
        virDomainDefFree(def);
        return dom;
8777
    }
8778

8779 8780 8781 8782 8783 8784
    if ((autostartLink = virDomainConfigFile(autostartDir, name)) == NULL)
        goto error;

    if ((autostart = virFileLinkPointsTo(autostartLink, configFile)) < 0)
        goto error;

8785
    if (!(dom = virDomainAssignDef(caps, doms, def, false)))
8786 8787 8788 8789
        goto error;

    dom->autostart = autostart;

8790 8791 8792
    if (notify)
        (*notify)(dom, newVM, opaque);

8793 8794
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
8795 8796 8797 8798 8799 8800 8801 8802 8803
    return dom;

error:
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
    virDomainDefFree(def);
    return NULL;
}

8804
static virDomainObjPtr virDomainLoadStatus(virCapsPtr caps,
8805 8806 8807 8808 8809 8810 8811 8812
                                           virDomainObjListPtr doms,
                                           const char *statusDir,
                                           const char *name,
                                           virDomainLoadConfigNotify notify,
                                           void *opaque)
{
    char *statusFile = NULL;
    virDomainObjPtr obj = NULL;
8813
    char uuidstr[VIR_UUID_STRING_BUFLEN];
8814

8815
    if ((statusFile = virDomainConfigFile(statusDir, name)) == NULL)
8816 8817
        goto error;

8818
    if (!(obj = virDomainObjParseFile(caps, statusFile)))
8819 8820
        goto error;

8821 8822 8823
    virUUIDFormat(obj->def->uuid, uuidstr);

    if (virHashLookup(doms->objs, uuidstr) != NULL) {
8824
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
8825 8826 8827 8828 8829
                             _("unexpected domain %s already exists"),
                             obj->def->name);
        goto error;
    }

8830
    if (virHashAddEntry(doms->objs, uuidstr, obj) < 0)
8831 8832 8833 8834 8835 8836 8837 8838 8839
        goto error;

    if (notify)
        (*notify)(obj, 1, opaque);

    VIR_FREE(statusFile);
    return obj;

error:
8840
    /* obj was never shared, so unref should return 0 */
8841
    if (obj)
8842
        ignore_value(virDomainObjUnref(obj));
8843 8844 8845 8846
    VIR_FREE(statusFile);
    return NULL;
}

8847
int virDomainLoadAllConfigs(virCapsPtr caps,
8848
                            virDomainObjListPtr doms,
8849
                            const char *configDir,
8850
                            const char *autostartDir,
8851
                            int liveStatus,
8852 8853
                            virDomainLoadConfigNotify notify,
                            void *opaque)
8854 8855 8856 8857
{
    DIR *dir;
    struct dirent *entry;

8858 8859
    VIR_INFO("Scanning for configs in %s", configDir);

8860 8861 8862
    if (!(dir = opendir(configDir))) {
        if (errno == ENOENT)
            return 0;
8863
        virReportSystemError(errno,
8864 8865
                             _("Failed to open dir '%s'"),
                             configDir);
8866 8867 8868 8869
        return -1;
    }

    while ((entry = readdir(dir))) {
8870 8871
        virDomainObjPtr dom;

8872 8873 8874
        if (entry->d_name[0] == '.')
            continue;

8875
        if (!virFileStripSuffix(entry->d_name, ".xml"))
8876 8877 8878 8879
            continue;

        /* NB: ignoring errors, so one malformed config doesn't
           kill the whole process */
8880 8881
        VIR_INFO("Loading config file '%s.xml'", entry->d_name);
        if (liveStatus)
8882
            dom = virDomainLoadStatus(caps,
8883 8884 8885 8886 8887 8888
                                      doms,
                                      configDir,
                                      entry->d_name,
                                      notify,
                                      opaque);
        else
8889
            dom = virDomainLoadConfig(caps,
8890 8891 8892 8893 8894 8895
                                      doms,
                                      configDir,
                                      autostartDir,
                                      entry->d_name,
                                      notify,
                                      opaque);
8896 8897
        if (dom) {
            virDomainObjUnlock(dom);
D
Daniel Veillard 已提交
8898 8899
            if (!liveStatus)
                dom->persistent = 1;
8900
        }
8901 8902 8903 8904 8905 8906 8907
    }

    closedir(dir);

    return 0;
}

8908
int virDomainDeleteConfig(const char *configDir,
8909 8910
                          const char *autostartDir,
                          virDomainObjPtr dom)
8911
{
8912 8913 8914
    char *configFile = NULL, *autostartLink = NULL;
    int ret = -1;

8915
    if ((configFile = virDomainConfigFile(configDir, dom->def->name)) == NULL)
8916
        goto cleanup;
8917
    if ((autostartLink = virDomainConfigFile(autostartDir, dom->def->name)) == NULL)
8918
        goto cleanup;
8919 8920

    /* Not fatal if this doesn't work */
8921
    unlink(autostartLink);
8922

8923 8924
    if (unlink(configFile) < 0 &&
        errno != ENOENT) {
8925
        virReportSystemError(errno,
8926 8927
                             _("cannot remove config %s"),
                             configFile);
8928
        goto cleanup;
8929 8930
    }

8931 8932 8933 8934 8935 8936
    ret = 0;

cleanup:
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
    return ret;
8937
}
8938

8939
char *virDomainConfigFile(const char *dir,
8940 8941 8942 8943
                          const char *name)
{
    char *ret = NULL;

8944
    if (virAsprintf(&ret, "%s/%s.xml", dir, name) < 0) {
8945
        virReportOOMError();
8946 8947 8948 8949 8950 8951
        return NULL;
    }

    return ret;
}

8952 8953
/* Translates a device name of the form (regex) "[fhv]d[a-z]+" into
 * the corresponding bus,index combination (e.g. sda => (0,0), sdi (1,1),
D
Daniel Veillard 已提交
8954
 *                                               hdd => (1,1), vdaa => (0,26))
8955 8956 8957 8958 8959
 * @param disk The disk device
 * @param busIdx parsed bus number
 * @param devIdx parsed device number
 * @return 0 on success, -1 on failure
 */
8960
int virDiskNameToBusDeviceIndex(const virDomainDiskDefPtr disk,
8961 8962 8963 8964
                                int *busIdx,
                                int *devIdx) {

    int idx = virDiskNameToIndex(disk->dst);
8965
    if (idx < 0)
8966 8967 8968 8969 8970 8971 8972 8973 8974 8975 8976 8977 8978 8979 8980 8981 8982 8983 8984 8985 8986 8987 8988
        return -1;

    switch (disk->bus) {
        case VIR_DOMAIN_DISK_BUS_IDE:
            *busIdx = idx / 2;
            *devIdx = idx % 2;
            break;
        case VIR_DOMAIN_DISK_BUS_SCSI:
            *busIdx = idx / 7;
            *devIdx = idx % 7;
            break;
        case VIR_DOMAIN_DISK_BUS_FDC:
        case VIR_DOMAIN_DISK_BUS_USB:
        case VIR_DOMAIN_DISK_BUS_VIRTIO:
        case VIR_DOMAIN_DISK_BUS_XEN:
        default:
            *busIdx = 0;
            *devIdx = idx;
            break;
    }

    return 0;
}
8989

8990 8991 8992 8993 8994 8995 8996 8997 8998 8999 9000 9001 9002 9003 9004
virDomainFSDefPtr virDomainGetRootFilesystem(virDomainDefPtr def)
{
    int i;

    for (i = 0 ; i < def->nfss ; i++) {
        if (def->fss[i]->type != VIR_DOMAIN_FS_TYPE_MOUNT)
            continue;

        if (STREQ(def->fss[i]->dst, "/"))
            return def->fss[i];
    }

    return NULL;
}

9005 9006 9007 9008 9009 9010 9011 9012 9013 9014 9015 9016 9017 9018 9019 9020 9021 9022 9023 9024 9025 9026 9027 9028 9029 9030
/*
 * virDomainObjIsDuplicate:
 * @doms : virDomainObjListPtr to search
 * @def  : virDomainDefPtr definition of domain to lookup
 * @check_active: If true, ensure that domain is not active
 *
 * Returns: -1 on error
 *          0 if domain is new
 *          1 if domain is a duplicate
 */
int
virDomainObjIsDuplicate(virDomainObjListPtr doms,
                        virDomainDefPtr def,
                        unsigned int check_active)
{
    int ret = -1;
    int dupVM = 0;
    virDomainObjPtr vm = NULL;

    /* See if a VM with matching UUID already exists */
    vm = virDomainFindByUUID(doms, def->uuid);
    if (vm) {
        /* UUID matches, but if names don't match, refuse it */
        if (STRNEQ(vm->def->name, def->name)) {
            char uuidstr[VIR_UUID_STRING_BUFLEN];
            virUUIDFormat(vm->def->uuid, uuidstr);
9031 9032 9033
            virDomainReportError(VIR_ERR_OPERATION_FAILED,
                                 _("domain '%s' is already defined with uuid %s"),
                                 vm->def->name, uuidstr);
9034 9035 9036 9037 9038 9039
            goto cleanup;
        }

        if (check_active) {
            /* UUID & name match, but if VM is already active, refuse it */
            if (virDomainObjIsActive(vm)) {
9040
                virDomainReportError(VIR_ERR_OPERATION_INVALID,
9041 9042 9043 9044 9045 9046 9047 9048 9049 9050 9051 9052 9053
                                     _("domain is already active as '%s'"),
                                     vm->def->name);
                goto cleanup;
            }
        }

        dupVM = 1;
    } else {
        /* UUID does not match, but if a name matches, refuse it */
        vm = virDomainFindByName(doms, def->name);
        if (vm) {
            char uuidstr[VIR_UUID_STRING_BUFLEN];
            virUUIDFormat(vm->def->uuid, uuidstr);
9054
            virDomainReportError(VIR_ERR_OPERATION_FAILED,
9055 9056 9057 9058 9059 9060 9061 9062 9063 9064 9065 9066 9067
                                 _("domain '%s' already exists with uuid %s"),
                                 def->name, uuidstr);
            goto cleanup;
        }
    }

    ret = dupVM;
cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    return ret;
}

9068

9069 9070
void virDomainObjLock(virDomainObjPtr obj)
{
9071
    virMutexLock(&obj->lock);
9072 9073 9074 9075
}

void virDomainObjUnlock(virDomainObjPtr obj)
{
9076
    virMutexUnlock(&obj->lock);
9077 9078
}

9079

9080
static void virDomainObjListCountActive(void *payload, const void *name ATTRIBUTE_UNUSED, void *data)
9081 9082 9083 9084
{
    virDomainObjPtr obj = payload;
    int *count = data;
    virDomainObjLock(obj);
D
Daniel P. Berrange 已提交
9085
    if (virDomainObjIsActive(obj))
9086 9087 9088 9089
        (*count)++;
    virDomainObjUnlock(obj);
}

9090
static void virDomainObjListCountInactive(void *payload, const void *name ATTRIBUTE_UNUSED, void *data)
9091 9092 9093 9094
{
    virDomainObjPtr obj = payload;
    int *count = data;
    virDomainObjLock(obj);
D
Daniel P. Berrange 已提交
9095
    if (!virDomainObjIsActive(obj))
9096 9097 9098 9099 9100 9101 9102 9103 9104 9105 9106 9107 9108 9109 9110 9111 9112 9113 9114 9115
        (*count)++;
    virDomainObjUnlock(obj);
}

int virDomainObjListNumOfDomains(virDomainObjListPtr doms, int active)
{
    int count = 0;
    if (active)
        virHashForEach(doms->objs, virDomainObjListCountActive, &count);
    else
        virHashForEach(doms->objs, virDomainObjListCountInactive, &count);
    return count;
}

struct virDomainIDData {
    int numids;
    int maxids;
    int *ids;
};

9116
static void virDomainObjListCopyActiveIDs(void *payload, const void *name ATTRIBUTE_UNUSED, void *opaque)
9117 9118 9119 9120
{
    virDomainObjPtr obj = payload;
    struct virDomainIDData *data = opaque;
    virDomainObjLock(obj);
D
Daniel P. Berrange 已提交
9121
    if (virDomainObjIsActive(obj) && data->numids < data->maxids)
9122 9123 9124 9125 9126 9127 9128 9129 9130 9131 9132 9133 9134 9135 9136 9137 9138 9139 9140 9141
        data->ids[data->numids++] = obj->def->id;
    virDomainObjUnlock(obj);
}

int virDomainObjListGetActiveIDs(virDomainObjListPtr doms,
                                 int *ids,
                                 int maxids)
{
    struct virDomainIDData data = { 0, maxids, ids };
    virHashForEach(doms->objs, virDomainObjListCopyActiveIDs, &data);
    return data.numids;
}

struct virDomainNameData {
    int oom;
    int numnames;
    int maxnames;
    char **const names;
};

9142
static void virDomainObjListCopyInactiveNames(void *payload, const void *name ATTRIBUTE_UNUSED, void *opaque)
9143 9144 9145 9146 9147 9148 9149 9150
{
    virDomainObjPtr obj = payload;
    struct virDomainNameData *data = opaque;

    if (data->oom)
        return;

    virDomainObjLock(obj);
D
Daniel P. Berrange 已提交
9151
    if (!virDomainObjIsActive(obj) && data->numnames < data->maxnames) {
9152 9153 9154 9155 9156 9157 9158 9159 9160 9161 9162 9163 9164 9165 9166 9167 9168
        if (!(data->names[data->numnames] = strdup(obj->def->name)))
            data->oom = 1;
        else
            data->numnames++;
    }
    virDomainObjUnlock(obj);
}


int virDomainObjListGetInactiveNames(virDomainObjListPtr doms,
                                     char **const names,
                                     int maxnames)
{
    struct virDomainNameData data = { 0, 0, maxnames, names };
    int i;
    virHashForEach(doms->objs, virDomainObjListCopyInactiveNames, &data);
    if (data.oom) {
9169
        virReportOOMError();
9170 9171 9172 9173 9174 9175 9176 9177 9178 9179 9180
        goto cleanup;
    }

    return data.numnames;

cleanup:
    for (i = 0 ; i < data.numnames ; i++)
        VIR_FREE(data.names[i]);
    return -1;
}

C
Chris Lalancette 已提交
9181 9182 9183 9184 9185 9186 9187 9188 9189 9190 9191 9192 9193 9194 9195 9196 9197 9198 9199 9200 9201 9202 9203 9204 9205 9206 9207 9208 9209 9210 9211 9212 9213 9214 9215 9216 9217 9218
/* Snapshot Def functions */
void virDomainSnapshotDefFree(virDomainSnapshotDefPtr def)
{
    if (!def)
        return;

    VIR_FREE(def->name);
    VIR_FREE(def->description);
    VIR_FREE(def->parent);
    VIR_FREE(def);
}

virDomainSnapshotDefPtr virDomainSnapshotDefParseString(const char *xmlStr,
                                                        int newSnapshot)
{
    xmlXPathContextPtr ctxt = NULL;
    xmlDocPtr xml = NULL;
    virDomainSnapshotDefPtr def = NULL;
    virDomainSnapshotDefPtr ret = NULL;
    char *creation = NULL, *state = NULL;
    struct timeval tv;

    xml = virXMLParse(NULL, xmlStr, "domainsnapshot.xml");
    if (!xml) {
        return NULL;
    }

    ctxt = xmlXPathNewContext(xml);
    if (ctxt == NULL) {
        virReportOOMError();
        goto cleanup;
    }

    if (VIR_ALLOC(def) < 0) {
        virReportOOMError();
        goto cleanup;
    }

9219 9220 9221 9222 9223
    ctxt->node = xmlDocGetRootElement(xml);
    if (!xmlStrEqual(ctxt->node->name, BAD_CAST "domainsnapshot")) {
        virDomainReportError(VIR_ERR_XML_ERROR, "%s", _("domainsnapshot"));
        goto cleanup;
    }
C
Chris Lalancette 已提交
9224 9225 9226 9227 9228

    gettimeofday(&tv, NULL);

    def->name = virXPathString("string(./name)", ctxt);
    if (def->name == NULL)
9229
        ignore_value(virAsprintf(&def->name, "%lld", (long long)tv.tv_sec));
C
Chris Lalancette 已提交
9230 9231 9232 9233 9234 9235 9236 9237 9238

    if (def->name == NULL) {
        virReportOOMError();
        goto cleanup;
    }

    def->description = virXPathString("string(./description)", ctxt);

    if (!newSnapshot) {
9239 9240
        if (virXPathLongLong("string(./creationTime)", ctxt,
                             &def->creationTime) < 0) {
C
Chris Lalancette 已提交
9241 9242 9243 9244 9245 9246 9247 9248 9249 9250 9251 9252 9253 9254 9255 9256 9257 9258 9259 9260 9261 9262 9263 9264 9265 9266 9267 9268 9269 9270 9271 9272 9273 9274 9275 9276 9277 9278 9279 9280 9281 9282 9283 9284 9285 9286 9287 9288 9289 9290 9291 9292 9293
            virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                 _("missing creationTime from existing snapshot"));
            goto cleanup;
        }

        def->parent = virXPathString("string(./parent/name)", ctxt);

        state = virXPathString("string(./state)", ctxt);
        if (state == NULL) {
            /* there was no state in an existing snapshot; this
             * should never happen
             */
            virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                 _("missing state from existing snapshot"));
            goto cleanup;
        }
        def->state = virDomainStateTypeFromString(state);
        if (def->state < 0) {
            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                                 _("Invalid state '%s' in domain snapshot XML"),
                                 state);
            goto cleanup;
        }

        if (virXPathLong("string(./active)", ctxt, &def->active) < 0) {
            virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                 _("Could not find 'active' element"));
            goto cleanup;
        }
    }
    else
        def->creationTime = tv.tv_sec;

    ret = def;

cleanup:
    VIR_FREE(creation);
    VIR_FREE(state);
    xmlXPathFreeContext(ctxt);
    if (ret == NULL)
        virDomainSnapshotDefFree(def);
    xmlFreeDoc(xml);

    return ret;
}

char *virDomainSnapshotDefFormat(char *domain_uuid,
                                 virDomainSnapshotDefPtr def,
                                 int internal)
{
    virBuffer buf = VIR_BUFFER_INITIALIZER;

    virBufferAddLit(&buf, "<domainsnapshot>\n");
9294
    virBufferAsprintf(&buf, "  <name>%s</name>\n", def->name);
C
Chris Lalancette 已提交
9295
    if (def->description)
9296
        virBufferAsprintf(&buf, "  <description>%s</description>\n",
C
Chris Lalancette 已提交
9297
                          def->description);
9298
    virBufferAsprintf(&buf, "  <state>%s</state>\n",
C
Chris Lalancette 已提交
9299 9300 9301
                      virDomainStateTypeToString(def->state));
    if (def->parent) {
        virBufferAddLit(&buf, "  <parent>\n");
9302
        virBufferAsprintf(&buf, "    <name>%s</name>\n", def->parent);
C
Chris Lalancette 已提交
9303 9304
        virBufferAddLit(&buf, "  </parent>\n");
    }
9305
    virBufferAsprintf(&buf, "  <creationTime>%lld</creationTime>\n",
C
Chris Lalancette 已提交
9306 9307
                      def->creationTime);
    virBufferAddLit(&buf, "  <domain>\n");
9308
    virBufferAsprintf(&buf, "    <uuid>%s</uuid>\n", domain_uuid);
C
Chris Lalancette 已提交
9309 9310
    virBufferAddLit(&buf, "  </domain>\n");
    if (internal)
9311
        virBufferAsprintf(&buf, "  <active>%ld</active>\n", def->active);
C
Chris Lalancette 已提交
9312 9313 9314 9315 9316 9317 9318 9319 9320 9321 9322 9323 9324 9325 9326 9327 9328 9329 9330 9331 9332 9333 9334 9335 9336 9337 9338 9339 9340 9341 9342 9343 9344 9345
    virBufferAddLit(&buf, "</domainsnapshot>\n");

    if (virBufferError(&buf)) {
        virBufferFreeAndReset(&buf);
        virReportOOMError();
        return NULL;
    }

    return virBufferContentAndReset(&buf);
}

/* Snapshot Obj functions */
static virDomainSnapshotObjPtr virDomainSnapshotObjNew(void)
{
    virDomainSnapshotObjPtr snapshot;

    if (VIR_ALLOC(snapshot) < 0) {
        virReportOOMError();
        return NULL;
    }

    VIR_DEBUG("obj=%p", snapshot);

    return snapshot;
}

static void virDomainSnapshotObjFree(virDomainSnapshotObjPtr snapshot)
{
    if (!snapshot)
        return;

    VIR_DEBUG("obj=%p", snapshot);

    virDomainSnapshotDefFree(snapshot->def);
9346
    VIR_FREE(snapshot);
C
Chris Lalancette 已提交
9347 9348 9349 9350 9351 9352 9353 9354 9355 9356 9357 9358 9359 9360 9361 9362 9363 9364 9365 9366 9367 9368 9369 9370 9371 9372 9373
}

virDomainSnapshotObjPtr virDomainSnapshotAssignDef(virDomainSnapshotObjListPtr snapshots,
                                                   const virDomainSnapshotDefPtr def)
{
    virDomainSnapshotObjPtr snap;

    if (virHashLookup(snapshots->objs, def->name) != NULL) {
        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                             _("unexpected domain snapshot %s already exists"),
                             def->name);
        return NULL;
    }

    if (!(snap = virDomainSnapshotObjNew()))
        return NULL;
    snap->def = def;

    if (virHashAddEntry(snapshots->objs, snap->def->name, snap) < 0) {
        VIR_FREE(snap);
        return NULL;
    }

    return snap;
}

/* Snapshot Obj List functions */
9374
static void
9375
virDomainSnapshotObjListDataFree(void *payload,
9376
                                 const void *name ATTRIBUTE_UNUSED)
9377 9378 9379
{
    virDomainSnapshotObjPtr obj = payload;

9380
    virDomainSnapshotObjFree(obj);
9381 9382
}

C
Chris Lalancette 已提交
9383 9384
int virDomainSnapshotObjListInit(virDomainSnapshotObjListPtr snapshots)
{
9385
    snapshots->objs = virHashCreate(50, virDomainSnapshotObjListDataFree);
9386
    if (!snapshots->objs)
C
Chris Lalancette 已提交
9387 9388 9389 9390
        return -1;
    return 0;
}

9391 9392
static void
virDomainSnapshotObjListDeinit(virDomainSnapshotObjListPtr snapshots)
C
Chris Lalancette 已提交
9393
{
9394
    virHashFree(snapshots->objs);
C
Chris Lalancette 已提交
9395 9396 9397 9398 9399 9400 9401 9402 9403 9404
}

struct virDomainSnapshotNameData {
    int oom;
    int numnames;
    int maxnames;
    char **const names;
};

static void virDomainSnapshotObjListCopyNames(void *payload,
9405
                                              const void *name ATTRIBUTE_UNUSED,
C
Chris Lalancette 已提交
9406 9407 9408 9409 9410 9411 9412 9413 9414 9415 9416 9417 9418 9419 9420 9421 9422 9423 9424 9425 9426 9427 9428 9429 9430 9431 9432 9433 9434 9435 9436 9437 9438 9439 9440 9441 9442
                                              void *opaque)
{
    virDomainSnapshotObjPtr obj = payload;
    struct virDomainSnapshotNameData *data = opaque;

    if (data->oom)
        return;

    if (data->numnames < data->maxnames) {
        if (!(data->names[data->numnames] = strdup(obj->def->name)))
            data->oom = 1;
        else
            data->numnames++;
    }
}

int virDomainSnapshotObjListGetNames(virDomainSnapshotObjListPtr snapshots,
                                     char **const names, int maxnames)
{
    struct virDomainSnapshotNameData data = { 0, 0, maxnames, names };
    int i;

    virHashForEach(snapshots->objs, virDomainSnapshotObjListCopyNames, &data);
    if (data.oom) {
        virReportOOMError();
        goto cleanup;
    }

    return data.numnames;

cleanup:
    for (i = 0; i < data.numnames; i++)
        VIR_FREE(data.names[i]);
    return -1;
}

static void virDomainSnapshotObjListCount(void *payload ATTRIBUTE_UNUSED,
9443
                                          const void *name ATTRIBUTE_UNUSED,
C
Chris Lalancette 已提交
9444 9445 9446 9447 9448 9449 9450 9451 9452 9453 9454 9455 9456 9457 9458 9459 9460
                                          void *data)
{
    int *count = data;

    (*count)++;
}

int virDomainSnapshotObjListNum(virDomainSnapshotObjListPtr snapshots)
{
    int count = 0;

    virHashForEach(snapshots->objs, virDomainSnapshotObjListCount, &count);

    return count;
}

static int virDomainSnapshotObjListSearchName(const void *payload,
9461
                                              const void *name ATTRIBUTE_UNUSED,
C
Chris Lalancette 已提交
9462 9463 9464 9465 9466 9467 9468 9469 9470 9471 9472 9473 9474 9475 9476 9477 9478 9479 9480 9481
                                              const void *data)
{
    virDomainSnapshotObjPtr obj = (virDomainSnapshotObjPtr)payload;
    int want = 0;

    if (STREQ(obj->def->name, (const char *)data))
        want = 1;

    return want;
}

virDomainSnapshotObjPtr virDomainSnapshotFindByName(const virDomainSnapshotObjListPtr snapshots,
                                                    const char *name)
{
    return virHashSearch(snapshots->objs, virDomainSnapshotObjListSearchName, name);
}

void virDomainSnapshotObjListRemove(virDomainSnapshotObjListPtr snapshots,
                                    virDomainSnapshotObjPtr snapshot)
{
9482
    virHashRemoveEntry(snapshots->objs, snapshot->def->name);
C
Chris Lalancette 已提交
9483 9484 9485 9486 9487 9488 9489 9490
}

struct snapshot_has_children {
    char *name;
    int number;
};

static void virDomainSnapshotCountChildren(void *payload,
9491
                                           const void *name ATTRIBUTE_UNUSED,
C
Chris Lalancette 已提交
9492 9493 9494 9495 9496 9497 9498 9499 9500 9501 9502 9503 9504 9505 9506 9507 9508 9509 9510 9511 9512 9513
                                           void *data)
{
    virDomainSnapshotObjPtr obj = payload;
    struct snapshot_has_children *curr = data;

    if (obj->def->parent && STREQ(obj->def->parent, curr->name))
        curr->number++;
}

int virDomainSnapshotHasChildren(virDomainSnapshotObjPtr snap,
                                virDomainSnapshotObjListPtr snapshots)
{
    struct snapshot_has_children children;

    children.name = snap->def->name;
    children.number = 0;
    virHashForEach(snapshots->objs, virDomainSnapshotCountChildren, &children);

    return children.number;
}


9514 9515 9516 9517 9518 9519 9520 9521 9522 9523 9524 9525 9526 9527 9528 9529 9530 9531 9532 9533 9534 9535 9536 9537 9538 9539 9540 9541 9542 9543 9544 9545 9546 9547 9548 9549 9550 9551 9552 9553 9554 9555 9556 9557 9558 9559 9560 9561 9562 9563 9564 9565
int virDomainChrDefForeach(virDomainDefPtr def,
                           bool abortOnError,
                           virDomainChrDefIterator iter,
                           void *opaque)
{
    int i;
    int rc = 0;

    for (i = 0 ; i < def->nserials ; i++) {
        if ((iter)(def,
                   def->serials[i],
                   opaque) < 0)
            rc = -1;

        if (abortOnError && rc != 0)
            goto done;
    }

    for (i = 0 ; i < def->nparallels ; i++) {
        if ((iter)(def,
                   def->parallels[i],
                   opaque) < 0)
            rc = -1;

        if (abortOnError && rc != 0)
            goto done;
    }

    for (i = 0 ; i < def->nchannels ; i++) {
        if ((iter)(def,
                   def->channels[i],
                   opaque) < 0)
            rc = -1;

        if (abortOnError && rc != 0)
            goto done;
    }
    if (def->console) {
        if ((iter)(def,
                   def->console,
                   opaque) < 0)
            rc = -1;

        if (abortOnError && rc != 0)
            goto done;
    }

done:
    return rc;
}


E
Eric Blake 已提交
9566 9567 9568 9569 9570 9571 9572 9573 9574 9575 9576 9577 9578 9579 9580 9581 9582 9583 9584 9585 9586 9587 9588
int virDomainSmartcardDefForeach(virDomainDefPtr def,
                                 bool abortOnError,
                                 virDomainSmartcardDefIterator iter,
                                 void *opaque)
{
    int i;
    int rc = 0;

    for (i = 0 ; i < def->nsmartcards ; i++) {
        if ((iter)(def,
                   def->smartcards[i],
                   opaque) < 0)
            rc = -1;

        if (abortOnError && rc != 0)
            goto done;
    }

done:
    return rc;
}


9589 9590 9591 9592 9593 9594 9595 9596 9597 9598 9599 9600
int virDomainDiskDefForeachPath(virDomainDiskDefPtr disk,
                                bool allowProbing,
                                bool ignoreOpenFailure,
                                virDomainDiskDefPathIterator iter,
                                void *opaque)
{
    virHashTablePtr paths;
    int format;
    int ret = -1;
    size_t depth = 0;
    char *nextpath = NULL;

9601
    if (!disk->src || disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK)
9602 9603 9604 9605 9606 9607 9608 9609 9610 9611 9612 9613 9614 9615 9616 9617 9618 9619 9620 9621 9622 9623 9624 9625
        return 0;

    if (disk->driverType) {
        const char *formatStr = disk->driverType;
        if (STREQ(formatStr, "aio"))
            formatStr = "raw"; /* Xen compat */

        if ((format = virStorageFileFormatTypeFromString(formatStr)) < 0) {
            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                                 _("unknown disk format '%s' for %s"),
                                 disk->driverType, disk->src);
            return -1;
        }
    } else {
        if (allowProbing) {
            format = VIR_STORAGE_FILE_AUTO;
        } else {
            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                                 _("no disk format for %s and probing is disabled"),
                                 disk->src);
            return -1;
        }
    }

9626
    paths = virHashCreate(5, NULL);
9627 9628 9629 9630 9631 9632 9633 9634 9635 9636 9637 9638 9639 9640 9641 9642 9643 9644 9645 9646 9647 9648 9649 9650 9651 9652 9653 9654 9655 9656 9657

    do {
        virStorageFileMetadata meta;
        const char *path = nextpath ? nextpath : disk->src;
        int fd;

        if (iter(disk, path, depth, opaque) < 0)
            goto cleanup;

        if (virHashLookup(paths, path)) {
            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                                 _("backing store for %s is self-referential"),
                                 disk->src);
            goto cleanup;
        }

        if ((fd = open(path, O_RDONLY)) < 0) {
            if (ignoreOpenFailure) {
                char ebuf[1024];
                VIR_WARN("Ignoring open failure on %s: %s", path,
                         virStrerror(errno, ebuf, sizeof(ebuf)));
                break;
            } else {
                virReportSystemError(errno,
                                     _("unable to open disk path %s"),
                                     path);
                goto cleanup;
            }
        }

        if (virStorageFileGetMetadataFromFD(path, fd, format, &meta) < 0) {
9658
            VIR_FORCE_CLOSE(fd);
9659 9660
            goto cleanup;
        }
9661 9662 9663 9664 9665

        if (VIR_CLOSE(fd) < 0)
            virReportSystemError(errno,
                                 _("could not close file %s"),
                                 path);
9666

9667
        if (virHashAddEntry(paths, path, (void*)0x1) < 0)
9668 9669 9670 9671 9672
            goto cleanup;

        depth++;
        nextpath = meta.backingStore;

A
Adam Litke 已提交
9673 9674 9675 9676 9677 9678 9679
        /* Stop iterating if we reach a non-file backing store */
        if (nextpath && !meta.backingStoreIsFile) {
            VIR_DEBUG("Stopping iteration on non-file backing store: %s",
                      nextpath);
            break;
        }

9680 9681 9682 9683 9684
        format = meta.backingStoreFormat;

        if (format == VIR_STORAGE_FILE_AUTO &&
            !allowProbing)
            format = VIR_STORAGE_FILE_RAW; /* Stops further recursion */
9685 9686 9687 9688

        /* Allow probing for image formats that are safe */
        if (format == VIR_STORAGE_FILE_AUTO_SAFE)
            format = VIR_STORAGE_FILE_AUTO;
9689 9690 9691 9692 9693
    } while (nextpath);

    ret = 0;

cleanup:
9694
    virHashFree(paths);
9695 9696 9697 9698
    VIR_FREE(nextpath);

    return ret;
}
9699 9700 9701 9702 9703 9704 9705 9706 9707 9708 9709 9710 9711 9712 9713 9714 9715 9716 9717


virDomainDefPtr
virDomainObjCopyPersistentDef(virCapsPtr caps, virDomainObjPtr dom)
{
    char *xml;
    virDomainDefPtr cur, ret;

    cur = virDomainObjGetPersistentDef(caps, dom);

    xml = virDomainDefFormat(cur, VIR_DOMAIN_XML_WRITE_FLAGS);
    if (!xml)
        return NULL;

    ret = virDomainDefParseString(caps, xml, VIR_DOMAIN_XML_READ_FLAGS);

    VIR_FREE(xml);
    return ret;
}
J
Jiri Denemark 已提交
9718 9719 9720 9721 9722 9723 9724 9725 9726 9727 9728 9729 9730 9731 9732 9733 9734 9735 9736 9737 9738 9739 9740 9741 9742 9743 9744 9745 9746 9747 9748 9749 9750 9751 9752 9753 9754 9755 9756 9757 9758 9759 9760 9761 9762 9763 9764 9765 9766 9767 9768 9769 9770 9771 9772 9773 9774 9775 9776 9777 9778 9779 9780 9781 9782 9783 9784 9785 9786 9787 9788 9789 9790 9791 9792 9793 9794 9795 9796 9797 9798 9799 9800 9801 9802 9803


virDomainState
virDomainObjGetState(virDomainObjPtr dom, int *reason)
{
    if (reason)
        *reason = dom->state.reason;

    return dom->state.state;
}


void
virDomainObjSetState(virDomainObjPtr dom, virDomainState state, int reason)
{
    int last = -1;

    switch (state) {
    case VIR_DOMAIN_NOSTATE:    last = VIR_DOMAIN_NOSTATE_LAST;     break;
    case VIR_DOMAIN_RUNNING:    last = VIR_DOMAIN_RUNNING_LAST;     break;
    case VIR_DOMAIN_BLOCKED:    last = VIR_DOMAIN_BLOCKED_LAST;     break;
    case VIR_DOMAIN_PAUSED:     last = VIR_DOMAIN_PAUSED_LAST;      break;
    case VIR_DOMAIN_SHUTDOWN:   last = VIR_DOMAIN_SHUTDOWN_LAST;    break;
    case VIR_DOMAIN_SHUTOFF:    last = VIR_DOMAIN_SHUTOFF_LAST;     break;
    case VIR_DOMAIN_CRASHED:    last = VIR_DOMAIN_CRASHED_LAST;     break;
    }

    if (last < 0) {
        VIR_ERROR(_("invalid domain state: %d"), state);
        return;
    }

    dom->state.state = state;
    if (reason > 0 && reason < last)
        dom->state.reason = reason;
    else
        dom->state.reason = 0;
}


const char *
virDomainStateReasonToString(virDomainState state, int reason)
{
    switch (state) {
    case VIR_DOMAIN_NOSTATE:
        return virDomainNostateReasonTypeToString(reason);
    case VIR_DOMAIN_RUNNING:
        return virDomainRunningReasonTypeToString(reason);
    case VIR_DOMAIN_BLOCKED:
        return virDomainBlockedReasonTypeToString(reason);
    case VIR_DOMAIN_PAUSED:
        return virDomainPausedReasonTypeToString(reason);
    case VIR_DOMAIN_SHUTDOWN:
        return virDomainShutdownReasonTypeToString(reason);
    case VIR_DOMAIN_SHUTOFF:
        return virDomainShutoffReasonTypeToString(reason);
    case VIR_DOMAIN_CRASHED:
        return virDomainCrashedReasonTypeToString(reason);
    }

    return NULL;
}


int
virDomainStateReasonFromString(virDomainState state, const char *reason)
{
    switch (state) {
    case VIR_DOMAIN_NOSTATE:
        return virDomainNostateReasonTypeFromString(reason);
    case VIR_DOMAIN_RUNNING:
        return virDomainRunningReasonTypeFromString(reason);
    case VIR_DOMAIN_BLOCKED:
        return virDomainBlockedReasonTypeFromString(reason);
    case VIR_DOMAIN_PAUSED:
        return virDomainPausedReasonTypeFromString(reason);
    case VIR_DOMAIN_SHUTDOWN:
        return virDomainShutdownReasonTypeFromString(reason);
    case VIR_DOMAIN_SHUTOFF:
        return virDomainShutoffReasonTypeFromString(reason);
    case VIR_DOMAIN_CRASHED:
        return virDomainCrashedReasonTypeFromString(reason);
    }

    return -1;
}