domain_conf.c 680.0 KB
Newer Older
1 2 3
/*
 * domain_conf.c: domain XML processing
 *
M
Martin Kletzander 已提交
4
 * Copyright (C) 2006-2014 Red Hat, Inc.
5 6 7 8 9 10 11 12 13 14 15 16 17
 * 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
18
 * License along with this library.  If not, see
O
Osier Yang 已提交
19
 * <http://www.gnu.org/licenses/>.
20 21 22 23 24 25 26
 *
 * Author: Daniel P. Berrange <berrange@redhat.com>
 */

#include <config.h>

#include <dirent.h>
27
#include <fcntl.h>
E
Eric Blake 已提交
28
#include <strings.h>
29 30
#include <sys/stat.h>
#include <unistd.h>
31

A
Ansis Atteka 已提交
32
#include "internal.h"
33
#include "virerror.h"
34
#include "datatypes.h"
35
#include "domain_conf.h"
36
#include "snapshot_conf.h"
37
#include "viralloc.h"
38
#include "verify.h"
39
#include "virxml.h"
40
#include "viruuid.h"
41
#include "virbuffer.h"
42
#include "virlog.h"
43
#include "nwfilter_conf.h"
44
#include "storage_conf.h"
45
#include "virstoragefile.h"
E
Eric Blake 已提交
46
#include "virfile.h"
47
#include "virbitmap.h"
M
Matthias Bolte 已提交
48
#include "count-one-bits.h"
49
#include "secret_conf.h"
50 51
#include "netdev_vport_profile_conf.h"
#include "netdev_bandwidth_conf.h"
52
#include "netdev_vlan_conf.h"
53
#include "device_conf.h"
54
#include "virtpm.h"
55
#include "virstring.h"
56

57 58
#define VIR_FROM_THIS VIR_FROM_DOMAIN

59 60
VIR_LOG_INIT("conf.domain_conf");

M
Matthias Bolte 已提交
61 62 63 64
/* virDomainVirtType is used to set bits in the expectedVirtTypes bitmask,
 * verify that it doesn't overflow an unsigned int when shifting */
verify(VIR_DOMAIN_VIRT_LAST <= 32);

65 66 67 68 69 70 71 72 73

struct _virDomainObjList {
    virObjectLockable parent;

    /* uuid string -> virDomainObj  mapping
     * for O(1), lockless lookup-by-uuid */
    virHashTable *objs;
};

74 75 76

/* This structure holds various callbacks and data needed
 * while parsing and creating domain XMLs */
77
struct _virDomainXMLOption {
78 79
    virObject parent;

80 81 82
    /* XML parser callbacks and defaults */
    virDomainDefParserConfig config;

83 84 85 86 87 88 89 90
    /* domain private data management callbacks */
    virDomainXMLPrivateDataCallbacks privateData;

    /* XML namespace callbacks */
    virDomainXMLNamespace ns;
 };


91
/* Private flags used internally by virDomainSaveStatus and
92
 * virDomainLoadStatus, in addition to the public virDomainXMLFlags. */
93
typedef enum {
94
   /* dump internal domain status information */
95
   VIR_DOMAIN_XML_INTERNAL_STATUS          = 1 << 16,
96
   /* dump/parse <actual> element */
97
   VIR_DOMAIN_XML_INTERNAL_ACTUAL_NET      = 1 << 17,
98
   /* dump/parse original states of host PCI device */
99 100 101 102
   VIR_DOMAIN_XML_INTERNAL_PCI_ORIG_STATES = 1 << 18,
   VIR_DOMAIN_XML_INTERNAL_ALLOW_ROM       = 1 << 19,
   VIR_DOMAIN_XML_INTERNAL_ALLOW_BOOT      = 1 << 20,
   VIR_DOMAIN_XML_INTERNAL_CLOCK_ADJUST    = 1 << 21,
103 104
   /* parse only source half of <disk> */
   VIR_DOMAIN_XML_INTERNAL_DISK_SOURCE     = 1 << 22,
105 106
} virDomainXMLInternalFlags;

107 108 109 110 111 112 113 114 115 116 117
#define DUMPXML_FLAGS                           \
    (VIR_DOMAIN_XML_SECURE |                    \
     VIR_DOMAIN_XML_INACTIVE |                  \
     VIR_DOMAIN_XML_UPDATE_CPU |                \
     VIR_DOMAIN_XML_MIGRATABLE)

verify(((VIR_DOMAIN_XML_INTERNAL_STATUS |
         VIR_DOMAIN_XML_INTERNAL_ACTUAL_NET |
         VIR_DOMAIN_XML_INTERNAL_PCI_ORIG_STATES |
         VIR_DOMAIN_XML_INTERNAL_ALLOW_ROM |
         VIR_DOMAIN_XML_INTERNAL_ALLOW_BOOT |
118 119
         VIR_DOMAIN_XML_INTERNAL_CLOCK_ADJUST |
         VIR_DOMAIN_XML_INTERNAL_DISK_SOURCE)
120 121
        & DUMPXML_FLAGS) == 0);

122 123 124 125 126
VIR_ENUM_IMPL(virDomainTaint, VIR_DOMAIN_TAINT_LAST,
              "custom-argv",
              "custom-monitor",
              "high-privileges",
              "shell-scripts",
127
              "disk-probing",
128
              "external-launch",
129 130
              "host-cpu",
              "hook-script");
131

132 133 134 135 136 137 138 139 140 141
VIR_ENUM_IMPL(virDomainVirt, VIR_DOMAIN_VIRT_LAST,
              "qemu",
              "kqemu",
              "kvm",
              "xen",
              "lxc",
              "uml",
              "openvz",
              "test",
              "vmware",
142
              "hyperv",
D
Daniel Veillard 已提交
143
              "vbox",
D
Dmitry Guryanov 已提交
144
              "phyp",
R
Roman Bogorodskiy 已提交
145 146
              "parallels",
              "bhyve")
147 148 149 150 151 152 153 154 155 156

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 已提交
157
              "pae",
158
              "hap",
159
              "viridian",
160
              "privnet",
161
              "hyperv",
162
              "kvm",
163 164
              "pvspinlock",
              "capabilities")
165

166 167 168 169 170
VIR_ENUM_IMPL(virDomainCapabilitiesPolicy, VIR_DOMAIN_CAPABILITIES_POLICY_LAST,
              "default",
              "allow",
              "deny")

171
VIR_ENUM_IMPL(virDomainHyperv, VIR_DOMAIN_HYPERV_LAST,
172 173 174
              "relaxed",
              "vapic",
              "spinlocks")
175

176 177 178
VIR_ENUM_IMPL(virDomainKVM, VIR_DOMAIN_KVM_LAST,
              "hidden")

179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
VIR_ENUM_IMPL(virDomainCapsFeature, VIR_DOMAIN_CAPS_FEATURE_LAST,
              "audit_control",
              "audit_write",
              "block_suspend",
              "chown",
              "dac_override",
              "dac_read_search",
              "fowner",
              "fsetid",
              "ipc_lock",
              "ipc_owner",
              "kill",
              "lease",
              "linux_immutable",
              "mac_admin",
              "mac_override",
              "mknod",
              "net_admin",
              "net_bind_service",
              "net_broadcast",
              "net_raw",
              "setgid",
              "setfcap",
              "setpcap",
              "setuid",
              "sys_admin",
              "sys_boot",
              "sys_chroot",
              "sys_module",
              "sys_nice",
              "sys_pacct",
              "sys_ptrace",
              "sys_rawio",
              "sys_resource",
              "sys_time",
              "sys_tty_config",
              "syslog",
              "wake_alarm")

218 219 220 221 222 223
VIR_ENUM_IMPL(virDomainLifecycle, VIR_DOMAIN_LIFECYCLE_LAST,
              "destroy",
              "restart",
              "rename-restart",
              "preserve")

224 225 226 227 228 229 230 231
VIR_ENUM_IMPL(virDomainLifecycleCrash, VIR_DOMAIN_LIFECYCLE_CRASH_LAST,
              "destroy",
              "restart",
              "rename-restart",
              "preserve",
              "coredump-destroy",
              "coredump-restart")

232 233 234 235 236 237 238
VIR_ENUM_IMPL(virDomainLockFailure, VIR_DOMAIN_LOCK_FAILURE_LAST,
              "default",
              "poweroff",
              "restart",
              "pause",
              "ignore")

239
VIR_ENUM_IMPL(virDomainDevice, VIR_DOMAIN_DEVICE_LAST,
240
              "none",
241
              "disk",
242
              "lease",
243 244 245 246
              "filesystem",
              "interface",
              "input",
              "sound",
247
              "video",
R
Richard Jones 已提交
248
              "hostdev",
249
              "watchdog",
250
              "controller",
M
Marc-André Lureau 已提交
251
              "graphics",
252
              "hub",
253 254 255
              "redirdev",
              "smartcard",
              "chr",
256
              "memballoon",
L
Li Zhang 已提交
257
              "nvram",
258 259
              "rng",
              "shmem")
260

261 262
VIR_ENUM_IMPL(virDomainDeviceAddress, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST,
              "none",
263
              "pci",
264
              "drive",
E
Eric Blake 已提交
265
              "virtio-serial",
266
              "ccid",
267
              "usb",
268
              "spapr-vio",
269
              "virtio-s390",
270
              "ccw",
H
Hu Tao 已提交
271 272
              "virtio-mmio",
              "isa")
273

274 275 276
VIR_ENUM_IMPL(virDomainDiskDevice, VIR_DOMAIN_DISK_DEVICE_LAST,
              "disk",
              "cdrom",
277 278
              "floppy",
              "lun")
279

J
J.B. Joret 已提交
280 281 282 283 284 285
VIR_ENUM_IMPL(virDomainDiskGeometryTrans, VIR_DOMAIN_DISK_TRANS_LAST,
              "default",
              "none",
              "auto",
              "lba")

286 287 288 289 290
VIR_ENUM_IMPL(virDomainDiskBus, VIR_DOMAIN_DISK_BUS_LAST,
              "ide",
              "fdc",
              "scsi",
              "virtio",
291
              "xen",
292
              "usb",
293
              "uml",
294 295
              "sata",
              "sd")
296

297 298 299 300
VIR_ENUM_IMPL(virDomainDiskCache, VIR_DOMAIN_DISK_CACHE_LAST,
              "default",
              "none",
              "writethrough",
301
              "writeback",
302 303
              "directsync",
              "unsafe")
304

305 306 307
VIR_ENUM_IMPL(virDomainDiskErrorPolicy, VIR_DOMAIN_DISK_ERROR_POLICY_LAST,
              "default",
              "stop",
308
              "report",
309 310
              "ignore",
              "enospace")
311

M
Matthias Dahl 已提交
312 313 314 315
VIR_ENUM_IMPL(virDomainDiskIo, VIR_DOMAIN_DISK_IO_LAST,
              "default",
              "native",
              "threads")
O
Osier Yang 已提交
316

317
VIR_ENUM_IMPL(virDomainDeviceSGIO, VIR_DOMAIN_DEVICE_SGIO_LAST,
O
Osier Yang 已提交
318 319 320 321
              "default",
              "filtered",
              "unfiltered")

322 323 324 325
VIR_ENUM_IMPL(virDomainController, VIR_DOMAIN_CONTROLLER_TYPE_LAST,
              "ide",
              "fdc",
              "scsi",
326
              "sata",
E
Eric Blake 已提交
327
              "virtio-serial",
328
              "ccid",
J
Ján Tomko 已提交
329 330 331 332 333
              "usb",
              "pci")

VIR_ENUM_IMPL(virDomainControllerModelPCI, VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST,
              "pci-root",
L
Laine Stump 已提交
334
              "pcie-root",
335 336
              "pci-bridge",
              "dmi-to-pci-bridge")
337

338
VIR_ENUM_IMPL(virDomainControllerModelSCSI, VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LAST,
339
              "auto",
340 341
              "buslogic",
              "lsilogic",
342
              "lsisas1068",
343
              "vmpvscsi",
344
              "ibmvscsi",
345 346
              "virtio-scsi",
              "lsisas1078");
347

M
Marc-André Lureau 已提交
348 349 350 351 352 353 354 355 356
VIR_ENUM_IMPL(virDomainControllerModelUSB, VIR_DOMAIN_CONTROLLER_MODEL_USB_LAST,
              "piix3-uhci",
              "piix4-uhci",
              "ehci",
              "ich9-ehci1",
              "ich9-uhci1",
              "ich9-uhci2",
              "ich9-uhci3",
              "vt82c686b-uhci",
G
Gerd Hoffmann 已提交
357
              "pci-ohci",
358 359
              "nec-xhci",
              "none")
M
Marc-André Lureau 已提交
360

361 362 363 364
VIR_ENUM_IMPL(virDomainFS, VIR_DOMAIN_FS_TYPE_LAST,
              "mount",
              "block",
              "file",
365
              "template",
366 367
              "ram",
              "bind")
368

369
VIR_ENUM_IMPL(virDomainFSDriver, VIR_DOMAIN_FS_DRIVER_TYPE_LAST,
370 371
              "default",
              "path",
372
              "handle",
373 374
              "loop",
              "nbd")
375

376 377 378 379 380
VIR_ENUM_IMPL(virDomainFSAccessMode, VIR_DOMAIN_FS_ACCESSMODE_LAST,
              "passthrough",
              "mapped",
              "squash")

381 382 383
VIR_ENUM_IMPL(virDomainFSWrpolicy, VIR_DOMAIN_FS_WRPOLICY_LAST,
              "default",
              "immediate")
384

385 386 387
VIR_ENUM_IMPL(virDomainNet, VIR_DOMAIN_NET_TYPE_LAST,
              "user",
              "ethernet",
M
Michele Paolino 已提交
388
              "vhostuser",
389 390 391 392
              "server",
              "client",
              "mcast",
              "network",
D
Daniel Veillard 已提交
393
              "bridge",
394
              "internal",
395 396
              "direct",
              "hostdev")
397

398 399 400 401 402
VIR_ENUM_IMPL(virDomainNetBackend, VIR_DOMAIN_NET_BACKEND_TYPE_LAST,
              "default",
              "qemu",
              "vhost")

403 404 405 406 407
VIR_ENUM_IMPL(virDomainNetVirtioTxMode, VIR_DOMAIN_NET_VIRTIO_TX_MODE_LAST,
              "default",
              "iothread",
              "timer")

408 409 410 411 412
VIR_ENUM_IMPL(virDomainNetInterfaceLinkState, VIR_DOMAIN_NET_INTERFACE_LINK_STATE_LAST,
              "default",
              "up",
              "down")

G
Guannan Ren 已提交
413 414 415 416 417
VIR_ENUM_IMPL(virDomainChrSerialTarget,
              VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_LAST,
              "isa-serial",
              "usb-serial")

418 419
VIR_ENUM_IMPL(virDomainChrChannelTarget,
              VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_LAST,
420
              "none",
421 422 423
              "guestfwd",
              "virtio")

424 425
VIR_ENUM_IMPL(virDomainChrConsoleTarget,
              VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_LAST,
426
              "none",
427 428
              "serial",
              "xen",
C
Cole Robinson 已提交
429
              "uml",
430 431
              "virtio",
              "lxc",
432 433 434
              "openvz",
              "sclp",
              "sclplm")
435

436
VIR_ENUM_IMPL(virDomainChrDevice, VIR_DOMAIN_CHR_DEVICE_TYPE_LAST,
437 438
              "parallel",
              "serial",
439
              "console",
440
              "channel")
441

442 443 444 445 446 447 448 449 450 451
VIR_ENUM_IMPL(virDomainChr, VIR_DOMAIN_CHR_TYPE_LAST,
              "null",
              "vc",
              "pty",
              "dev",
              "file",
              "pipe",
              "stdio",
              "udp",
              "tcp",
452
              "unix",
453
              "spicevmc",
454 455
              "spiceport",
              "nmdm")
456

457 458 459 460 461 462
VIR_ENUM_IMPL(virDomainChrTcpProtocol, VIR_DOMAIN_CHR_TCP_PROTOCOL_LAST,
              "raw",
              "telnet",
              "telnets",
              "tls")

E
Eric Blake 已提交
463 464
VIR_ENUM_IMPL(virDomainChrSpicevmc, VIR_DOMAIN_CHR_SPICEVMC_LAST,
              "vdagent",
465 466
              "smartcard",
              "usbredir")
E
Eric Blake 已提交
467

E
Eric Blake 已提交
468 469 470 471 472
VIR_ENUM_IMPL(virDomainSmartcard, VIR_DOMAIN_SMARTCARD_TYPE_LAST,
              "host",
              "host-certificates",
              "passthrough")

473 474 475 476
VIR_ENUM_IMPL(virDomainSoundCodec, VIR_DOMAIN_SOUND_CODEC_TYPE_LAST,
              "duplex",
              "micro")

477 478 479
VIR_ENUM_IMPL(virDomainSoundModel, VIR_DOMAIN_SOUND_MODEL_LAST,
              "sb16",
              "es1370",
480
              "pcspk",
481
              "ac97",
482
              "ich6",
483 484
              "ich9",
              "usb")
485

486 487
VIR_ENUM_IMPL(virDomainMemballoonModel, VIR_DOMAIN_MEMBALLOON_MODEL_LAST,
              "virtio",
488
              "xen",
489 490
              "none")

491 492 493 494 495 496
VIR_ENUM_IMPL(virDomainSmbiosMode, VIR_DOMAIN_SMBIOS_LAST,
              "none",
              "emulate",
              "host",
              "sysinfo")

R
Richard Jones 已提交
497 498 499 500 501 502 503 504 505
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 已提交
506
              "dump",
R
Richard Jones 已提交
507 508
              "none")

509 510 511 512 513
VIR_ENUM_IMPL(virDomainVideo, VIR_DOMAIN_VIDEO_TYPE_LAST,
              "vga",
              "cirrus",
              "vmvga",
              "xen",
514 515
              "vbox",
              "qxl")
516

517 518
VIR_ENUM_IMPL(virDomainInput, VIR_DOMAIN_INPUT_TYPE_LAST,
              "mouse",
L
Li Zhang 已提交
519 520
              "tablet",
              "keyboard")
521 522 523 524 525 526 527 528

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

VIR_ENUM_IMPL(virDomainGraphics, VIR_DOMAIN_GRAPHICS_TYPE_LAST,
              "sdl",
529 530
              "vnc",
              "rdp",
531 532
              "desktop",
              "spice")
533

534 535 536 537 538
VIR_ENUM_IMPL(virDomainGraphicsListen, VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_LAST,
              "none",
              "address",
              "network")

539 540 541 542 543 544 545
VIR_ENUM_IMPL(virDomainGraphicsAuthConnected,
              VIR_DOMAIN_GRAPHICS_AUTH_CONNECTED_LAST,
              "default",
              "fail",
              "disconnect",
              "keep")

546 547 548 549 550 551 552
VIR_ENUM_IMPL(virDomainGraphicsVNCSharePolicy,
              VIR_DOMAIN_GRAPHICS_VNC_SHARE_LAST,
              "default",
              "allow-exclusive",
              "force-shared",
              "ignore")

553 554 555 556 557 558 559
VIR_ENUM_IMPL(virDomainGraphicsSpiceChannelName,
              VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_LAST,
              "main",
              "display",
              "inputs",
              "cursor",
              "playback",
E
Eric Blake 已提交
560
              "record",
561 562
              "smartcard",
              "usbredir");
563 564 565 566 567 568 569

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

570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593
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");

P
Peng Zhou 已提交
594 595 596 597 598 599
VIR_ENUM_IMPL(virDomainGraphicsSpiceMouseMode,
              VIR_DOMAIN_GRAPHICS_SPICE_MOUSE_MODE_LAST,
              "default",
              "server",
              "client");

600 601 602 603 604 605 606
VIR_ENUM_IMPL(virDomainGraphicsSpiceStreamingMode,
              VIR_DOMAIN_GRAPHICS_SPICE_STREAMING_MODE_LAST,
              "default",
              "filter",
              "all",
              "off");

607 608 609 610 611 612
VIR_ENUM_IMPL(virDomainHostdevMode, VIR_DOMAIN_HOSTDEV_MODE_LAST,
              "subsystem",
              "capabilities")

VIR_ENUM_IMPL(virDomainHostdevSubsys, VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST,
              "usb",
H
Han Cheng 已提交
613 614
              "pci",
              "scsi")
615

616
VIR_ENUM_IMPL(virDomainHostdevSubsysPCIBackend,
617 618 619
              VIR_DOMAIN_HOSTDEV_PCI_BACKEND_TYPE_LAST,
              "default",
              "kvm",
620 621
              "vfio",
              "xen")
622

J
John Ferlan 已提交
623 624 625 626 627
VIR_ENUM_IMPL(virDomainHostdevSubsysSCSIProtocol,
              VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_LAST,
              "adapter",
              "iscsi")

628 629
VIR_ENUM_IMPL(virDomainHostdevCaps, VIR_DOMAIN_HOSTDEV_CAPS_TYPE_LAST,
              "storage",
630 631
              "misc",
              "net")
632

633 634 635 636 637 638 639
VIR_ENUM_IMPL(virDomainHub, VIR_DOMAIN_HUB_TYPE_LAST,
              "usb")

VIR_ENUM_IMPL(virDomainRedirdevBus, VIR_DOMAIN_REDIRDEV_BUS_LAST,
              "usb")

VIR_ENUM_IMPL(virDomainState, VIR_DOMAIN_LAST,
640 641 642 643 644 645
              "nostate",
              "running",
              "blocked",
              "paused",
              "shutdown",
              "shutoff",
O
Osier Yang 已提交
646 647
              "crashed",
              "pmsuspended")
648

J
Jiri Denemark 已提交
649 650 651 652 653 654 655 656 657 658 659
VIR_ENUM_IMPL(virDomainNostateReason, VIR_DOMAIN_NOSTATE_LAST,
              "unknown")

VIR_ENUM_IMPL(virDomainRunningReason, VIR_DOMAIN_RUNNING_LAST,
              "unknown",
              "booted",
              "migrated",
              "restored",
              "from snapshot",
              "unpaused",
              "migration canceled",
660
              "save canceled",
661 662
              "wakeup",
              "crashed")
J
Jiri Denemark 已提交
663 664 665 666 667 668 669 670 671 672 673 674

VIR_ENUM_IMPL(virDomainBlockedReason, VIR_DOMAIN_BLOCKED_LAST,
              "unknown")

VIR_ENUM_IMPL(virDomainPausedReason, VIR_DOMAIN_PAUSED_LAST,
              "unknown",
              "user",
              "migration",
              "save",
              "dump",
              "ioerror",
              "watchdog",
675
              "from snapshot",
676
              "shutdown",
677 678
              "snapshot",
              "panicked")
J
Jiri Denemark 已提交
679 680 681

VIR_ENUM_IMPL(virDomainShutdownReason, VIR_DOMAIN_SHUTDOWN_LAST,
              "unknown",
682
              "user")
J
Jiri Denemark 已提交
683 684 685 686 687 688 689 690 691 692 693 694

VIR_ENUM_IMPL(virDomainShutoffReason, VIR_DOMAIN_SHUTOFF_LAST,
              "unknown",
              "shutdown",
              "destroyed",
              "crashed",
              "migrated",
              "saved",
              "failed",
              "from snapshot")

VIR_ENUM_IMPL(virDomainCrashedReason, VIR_DOMAIN_CRASHED_LAST,
695 696
              "unknown",
              "panicked")
J
Jiri Denemark 已提交
697

698 699 700
VIR_ENUM_IMPL(virDomainPMSuspendedReason, VIR_DOMAIN_PMSUSPENDED_LAST,
              "unknown")

701
VIR_ENUM_IMPL(virDomainSeclabel, VIR_DOMAIN_SECLABEL_LAST,
702 703
              "default",
              "none",
704 705 706
              "dynamic",
              "static")

707 708
VIR_ENUM_IMPL(virDomainClockOffset, VIR_DOMAIN_CLOCK_OFFSET_LAST,
              "utc",
709
              "localtime",
710 711
              "variable",
              "timezone");
712

713 714 715 716
VIR_ENUM_IMPL(virDomainClockBasis, VIR_DOMAIN_CLOCK_BASIS_LAST,
              "utc",
              "localtime");

717 718 719 720 721
VIR_ENUM_IMPL(virDomainTimerName, VIR_DOMAIN_TIMER_NAME_LAST,
              "platform",
              "pit",
              "rtc",
              "hpet",
P
Paolo Bonzini 已提交
722
              "tsc",
723 724
              "kvmclock",
              "hypervclock");
725

726 727 728 729
VIR_ENUM_IMPL(virDomainTimerTrack, VIR_DOMAIN_TIMER_TRACK_LAST,
              "boot",
              "guest",
              "wall");
730 731 732 733 734 735 736 737 738 739 740

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",
741 742
              "paravirt",
              "smpsafe");
743

744 745 746 747 748 749
VIR_ENUM_IMPL(virDomainStartupPolicy, VIR_DOMAIN_STARTUP_POLICY_LAST,
              "default",
              "mandatory",
              "requisite",
              "optional");

O
Osier Yang 已提交
750 751 752 753
VIR_ENUM_IMPL(virDomainCpuPlacementMode, VIR_DOMAIN_CPU_PLACEMENT_MODE_LAST,
              "static",
              "auto");

754 755 756 757
VIR_ENUM_IMPL(virDomainDiskTray, VIR_DOMAIN_DISK_TRAY_LAST,
              "closed",
              "open");

758 759 760 761 762 763 764 765 766
VIR_ENUM_IMPL(virDomainRNGModel,
              VIR_DOMAIN_RNG_MODEL_LAST,
              "virtio");

VIR_ENUM_IMPL(virDomainRNGBackend,
              VIR_DOMAIN_RNG_BACKEND_LAST,
              "random",
              "egd");

767 768 769 770 771 772
VIR_ENUM_IMPL(virDomainTPMModel, VIR_DOMAIN_TPM_MODEL_LAST,
              "tpm-tis")

VIR_ENUM_IMPL(virDomainTPMBackend, VIR_DOMAIN_TPM_TYPE_LAST,
              "passthrough")

O
Osier Yang 已提交
773 774
VIR_ENUM_IMPL(virDomainDiskDiscard, VIR_DOMAIN_DISK_DISCARD_LAST,
              "default",
O
Osier Yang 已提交
775 776
              "unmap",
              "ignore")
777

778 779 780 781 782 783
VIR_ENUM_IMPL(virDomainDiskMirrorState, VIR_DOMAIN_DISK_MIRROR_STATE_LAST,
              "none",
              "yes",
              "abort",
              "pivot")

784 785 786 787 788
VIR_ENUM_IMPL(virDomainLoader,
              VIR_DOMAIN_LOADER_TYPE_LAST,
              "rom",
              "pflash")

E
Eric Blake 已提交
789 790 791 792 793 794
/* Internal mapping: subset of block job types that can be present in
 * <mirror> XML (remaining types are not two-phase). */
VIR_ENUM_DECL(virDomainBlockJob)
VIR_ENUM_IMPL(virDomainBlockJob, VIR_DOMAIN_BLOCK_JOB_TYPE_LAST,
              "", "", "copy", "", "active-commit")

795 796 797
#define VIR_DOMAIN_XML_WRITE_FLAGS  VIR_DOMAIN_XML_SECURE
#define VIR_DOMAIN_XML_READ_FLAGS   VIR_DOMAIN_XML_INACTIVE

798
static virClassPtr virDomainObjClass;
799
static virClassPtr virDomainObjListClass;
800
static virClassPtr virDomainXMLOptionClass;
801
static void virDomainObjDispose(void *obj);
802
static void virDomainObjListDispose(void *obj);
803
static void virDomainXMLOptionClassDispose(void *obj);
804 805 806

static int virDomainObjOnceInit(void)
{
807
    if (!(virDomainObjClass = virClassNew(virClassForObjectLockable(),
808
                                          "virDomainObj",
809 810 811 812
                                          sizeof(virDomainObj),
                                          virDomainObjDispose)))
        return -1;

813 814 815 816 817 818
    if (!(virDomainObjListClass = virClassNew(virClassForObjectLockable(),
                                              "virDomainObjList",
                                              sizeof(virDomainObjList),
                                              virDomainObjListDispose)))
        return -1;

819 820 821
    if (!(virDomainXMLOptionClass = virClassNew(virClassForObject(),
                                                "virDomainXMLOption",
                                                sizeof(virDomainXMLOption),
822
                                                virDomainXMLOptionClassDispose)))
823 824
        return -1;

825 826 827 828 829
    return 0;
}

VIR_ONCE_GLOBAL_INIT(virDomainObj)

830

831 832 833 834 835 836 837 838 839 840
static void
virDomainXMLOptionClassDispose(void *obj)
{
    virDomainXMLOptionPtr xmlopt = obj;

    if (xmlopt->config.privFree)
        (xmlopt->config.privFree)(xmlopt->config.priv);
}


841
/**
842
 * virDomainXMLOptionNew:
843 844 845
 *
 * Allocate a new domain XML configuration
 */
846
virDomainXMLOptionPtr
847 848
virDomainXMLOptionNew(virDomainDefParserConfigPtr config,
                      virDomainXMLPrivateDataCallbacksPtr priv,
849
                      virDomainXMLNamespacePtr xmlns)
850
{
851
    virDomainXMLOptionPtr xmlopt;
852 853 854 855

    if (virDomainObjInitialize() < 0)
        return NULL;

856
    if (!(xmlopt = virObjectNew(virDomainXMLOptionClass)))
857 858 859
        return NULL;

    if (priv)
860
        xmlopt->privateData = *priv;
861

862 863 864
    if (config)
        xmlopt->config = *config;

865
    if (xmlns)
866
        xmlopt->ns = *xmlns;
867

868 869 870 871 872 873 874 875 876 877 878 879
    /* Technically this forbids to use one of Xerox's MAC address prefixes in
     * our hypervisor drivers. This shouldn't ever be a problem.
     *
     * Use the KVM prefix as default as it's in the privately administered
     * range */
    if (xmlopt->config.macPrefix[0] == 0 &&
        xmlopt->config.macPrefix[1] == 0 &&
        xmlopt->config.macPrefix[2] == 0) {
        xmlopt->config.macPrefix[0] = 0x52;
        xmlopt->config.macPrefix[1] = 0x54;
    }

880
    return xmlopt;
881 882 883
}

/**
884
 * virDomainXMLOptionGetNamespace:
885
 *
886
 * @xmlopt: XML parser configuration object
887 888
 *
 * Returns a pointer to the stored namespace structure.
889
 * The lifetime of the pointer is equal to @xmlopt;
890 891
 */
virDomainXMLNamespacePtr
892
virDomainXMLOptionGetNamespace(virDomainXMLOptionPtr xmlopt)
893
{
894
    return &xmlopt->ns;
895 896 897
}


898
void
899
virBlkioDeviceArrayClear(virBlkioDevicePtr devices,
900
                         int ndevices)
901
{
902
    size_t i;
903 904

    for (i = 0; i < ndevices; i++)
905
        VIR_FREE(devices[i].path);
906 907 908
}

/**
909
 * virDomainBlkioDeviceParseXML
910 911 912 913 914 915
 *
 * this function parses a XML node:
 *
 *   <device>
 *     <path>/fully/qualified/device/path</path>
 *     <weight>weight</weight>
916 917 918 919
 *     <read_bytes_sec>bps</read_bytes_sec>
 *     <write_bytes_sec>bps</write_bytes_sec>
 *     <read_iops_sec>iops</read_iops_sec>
 *     <write_iops_sec>iops</write_iops_sec>
920 921
 *   </device>
 *
922
 * and fills a virBlkioDevicePtr struct.
923 924
 */
static int
925
virDomainBlkioDeviceParseXML(xmlNodePtr root,
926
                             virBlkioDevicePtr dev)
927
{
928
    char *c = NULL;
929 930 931 932 933
    xmlNodePtr node;

    node = root->children;
    while (node) {
        if (node->type == XML_ELEMENT_NODE) {
934 935
            if (xmlStrEqual(node->name, BAD_CAST "path") && !dev->path) {
                dev->path = (char *)xmlNodeGetContent(node);
936 937
            } else if (xmlStrEqual(node->name, BAD_CAST "weight")) {
                c = (char *)xmlNodeGetContent(node);
938
                if (virStrToLong_ui(c, NULL, 10, &dev->weight) < 0) {
939 940 941
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("could not parse weight %s"),
                                   c);
942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978
                        goto error;
                }
                VIR_FREE(c);
            } else if (xmlStrEqual(node->name, BAD_CAST "read_bytes_sec")) {
                c = (char *)xmlNodeGetContent(node);
                if (virStrToLong_ull(c, NULL, 10, &dev->rbps) < 0) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("could not parse read bytes sec %s"),
                                   c);
                    goto error;
                }
                VIR_FREE(c);
            } else if (xmlStrEqual(node->name, BAD_CAST "write_bytes_sec")) {
                c = (char *)xmlNodeGetContent(node);
                if (virStrToLong_ull(c, NULL, 10, &dev->wbps) < 0) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("could not parse write bytes sec %s"),
                                   c);
                    goto error;
                }
                VIR_FREE(c);
            } else if (xmlStrEqual(node->name, BAD_CAST "read_iops_sec")) {
                c = (char *)xmlNodeGetContent(node);
                if (virStrToLong_ui(c, NULL, 10, &dev->riops) < 0) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("could not parse read iops sec %s"),
                                   c);
                    goto error;
                }
                VIR_FREE(c);
            } else if (xmlStrEqual(node->name, BAD_CAST "write_iops_sec")) {
                c = (char *)xmlNodeGetContent(node);
                if (virStrToLong_ui(c, NULL, 10, &dev->wiops) < 0) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("could not parse write iops sec %s"),
                                   c);
                    goto error;
979 980 981 982 983 984
                }
                VIR_FREE(c);
            }
        }
        node = node->next;
    }
985
    if (!dev->path) {
986 987
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("missing per-device path"));
988 989 990 991
        return -1;
    }

    return 0;
992

993
 error:
994 995 996
    VIR_FREE(c);
    VIR_FREE(dev->path);
    return -1;
997 998 999 1000
}



1001
static void
1002
virDomainObjListDataFree(void *payload, const void *name ATTRIBUTE_UNUSED)
1003 1004
{
    virDomainObjPtr obj = payload;
1005
    virObjectUnref(obj);
1006 1007
}

1008
virDomainObjListPtr virDomainObjListNew(void)
1009
{
1010 1011
    virDomainObjListPtr doms;

1012 1013 1014 1015
    if (virDomainObjInitialize() < 0)
        return NULL;

    if (!(doms = virObjectLockableNew(virDomainObjListClass)))
1016 1017
        return NULL;

1018 1019
    if (!(doms->objs = virHashCreate(50, virDomainObjListDataFree))) {
        virObjectUnref(doms);
1020 1021
        return NULL;
    }
1022

1023
    return doms;
1024
}
1025

1026

1027
static void virDomainObjListDispose(void *obj)
1028
{
1029 1030
    virDomainObjListPtr doms = obj;

1031
    virHashFree(doms->objs);
1032 1033 1034 1035
}


static int virDomainObjListSearchID(const void *payload,
1036
                                    const void *name ATTRIBUTE_UNUSED,
1037 1038 1039 1040 1041 1042
                                    const void *data)
{
    virDomainObjPtr obj = (virDomainObjPtr)payload;
    const int *id = data;
    int want = 0;

1043
    virObjectLock(obj);
D
Daniel P. Berrange 已提交
1044
    if (virDomainObjIsActive(obj) &&
1045 1046
        obj->def->id == *id)
        want = 1;
1047
    virObjectUnlock(obj);
1048 1049 1050
    return want;
}

1051
virDomainObjPtr virDomainObjListFindByID(virDomainObjListPtr doms,
1052
                                         int id)
1053 1054
{
    virDomainObjPtr obj;
1055
    virObjectLock(doms);
1056 1057
    obj = virHashSearch(doms->objs, virDomainObjListSearchID, &id);
    if (obj)
1058
        virObjectLock(obj);
1059
    virObjectUnlock(doms);
1060
    return obj;
1061 1062 1063
}


1064
virDomainObjPtr virDomainObjListFindByUUID(virDomainObjListPtr doms,
1065
                                           const unsigned char *uuid)
1066
{
1067 1068
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    virDomainObjPtr obj;
1069

1070
    virObjectLock(doms);
1071
    virUUIDFormat(uuid, uuidstr);
1072

1073 1074
    obj = virHashLookup(doms->objs, uuidstr);
    if (obj)
1075
        virObjectLock(obj);
1076
    virObjectUnlock(doms);
1077 1078 1079 1080
    return obj;
}

static int virDomainObjListSearchName(const void *payload,
1081
                                      const void *name ATTRIBUTE_UNUSED,
1082 1083 1084 1085 1086
                                      const void *data)
{
    virDomainObjPtr obj = (virDomainObjPtr)payload;
    int want = 0;

1087
    virObjectLock(obj);
1088 1089
    if (STREQ(obj->def->name, (const char *)data))
        want = 1;
1090
    virObjectUnlock(obj);
1091
    return want;
1092 1093
}

1094
virDomainObjPtr virDomainObjListFindByName(virDomainObjListPtr doms,
1095
                                           const char *name)
1096
{
1097
    virDomainObjPtr obj;
1098
    virObjectLock(doms);
1099 1100
    obj = virHashSearch(doms->objs, virDomainObjListSearchName, name);
    if (obj)
1101
        virObjectLock(obj);
1102
    virObjectUnlock(doms);
1103
    return obj;
1104 1105
}

1106 1107

bool virDomainObjTaint(virDomainObjPtr obj,
1108
                       virDomainTaintFlags taint)
1109
{
E
Eric Blake 已提交
1110
    unsigned int flag = (1 << taint);
1111 1112 1113 1114 1115 1116 1117 1118

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

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

1119 1120 1121 1122 1123 1124 1125 1126 1127
static void
virDomainDeviceInfoFree(virDomainDeviceInfoPtr info)
{
    if (info) {
        virDomainDeviceInfoClear(info);
        VIR_FREE(info);
    }
}

1128

1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139
static void
virDomainGraphicsAuthDefClear(virDomainGraphicsAuthDefPtr def)
{
    if (!def)
        return;

    VIR_FREE(def->passwd);

    /* Don't free def */
}

1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150
static void
virDomainGraphicsListenDefClear(virDomainGraphicsListenDefPtr def)
{
    if (!def)
        return;

    VIR_FREE(def->address);
    VIR_FREE(def->network);
    return;
}

1151

1152 1153
void virDomainGraphicsDefFree(virDomainGraphicsDefPtr def)
{
1154
    size_t i;
1155

1156 1157 1158
    if (!def)
        return;

1159
    switch ((virDomainGraphicsType)def->type) {
1160
    case VIR_DOMAIN_GRAPHICS_TYPE_VNC:
1161
        VIR_FREE(def->data.vnc.socket);
1162
        VIR_FREE(def->data.vnc.keymap);
1163
        virDomainGraphicsAuthDefClear(&def->data.vnc.auth);
1164 1165 1166 1167 1168 1169
        break;

    case VIR_DOMAIN_GRAPHICS_TYPE_SDL:
        VIR_FREE(def->data.sdl.display);
        VIR_FREE(def->data.sdl.xauth);
        break;
1170 1171 1172 1173 1174 1175 1176

    case VIR_DOMAIN_GRAPHICS_TYPE_RDP:
        break;

    case VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP:
        VIR_FREE(def->data.desktop.display);
        break;
1177 1178 1179

    case VIR_DOMAIN_GRAPHICS_TYPE_SPICE:
        VIR_FREE(def->data.spice.keymap);
1180
        virDomainGraphicsAuthDefClear(&def->data.spice.auth);
1181
        break;
1182 1183 1184

    case VIR_DOMAIN_GRAPHICS_TYPE_LAST:
        break;
1185 1186
    }

1187 1188
    for (i = 0; i < def->nListens; i++)
        virDomainGraphicsListenDefClear(&def->listens[i]);
1189 1190
    VIR_FREE(def->listens);

1191 1192 1193 1194 1195 1196 1197 1198
    VIR_FREE(def);
}

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

1199
    virDomainDeviceInfoClear(&def->info);
1200 1201 1202
    VIR_FREE(def);
}

1203
void virDomainLeaseDefFree(virDomainLeaseDefPtr def)
1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214
{
    if (!def)
        return;

    VIR_FREE(def->lockspace);
    VIR_FREE(def->key);
    VIR_FREE(def->path);

    VIR_FREE(def);
}

1215

1216 1217 1218 1219 1220
virDomainDiskDefPtr
virDomainDiskDefNew(void)
{
    virDomainDiskDefPtr ret;

1221 1222 1223 1224
    if (VIR_ALLOC(ret) < 0)
        return NULL;
    if (VIR_ALLOC(ret->src) < 0)
        VIR_FREE(ret);
1225 1226 1227 1228
    return ret;
}


1229 1230 1231 1232 1233 1234
void
virDomainDiskDefFree(virDomainDiskDefPtr def)
{
    if (!def)
        return;

1235
    virStorageSourceFree(def->src);
1236 1237
    VIR_FREE(def->serial);
    VIR_FREE(def->dst);
1238
    virStorageSourceFree(def->mirror);
1239 1240 1241 1242
    VIR_FREE(def->wwn);
    VIR_FREE(def->vendor);
    VIR_FREE(def->product);
    virDomainDeviceInfoClear(&def->info);
1243

1244 1245 1246
    VIR_FREE(def);
}

1247

1248 1249 1250
int
virDomainDiskGetType(virDomainDiskDefPtr def)
{
1251
    return def->src->type;
1252 1253 1254 1255 1256 1257
}


void
virDomainDiskSetType(virDomainDiskDefPtr def, int type)
{
1258
    def->src->type = type;
1259 1260 1261 1262 1263 1264
}


const char *
virDomainDiskGetSource(virDomainDiskDefPtr def)
{
1265
    return def->src->path;
1266 1267 1268 1269 1270 1271 1272
}


int
virDomainDiskSetSource(virDomainDiskDefPtr def, const char *src)
{
    int ret;
1273
    char *tmp = def->src->path;
1274

1275
    ret = VIR_STRDUP(def->src->path, src);
1276
    if (ret < 0)
1277
        def->src->path = tmp;
1278 1279 1280 1281 1282 1283 1284 1285 1286
    else
        VIR_FREE(tmp);
    return ret;
}


const char *
virDomainDiskGetDriver(virDomainDiskDefPtr def)
{
1287
    return def->src->driverName;
1288 1289 1290 1291 1292 1293 1294
}


int
virDomainDiskSetDriver(virDomainDiskDefPtr def, const char *name)
{
    int ret;
1295
    char *tmp = def->src->driverName;
1296

1297
    ret = VIR_STRDUP(def->src->driverName, name);
1298
    if (ret < 0)
1299
        def->src->driverName = tmp;
1300 1301 1302 1303 1304 1305 1306 1307 1308
    else
        VIR_FREE(tmp);
    return ret;
}


int
virDomainDiskGetFormat(virDomainDiskDefPtr def)
{
1309
    return def->src->format;
1310 1311 1312 1313 1314 1315
}


void
virDomainDiskSetFormat(virDomainDiskDefPtr def, int format)
{
1316
    def->src->format = format;
1317 1318 1319
}


1320 1321 1322 1323 1324 1325 1326 1327 1328 1329
void virDomainControllerDefFree(virDomainControllerDefPtr def)
{
    if (!def)
        return;

    virDomainDeviceInfoClear(&def->info);

    VIR_FREE(def);
}

1330 1331 1332 1333 1334 1335 1336
void virDomainFSDefFree(virDomainFSDefPtr def)
{
    if (!def)
        return;

    VIR_FREE(def->src);
    VIR_FREE(def->dst);
1337
    virDomainDeviceInfoClear(&def->info);
1338 1339 1340 1341

    VIR_FREE(def);
}

1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354
void
virDomainActualNetDefFree(virDomainActualNetDefPtr def)
{
    if (!def)
        return;

    switch (def->type) {
    case VIR_DOMAIN_NET_TYPE_BRIDGE:
        VIR_FREE(def->data.bridge.brname);
        break;
    case VIR_DOMAIN_NET_TYPE_DIRECT:
        VIR_FREE(def->data.direct.linkdev);
        break;
1355 1356 1357
    case VIR_DOMAIN_NET_TYPE_HOSTDEV:
        virDomainHostdevDefClear(&def->data.hostdev.def);
        break;
1358 1359 1360 1361
    default:
        break;
    }

1362
    VIR_FREE(def->virtPortProfile);
1363
    virNetDevBandwidthFree(def->bandwidth);
1364
    virNetDevVlanClear(&def->vlan);
1365 1366 1367
    VIR_FREE(def);
}

1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380
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.ipaddr);
        break;

M
Michele Paolino 已提交
1381 1382 1383 1384
    case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
        virDomainChrSourceDefFree(def->data.vhostuser);
        break;

1385 1386 1387 1388 1389 1390 1391 1392
    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);
1393 1394
        VIR_FREE(def->data.network.portgroup);
        virDomainActualNetDefFree(def->data.network.actual);
1395 1396 1397 1398
        break;

    case VIR_DOMAIN_NET_TYPE_BRIDGE:
        VIR_FREE(def->data.bridge.brname);
1399
        VIR_FREE(def->data.bridge.ipaddr);
1400
        break;
D
Daniel Veillard 已提交
1401 1402 1403 1404

    case VIR_DOMAIN_NET_TYPE_INTERNAL:
        VIR_FREE(def->data.internal.name);
        break;
1405 1406 1407 1408

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

1410 1411 1412 1413
    case VIR_DOMAIN_NET_TYPE_HOSTDEV:
        virDomainHostdevDefClear(&def->data.hostdev.def);
        break;

S
Stefan Berger 已提交
1414 1415 1416
    case VIR_DOMAIN_NET_TYPE_USER:
    case VIR_DOMAIN_NET_TYPE_LAST:
        break;
1417 1418
    }

1419 1420
    VIR_FREE(def->backend.tap);
    VIR_FREE(def->backend.vhost);
1421
    VIR_FREE(def->virtPortProfile);
1422
    VIR_FREE(def->script);
1423
    VIR_FREE(def->ifname);
1424 1425
    VIR_FREE(def->ifname_guest);
    VIR_FREE(def->ifname_guest_actual);
1426 1427 1428

    virDomainDeviceInfoClear(&def->info);

1429 1430 1431
    VIR_FREE(def->filter);
    virNWFilterHashTableFree(def->filterparams);

1432
    virNetDevBandwidthFree(def->bandwidth);
1433
    virNetDevVlanClear(&def->vlan);
1434

1435 1436 1437
    VIR_FREE(def);
}

1438
void ATTRIBUTE_NONNULL(1)
1439
virDomainChrSourceDefClear(virDomainChrSourceDefPtr def)
1440 1441 1442 1443 1444 1445 1446 1447 1448
{
    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;

1449 1450 1451 1452 1453
    case VIR_DOMAIN_CHR_TYPE_NMDM:
        VIR_FREE(def->data.nmdm.master);
        VIR_FREE(def->data.nmdm.slave);
        break;

1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468
    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;
1469 1470 1471 1472

    case VIR_DOMAIN_CHR_TYPE_SPICEPORT:
        VIR_FREE(def->data.spiceport.channel);
        break;
1473
    }
1474 1475
}

1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491
/* Deep copies the contents of src into dest.  Return -1 and report
 * error on failure.  */
int
virDomainChrSourceDefCopy(virDomainChrSourceDefPtr dest,
                          virDomainChrSourceDefPtr src)
{
    if (!dest || !src)
        return -1;

    virDomainChrSourceDefClear(dest);

    switch (src->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:
1492
        if (VIR_STRDUP(dest->data.file.path, src->data.file.path) < 0)
1493 1494 1495 1496
            return -1;
        break;

    case VIR_DOMAIN_CHR_TYPE_UDP:
1497
        if (VIR_STRDUP(dest->data.udp.bindHost, src->data.udp.bindHost) < 0)
1498 1499
            return -1;

1500
        if (VIR_STRDUP(dest->data.udp.bindService, src->data.udp.bindService) < 0)
1501 1502
            return -1;

1503
        if (VIR_STRDUP(dest->data.udp.connectHost, src->data.udp.connectHost) < 0)
1504 1505
            return -1;

1506
        if (VIR_STRDUP(dest->data.udp.connectService, src->data.udp.connectService) < 0)
1507 1508 1509 1510
            return -1;
        break;

    case VIR_DOMAIN_CHR_TYPE_TCP:
1511
        if (VIR_STRDUP(dest->data.tcp.host, src->data.tcp.host) < 0)
1512 1513
            return -1;

1514
        if (VIR_STRDUP(dest->data.tcp.service, src->data.tcp.service) < 0)
1515 1516 1517 1518
            return -1;
        break;

    case VIR_DOMAIN_CHR_TYPE_UNIX:
1519
        if (VIR_STRDUP(dest->data.nix.path, src->data.nix.path) < 0)
1520 1521
            return -1;
        break;
1522 1523 1524 1525 1526 1527 1528 1529

    case VIR_DOMAIN_CHR_TYPE_NMDM:
        if (VIR_STRDUP(dest->data.nmdm.master, src->data.nmdm.master) < 0)
            return -1;
        if (VIR_STRDUP(dest->data.nmdm.slave, src->data.nmdm.slave) < 0)
            return -1;

        break;
1530 1531
    }

S
Stefan Berger 已提交
1532 1533
    dest->type = src->type;

1534 1535 1536
    return 0;
}

1537 1538 1539 1540 1541 1542 1543 1544 1545
void virDomainChrSourceDefFree(virDomainChrSourceDefPtr def)
{
    if (!def)
        return;

    virDomainChrSourceDefClear(def);

    VIR_FREE(def);
}
1546

1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560
/* virDomainChrSourceDefIsEqual:
 * @src: Source
 * @tgt: Target
 *
 * Compares source and target if they contain
 * the same information.
 */
static bool
virDomainChrSourceDefIsEqual(const virDomainChrSourceDef *src,
                             const virDomainChrSourceDef *tgt)
{
    if (tgt->type != src->type)
        return false;

1561
    switch ((virDomainChrType)src->type) {
1562 1563 1564 1565 1566 1567
    case VIR_DOMAIN_CHR_TYPE_PTY:
    case VIR_DOMAIN_CHR_TYPE_DEV:
    case VIR_DOMAIN_CHR_TYPE_FILE:
    case VIR_DOMAIN_CHR_TYPE_PIPE:
        return STREQ_NULLABLE(src->data.file.path, tgt->data.file.path);
        break;
1568 1569 1570 1571
    case VIR_DOMAIN_CHR_TYPE_NMDM:
        return STREQ_NULLABLE(src->data.nmdm.master, tgt->data.nmdm.master) &&
            STREQ_NULLABLE(src->data.nmdm.slave, tgt->data.nmdm.slave);
        break;
1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588
    case VIR_DOMAIN_CHR_TYPE_UDP:
        return STREQ_NULLABLE(src->data.udp.bindHost, tgt->data.udp.bindHost) &&
            STREQ_NULLABLE(src->data.udp.bindService, tgt->data.udp.bindService) &&
            STREQ_NULLABLE(src->data.udp.connectHost, tgt->data.udp.connectHost) &&
            STREQ_NULLABLE(src->data.udp.connectService, tgt->data.udp.connectService);
        break;
    case VIR_DOMAIN_CHR_TYPE_TCP:
        return src->data.tcp.listen == tgt->data.tcp.listen &&
            src->data.tcp.protocol == tgt->data.tcp.protocol &&
            STREQ_NULLABLE(src->data.tcp.host, tgt->data.tcp.host) &&
            STREQ_NULLABLE(src->data.tcp.service, tgt->data.tcp.service);
        break;
    case VIR_DOMAIN_CHR_TYPE_UNIX:
        return src->data.nix.listen == tgt->data.nix.listen &&
            STREQ_NULLABLE(src->data.nix.path, tgt->data.nix.path);
        break;

1589 1590 1591 1592 1593
    case VIR_DOMAIN_CHR_TYPE_SPICEPORT:
        return STREQ_NULLABLE(src->data.spiceport.channel,
                              tgt->data.spiceport.channel);
        break;

1594
    case VIR_DOMAIN_CHR_TYPE_NULL:
1595 1596 1597
    case VIR_DOMAIN_CHR_TYPE_VC:
    case VIR_DOMAIN_CHR_TYPE_STDIO:
    case VIR_DOMAIN_CHR_TYPE_SPICEVMC:
1598
    case VIR_DOMAIN_CHR_TYPE_LAST:
1599
        /* nada */
1600
        break;
1601 1602 1603 1604 1605
    }

    return false;
}

1606 1607
void virDomainChrDefFree(virDomainChrDefPtr def)
{
1608 1609
    size_t i;

1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630
    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);
1631 1632
    virDomainDeviceInfoClear(&def->info);

1633 1634 1635 1636 1637 1638
    if (def->seclabels) {
        for (i = 0; i < def->nseclabels; i++)
            virSecurityDeviceLabelDefFree(def->seclabels[i]);
        VIR_FREE(def->seclabels);
    }

1639 1640 1641
    VIR_FREE(def);
}

E
Eric Blake 已提交
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
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);
}

1671 1672 1673 1674 1675 1676 1677 1678
void virDomainSoundCodecDefFree(virDomainSoundCodecDefPtr def)
{
    if (!def)
        return;

    VIR_FREE(def);
}

1679 1680 1681 1682 1683
void virDomainSoundDefFree(virDomainSoundDefPtr def)
{
    if (!def)
        return;

1684 1685
    virDomainDeviceInfoClear(&def->info);

1686
    size_t i;
1687
    for (i = 0; i < def->ncodecs; i++)
1688 1689 1690
        virDomainSoundCodecDefFree(def->codecs[i]);
    VIR_FREE(def->codecs);

1691 1692 1693
    VIR_FREE(def);
}

1694 1695 1696 1697 1698 1699 1700 1701 1702 1703
void virDomainMemballoonDefFree(virDomainMemballoonDefPtr def)
{
    if (!def)
        return;

    virDomainDeviceInfoClear(&def->info);

    VIR_FREE(def);
}

L
Li Zhang 已提交
1704 1705 1706 1707 1708 1709 1710 1711 1712 1713
void virDomainNVRAMDefFree(virDomainNVRAMDefPtr def)
{
    if (!def)
        return;

    virDomainDeviceInfoClear(&def->info);

    VIR_FREE(def);
}

R
Richard Jones 已提交
1714 1715 1716 1717 1718
void virDomainWatchdogDefFree(virDomainWatchdogDefPtr def)
{
    if (!def)
        return;

1719 1720
    virDomainDeviceInfoClear(&def->info);

R
Richard Jones 已提交
1721 1722 1723
    VIR_FREE(def);
}

1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734
void virDomainShmemDefFree(virDomainShmemDefPtr def)
{
    if (!def)
        return;

    virDomainDeviceInfoClear(&def->info);
    VIR_FREE(def->server.path);
    VIR_FREE(def->name);
    VIR_FREE(def);
}

1735 1736 1737 1738 1739
void virDomainVideoDefFree(virDomainVideoDefPtr def)
{
    if (!def)
        return;

1740 1741
    virDomainDeviceInfoClear(&def->info);

1742
    VIR_FREE(def->accel);
1743 1744 1745
    VIR_FREE(def);
}

1746 1747 1748 1749
virDomainHostdevDefPtr virDomainHostdevDefAlloc(void)
{
    virDomainHostdevDefPtr def = NULL;

1750 1751
    if (VIR_ALLOC(def) < 0 ||
        VIR_ALLOC(def->info) < 0)
1752 1753 1754 1755
        VIR_FREE(def);
    return def;
}

1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766
static void
virDomainHostdevSubsysSCSIiSCSIClear(virDomainHostdevSubsysSCSIiSCSIPtr iscsisrc)
{
    if (!iscsisrc)
        return;
    VIR_FREE(iscsisrc->path);
    virStorageNetHostDefFree(iscsisrc->nhosts, iscsisrc->hosts);
    virStorageAuthDefFree(iscsisrc->auth);
    iscsisrc->auth = NULL;
}

1767 1768 1769 1770 1771 1772 1773 1774 1775
void virDomainHostdevDefClear(virDomainHostdevDefPtr def)
{
    if (!def)
        return;

    /* Free all resources in the hostdevdef. Currently the only
     * such resource is the virDomainDeviceInfo.
     */

1776 1777 1778 1779 1780
    /* If there is a parent device object, it will handle freeing
     * def->info.
     */
    if (def->parent.type == VIR_DOMAIN_DEVICE_NONE)
        virDomainDeviceInfoFree(def->info);
1781

H
Han Cheng 已提交
1782 1783
    switch (def->mode) {
    case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
1784 1785 1786 1787 1788 1789 1790
        switch (def->source.caps.type) {
        case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_STORAGE:
            VIR_FREE(def->source.caps.u.storage.block);
            break;
        case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_MISC:
            VIR_FREE(def->source.caps.u.misc.chardev);
            break;
1791 1792 1793
        case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_NET:
            VIR_FREE(def->source.caps.u.net.iface);
            break;
1794
        }
H
Han Cheng 已提交
1795 1796
        break;
    case VIR_DOMAIN_HOSTDEV_MODE_SUBSYS:
1797 1798 1799 1800 1801 1802 1803 1804 1805
        if (def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI) {
            virDomainHostdevSubsysSCSIPtr scsisrc = &def->source.subsys.u.scsi;
            if (scsisrc->protocol ==
                VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_ISCSI) {
                virDomainHostdevSubsysSCSIiSCSIClear(&scsisrc->u.iscsi);
            } else {
                VIR_FREE(scsisrc->u.host.adapter);
            }
        }
H
Han Cheng 已提交
1806
        break;
1807
    }
1808 1809
}

1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826
void virDomainTPMDefFree(virDomainTPMDefPtr def)
{
    if (!def)
        return;

    switch (def->type) {
    case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH:
        VIR_FREE(def->data.passthrough.source.data.file.path);
        break;
    case VIR_DOMAIN_TPM_TYPE_LAST:
        break;
    }

    virDomainDeviceInfoClear(&def->info);
    VIR_FREE(def);
}

1827 1828 1829 1830 1831
void virDomainHostdevDefFree(virDomainHostdevDefPtr def)
{
    if (!def)
        return;

1832 1833 1834
    /* free all subordinate objects */
    virDomainHostdevDefClear(def);

1835 1836 1837 1838 1839
    /* If there is a parent device object, it will handle freeing
     * the memory.
     */
    if (def->parent.type == VIR_DOMAIN_DEVICE_NONE)
        VIR_FREE(def);
1840 1841
}

M
Marc-André Lureau 已提交
1842 1843 1844 1845 1846 1847 1848 1849 1850
void virDomainHubDefFree(virDomainHubDefPtr def)
{
    if (!def)
        return;

    virDomainDeviceInfoClear(&def->info);
    VIR_FREE(def);
}

1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861
void virDomainRedirdevDefFree(virDomainRedirdevDefPtr def)
{
    if (!def)
        return;

    virDomainChrSourceDefClear(&def->source.chr);
    virDomainDeviceInfoClear(&def->info);

    VIR_FREE(def);
}

1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875
void virDomainRedirFilterDefFree(virDomainRedirFilterDefPtr def)
{
    size_t i;

    if (!def)
        return;

    for (i = 0; i < def->nusbdevs; i++)
        VIR_FREE(def->usbdevs[i]);

    VIR_FREE(def->usbdevs);
    VIR_FREE(def);
}

1876 1877 1878 1879 1880
void virDomainDeviceDefFree(virDomainDeviceDefPtr def)
{
    if (!def)
        return;

1881
    switch ((virDomainDeviceType) def->type) {
1882 1883 1884
    case VIR_DOMAIN_DEVICE_DISK:
        virDomainDiskDefFree(def->data.disk);
        break;
1885 1886 1887
    case VIR_DOMAIN_DEVICE_LEASE:
        virDomainLeaseDefFree(def->data.lease);
        break;
1888 1889 1890 1891 1892 1893 1894 1895 1896
    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;
1897 1898 1899
    case VIR_DOMAIN_DEVICE_VIDEO:
        virDomainVideoDefFree(def->data.video);
        break;
1900 1901 1902
    case VIR_DOMAIN_DEVICE_HOSTDEV:
        virDomainHostdevDefFree(def->data.hostdev);
        break;
R
Richard Jones 已提交
1903 1904 1905
    case VIR_DOMAIN_DEVICE_WATCHDOG:
        virDomainWatchdogDefFree(def->data.watchdog);
        break;
1906 1907 1908
    case VIR_DOMAIN_DEVICE_CONTROLLER:
        virDomainControllerDefFree(def->data.controller);
        break;
1909 1910 1911
    case VIR_DOMAIN_DEVICE_GRAPHICS:
        virDomainGraphicsDefFree(def->data.graphics);
        break;
M
Marc-André Lureau 已提交
1912 1913 1914
    case VIR_DOMAIN_DEVICE_HUB:
        virDomainHubDefFree(def->data.hub);
        break;
1915 1916 1917
    case VIR_DOMAIN_DEVICE_REDIRDEV:
        virDomainRedirdevDefFree(def->data.redirdev);
        break;
1918 1919 1920
    case VIR_DOMAIN_DEVICE_RNG:
        virDomainRNGDefFree(def->data.rng);
        break;
1921 1922 1923
    case VIR_DOMAIN_DEVICE_CHR:
        virDomainChrDefFree(def->data.chr);
        break;
1924
    case VIR_DOMAIN_DEVICE_FS:
1925 1926
        virDomainFSDefFree(def->data.fs);
        break;
1927
    case VIR_DOMAIN_DEVICE_SMARTCARD:
1928 1929
        virDomainSmartcardDefFree(def->data.smartcard);
        break;
1930
    case VIR_DOMAIN_DEVICE_MEMBALLOON:
1931 1932
        virDomainMemballoonDefFree(def->data.memballoon);
        break;
L
Li Zhang 已提交
1933
    case VIR_DOMAIN_DEVICE_NVRAM:
1934 1935
        virDomainNVRAMDefFree(def->data.nvram);
        break;
1936 1937 1938
    case VIR_DOMAIN_DEVICE_SHMEM:
        virDomainShmemDefFree(def->data.shmem);
        break;
1939
    case VIR_DOMAIN_DEVICE_LAST:
1940
    case VIR_DOMAIN_DEVICE_NONE:
1941
        break;
1942 1943 1944 1945 1946
    }

    VIR_FREE(def);
}

1947 1948 1949 1950 1951 1952
static void
virDomainClockDefClear(virDomainClockDefPtr def)
{
    if (def->offset == VIR_DOMAIN_CLOCK_OFFSET_TIMEZONE)
        VIR_FREE(def->data.timezone);

1953
    size_t i;
1954 1955 1956 1957 1958
    for (i = 0; i < def->ntimers; i++)
        VIR_FREE(def->timers[i]);
    VIR_FREE(def->timers);
}

1959 1960 1961
virDomainVcpuPinDefPtr *
virDomainVcpuPinDefCopy(virDomainVcpuPinDefPtr *src, int nvcpupin)
{
1962
    size_t i;
1963
    virDomainVcpuPinDefPtr *ret = NULL;
1964

1965 1966
    if (VIR_ALLOC_N(ret, nvcpupin) < 0)
        goto error;
1967 1968 1969

    for (i = 0; i < nvcpupin; i++) {
        if (VIR_ALLOC(ret[i]) < 0)
1970
            goto error;
1971
        ret[i]->vcpuid = src[i]->vcpuid;
H
Hu Tao 已提交
1972
        if ((ret[i]->cpumask = virBitmapNewCopy(src[i]->cpumask)) == NULL)
1973
            goto error;
1974 1975 1976 1977
    }

    return ret;

1978
 error:
1979
    if (ret) {
1980
        for (i = 0; i < nvcpupin; i++) {
1981
            if (ret[i]) {
H
Hu Tao 已提交
1982
                virBitmapFree(ret[i]->cpumask);
1983 1984 1985 1986
                VIR_FREE(ret[i]);
            }
        }
        VIR_FREE(ret);
1987 1988 1989 1990 1991 1992
    }

    return NULL;
}

void
H
Hu Tao 已提交
1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003
virDomainVcpuPinDefFree(virDomainVcpuPinDefPtr def)
{
    if (def) {
        virBitmapFree(def->cpumask);
        VIR_FREE(def);
    }
}

void
virDomainVcpuPinDefArrayFree(virDomainVcpuPinDefPtr *def,
                             int nvcpupin)
2004
{
2005
    size_t i;
2006

2007
    if (!def)
2008 2009
        return;

2010
    for (i = 0; i < nvcpupin; i++) {
H
Hu Tao 已提交
2011
        virDomainVcpuPinDefFree(def[i]);
2012 2013 2014 2015 2016
    }

    VIR_FREE(def);
}

2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027

void
virDomainResourceDefFree(virDomainResourceDefPtr resource)
{
    if (!resource)
        return;

    VIR_FREE(resource->partition);
    VIR_FREE(resource);
}

H
Hu Tao 已提交
2028 2029 2030 2031 2032 2033 2034 2035 2036
void
virDomainPanicDefFree(virDomainPanicDefPtr panic)
{
    if (!panic)
        return;

    virDomainDeviceInfoClear(&panic->info);
    VIR_FREE(panic);
}
2037

2038 2039 2040 2041 2042 2043 2044 2045
void
virDomainLoaderDefFree(virDomainLoaderDefPtr loader)
{
    if (!loader)
        return;

    VIR_FREE(loader->path);
    VIR_FREE(loader->nvram);
2046
    VIR_FREE(loader->templt);
2047 2048 2049
    VIR_FREE(loader);
}

2050 2051
void virDomainDefFree(virDomainDefPtr def)
{
2052
    size_t i;
2053

2054 2055 2056
    if (!def)
        return;

2057 2058
    virDomainResourceDefFree(def->resource);

2059 2060 2061 2062 2063 2064
    /* hostdevs must be freed before nets (or any future "intelligent
     * hostdevs") because the pointer to the hostdev is really
     * pointing into the middle of the higher level device's object,
     * so the original object must still be available during the call
     * to virDomainHostdevDefFree().
     */
2065
    for (i = 0; i < def->nhostdevs; i++)
2066 2067 2068
        virDomainHostdevDefFree(def->hostdevs[i]);
    VIR_FREE(def->hostdevs);

2069
    for (i = 0; i < def->nleases; i++)
2070 2071 2072
        virDomainLeaseDefFree(def->leases[i]);
    VIR_FREE(def->leases);

2073
    for (i = 0; i < def->ngraphics; i++)
2074 2075
        virDomainGraphicsDefFree(def->graphics[i]);
    VIR_FREE(def->graphics);
2076

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

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

2085
    for (i = 0; i < def->ncontrollers; i++)
2086 2087 2088
        virDomainControllerDefFree(def->controllers[i]);
    VIR_FREE(def->controllers);

2089
    for (i = 0; i < def->nfss; i++)
2090 2091 2092
        virDomainFSDefFree(def->fss[i]);
    VIR_FREE(def->fss);

2093
    for (i = 0; i < def->nnets; i++)
2094 2095
        virDomainNetDefFree(def->nets[i]);
    VIR_FREE(def->nets);
2096

2097
    for (i = 0; i < def->nsmartcards; i++)
E
Eric Blake 已提交
2098 2099 2100
        virDomainSmartcardDefFree(def->smartcards[i]);
    VIR_FREE(def->smartcards);

2101
    for (i = 0; i < def->nserials; i++)
2102 2103 2104
        virDomainChrDefFree(def->serials[i]);
    VIR_FREE(def->serials);

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

2109
    for (i = 0; i < def->nchannels; i++)
2110 2111 2112
        virDomainChrDefFree(def->channels[i]);
    VIR_FREE(def->channels);

2113
    for (i = 0; i < def->nconsoles; i++)
2114 2115
        virDomainChrDefFree(def->consoles[i]);
    VIR_FREE(def->consoles);
2116

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

2121
    for (i = 0; i < def->nvideos; i++)
2122 2123 2124
        virDomainVideoDefFree(def->videos[i]);
    VIR_FREE(def->videos);

2125
    for (i = 0; i < def->nhubs; i++)
M
Marc-André Lureau 已提交
2126 2127 2128
        virDomainHubDefFree(def->hubs[i]);
    VIR_FREE(def->hubs);

2129
    for (i = 0; i < def->nredirdevs; i++)
2130 2131 2132
        virDomainRedirdevDefFree(def->redirdevs[i]);
    VIR_FREE(def->redirdevs);

2133 2134 2135
    for (i = 0; i < def->nrngs; i++)
        virDomainRNGDefFree(def->rngs[i]);
    VIR_FREE(def->rngs);
2136

2137 2138
    virDomainTPMDefFree(def->tpm);

H
Hu Tao 已提交
2139 2140
    virDomainPanicDefFree(def->panic);

2141 2142 2143
    VIR_FREE(def->idmap.uidmap);
    VIR_FREE(def->idmap.gidmap);

2144 2145
    VIR_FREE(def->os.type);
    VIR_FREE(def->os.machine);
2146
    VIR_FREE(def->os.init);
2147
    for (i = 0; def->os.initargv && def->os.initargv[i]; i++)
2148 2149
        VIR_FREE(def->os.initargv[i]);
    VIR_FREE(def->os.initargv);
2150 2151 2152
    VIR_FREE(def->os.kernel);
    VIR_FREE(def->os.initrd);
    VIR_FREE(def->os.cmdline);
2153
    VIR_FREE(def->os.dtb);
2154
    VIR_FREE(def->os.root);
2155
    virDomainLoaderDefFree(def->os.loader);
2156 2157 2158
    VIR_FREE(def->os.bootloader);
    VIR_FREE(def->os.bootloaderArgs);

2159
    virDomainClockDefClear(&def->clock);
2160

2161
    VIR_FREE(def->name);
2162
    virBitmapFree(def->cpumask);
2163
    VIR_FREE(def->emulator);
2164
    VIR_FREE(def->description);
2165
    VIR_FREE(def->title);
2166

2167 2168
    virBlkioDeviceArrayClear(def->blkio.devices,
                             def->blkio.ndevices);
2169 2170
    VIR_FREE(def->blkio.devices);

R
Richard Jones 已提交
2171 2172
    virDomainWatchdogDefFree(def->watchdog);

C
Chris Lalancette 已提交
2173
    virDomainMemballoonDefFree(def->memballoon);
L
Li Zhang 已提交
2174
    virDomainNVRAMDefFree(def->nvram);
C
Chris Lalancette 已提交
2175

2176 2177 2178 2179
    for (i = 0; i < def->mem.nhugepages; i++)
        virBitmapFree(def->mem.hugepages[i].nodemask);
    VIR_FREE(def->mem.hugepages);

2180 2181 2182
    for (i = 0; i < def->nseclabels; i++)
        virSecurityLabelDefFree(def->seclabels[i]);
    VIR_FREE(def->seclabels);
2183

2184 2185
    virCPUDefFree(def->cpu);

H
Hu Tao 已提交
2186 2187 2188
    virDomainVcpuPinDefArrayFree(def->cputune.vcpupin, def->cputune.nvcpupin);

    virDomainVcpuPinDefFree(def->cputune.emulatorpin);
2189

2190 2191 2192
    virDomainVcpuPinDefArrayFree(def->cputune.iothreadspin,
                                 def->cputune.niothreadspin);

2193
    virDomainNumatuneFree(def->numatune);
O
Osier Yang 已提交
2194

2195 2196
    virSysinfoDefFree(def->sysinfo);

2197 2198
    virDomainRedirFilterDefFree(def->redirfilter);

2199 2200 2201 2202
    for (i = 0; i < def->nshmems; i++)
        virDomainShmemDefFree(def->shmems[i]);
    VIR_FREE(def->shmems);

2203 2204 2205
    if (def->namespaceData && def->ns.free)
        (def->ns.free)(def->namespaceData);

2206 2207
    xmlFreeNode(def->metadata);

2208 2209 2210
    VIR_FREE(def);
}

2211
static void virDomainObjDispose(void *obj)
2212
{
2213
    virDomainObjPtr dom = obj;
2214

2215
    VIR_DEBUG("obj=%p", dom);
2216 2217 2218
    virDomainDefFree(dom->def);
    virDomainDefFree(dom->newDef);

2219 2220 2221
    if (dom->privateDataFreeFunc)
        (dom->privateDataFreeFunc)(dom->privateData);

2222
    virDomainSnapshotObjListFree(dom->snapshots);
2223 2224
}

2225
virDomainObjPtr
2226
virDomainObjNew(virDomainXMLOptionPtr xmlopt)
2227 2228 2229
{
    virDomainObjPtr domain;

2230 2231 2232
    if (virDomainObjInitialize() < 0)
        return NULL;

2233
    if (!(domain = virObjectLockableNew(virDomainObjClass)))
2234 2235
        return NULL;

2236
    if (xmlopt->privateData.alloc) {
2237
        if (!(domain->privateData = (xmlopt->privateData.alloc)()))
2238
            goto error;
2239
        domain->privateDataFreeFunc = xmlopt->privateData.free;
2240 2241 2242 2243 2244
    }

    if (!(domain->snapshots = virDomainSnapshotObjListNew()))
        goto error;

2245
    virObjectLock(domain);
J
Jiri Denemark 已提交
2246 2247
    virDomainObjSetState(domain, VIR_DOMAIN_SHUTOFF,
                                 VIR_DOMAIN_SHUTOFF_UNKNOWN);
2248

2249
    VIR_DEBUG("obj=%p", domain);
2250
    return domain;
2251

2252
 error:
2253 2254
    virObjectUnref(domain);
    return NULL;
2255 2256
}

2257 2258 2259 2260 2261 2262 2263

virDomainDefPtr virDomainDefNew(const char *name,
                                const unsigned char *uuid,
                                int id)
{
    virDomainDefPtr def;

2264
    if (VIR_ALLOC(def) < 0)
2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278
        return NULL;

    if (VIR_STRDUP(def->name, name) < 0) {
        VIR_FREE(def);
        return NULL;
    }

    memcpy(def->uuid, uuid, VIR_UUID_BUFLEN);
    def->id = id;

    return def;
}


2279
void virDomainObjAssignDef(virDomainObjPtr domain,
2280
                           virDomainDefPtr def,
2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292
                           bool live,
                           virDomainDefPtr *oldDef)
{
    if (oldDef)
        *oldDef = NULL;
    if (virDomainObjIsActive(domain)) {
        if (oldDef)
            *oldDef = domain->newDef;
        else
            virDomainDefFree(domain->newDef);
        domain->newDef = def;
    } else {
2293
        if (live) {
2294 2295 2296 2297 2298
            /* save current configuration to be restored on domain shutdown */
            if (!domain->newDef)
                domain->newDef = domain->def;
            else
                virDomainDefFree(domain->def);
2299 2300
            domain->def = def;
        } else {
2301 2302 2303 2304
            if (oldDef)
                *oldDef = domain->def;
            else
                virDomainDefFree(domain->def);
2305 2306 2307 2308 2309
            domain->def = def;
        }
    }
}

2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322


/*
 *
 * If flags & VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE then
 * this will refuse updating an existing def if the
 * current def is Live
 *
 * If flags & VIR_DOMAIN_OBJ_LIST_ADD_LIVE then
 * the @def being added is assumed to represent a
 * live config, not a future inactive config
 *
 */
2323 2324
static virDomainObjPtr
virDomainObjListAddLocked(virDomainObjListPtr doms,
2325
                          virDomainDefPtr def,
2326
                          virDomainXMLOptionPtr xmlopt,
2327 2328
                          unsigned int flags,
                          virDomainDefPtr *oldDef)
2329
{
2330
    virDomainObjPtr vm;
2331
    char uuidstr[VIR_UUID_STRING_BUFLEN];
2332

2333 2334
    if (oldDef)
        *oldDef = false;
2335

2336 2337
    virUUIDFormat(def->uuid, uuidstr);

2338
    /* See if a VM with matching UUID already exists */
2339 2340
    if ((vm = virHashLookup(doms->objs, uuidstr))) {
        virObjectLock(vm);
2341 2342 2343 2344 2345 2346 2347 2348
        /* UUID matches, but if names don't match, refuse it */
        if (STRNEQ(vm->def->name, def->name)) {
            virUUIDFormat(vm->def->uuid, uuidstr);
            virReportError(VIR_ERR_OPERATION_FAILED,
                           _("domain '%s' is already defined with uuid %s"),
                           vm->def->name, uuidstr);
            goto error;
        }
2349

2350 2351 2352 2353
        if (flags & VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE) {
            /* UUID & name match, but if VM is already active, refuse it */
            if (virDomainObjIsActive(vm)) {
                virReportError(VIR_ERR_OPERATION_INVALID,
2354 2355 2356 2357 2358 2359 2360
                               _("domain '%s' is already active"),
                               vm->def->name);
                goto error;
            }
            if (!vm->persistent) {
                virReportError(VIR_ERR_OPERATION_INVALID,
                               _("domain '%s' is already being started"),
2361 2362 2363 2364
                               vm->def->name);
                goto error;
            }
        }
2365

2366 2367 2368 2369 2370 2371
        virDomainObjAssignDef(vm,
                              def,
                              !!(flags & VIR_DOMAIN_OBJ_LIST_ADD_LIVE),
                              oldDef);
    } else {
        /* UUID does not match, but if a name matches, refuse it */
2372 2373
        if ((vm = virHashSearch(doms->objs, virDomainObjListSearchName, def->name))) {
            virObjectLock(vm);
2374 2375 2376 2377 2378 2379 2380
            virUUIDFormat(vm->def->uuid, uuidstr);
            virReportError(VIR_ERR_OPERATION_FAILED,
                           _("domain '%s' already exists with uuid %s"),
                           def->name, uuidstr);
            goto error;
        }

2381
        if (!(vm = virDomainObjNew(xmlopt)))
2382 2383 2384 2385 2386 2387 2388 2389
            goto cleanup;
        vm->def = def;

        virUUIDFormat(def->uuid, uuidstr);
        if (virHashAddEntry(doms->objs, uuidstr, vm) < 0) {
            virObjectUnref(vm);
            return NULL;
        }
2390
    }
2391
 cleanup:
2392
    return vm;
2393

2394
 error:
2395 2396 2397
    virObjectUnlock(vm);
    vm = NULL;
    goto cleanup;
2398 2399
}

2400 2401

virDomainObjPtr virDomainObjListAdd(virDomainObjListPtr doms,
2402
                                    virDomainDefPtr def,
2403
                                    virDomainXMLOptionPtr xmlopt,
2404 2405 2406 2407 2408 2409
                                    unsigned int flags,
                                    virDomainDefPtr *oldDef)
{
    virDomainObjPtr ret;

    virObjectLock(doms);
2410
    ret = virDomainObjListAddLocked(doms, def, xmlopt, flags, oldDef);
2411 2412 2413 2414
    virObjectUnlock(doms);
    return ret;
}

2415 2416 2417 2418 2419
/*
 * Mark the running VM config as transient. Ensures transient hotplug
 * operations do not persist past shutdown.
 *
 * @param caps pointer to capabilities info
W
Wang Rui 已提交
2420
 * @param xmlopt pointer to XML parser configuration object
2421
 * @param domain domain object pointer
2422 2423 2424 2425
 * @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.
2426 2427 2428 2429
 * @return 0 on success, -1 on failure
 */
int
virDomainObjSetDefTransient(virCapsPtr caps,
2430
                            virDomainXMLOptionPtr xmlopt,
2431 2432
                            virDomainObjPtr domain,
                            bool live)
2433 2434 2435
{
    int ret = -1;

2436
    if (!virDomainObjIsActive(domain) && !live)
2437 2438 2439 2440 2441 2442 2443 2444
        return 0;

    if (!domain->persistent)
        return 0;

    if (domain->newDef)
        return 0;

2445
    if (!(domain->newDef = virDomainDefCopy(domain->def, caps, xmlopt, false)))
2446 2447 2448
        goto out;

    ret = 0;
2449
 out:
2450 2451 2452
    return ret;
}

2453 2454 2455 2456 2457
/*
 * Return the persistent domain configuration. If domain is transient,
 * return the running config.
 *
 * @param caps pointer to capabilities info
W
Wang Rui 已提交
2458
 * @param xmlopt pointer to XML parser configuration object
2459 2460 2461 2462 2463
 * @param domain domain object pointer
 * @return NULL on error, virDOmainDefPtr on success
 */
virDomainDefPtr
virDomainObjGetPersistentDef(virCapsPtr caps,
2464
                             virDomainXMLOptionPtr xmlopt,
2465 2466
                             virDomainObjPtr domain)
{
2467
    if (virDomainObjSetDefTransient(caps, xmlopt, domain, false) < 0)
2468 2469 2470 2471 2472 2473 2474 2475
        return NULL;

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

2476 2477 2478 2479 2480 2481 2482 2483 2484
/*
 * Helper method for --current, --live, and --config options, and check
 * whether domain is active or can get persistent domain configuration.
 *
 * Return 0 if success, also change the flags and get the persistent
 * domain configuration if needed. Return -1 on error.
 */
int
virDomainLiveConfigHelperMethod(virCapsPtr caps,
2485
                                virDomainXMLOptionPtr xmlopt,
2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503
                                virDomainObjPtr dom,
                                unsigned int *flags,
                                virDomainDefPtr *persistentDef)
{
    bool isActive;
    int ret = -1;

    isActive = virDomainObjIsActive(dom);

    if ((*flags & (VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG)) ==
        VIR_DOMAIN_AFFECT_CURRENT) {
        if (isActive)
            *flags |= VIR_DOMAIN_AFFECT_LIVE;
        else
            *flags |= VIR_DOMAIN_AFFECT_CONFIG;
    }

    if (!isActive && (*flags & VIR_DOMAIN_AFFECT_LIVE)) {
2504 2505
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("domain is not running"));
2506 2507 2508 2509 2510
        goto cleanup;
    }

    if (*flags & VIR_DOMAIN_AFFECT_CONFIG) {
        if (!dom->persistent) {
2511
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
2512 2513
                           _("transient domains do not have any "
                             "persistent config"));
2514 2515
            goto cleanup;
        }
2516
        if (!(*persistentDef = virDomainObjGetPersistentDef(caps, xmlopt, dom))) {
2517 2518
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Get persistent config failed"));
2519 2520 2521 2522 2523 2524
            goto cleanup;
        }
    }

    ret = 0;

2525
 cleanup:
2526 2527 2528
    return ret;
}

2529
/*
2530
 * The caller must hold a lock on the driver owning 'doms',
2531
 * and must also have locked 'dom', to ensure no one else
2532
 * is either waiting for 'dom' or still using it
2533
 */
2534 2535
void virDomainObjListRemove(virDomainObjListPtr doms,
                            virDomainObjPtr dom)
2536
{
2537
    char uuidstr[VIR_UUID_STRING_BUFLEN];
2538

2539
    virUUIDFormat(dom->def->uuid, uuidstr);
2540
    virObjectRef(dom);
2541
    virObjectUnlock(dom);
2542

2543
    virObjectLock(doms);
2544
    virObjectLock(dom);
2545
    virHashRemoveEntry(doms->objs, uuidstr);
2546 2547
    virObjectUnlock(dom);
    virObjectUnref(dom);
2548
    virObjectUnlock(doms);
2549
}
D
Daniel P. Berrange 已提交
2550

2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567
/* The caller must hold lock on 'doms' in addition to 'virDomainObjListRemove'
 * requirements
 *
 * Can be used to remove current element while iterating with
 * virDomainObjListForEach
 */
void virDomainObjListRemoveLocked(virDomainObjListPtr doms,
                                  virDomainObjPtr dom)
{
    char uuidstr[VIR_UUID_STRING_BUFLEN];

    virUUIDFormat(dom->def->uuid, uuidstr);
    virObjectUnlock(dom);

    virHashRemoveEntry(doms->objs, uuidstr);
}

2568 2569 2570 2571 2572 2573 2574
static int
virDomainDeviceCCWAddressIsValid(virDomainDeviceCCWAddressPtr addr)
{
    return addr->cssid <= VIR_DOMAIN_DEVICE_CCW_MAX_CSSID &&
        addr->ssid <= VIR_DOMAIN_DEVICE_CCW_MAX_SSID &&
        addr->devno <= VIR_DOMAIN_DEVICE_CCW_MAX_DEVNO;
}
2575

2576 2577 2578 2579 2580 2581 2582 2583
int virDomainDeviceAddressIsValid(virDomainDeviceInfoPtr info,
                                  int type)
{
    if (info->type != type)
        return 0;

    switch (info->type) {
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI:
2584
        return virDevicePCIAddressIsValid(&info->addr.pci);
2585 2586

    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE:
2587
        return 1;
2588

2589
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390:
2590
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO:
2591 2592 2593 2594 2595
        return 1;

    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW:
        return virDomainDeviceCCWAddressIsValid(&info->addr.ccw);

2596
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB:
2597
        return 1;
2598 2599 2600 2601 2602
    }

    return 0;
}

2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636
virDomainDeviceInfoPtr
virDomainDeviceGetInfo(virDomainDeviceDefPtr device)
{
    switch ((virDomainDeviceType) device->type) {
    case VIR_DOMAIN_DEVICE_DISK:
        return &device->data.disk->info;
    case VIR_DOMAIN_DEVICE_FS:
        return &device->data.fs->info;
    case VIR_DOMAIN_DEVICE_NET:
        return &device->data.net->info;
    case VIR_DOMAIN_DEVICE_INPUT:
        return &device->data.input->info;
    case VIR_DOMAIN_DEVICE_SOUND:
        return &device->data.sound->info;
    case VIR_DOMAIN_DEVICE_VIDEO:
        return &device->data.video->info;
    case VIR_DOMAIN_DEVICE_HOSTDEV:
        return device->data.hostdev->info;
    case VIR_DOMAIN_DEVICE_WATCHDOG:
        return &device->data.watchdog->info;
    case VIR_DOMAIN_DEVICE_CONTROLLER:
        return &device->data.controller->info;
    case VIR_DOMAIN_DEVICE_HUB:
        return &device->data.hub->info;
    case VIR_DOMAIN_DEVICE_REDIRDEV:
        return &device->data.redirdev->info;
    case VIR_DOMAIN_DEVICE_SMARTCARD:
        return &device->data.smartcard->info;
    case VIR_DOMAIN_DEVICE_CHR:
        return &device->data.chr->info;
    case VIR_DOMAIN_DEVICE_MEMBALLOON:
        return &device->data.memballoon->info;
    case VIR_DOMAIN_DEVICE_NVRAM:
        return &device->data.nvram->info;
2637 2638
    case VIR_DOMAIN_DEVICE_SHMEM:
        return &device->data.shmem->info;
2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651
    case VIR_DOMAIN_DEVICE_RNG:
        return &device->data.rng->info;

    /* The following devices do not contain virDomainDeviceInfo */
    case VIR_DOMAIN_DEVICE_LEASE:
    case VIR_DOMAIN_DEVICE_GRAPHICS:
    case VIR_DOMAIN_DEVICE_LAST:
    case VIR_DOMAIN_DEVICE_NONE:
        break;
    }
    return NULL;
}

2652
static bool
2653
virDomainDeviceInfoIsSet(virDomainDeviceInfoPtr info, unsigned int flags)
2654 2655
{
    if (info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
2656
        return true;
2657
    if (info->alias && !(flags & VIR_DOMAIN_XML_INACTIVE))
2658 2659 2660
        return true;
    if (info->mastertype != VIR_DOMAIN_CONTROLLER_MASTER_NONE)
        return true;
J
Ján Tomko 已提交
2661
    if ((info->rombar != VIR_TRISTATE_SWITCH_ABSENT) ||
2662 2663 2664 2665 2666
        info->romfile)
        return true;
    if (info->bootIndex)
        return true;
    return false;
2667 2668
}

2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681
int
virDomainDeviceInfoCopy(virDomainDeviceInfoPtr dst,
                        virDomainDeviceInfoPtr src)
{
    /* Assume that dst is already cleared */

    /* first a shallow copy of *everything* */
    *dst = *src;

    /* then redo the two fields that are pointers */
    dst->alias = NULL;
    dst->romfile = NULL;

2682 2683
    if (VIR_STRDUP(dst->alias, src->alias) < 0 ||
        VIR_STRDUP(dst->romfile, src->romfile) < 0)
2684 2685 2686 2687
        return -1;
    return 0;
}

2688 2689
void virDomainDeviceInfoClear(virDomainDeviceInfoPtr info)
{
2690 2691 2692 2693
    VIR_FREE(info->alias);
    if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB) {
        VIR_FREE(info->addr.usb.port);
    }
2694 2695
    memset(&info->addr, 0, sizeof(info->addr));
    info->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE;
2696
    VIR_FREE(info->romfile);
2697 2698 2699
}


2700
static int virDomainDeviceInfoClearAlias(virDomainDefPtr def ATTRIBUTE_UNUSED,
2701
                                         virDomainDeviceDefPtr device ATTRIBUTE_UNUSED,
2702 2703
                                         virDomainDeviceInfoPtr info,
                                         void *opaque ATTRIBUTE_UNUSED)
2704
{
2705 2706 2707 2708 2709
    VIR_FREE(info->alias);
    return 0;
}

static int virDomainDeviceInfoClearPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED,
2710
                                              virDomainDeviceDefPtr device ATTRIBUTE_UNUSED,
2711 2712 2713 2714
                                              virDomainDeviceInfoPtr info,
                                              void *opaque ATTRIBUTE_UNUSED)
{
    if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
2715 2716 2717
        memset(&info->addr, 0, sizeof(info->addr));
        info->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE;
    }
2718
    return 0;
2719 2720
}

2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733
static int
virDomainDeviceInfoClearCCWAddress(virDomainDefPtr def ATTRIBUTE_UNUSED,
                                   virDomainDeviceDefPtr device ATTRIBUTE_UNUSED,
                                   virDomainDeviceInfoPtr info,
                                   void *opaque ATTRIBUTE_UNUSED)
{
    if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW) {
        memset(&info->addr, 0, sizeof(info->addr));
        info->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE;
    }
    return 0;
}

2734 2735 2736 2737 2738
static int
virDomainDeviceInfoIterateInternal(virDomainDefPtr def,
                                   virDomainDeviceInfoCallback cb,
                                   bool all,
                                   void *opaque)
2739
{
2740
    size_t i;
2741
    virDomainDeviceDef device;
2742

2743
    device.type = VIR_DOMAIN_DEVICE_DISK;
2744
    for (i = 0; i < def->ndisks; i++) {
2745 2746
        device.data.disk = def->disks[i];
        if (cb(def, &device, &def->disks[i]->info, opaque) < 0)
2747
            return -1;
2748 2749
    }
    device.type = VIR_DOMAIN_DEVICE_NET;
2750
    for (i = 0; i < def->nnets; i++) {
2751 2752
        device.data.net = def->nets[i];
        if (cb(def, &device, &def->nets[i]->info, opaque) < 0)
2753
            return -1;
2754 2755
    }
    device.type = VIR_DOMAIN_DEVICE_SOUND;
2756
    for (i = 0; i < def->nsounds; i++) {
2757 2758
        device.data.sound = def->sounds[i];
        if (cb(def, &device, &def->sounds[i]->info, opaque) < 0)
2759
            return -1;
2760 2761
    }
    device.type = VIR_DOMAIN_DEVICE_HOSTDEV;
2762
    for (i = 0; i < def->nhostdevs; i++) {
2763
        device.data.hostdev = def->hostdevs[i];
2764
        if (cb(def, &device, def->hostdevs[i]->info, opaque) < 0)
2765
            return -1;
2766 2767
    }
    device.type = VIR_DOMAIN_DEVICE_VIDEO;
2768
    for (i = 0; i < def->nvideos; i++) {
2769 2770
        device.data.video = def->videos[i];
        if (cb(def, &device, &def->videos[i]->info, opaque) < 0)
2771
            return -1;
2772 2773
    }
    device.type = VIR_DOMAIN_DEVICE_CONTROLLER;
2774
    for (i = 0; i < def->ncontrollers; i++) {
2775 2776
        device.data.controller = def->controllers[i];
        if (cb(def, &device, &def->controllers[i]->info, opaque) < 0)
2777
            return -1;
2778 2779
    }
    device.type = VIR_DOMAIN_DEVICE_SMARTCARD;
2780
    for (i = 0; i < def->nsmartcards; i++) {
2781 2782
        device.data.smartcard = def->smartcards[i];
        if (cb(def, &device, &def->smartcards[i]->info, opaque) < 0)
E
Eric Blake 已提交
2783
            return -1;
2784 2785
    }
    device.type = VIR_DOMAIN_DEVICE_CHR;
2786
    for (i = 0; i < def->nserials; i++) {
2787 2788
        device.data.chr = def->serials[i];
        if (cb(def, &device, &def->serials[i]->info, opaque) < 0)
2789
            return -1;
2790
    }
2791
    for (i = 0; i < def->nparallels; i++) {
2792 2793
        device.data.chr = def->parallels[i];
        if (cb(def, &device, &def->parallels[i]->info, opaque) < 0)
2794
            return -1;
2795
    }
2796
    for (i = 0; i < def->nchannels; i++) {
2797 2798
        device.data.chr = def->channels[i];
        if (cb(def, &device, &def->channels[i]->info, opaque) < 0)
2799
            return -1;
2800
    }
2801
    for (i = 0; i < def->nconsoles; i++) {
2802 2803 2804 2805 2806
        if (!all &&
            i == 0 &&
            (def->consoles[i]->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL ||
             def->consoles[i]->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_NONE) &&
             STREQ_NULLABLE(def->os.type, "hvm"))
2807
            continue;
2808 2809
        device.data.chr = def->consoles[i];
        if (cb(def, &device, &def->consoles[i]->info, opaque) < 0)
2810
            return -1;
2811 2812
    }
    device.type = VIR_DOMAIN_DEVICE_INPUT;
2813
    for (i = 0; i < def->ninputs; i++) {
2814 2815
        device.data.input = def->inputs[i];
        if (cb(def, &device, &def->inputs[i]->info, opaque) < 0)
2816
            return -1;
2817 2818
    }
    device.type = VIR_DOMAIN_DEVICE_FS;
2819
    for (i = 0; i < def->nfss; i++) {
2820 2821
        device.data.fs = def->fss[i];
        if (cb(def, &device, &def->fss[i]->info, opaque) < 0)
2822
            return -1;
2823 2824 2825 2826 2827
    }
    if (def->watchdog) {
        device.type = VIR_DOMAIN_DEVICE_WATCHDOG;
        device.data.watchdog = def->watchdog;
        if (cb(def, &device, &def->watchdog->info, opaque) < 0)
2828
            return -1;
2829 2830 2831 2832 2833
    }
    if (def->memballoon) {
        device.type = VIR_DOMAIN_DEVICE_MEMBALLOON;
        device.data.memballoon = def->memballoon;
        if (cb(def, &device, &def->memballoon->info, opaque) < 0)
2834
            return -1;
2835
    }
2836 2837 2838 2839
    device.type = VIR_DOMAIN_DEVICE_RNG;
    for (i = 0; i < def->nrngs; i++) {
        device.data.rng = def->rngs[i];
        if (cb(def, &device, &def->rngs[i]->info, opaque) < 0)
2840 2841
            return -1;
    }
L
Li Zhang 已提交
2842 2843 2844 2845 2846 2847
    if (def->nvram) {
        device.type = VIR_DOMAIN_DEVICE_NVRAM;
        device.data.nvram = def->nvram;
        if (cb(def, &device, &def->nvram->info, opaque) < 0)
            return -1;
    }
2848
    device.type = VIR_DOMAIN_DEVICE_HUB;
2849
    for (i = 0; i < def->nhubs; i++) {
2850 2851
        device.data.hub = def->hubs[i];
        if (cb(def, &device, &def->hubs[i]->info, opaque) < 0)
M
Marc-André Lureau 已提交
2852
            return -1;
2853
    }
2854 2855 2856 2857 2858 2859
    device.type = VIR_DOMAIN_DEVICE_SHMEM;
    for (i = 0; i < def->nshmems; i++) {
        device.data.shmem = def->shmems[i];
        if (cb(def, &device, &def->shmems[i]->info, opaque) < 0)
            return -1;
    }
2860

2861 2862
    /* Coverity is not very happy with this - all dead_error_condition */
#if !STATIC_ANALYSIS
2863
    /* This switch statement is here to trigger compiler warning when adding
E
Eric Blake 已提交
2864
     * a new device type. When you are adding a new field to the switch you
M
Martin Kletzander 已提交
2865
     * also have to add an iteration statement above. Otherwise the switch
2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886
     * statement has no real function here and should be optimized out by the
     * compiler. */
    i = VIR_DOMAIN_DEVICE_LAST;
    switch ((virDomainDeviceType) i) {
    case VIR_DOMAIN_DEVICE_DISK:
    case VIR_DOMAIN_DEVICE_LEASE:
    case VIR_DOMAIN_DEVICE_FS:
    case VIR_DOMAIN_DEVICE_NET:
    case VIR_DOMAIN_DEVICE_INPUT:
    case VIR_DOMAIN_DEVICE_SOUND:
    case VIR_DOMAIN_DEVICE_VIDEO:
    case VIR_DOMAIN_DEVICE_HOSTDEV:
    case VIR_DOMAIN_DEVICE_WATCHDOG:
    case VIR_DOMAIN_DEVICE_CONTROLLER:
    case VIR_DOMAIN_DEVICE_GRAPHICS:
    case VIR_DOMAIN_DEVICE_HUB:
    case VIR_DOMAIN_DEVICE_REDIRDEV:
    case VIR_DOMAIN_DEVICE_NONE:
    case VIR_DOMAIN_DEVICE_SMARTCARD:
    case VIR_DOMAIN_DEVICE_CHR:
    case VIR_DOMAIN_DEVICE_MEMBALLOON:
L
Li Zhang 已提交
2887
    case VIR_DOMAIN_DEVICE_NVRAM:
2888
    case VIR_DOMAIN_DEVICE_SHMEM:
2889
    case VIR_DOMAIN_DEVICE_LAST:
2890
    case VIR_DOMAIN_DEVICE_RNG:
2891 2892
        break;
    }
2893
#endif
2894

2895
    return 0;
2896 2897 2898
}


2899 2900 2901 2902 2903 2904 2905 2906 2907
int
virDomainDeviceInfoIterate(virDomainDefPtr def,
                           virDomainDeviceInfoCallback cb,
                           void *opaque)
{
    return virDomainDeviceInfoIterateInternal(def, cb, false, opaque);
}


2908 2909 2910 2911 2912 2913 2914 2915 2916
static int
virDomainDefRejectDuplicateControllers(virDomainDefPtr def)
{
    int max_idx[VIR_DOMAIN_CONTROLLER_TYPE_LAST];
    virBitmapPtr bitmaps[VIR_DOMAIN_CONTROLLER_TYPE_LAST] = { NULL };
    virDomainControllerDefPtr cont;
    size_t nbitmaps = 0;
    int ret = -1;
    bool b;
2917
    size_t i;
2918 2919 2920 2921 2922

    memset(max_idx, -1, sizeof(max_idx));

    for (i = 0; i < def->ncontrollers; i++) {
        cont = def->controllers[i];
2923
        if ((int) cont->idx > max_idx[cont->type])
2924 2925 2926 2927 2928 2929 2930 2931
            max_idx[cont->type] = cont->idx;
    }

    /* multiple USB controllers with the same index are allowed */
    max_idx[VIR_DOMAIN_CONTROLLER_TYPE_USB] = -1;

    for (i = 0; i < VIR_DOMAIN_CONTROLLER_TYPE_LAST; i++) {
        if (max_idx[i] >= 0 && !(bitmaps[i] = virBitmapNew(max_idx[i] + 1)))
2932
            goto cleanup;
2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953
        nbitmaps++;
    }

    for (i = 0; i < def->ncontrollers; i++) {
        cont = def->controllers[i];

        if (max_idx[cont->type] == -1)
            continue;

        ignore_value(virBitmapGetBit(bitmaps[cont->type], cont->idx, &b));
        if (b) {
            virReportError(VIR_ERR_XML_ERROR,
                           _("Multiple '%s' controllers with index '%d'"),
                           virDomainControllerTypeToString(cont->type),
                           cont->idx);
            goto cleanup;
        }
        ignore_value(virBitmapSetBit(bitmaps[cont->type], cont->idx));
    }

    ret = 0;
2954
 cleanup:
2955 2956 2957 2958 2959 2960
    for (i = 0; i < nbitmaps; i++)
        virBitmapFree(bitmaps[i]);
    return ret;
}


2961 2962 2963 2964
static int
virDomainDefPostParseInternal(virDomainDefPtr def,
                              virCapsPtr caps ATTRIBUTE_UNUSED)
{
2965
    size_t i;
2966

2967 2968 2969 2970 2971 2972
    if (!def->os.type) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("hypervisor type must be specified"));
        return -1;
    }

2973 2974 2975 2976 2977 2978 2979
    /* verify init path for container based domains */
    if (STREQ(def->os.type, "exe") && !def->os.init) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("init binary must be specified"));
        return -1;
    }

2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018
    /*
     * Some really crazy backcompat stuff for consoles
     *
     * Historically the first (and only) '<console>' element in an HVM guest
     * was treated as being an alias for a <serial> device.
     *
     * So if we see that this console device should be a serial device, then we
     * move the config over to def->serials[0] (or discard it if that already
     * exists). However, given console can already be filled with aliased data
     * of def->serials[0]. Keep it then.
     *
     * We then fill def->consoles[0] with a stub just so we get sequencing
     * correct for consoles > 0
     */
    if (def->nconsoles > 0 && STREQ(def->os.type, "hvm") &&
        (def->consoles[0]->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL ||
         def->consoles[0]->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_NONE)) {
        /* First verify that only the first console is of type serial */
        for (i = 1; i < def->nconsoles; i++) {
            virDomainChrDefPtr cons = def->consoles[i];

            if (cons->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                               _("Only the first console can be a serial port"));
                return -1;
            }
        }

        /* If there isn't a corresponding serial port:
         *  - create one and set, the console to be an alias for it
         *
         * If there is a corresponding serial port:
         * - Check if the source definition is equal:
         *    - if yes: leave it as-is
         *    - if no: change the console to be alias of the serial port
         */

        /* create the serial port definition from the console definition */
        if (def->nserials == 0) {
3019 3020 3021 3022
            if (VIR_APPEND_ELEMENT(def->serials,
                                   def->nserials,
                                   def->consoles[0]) < 0)
                return -1;
3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039

            /* modify it to be a serial port */
            def->serials[0]->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL;
            def->serials[0]->targetType = VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_ISA;
            def->serials[0]->target.port = 0;
        } else {
            /* if the console source doesn't match */
            if (!virDomainChrSourceDefIsEqual(&def->serials[0]->source,
                                              &def->consoles[0]->source)) {
                virDomainChrDefFree(def->consoles[0]);
                def->consoles[0] = NULL;
            }
        }

        if (!def->consoles[0]) {
            /* allocate a new console type for the stolen one */
            if (VIR_ALLOC(def->consoles[0]) < 0)
3040
                return -1;
3041 3042 3043 3044 3045 3046 3047

            /* Create an console alias for the serial port */
            def->consoles[0]->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE;
            def->consoles[0]->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL;
        }
    }

3048 3049
    if (virDomainDefRejectDuplicateControllers(def) < 0)
        return -1;
3050 3051 3052 3053 3054

    /* verify settings of guest timers */
    for (i = 0; i < def->clock.ntimers; i++) {
        virDomainTimerDefPtr timer = def->clock.timers[i];

3055 3056
        if (timer->name == VIR_DOMAIN_TIMER_NAME_KVMCLOCK ||
            timer->name == VIR_DOMAIN_TIMER_NAME_HYPERVCLOCK) {
3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 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 3104 3105
            if (timer->tickpolicy != -1) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("timer %s doesn't support setting of "
                                 "timer tickpolicy"),
                               virDomainTimerNameTypeToString(timer->name));
                return -1;
            }
        }

        if (timer->tickpolicy != VIR_DOMAIN_TIMER_TICKPOLICY_CATCHUP &&
            (timer->catchup.threshold != 0 ||
             timer->catchup.limit != 0 ||
             timer->catchup.slew != 0)) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("setting of timer catchup policies is only "
                             "supported with tickpolicy='catchup'"));
            return -1;
        }

        if (timer->name != VIR_DOMAIN_TIMER_NAME_TSC) {
            if (timer->frequency != 0) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("timer %s doesn't support setting of "
                                 "timer frequency"),
                               virDomainTimerNameTypeToString(timer->name));
                return -1;
             }

            if (timer->mode != -1) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("timer %s doesn't support setting of "
                                 "timer mode"),
                               virDomainTimerNameTypeToString(timer->name));
                return -1;
             }
        }

        if (timer->name != VIR_DOMAIN_TIMER_NAME_PLATFORM &&
            timer->name != VIR_DOMAIN_TIMER_NAME_RTC) {
            if (timer->track != -1) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("timer %s doesn't support setting of "
                                 "timer track"),
                               virDomainTimerNameTypeToString(timer->name));
                return -1;
            }
        }
    }

3106 3107 3108 3109 3110 3111
    return 0;
}


static int
virDomainDeviceDefPostParseInternal(virDomainDeviceDefPtr dev,
3112
                                    const virDomainDef *def,
3113 3114
                                    virCapsPtr caps ATTRIBUTE_UNUSED)
{
3115 3116
    if (dev->type == VIR_DOMAIN_DEVICE_CHR) {
        virDomainChrDefPtr chr = dev->data.chr;
3117 3118
        const virDomainChrDef **arrPtr;
        size_t i, cnt;
3119

3120
        virDomainChrGetDomainPtrs(def, chr->deviceType, &arrPtr, &cnt);
3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131

        if (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE &&
            chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_NONE)
            chr->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL;

        if (chr->target.port == -1 &&
            (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL ||
             chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL ||
             chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE)) {
            int maxport = -1;

3132 3133 3134
            for (i = 0; i < cnt; i++) {
                if (arrPtr[i]->target.port > maxport)
                    maxport = arrPtr[i]->target.port;
3135 3136 3137 3138 3139 3140 3141 3142 3143
            }

            chr->target.port = maxport + 1;
        }

        if (chr->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL &&
            chr->info.addr.vioserial.port == 0) {
            int maxport = 0;

3144 3145
            for (i = 0; i < cnt; i++) {
                const virDomainChrDef *thischr = arrPtr[i];
3146 3147 3148 3149 3150 3151 3152 3153 3154
                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;
        }
    }
3155

3156 3157 3158 3159 3160 3161 3162 3163
    /* set default path for virtio-rng "random" backend to /dev/random */
    if (dev->type == VIR_DOMAIN_DEVICE_RNG &&
        dev->data.rng->backend == VIR_DOMAIN_RNG_BACKEND_RANDOM &&
        !dev->data.rng->source.file) {
        if (VIR_STRDUP(dev->data.rng->source.file, "/dev/random") < 0)
            return -1;
    }

3164 3165 3166 3167
    return 0;
}


3168 3169
static int
virDomainDeviceDefPostParse(virDomainDeviceDefPtr dev,
3170
                            const virDomainDef *def,
3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182
                            virCapsPtr caps,
                            virDomainXMLOptionPtr xmlopt)
{
    int ret;

    if (xmlopt && xmlopt->config.devicesPostParseCallback) {
        ret = xmlopt->config.devicesPostParseCallback(dev, def, caps,
                                                      xmlopt->config.priv);
        if (ret < 0)
            return ret;
    }

3183 3184 3185
    if ((ret = virDomainDeviceDefPostParseInternal(dev, def, caps)) < 0)
        return ret;

3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207
    return 0;
}


struct virDomainDefPostParseDeviceIteratorData {
    virDomainDefPtr def;
    virCapsPtr caps;
    virDomainXMLOptionPtr xmlopt;
};


static int
virDomainDefPostParseDeviceIterator(virDomainDefPtr def ATTRIBUTE_UNUSED,
                                    virDomainDeviceDefPtr dev,
                                    virDomainDeviceInfoPtr info ATTRIBUTE_UNUSED,
                                    void *opaque)
{
    struct virDomainDefPostParseDeviceIteratorData *data = opaque;
    return virDomainDeviceDefPostParse(dev, data->def, data->caps, data->xmlopt);
}


3208
int
3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228
virDomainDefPostParse(virDomainDefPtr def,
                      virCapsPtr caps,
                      virDomainXMLOptionPtr xmlopt)
{
    int ret;
    struct virDomainDefPostParseDeviceIteratorData data = {
        .def = def,
        .caps = caps,
        .xmlopt = xmlopt,
    };

    /* call the domain config callback */
    if (xmlopt && xmlopt->config.domainPostParseCallback) {
        ret = xmlopt->config.domainPostParseCallback(def, caps,
                                                     xmlopt->config.priv);
        if (ret < 0)
            return ret;
    }

    /* iterate the devices */
3229 3230 3231 3232
    if ((ret = virDomainDeviceInfoIterateInternal(def,
                                                  virDomainDefPostParseDeviceIterator,
                                                  true,
                                                  &data)) < 0)
3233 3234
        return ret;

3235 3236 3237 3238

    if ((ret = virDomainDefPostParseInternal(def, caps)) < 0)
        return ret;

3239 3240 3241 3242
    return 0;
}


3243 3244
void virDomainDefClearPCIAddresses(virDomainDefPtr def)
{
3245
    virDomainDeviceInfoIterate(def, virDomainDeviceInfoClearPCIAddress, NULL);
D
Daniel P. Berrange 已提交
3246 3247
}

3248 3249 3250 3251 3252
void virDomainDefClearCCWAddresses(virDomainDefPtr def)
{
    virDomainDeviceInfoIterate(def, virDomainDeviceInfoClearCCWAddress, NULL);
}

D
Daniel P. Berrange 已提交
3253 3254
void virDomainDefClearDeviceAliases(virDomainDefPtr def)
{
3255
    virDomainDeviceInfoIterate(def, virDomainDeviceInfoClearAlias, NULL);
3256 3257 3258
}


3259
/* Generate a string representation of a device address
3260
 * @info address Device address to stringify
3261
 */
E
Eric Blake 已提交
3262 3263 3264
static int ATTRIBUTE_NONNULL(2)
virDomainDeviceInfoFormat(virBufferPtr buf,
                          virDomainDeviceInfoPtr info,
E
Eric Blake 已提交
3265
                          unsigned int flags)
3266
{
3267
    if ((flags & VIR_DOMAIN_XML_INTERNAL_ALLOW_BOOT) && info->bootIndex)
3268
        virBufferAsprintf(buf, "<boot order='%d'/>\n", info->bootIndex);
3269

D
Daniel P. Berrange 已提交
3270 3271
    if (info->alias &&
        !(flags & VIR_DOMAIN_XML_INACTIVE)) {
3272
        virBufferAsprintf(buf, "<alias name='%s'/>\n", info->alias);
D
Daniel P. Berrange 已提交
3273 3274
    }

3275
    if (info->mastertype == VIR_DOMAIN_CONTROLLER_MASTER_USB) {
3276
        virBufferAsprintf(buf, "<master startport='%d'/>\n",
3277 3278 3279
                          info->master.usb.startport);
    }

3280 3281 3282
    if ((flags & VIR_DOMAIN_XML_INTERNAL_ALLOW_ROM) &&
        (info->rombar || info->romfile)) {

3283
        virBufferAddLit(buf, "<rom");
3284 3285
        if (info->rombar) {

J
Ján Tomko 已提交
3286
            const char *rombar = virTristateSwitchTypeToString(info->rombar);
3287 3288

            if (!rombar) {
3289 3290 3291
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unexpected rom bar value %d"),
                               info->rombar);
3292 3293 3294
                return -1;
            }
            virBufferAsprintf(buf, " bar='%s'", rombar);
3295
        }
3296 3297 3298
        if (info->romfile)
            virBufferAsprintf(buf, " file='%s'", info->romfile);
        virBufferAddLit(buf, "/>\n");
3299 3300
    }

3301 3302
    if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE ||
        info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390)
3303 3304 3305
        return 0;

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

3309
    switch ((virDomainDeviceAddressType) info->type) {
3310
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI:
3311
        virBufferAsprintf(buf, " domain='0x%.4x' bus='0x%.2x' slot='0x%.2x' function='0x%.1x'",
3312 3313 3314 3315
                          info->addr.pci.domain,
                          info->addr.pci.bus,
                          info->addr.pci.slot,
                          info->addr.pci.function);
3316 3317
        if (info->addr.pci.multi) {
           virBufferAsprintf(buf, " multifunction='%s'",
J
Ján Tomko 已提交
3318
                             virTristateSwitchTypeToString(info->addr.pci.multi));
3319
        }
3320 3321
        break;

3322
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE:
3323
        virBufferAsprintf(buf, " controller='%d' bus='%d' target='%d' unit='%d'",
3324 3325
                          info->addr.drive.controller,
                          info->addr.drive.bus,
3326
                          info->addr.drive.target,
3327 3328 3329
                          info->addr.drive.unit);
        break;

3330
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL:
3331
        virBufferAsprintf(buf, " controller='%d' bus='%d' port='%d'",
3332
                          info->addr.vioserial.controller,
3333 3334
                          info->addr.vioserial.bus,
                          info->addr.vioserial.port);
3335 3336
        break;

E
Eric Blake 已提交
3337
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCID:
3338
        virBufferAsprintf(buf, " controller='%d' slot='%d'",
E
Eric Blake 已提交
3339 3340 3341 3342
                          info->addr.ccid.controller,
                          info->addr.ccid.slot);
        break;

M
Marc-André Lureau 已提交
3343
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB:
3344
        virBufferAsprintf(buf, " bus='%d' port='%s'",
M
Marc-André Lureau 已提交
3345 3346 3347 3348
                          info->addr.usb.bus,
                          info->addr.usb.port);
        break;

3349 3350 3351 3352 3353
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO:
        if (info->addr.spaprvio.has_reg)
            virBufferAsprintf(buf, " reg='0x%llx'", info->addr.spaprvio.reg);
        break;

3354 3355 3356 3357 3358 3359 3360
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW:
        virBufferAsprintf(buf, " cssid='0x%x' ssid='0x%x' devno='0x%04x'",
                          info->addr.ccw.cssid,
                          info->addr.ccw.ssid,
                          info->addr.ccw.devno);
        break;

3361 3362 3363
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO:
        break;

H
Hu Tao 已提交
3364 3365 3366 3367 3368 3369 3370
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_ISA:
        if (info->addr.isa.iobase > 0)
            virBufferAsprintf(buf, " iobase='0x%x'", info->addr.isa.iobase);
        if (info->addr.isa.irq > 0)
            virBufferAsprintf(buf, " irq='0x%x'", info->addr.isa.irq);
        break;

3371 3372 3373 3374
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390:
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE:
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST:
        break;
3375 3376 3377 3378 3379 3380
    }

    virBufferAddLit(buf, "/>\n");
    return 0;
}

3381
static int
3382
virDomainDeviceDriveAddressParseXML(xmlNodePtr node,
3383 3384
                                    virDomainDeviceDriveAddressPtr addr)
{
3385
    char *bus, *unit, *controller, *target;
3386 3387 3388 3389 3390 3391
    int ret = -1;

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

    controller = virXMLPropString(node, "controller");
    bus = virXMLPropString(node, "bus");
3392
    target = virXMLPropString(node, "target");
3393 3394 3395 3396
    unit = virXMLPropString(node, "unit");

    if (controller &&
        virStrToLong_ui(controller, NULL, 10, &addr->controller) < 0) {
3397 3398
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Cannot parse <address> 'controller' attribute"));
3399 3400 3401 3402 3403
        goto cleanup;
    }

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

3409 3410
    if (target &&
        virStrToLong_ui(target, NULL, 10, &addr->target) < 0) {
3411 3412
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Cannot parse <address> 'target' attribute"));
3413 3414 3415
        goto cleanup;
    }

3416 3417
    if (unit &&
        virStrToLong_ui(unit, NULL, 10, &addr->unit) < 0) {
3418 3419
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Cannot parse <address> 'unit' attribute"));
3420 3421 3422 3423 3424
        goto cleanup;
    }

    ret = 0;

3425
 cleanup:
3426 3427
    VIR_FREE(controller);
    VIR_FREE(bus);
3428
    VIR_FREE(target);
3429 3430 3431 3432
    VIR_FREE(unit);
    return ret;
}

3433 3434 3435 3436 3437 3438 3439

static int
virDomainDeviceVirtioSerialAddressParseXML(
    xmlNodePtr node,
    virDomainDeviceVirtioSerialAddressPtr addr
)
{
3440
    char *controller, *bus, *port;
3441 3442 3443 3444 3445 3446
    int ret = -1;

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

    controller = virXMLPropString(node, "controller");
    bus = virXMLPropString(node, "bus");
3447
    port = virXMLPropString(node, "port");
3448 3449 3450

    if (controller &&
        virStrToLong_ui(controller, NULL, 10, &addr->controller) < 0) {
3451 3452
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Cannot parse <address> 'controller' attribute"));
3453 3454 3455 3456 3457
        goto cleanup;
    }

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

3463 3464
    if (port &&
        virStrToLong_ui(port, NULL, 10, &addr->port) < 0) {
3465 3466
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Cannot parse <address> 'port' attribute"));
3467 3468 3469
        goto cleanup;
    }

3470 3471
    ret = 0;

3472
 cleanup:
3473 3474
    VIR_FREE(controller);
    VIR_FREE(bus);
E
Eric Blake 已提交
3475
    VIR_FREE(port);
3476 3477 3478
    return ret;
}

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
static int
virDomainDeviceCCWAddressParseXML(xmlNodePtr node,
                                  virDomainDeviceCCWAddressPtr addr)
{
    int   ret = -1;
    char *cssid;
    char *ssid;
    char *devno;

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

    cssid = virXMLPropString(node, "cssid");
    ssid = virXMLPropString(node, "ssid");
    devno = virXMLPropString(node, "devno");

    if (cssid && ssid && devno) {
        if (cssid &&
            virStrToLong_ui(cssid, NULL, 0, &addr->cssid) < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Cannot parse <address> 'cssid' attribute"));
            goto cleanup;
        }
        if (ssid &&
            virStrToLong_ui(ssid, NULL, 0, &addr->ssid) < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Cannot parse <address> 'ssid' attribute"));
            goto cleanup;
        }
        if (devno &&
            virStrToLong_ui(devno, NULL, 0, &addr->devno) < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Cannot parse <address> 'devno' attribute"));
            goto cleanup;
        }
        if (!virDomainDeviceCCWAddressIsValid(addr)) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Invalid specification for virtio ccw"
                             " address: cssid='%s' ssid='%s' devno='%s'"),
                           cssid, ssid, devno);
            goto cleanup;
        }
        addr->assigned = true;
    } else if (cssid || ssid || devno) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Invalid partial specification for virtio ccw"
                         " address"));
        goto cleanup;
    }

    ret = 0;

3530
 cleanup:
3531 3532 3533 3534 3535 3536
    VIR_FREE(cssid);
    VIR_FREE(ssid);
    VIR_FREE(devno);
    return ret;
}

E
Eric Blake 已提交
3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550
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) {
3551 3552
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Cannot parse <address> 'controller' attribute"));
E
Eric Blake 已提交
3553 3554 3555 3556 3557
        goto cleanup;
    }

    if (slot &&
        virStrToLong_ui(slot, NULL, 10, &addr->slot) < 0) {
3558 3559
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Cannot parse <address> 'slot' attribute"));
E
Eric Blake 已提交
3560 3561 3562 3563 3564
        goto cleanup;
    }

    ret = 0;

3565
 cleanup:
E
Eric Blake 已提交
3566 3567 3568 3569 3570
    VIR_FREE(controller);
    VIR_FREE(slot);
    return ret;
}

3571 3572 3573 3574
static int
virDomainDeviceUSBAddressParseXML(xmlNodePtr node,
                                  virDomainDeviceUSBAddressPtr addr)
{
3575 3576
    char *port, *bus, *tmp;
    unsigned int p;
3577 3578 3579 3580 3581 3582 3583 3584
    int ret = -1;

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

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

    if (port &&
3585 3586 3587 3588
        ((virStrToLong_ui(port, &tmp, 10, &p) < 0 || (*tmp != '\0' && *tmp != '.')) ||
         (*tmp == '.' && (virStrToLong_ui(tmp + 1, &tmp, 10, &p) < 0 || (*tmp != '\0' && *tmp != '.'))) ||
         (*tmp == '.' && (virStrToLong_ui(tmp + 1, &tmp, 10, &p) < 0 || (*tmp != '\0' && *tmp != '.'))) ||
         (*tmp == '.' && (virStrToLong_ui(tmp + 1, &tmp, 10, &p) < 0 || (*tmp != '\0'))))) {
3589 3590
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Cannot parse <address> 'port' attribute"));
3591 3592 3593
        goto cleanup;
    }

3594 3595 3596
    addr->port = port;
    port = NULL;

3597 3598
    if (bus &&
        virStrToLong_ui(bus, NULL, 10, &addr->bus) < 0) {
3599 3600
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Cannot parse <address> 'bus' attribute"));
3601 3602 3603 3604 3605
        goto cleanup;
    }

    ret = 0;

3606
 cleanup:
3607 3608 3609 3610 3611
    VIR_FREE(bus);
    VIR_FREE(port);
    return ret;
}

3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623
static int
virDomainDeviceSpaprVioAddressParseXML(xmlNodePtr node,
                                      virDomainDeviceSpaprVioAddressPtr addr)
{
    char *reg;
    int ret;

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

    reg = virXMLPropString(node, "reg");
    if (reg) {
        if (virStrToLong_ull(reg, NULL, 16, &addr->reg) < 0) {
3624 3625
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Cannot parse <address> 'reg' attribute"));
3626 3627 3628 3629 3630 3631 3632 3633
            ret = -1;
            goto cleanup;
        }

        addr->has_reg = true;
    }

    ret = 0;
3634
 cleanup:
3635 3636 3637 3638
    VIR_FREE(reg);
    return ret;
}

3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651
static int
virDomainDeviceUSBMasterParseXML(xmlNodePtr node,
                                 virDomainDeviceUSBMasterPtr master)
{
    char *startport;
    int ret = -1;

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

    startport = virXMLPropString(node, "startport");

    if (startport &&
        virStrToLong_ui(startport, NULL, 10, &master->startport) < 0) {
3652 3653
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Cannot parse <master> 'startport' attribute"));
3654 3655 3656 3657 3658
        goto cleanup;
    }

    ret = 0;

3659
 cleanup:
3660 3661 3662 3663
    VIR_FREE(startport);
    return ret;
}

3664 3665 3666
static int
virDomainDeviceBootParseXML(xmlNodePtr node,
                            int *bootIndex,
3667
                            virHashTablePtr bootHash)
3668 3669 3670 3671 3672 3673 3674
{
    char *order;
    int boot;
    int ret = -1;

    order = virXMLPropString(node, "order");
    if (!order) {
3675 3676
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing boot order attribute"));
3677 3678 3679
        goto cleanup;
    } else if (virStrToLong_i(order, NULL, 10, &boot) < 0 ||
               boot <= 0) {
3680 3681 3682
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("incorrect boot order '%s', expecting positive integer"),
                       order);
3683 3684 3685
        goto cleanup;
    }

3686 3687 3688 3689 3690
    if (bootHash) {
        if (virHashLookup(bootHash, order)) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("boot order '%s' used for more than one device"),
                           order);
3691 3692
            goto cleanup;
        }
3693 3694 3695

        if (virHashAddEntry(bootHash, order, (void *) 1) < 0)
            goto cleanup;
3696 3697 3698 3699 3700
    }

    *bootIndex = boot;
    ret = 0;

3701
 cleanup:
3702 3703 3704 3705
    VIR_FREE(order);
    return ret;
}

H
Hu Tao 已提交
3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733
static int
virDomainDeviceISAAddressParseXML(xmlNodePtr node,
                                  virDomainDeviceISAAddressPtr addr)
{
    int ret = -1;
    char *iobase;
    char *irq;

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

    iobase = virXMLPropString(node, "iobase");
    irq = virXMLPropString(node, "irq");

    if (iobase &&
        virStrToLong_ui(iobase, NULL, 16, &addr->iobase) < 0) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Cannot parse <address> 'iobase' attribute"));
        goto cleanup;
    }

    if (irq &&
        virStrToLong_ui(irq, NULL, 16, &addr->irq) < 0) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Cannot parse <address> 'irq' attribute"));
        goto cleanup;
    }

    ret = 0;
3734
 cleanup:
H
Hu Tao 已提交
3735 3736 3737 3738 3739
    VIR_FREE(iobase);
    VIR_FREE(irq);
    return ret;
}

3740 3741 3742 3743
/* Parse the XML definition for a device address
 * @param node XML nodeset to parse for device address definition
 */
static int
3744
virDomainDeviceInfoParseXML(xmlNodePtr node,
3745
                            virHashTablePtr bootHash,
3746
                            virDomainDeviceInfoPtr info,
E
Eric Blake 已提交
3747
                            unsigned int flags)
3748 3749 3750
{
    xmlNodePtr cur;
    xmlNodePtr address = NULL;
3751
    xmlNodePtr master = NULL;
D
Daniel P. Berrange 已提交
3752
    xmlNodePtr alias = NULL;
3753 3754
    xmlNodePtr boot = NULL;
    xmlNodePtr rom = NULL;
3755 3756 3757 3758 3759 3760 3761 3762
    char *type = NULL;
    int ret = -1;

    virDomainDeviceInfoClear(info);

    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
D
Daniel P. Berrange 已提交
3763 3764 3765 3766 3767 3768
            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")) {
3769
                address = cur;
3770 3771 3772
            } else if (master == NULL &&
                       xmlStrEqual(cur->name, BAD_CAST "master")) {
                master = cur;
3773
            } else if (boot == NULL &&
3774 3775 3776 3777 3778 3779 3780
                       (flags & VIR_DOMAIN_XML_INTERNAL_ALLOW_BOOT) &&
                       xmlStrEqual(cur->name, BAD_CAST "boot")) {
                boot = cur;
            } else if (rom == NULL &&
                       (flags & VIR_DOMAIN_XML_INTERNAL_ALLOW_ROM) &&
                       xmlStrEqual(cur->name, BAD_CAST "rom")) {
                rom = cur;
3781 3782 3783 3784 3785
            }
        }
        cur = cur->next;
    }

D
Daniel P. Berrange 已提交
3786 3787 3788
    if (alias)
        info->alias = virXMLPropString(alias, "name");

3789 3790 3791 3792 3793 3794
    if (master) {
        info->mastertype = VIR_DOMAIN_CONTROLLER_MASTER_USB;
        if (virDomainDeviceUSBMasterParseXML(master, &info->master.usb) < 0)
            goto cleanup;
    }

3795
    if (boot) {
3796
        if (virDomainDeviceBootParseXML(boot, &info->bootIndex, bootHash))
3797 3798 3799 3800 3801
            goto cleanup;
    }

    if (rom) {
        char *rombar = virXMLPropString(rom, "bar");
3802
        if (rombar &&
J
Ján Tomko 已提交
3803
            ((info->rombar = virTristateSwitchTypeFromString(rombar)) <= 0)) {
3804 3805
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown rom bar value '%s'"), rombar);
3806 3807 3808 3809
            VIR_FREE(rombar);
            goto cleanup;
        }
        VIR_FREE(rombar);
3810
        info->romfile = virXMLPropString(rom, "file");
3811 3812
    }

3813 3814 3815 3816 3817 3818
    if (!address)
        return 0;

    type = virXMLPropString(address, "type");

    if (type) {
3819
        if ((info->type = virDomainDeviceAddressTypeFromString(type)) <= 0) {
3820
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
3821
                           _("unknown address type '%s'"), type);
3822 3823 3824
            goto cleanup;
        }
    } else {
3825 3826
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("No type specified for device address"));
3827 3828 3829
        goto cleanup;
    }

3830
    switch ((virDomainDeviceAddressType) info->type) {
3831
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI:
3832
        if (virDevicePCIAddressParseXML(address, &info->addr.pci) < 0)
3833 3834 3835
            goto cleanup;
        break;

3836
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE:
3837
        if (virDomainDeviceDriveAddressParseXML(address, &info->addr.drive) < 0)
3838 3839 3840
            goto cleanup;
        break;

3841 3842 3843 3844 3845 3846
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL:
        if (virDomainDeviceVirtioSerialAddressParseXML
                (address, &info->addr.vioserial) < 0)
            goto cleanup;
        break;

E
Eric Blake 已提交
3847 3848 3849 3850 3851
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCID:
        if (virDomainDeviceCcidAddressParseXML(address, &info->addr.ccid) < 0)
            goto cleanup;
        break;

3852 3853 3854 3855 3856
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB:
        if (virDomainDeviceUSBAddressParseXML(address, &info->addr.usb) < 0)
            goto cleanup;
        break;

3857 3858 3859 3860 3861
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO:
        if (virDomainDeviceSpaprVioAddressParseXML(address, &info->addr.spaprvio) < 0)
            goto cleanup;
        break;

3862 3863 3864 3865 3866 3867
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW:
        if (virDomainDeviceCCWAddressParseXML
                (address, &info->addr.ccw) < 0)
            goto cleanup;
        break;

3868 3869 3870
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO:
        break;

H
Hu Tao 已提交
3871 3872 3873 3874 3875
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_ISA:
        if (virDomainDeviceISAAddressParseXML(address, &info->addr.isa) < 0)
            goto cleanup;
        break;

3876 3877 3878
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390:
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("virtio-s390 bus doesn't have an address"));
3879
        goto cleanup;
3880 3881 3882 3883

    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE:
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST:
        break;
3884 3885 3886 3887
    }

    ret = 0;

3888
 cleanup:
D
Daniel P. Berrange 已提交
3889 3890
    if (ret == -1)
        VIR_FREE(info->alias);
3891 3892 3893 3894
    VIR_FREE(type);
    return ret;
}

3895 3896
static int
virDomainParseLegacyDeviceAddress(char *devaddr,
3897
                                  virDevicePCIAddressPtr pci)
3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911
{
    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;
}
3912

3913
static int
3914
virDomainHostdevSubsysUSBDefParseXML(xmlNodePtr node,
3915 3916 3917 3918
                                     virDomainHostdevDefPtr def)
{

    int ret = -1;
3919
    bool got_product, got_vendor;
3920
    xmlNodePtr cur;
3921
    char *startupPolicy = NULL;
3922
    char *autoAddress;
3923
    virDomainHostdevSubsysUSBPtr usbsrc = &def->source.subsys.u.usb;
3924 3925 3926 3927 3928

    if ((startupPolicy = virXMLPropString(node, "startupPolicy"))) {
        def->startupPolicy =
            virDomainStartupPolicyTypeFromString(startupPolicy);
        if (def->startupPolicy <= 0) {
3929
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
3930 3931 3932 3933 3934 3935 3936
                           _("Unknown startup policy '%s'"),
                           startupPolicy);
            VIR_FREE(startupPolicy);
            goto out;
        }
        VIR_FREE(startupPolicy);
    }
3937

3938 3939
    if ((autoAddress = virXMLPropString(node, "autoAddress"))) {
        if (STREQ(autoAddress, "yes"))
3940
            usbsrc->autoAddress = true;
3941 3942 3943
        VIR_FREE(autoAddress);
    }

3944 3945
    /* Product can validly be 0, so we need some extra help to determine
     * if it is uninitialized*/
3946 3947
    got_product = false;
    got_vendor = false;
3948 3949 3950 3951 3952 3953 3954 3955

    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) {
3956
                    got_vendor = true;
3957
                    if (virStrToLong_ui(vendor, NULL, 0, &usbsrc->vendor) < 0) {
3958 3959
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("cannot parse vendor id %s"), vendor);
3960 3961 3962 3963 3964
                        VIR_FREE(vendor);
                        goto out;
                    }
                    VIR_FREE(vendor);
                } else {
3965 3966
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   "%s", _("usb vendor needs id"));
3967 3968 3969 3970 3971 3972
                    goto out;
                }
            } else if (xmlStrEqual(cur->name, BAD_CAST "product")) {
                char* product = virXMLPropString(cur, "id");

                if (product) {
3973
                    got_product = true;
3974
                    if (virStrToLong_ui(product, NULL, 0,
3975
                                        &usbsrc->product) < 0) {
3976 3977 3978
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("cannot parse product %s"),
                                       product);
3979 3980 3981 3982 3983
                        VIR_FREE(product);
                        goto out;
                    }
                    VIR_FREE(product);
                } else {
3984 3985
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   "%s", _("usb product needs id"));
3986 3987 3988 3989 3990 3991 3992
                    goto out;
                }
            } else if (xmlStrEqual(cur->name, BAD_CAST "address")) {
                char *bus, *device;

                bus = virXMLPropString(cur, "bus");
                if (bus) {
3993
                    if (virStrToLong_ui(bus, NULL, 0, &usbsrc->bus) < 0) {
3994 3995
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("cannot parse bus %s"), bus);
3996 3997 3998 3999 4000
                        VIR_FREE(bus);
                        goto out;
                    }
                    VIR_FREE(bus);
                } else {
4001 4002
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   "%s", _("usb address needs bus id"));
4003 4004 4005 4006 4007
                    goto out;
                }

                device = virXMLPropString(cur, "device");
                if (device) {
4008
                    if (virStrToLong_ui(device, NULL, 0, &usbsrc->device) < 0) {
4009 4010 4011
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("cannot parse device %s"),
                                       device);
4012 4013 4014 4015 4016
                        VIR_FREE(device);
                        goto out;
                    }
                    VIR_FREE(device);
                } else {
4017 4018
                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                   _("usb address needs device id"));
4019 4020 4021
                    goto out;
                }
            } else {
4022 4023 4024
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unknown usb source type '%s'"),
                               cur->name);
4025 4026 4027 4028 4029 4030
                goto out;
            }
        }
        cur = cur->next;
    }

4031
    if (got_vendor && usbsrc->vendor == 0) {
4032 4033
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("vendor cannot be 0."));
4034 4035 4036 4037
        goto out;
    }

    if (!got_vendor && got_product) {
4038 4039
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing vendor"));
4040 4041 4042
        goto out;
    }
    if (got_vendor && !got_product) {
4043 4044
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing product"));
4045 4046 4047 4048
        goto out;
    }

    ret = 0;
4049
 out:
4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061
    return ret;
}

/* The internal XML for host PCI device's original states:
 *
 * <origstates>
 *   <unbind/>
 *   <removeslot/>
 *   <reprobe/>
 * </origstates>
 */
static int
4062
virDomainHostdevSubsysPCIOrigStatesDefParseXML(xmlNodePtr node,
4063 4064 4065 4066 4067 4068 4069 4070
                                               virDomainHostdevOrigStatesPtr def)
{
    xmlNodePtr cur;
    cur = node->children;

    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
            if (xmlStrEqual(cur->name, BAD_CAST "unbind")) {
4071
                def->states.pci.unbind_from_stub = true;
4072
            } else if (xmlStrEqual(cur->name, BAD_CAST "removeslot")) {
4073
                def->states.pci.remove_slot = true;
4074
            } else if (xmlStrEqual(cur->name, BAD_CAST "reprobe")) {
4075
                def->states.pci.reprobe = true;
4076
            } else {
4077 4078 4079
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unsupported element '%s' of 'origstates'"),
                               cur->name);
4080 4081 4082 4083 4084 4085 4086 4087 4088 4089
                return -1;
            }
        }
        cur = cur->next;
    }

    return 0;
}

static int
4090
virDomainHostdevSubsysPCIDefParseXML(xmlNodePtr node,
4091 4092 4093 4094 4095 4096 4097 4098 4099 4100
                                     virDomainHostdevDefPtr def,
                                     unsigned int flags)
{
    int ret = -1;
    xmlNodePtr cur;

    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
            if (xmlStrEqual(cur->name, BAD_CAST "address")) {
4101
                virDevicePCIAddressPtr addr =
4102
                    &def->source.subsys.u.pci.addr;
4103

4104
                if (virDevicePCIAddressParseXML(cur, addr) < 0)
4105 4106 4107 4108 4109 4110 4111
                    goto out;
            } else if ((flags & VIR_DOMAIN_XML_INTERNAL_STATUS) &&
                       xmlStrEqual(cur->name, BAD_CAST "state")) {
                /* Legacy back-compat. Don't add any more attributes here */
                char *devaddr = virXMLPropString(cur, "devaddr");
                if (devaddr &&
                    virDomainParseLegacyDeviceAddress(devaddr,
4112
                                                      &def->info->addr.pci) < 0) {
4113 4114 4115
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Unable to parse devaddr parameter '%s'"),
                                   devaddr);
4116 4117 4118
                    VIR_FREE(devaddr);
                    goto out;
                }
4119
                def->info->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
4120 4121 4122
            } else if ((flags & VIR_DOMAIN_XML_INTERNAL_PCI_ORIG_STATES) &&
                       xmlStrEqual(cur->name, BAD_CAST "origstates")) {
                virDomainHostdevOrigStatesPtr states = &def->origstates;
4123
                if (virDomainHostdevSubsysPCIOrigStatesDefParseXML(cur, states) < 0)
4124 4125
                    goto out;
            } else {
4126 4127 4128
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unknown pci source type '%s'"),
                               cur->name);
4129 4130 4131 4132 4133 4134 4135
                goto out;
            }
        }
        cur = cur->next;
    }

    ret = 0;
4136
 out:
4137 4138 4139
    return ret;
}

4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212
static int
virDomainStorageHostParse(xmlNodePtr node,
                          virStorageNetHostDefPtr *hosts,
                          size_t *nhosts)
{
    int ret = -1;
    xmlNodePtr child;
    char *transport = NULL;
    virStorageNetHostDef host;

    memset(&host, 0, sizeof(host));

    child = node->children;
    while (child != NULL) {
        if (child->type == XML_ELEMENT_NODE &&
            xmlStrEqual(child->name, BAD_CAST "host")) {

            host.transport = VIR_STORAGE_NET_HOST_TRANS_TCP;

            /* transport can be tcp (default), unix or rdma.  */
            if ((transport = virXMLPropString(child, "transport"))) {
                host.transport = virStorageNetHostTransportTypeFromString(transport);
                if (host.transport < 0) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("unknown protocol transport type '%s'"),
                                   transport);
                    goto cleanup;
                }
            }

            host.socket = virXMLPropString(child, "socket");

            if (host.transport == VIR_STORAGE_NET_HOST_TRANS_UNIX &&
                host.socket == NULL) {
                virReportError(VIR_ERR_XML_ERROR, "%s",
                               _("missing socket for unix transport"));
                goto cleanup;
            }

            if (host.transport != VIR_STORAGE_NET_HOST_TRANS_UNIX &&
                host.socket != NULL) {
                virReportError(VIR_ERR_XML_ERROR,
                               _("transport '%s' does not support "
                                 "socket attribute"),
                               transport);
                goto cleanup;
            }

            VIR_FREE(transport);

            if (host.transport != VIR_STORAGE_NET_HOST_TRANS_UNIX) {
                if (!(host.name = virXMLPropString(child, "name"))) {
                    virReportError(VIR_ERR_XML_ERROR, "%s",
                                   _("missing name for host"));
                    goto cleanup;
                }

                host.port = virXMLPropString(child, "port");
            }

            if (VIR_APPEND_ELEMENT(*hosts, *nhosts, host) < 0)
                goto cleanup;
        }
        child = child->next;
    }
    ret = 0;

 cleanup:
    virStorageNetHostDefClear(&host);
    VIR_FREE(transport);
    return ret;
}

H
Han Cheng 已提交
4213
static int
4214 4215
virDomainHostdevSubsysSCSIHostDefParseXML(xmlNodePtr sourcenode,
                                          virDomainHostdevSubsysSCSIPtr scsisrc)
H
Han Cheng 已提交
4216 4217 4218 4219 4220
{
    int ret = -1;
    bool got_address = false, got_adapter = false;
    xmlNodePtr cur;
    char *bus = NULL, *target = NULL, *unit = NULL;
4221
    virDomainHostdevSubsysSCSIHostPtr scsihostsrc = &scsisrc->u.host;
H
Han Cheng 已提交
4222

4223
    cur = sourcenode->children;
H
Han Cheng 已提交
4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
            if (xmlStrEqual(cur->name, BAD_CAST "address")) {
                if (got_address) {
                    virReportError(VIR_ERR_XML_ERROR, "%s",
                                   _("more than one source addresses is "
                                     "specified for scsi hostdev"));
                    goto cleanup;
                }

                if (!(bus = virXMLPropString(cur, "bus")) ||
                    !(target = virXMLPropString(cur, "target")) ||
                    !(unit = virXMLPropString(cur, "unit"))) {
                    virReportError(VIR_ERR_XML_ERROR, "%s",
                                   _("'bus', 'target', and 'unit' must be specified "
                                     "for scsi hostdev source address"));
                    goto cleanup;
                }

4243
                if (virStrToLong_ui(bus, NULL, 0, &scsihostsrc->bus) < 0) {
H
Han Cheng 已提交
4244 4245 4246 4247 4248
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("cannot parse bus '%s'"), bus);
                    goto cleanup;
                }

4249 4250
                if (virStrToLong_ui(target, NULL, 0,
                                    &scsihostsrc->target) < 0) {
H
Han Cheng 已提交
4251 4252 4253 4254 4255
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("cannot parse target '%s'"), target);
                    goto cleanup;
                }

4256
                if (virStrToLong_ui(unit, NULL, 0, &scsihostsrc->unit) < 0) {
H
Han Cheng 已提交
4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("cannot parse unit '%s'"), unit);
                    goto cleanup;
                }

                got_address = true;
            } else if (xmlStrEqual(cur->name, BAD_CAST "adapter")) {
                if (got_adapter) {
                    virReportError(VIR_ERR_XML_ERROR, "%s",
                                   _("more than one adapters is specified "
                                     "for scsi hostdev source"));
                    goto cleanup;
                }
4270
                if (!(scsihostsrc->adapter = virXMLPropString(cur, "name"))) {
H
Han Cheng 已提交
4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294
                    virReportError(VIR_ERR_XML_ERROR, "%s",
                                   _("'adapter' must be specified for scsi hostdev source"));
                    goto cleanup;
                }

                got_adapter = true;
            } else {
                virReportError(VIR_ERR_XML_ERROR,
                               _("unsupported element '%s' of scsi hostdev source"),
                               cur->name);
                goto cleanup;
            }
        }
        cur = cur->next;
    }

    if (!got_address || !got_adapter) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("'adapter' and 'address' must be specified for scsi "
                         "hostdev source"));
        goto cleanup;
    }

    ret = 0;
4295
 cleanup:
H
Han Cheng 已提交
4296 4297 4298 4299 4300 4301
    VIR_FREE(bus);
    VIR_FREE(target);
    VIR_FREE(unit);
    return ret;
}

J
John Ferlan 已提交
4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 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
static int
virDomainHostdevSubsysSCSIiSCSIDefParseXML(xmlNodePtr sourcenode,
                                           virDomainHostdevSubsysSCSIPtr def)
{
    int ret = -1;
    int auth_secret_usage = -1;
    xmlNodePtr cur;
    virStorageAuthDefPtr authdef = NULL;
    virDomainHostdevSubsysSCSIiSCSIPtr iscsisrc = &def->u.iscsi;

    /* Similar to virDomainDiskSourceParse for a VIR_STORAGE_TYPE_NETWORK */

    if (!(iscsisrc->path = virXMLPropString(sourcenode, "name"))) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("missing iSCSI hostdev source path name"));
        goto cleanup;
    }

    if (virDomainStorageHostParse(sourcenode, &iscsisrc->hosts,
                                  &iscsisrc->nhosts) < 0)
        goto cleanup;

    if (iscsisrc->nhosts < 1) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("missing the host address for the iSCSI hostdev"));
        goto cleanup;
    }
    if (iscsisrc->nhosts > 1) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("only one source host address may be specified "
                         "for the iSCSI hostdev"));
        goto cleanup;
    }

    cur = sourcenode->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE &&
            xmlStrEqual(cur->name, BAD_CAST "auth")) {
            if (!(authdef = virStorageAuthDefParse(sourcenode->doc, cur)))
                goto cleanup;
            if ((auth_secret_usage =
                 virSecretUsageTypeFromString(authdef->secrettype)) < 0) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("invalid secret type %s"),
                               authdef->secrettype);
                goto cleanup;
            }
            if (auth_secret_usage != VIR_SECRET_USAGE_TYPE_ISCSI) {
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("hostdev invalid secret type '%s'"),
                               authdef->secrettype);
                goto cleanup;
            }
            iscsisrc->auth = authdef;
            authdef = NULL;
        }
        cur = cur->next;
    }
    ret = 0;

 cleanup:
    virStorageAuthDefFree(authdef);
    return ret;
}

4367 4368 4369 4370
static int
virDomainHostdevSubsysSCSIDefParseXML(xmlNodePtr sourcenode,
                                      virDomainHostdevSubsysSCSIPtr scsisrc)
{
J
John Ferlan 已提交
4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392
    char *protocol = NULL;
    int ret = -1;

    if ((protocol = virXMLPropString(sourcenode, "protocol"))) {
        scsisrc->protocol =
            virDomainHostdevSubsysSCSIProtocolTypeFromString(protocol);
        if (scsisrc->protocol < 0) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unknown SCSI subsystem protocol '%s'"),
                           protocol);
            goto cleanup;
        }
    }

    if (scsisrc->protocol == VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_ISCSI)
        ret = virDomainHostdevSubsysSCSIiSCSIDefParseXML(sourcenode, scsisrc);
    else
        ret = virDomainHostdevSubsysSCSIHostDefParseXML(sourcenode, scsisrc);

 cleanup:
    VIR_FREE(protocol);
    return ret;
4393 4394
}

4395 4396 4397 4398
/* Check if a drive type address $controller:0:0:$unit is already
 * taken by a disk or not.
 */
static bool
4399
virDomainDriveAddressIsUsedByDisk(const virDomainDef *def,
4400
                                  virDomainDiskBus type,
4401 4402 4403 4404
                                  unsigned int controller,
                                  unsigned int unit)
{
    virDomainDiskDefPtr disk;
4405
    size_t i;
4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427

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

        if (disk->bus != type ||
            disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE)
            continue;

        if (disk->info.addr.drive.controller == controller &&
            disk->info.addr.drive.unit == unit &&
            disk->info.addr.drive.bus == 0 &&
            disk->info.addr.drive.target == 0)
            return true;
    }

    return false;
}

/* Check if a drive type address $controller:0:0:$unit is already
 * taken by a host device or not.
 */
static bool
4428
virDomainDriveAddressIsUsedByHostdev(const virDomainDef *def,
4429
                                     virDomainHostdevSubsysType type,
4430 4431 4432 4433
                                     unsigned int controller,
                                     unsigned int unit)
{
    virDomainHostdevDefPtr hostdev;
4434
    size_t i;
4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452

    for (i = 0; i < def->nhostdevs; i++) {
        hostdev = def->hostdevs[i];

        if (hostdev->source.subsys.type != type)
            continue;

        if (hostdev->info->addr.drive.controller == controller &&
            hostdev->info->addr.drive.unit == unit &&
            hostdev->info->addr.drive.bus == 0 &&
            hostdev->info->addr.drive.target == 0)
            return true;
    }

    return false;
}

static bool
4453
virDomainSCSIDriveAddressIsUsed(const virDomainDef *def,
4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473
                                unsigned int controller,
                                unsigned int unit)
{
    /* In current implementation, the maximum unit number of a controller
     * is either 16 or 7 (narrow SCSI bus), and if the maximum unit number
     * is 16, the controller itself is on unit 7 */
    if (unit == 7)
        return true;

    if (virDomainDriveAddressIsUsedByDisk(def, VIR_DOMAIN_DISK_BUS_SCSI,
                                          controller, unit) ||
        virDomainDriveAddressIsUsedByHostdev(def, VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI,
                                             controller, unit))
        return true;

    return false;
}

/* Find out the next usable "unit" of a specific controller */
static int
4474
virDomainControllerSCSINextUnit(const virDomainDef *def,
4475 4476 4477
                                unsigned int max_unit,
                                unsigned int controller)
{
4478
    size_t i;
4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492

    for (i = 0; i < max_unit; i++) {
        if (!virDomainSCSIDriveAddressIsUsed(def, controller, i))
            return i;
    }

    return -1;
}

#define SCSI_WIDE_BUS_MAX_CONT_UNIT 16
#define SCSI_NARROW_BUS_MAX_CONT_UNIT 7

static int
virDomainHostdevAssignAddress(virDomainXMLOptionPtr xmlopt,
4493
                              const virDomainDef *def,
4494 4495
                              virDomainHostdevDefPtr hostdev)
{
4496 4497
    int next_unit = 0;
    unsigned controller = 0;
4498
    size_t i;
4499
    int ret;
4500 4501 4502 4503

    if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI)
        return -1;

4504
    for (i = 0; i < def->ncontrollers; i++) {
4505 4506 4507
        if (def->controllers[i]->type != VIR_DOMAIN_CONTROLLER_TYPE_SCSI)
            continue;

4508 4509
        controller++;
        ret = virDomainControllerSCSINextUnit(def,
4510
                                              xmlopt->config.hasWideSCSIBus ?
4511 4512 4513 4514 4515 4516 4517 4518
                                              SCSI_WIDE_BUS_MAX_CONT_UNIT :
                                              SCSI_NARROW_BUS_MAX_CONT_UNIT,
                                              def->controllers[i]->idx);
        if (ret >= 0) {
            next_unit = ret;
            controller = def->controllers[i]->idx;
            break;
        }
4519 4520 4521
    }

    hostdev->info->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE;
4522
    hostdev->info->addr.drive.controller = controller;
4523 4524
    hostdev->info->addr.drive.bus = 0;
    hostdev->info->addr.drive.target = 0;
4525
    hostdev->info->addr.drive.unit = next_unit;
4526 4527 4528 4529

    return 0;
}

4530
static int
4531 4532 4533 4534 4535
virDomainHostdevDefParseXMLSubsys(xmlNodePtr node,
                                  xmlXPathContextPtr ctxt,
                                  const char *type,
                                  virDomainHostdevDefPtr def,
                                  unsigned int flags)
4536 4537 4538
{
    xmlNodePtr sourcenode;
    char *managed = NULL;
O
Osier Yang 已提交
4539
    char *sgio = NULL;
4540
    char *rawio = NULL;
4541 4542
    char *backendStr = NULL;
    int backend;
4543
    int ret = -1;
4544
    virDomainHostdevSubsysPCIPtr pcisrc = &def->source.subsys.u.pci;
4545
    virDomainHostdevSubsysSCSIPtr scsisrc = &def->source.subsys.u.scsi;
4546 4547 4548 4549 4550 4551

    /* @managed can be read from the xml document - it is always an
     * attribute of the toplevel element, no matter what type of
     * element that might be (pure hostdev, or higher level device
     * (e.g. <interface>) with type='hostdev')
     */
C
Chen Fan 已提交
4552
    if ((managed = virXMLPropString(node, "managed")) != NULL) {
4553
        if (STREQ(managed, "yes"))
4554
            def->managed = true;
4555 4556
    }

O
Osier Yang 已提交
4557
    sgio = virXMLPropString(node, "sgio");
4558
    rawio = virXMLPropString(node, "rawio");
O
Osier Yang 已提交
4559

4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570
    /* @type is passed in from the caller rather than read from the
     * xml document, because it is specified in different places for
     * different kinds of defs - it is an attribute of
     * <source>/<address> for an intelligent hostdev (<interface>),
     * but an attribute of the toplevel element for a standard
     * <hostdev>.  (the functions we're going to call expect address
     * type to already be known).
     */
    if (type) {
        if ((def->source.subsys.type
             = virDomainHostdevSubsysTypeFromString(type)) < 0) {
4571
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
4572 4573
                           _("unknown host device source address type '%s'"),
                           type);
4574 4575 4576
            goto error;
        }
    } else {
4577 4578
        virReportError(VIR_ERR_XML_ERROR,
                       "%s", _("missing source address type"));
4579 4580 4581 4582
        goto error;
    }

    if (!(sourcenode = virXPathNode("./source", ctxt))) {
4583 4584
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Missing <source> element in hostdev device"));
4585 4586
        goto error;
    }
4587 4588 4589 4590 4591 4592 4593 4594 4595

    if (def->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB &&
        virXPathBoolean("boolean(./source/@startupPolicy)", ctxt)) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Setting startupPolicy is only allowed for USB"
                         " devices"));
        goto error;
    }

O
Osier Yang 已提交
4596
    if (sgio) {
4597
        if (def->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI) {
O
Osier Yang 已提交
4598 4599 4600 4601 4602
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("sgio is only supported for scsi host device"));
            goto error;
        }

4603
        if ((scsisrc->sgio = virDomainDeviceSGIOTypeFromString(sgio)) <= 0) {
4604
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
O
Osier Yang 已提交
4605 4606 4607 4608 4609
                           _("unknown sgio mode '%s'"), sgio);
            goto error;
        }
    }

4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624
    if (rawio) {
        if (def->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("rawio is only supported for scsi host device"));
            goto error;
        }

        if ((scsisrc->rawio = virTristateBoolTypeFromString(rawio)) <= 0) {
            virReportError(VIR_ERR_XML_ERROR,
                           _("unknown hostdev rawio setting '%s'"),
                           rawio);
            goto error;
        }
    }

4625 4626
    switch (def->source.subsys.type) {
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
4627
        if (virDomainHostdevSubsysPCIDefParseXML(sourcenode, def, flags) < 0)
4628
            goto error;
4629

4630
        backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT;
4631
        if ((backendStr = virXPathString("string(./driver/@name)", ctxt)) &&
4632
            (((backend = virDomainHostdevSubsysPCIBackendTypeFromString(backendStr)) < 0) ||
4633
             backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT)) {
4634
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
4635 4636 4637 4638
                           _("Unknown PCI device <driver name='%s'/> "
                             "has been specified"), backendStr);
            goto error;
        }
4639
        pcisrc->backend = backend;
4640

4641
        break;
4642

4643
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
4644
        if (virDomainHostdevSubsysUSBDefParseXML(sourcenode, def) < 0)
4645 4646
            goto error;
        break;
H
Han Cheng 已提交
4647 4648

    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
4649
        if (virDomainHostdevSubsysSCSIDefParseXML(sourcenode, scsisrc) < 0)
H
Han Cheng 已提交
4650 4651 4652
            goto error;
        break;

4653
    default:
4654 4655 4656
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("address type='%s' not supported in hostdev interfaces"),
                       virDomainHostdevSubsysTypeToString(def->source.subsys.type));
4657 4658
        goto error;
    }
4659

4660
    ret = 0;
4661
 error:
4662
    VIR_FREE(managed);
O
Osier Yang 已提交
4663
    VIR_FREE(sgio);
4664
    VIR_FREE(rawio);
4665
    VIR_FREE(backendStr);
4666 4667 4668
    return ret;
}

4669 4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688
static int
virDomainHostdevDefParseXMLCaps(xmlNodePtr node ATTRIBUTE_UNUSED,
                                xmlXPathContextPtr ctxt,
                                const char *type,
                                virDomainHostdevDefPtr def)
{
    xmlNodePtr sourcenode;
    int ret = -1;

    /* @type is passed in from the caller rather than read from the
     * xml document, because it is specified in different places for
     * different kinds of defs - it is an attribute of
     * <source>/<address> for an intelligent hostdev (<interface>),
     * but an attribute of the toplevel element for a standard
     * <hostdev>.  (the functions we're going to call expect address
     * type to already be known).
     */
    if (type) {
        if ((def->source.caps.type
             = virDomainHostdevCapsTypeFromString(type)) < 0) {
4689
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722
                           _("unknown host device source address type '%s'"),
                           type);
            goto error;
        }
    } else {
        virReportError(VIR_ERR_XML_ERROR,
                       "%s", _("missing source address type"));
        goto error;
    }

    if (!(sourcenode = virXPathNode("./source", ctxt))) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Missing <source> element in hostdev device"));
        goto error;
    }

    switch (def->source.caps.type) {
    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_STORAGE:
        if (!(def->source.caps.u.storage.block =
              virXPathString("string(./source/block[1])", ctxt))) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("Missing <block> element in hostdev storage device"));
            goto error;
        }
        break;
    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_MISC:
        if (!(def->source.caps.u.misc.chardev =
              virXPathString("string(./source/char[1])", ctxt))) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("Missing <char> element in hostdev character device"));
            goto error;
        }
        break;
4723 4724 4725 4726 4727 4728 4729 4730
    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_NET:
        if (!(def->source.caps.u.net.iface =
              virXPathString("string(./source/interface[1])", ctxt))) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("Missing <interface> element in hostdev net device"));
            goto error;
        }
        break;
4731 4732 4733 4734 4735 4736 4737
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("address type='%s' not supported in hostdev interfaces"),
                       virDomainHostdevCapsTypeToString(def->source.caps.type));
        goto error;
    }
    ret = 0;
4738
 error:
4739 4740 4741
    return ret;
}

4742
int
H
Han Cheng 已提交
4743 4744 4745
virDomainDeviceFindControllerModel(virDomainDefPtr def,
                                   virDomainDeviceInfoPtr info,
                                   int controllerType)
4746 4747
{
    int model = -1;
4748
    size_t i;
4749 4750 4751

    for (i = 0; i < def->ncontrollers; i++) {
        if (def->controllers[i]->type == controllerType &&
H
Han Cheng 已提交
4752
            def->controllers[i]->idx == info->addr.drive.controller)
4753 4754 4755 4756 4757 4758
            model = def->controllers[i]->model;
    }

    return model;
}

4759 4760 4761 4762 4763
virDomainDiskDefPtr
virDomainDiskFindByBusAndDst(virDomainDefPtr def,
                             int bus,
                             char *dst)
{
4764
    size_t i;
4765 4766 4767 4768

    if (!dst)
        return NULL;

4769
    for (i = 0; i < def->ndisks; i++) {
4770 4771 4772 4773 4774 4775 4776 4777 4778
        if (def->disks[i]->bus == bus &&
            STREQ(def->disks[i]->dst, dst)) {
            return def->disks[i];
        }
    }

    return NULL;
}

4779
int
4780 4781
virDomainDiskDefAssignAddress(virDomainXMLOptionPtr xmlopt,
                              virDomainDiskDefPtr def)
4782 4783
{
    int idx = virDiskNameToIndex(def->dst);
4784 4785 4786 4787
    if (idx < 0) {
        virReportError(VIR_ERR_XML_ERROR,
                       _("Unknown disk name '%s' and no address specified"),
                       def->dst);
4788
        return -1;
4789
    }
4790 4791 4792 4793

    switch (def->bus) {
    case VIR_DOMAIN_DISK_BUS_SCSI:
        def->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE;
4794

4795
        if (xmlopt->config.hasWideSCSIBus) {
4796 4797 4798 4799 4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816
            /* 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;
        }

4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827
        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;

J
Jim Fehlig 已提交
4828 4829 4830 4831 4832 4833 4834 4835 4836
    case VIR_DOMAIN_DISK_BUS_SATA:
        /* For SATA we define the default mapping to be 6 units
         * per bus, 1 bus per controller, many controllers */
        def->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE;
        def->info.addr.drive.controller = idx / 6;
        def->info.addr.drive.bus = 0;
        def->info.addr.drive.unit = idx % 6;
        break;

4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849
    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;
    }
4850 4851

    return 0;
4852 4853
}

4854 4855
static virSecurityLabelDefPtr
virSecurityLabelDefParseXML(xmlXPathContextPtr ctxt,
4856
                            unsigned int flags)
E
Eric Blake 已提交
4857 4858
{
    char *p;
4859
    virSecurityLabelDefPtr seclabel = NULL;
E
Eric Blake 已提交
4860

4861 4862 4863 4864
    p = virXPathStringLimit("string(./@model)",
                            VIR_SECURITY_MODEL_BUFLEN - 1, ctxt);

    if (!(seclabel = virSecurityLabelDefNew(p)))
4865
        goto error;
4866
    VIR_FREE(p);
E
Eric Blake 已提交
4867

4868 4869 4870
    /* set default value */
    seclabel->type = VIR_DOMAIN_SECLABEL_DYNAMIC;

4871
    p = virXPathStringLimit("string(./@type)",
4872 4873 4874 4875
                            VIR_SECURITY_LABEL_BUFLEN - 1, ctxt);
    if (p) {
        seclabel->type = virDomainSeclabelTypeFromString(p);
        if (seclabel->type <= 0) {
4876
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
4877
                           _("invalid security type '%s'"), p);
E
Eric Blake 已提交
4878 4879
            goto error;
        }
4880
    }
4881

4882 4883 4884 4885 4886
    if (seclabel->type == VIR_DOMAIN_SECLABEL_STATIC ||
        seclabel->type == VIR_DOMAIN_SECLABEL_NONE)
        seclabel->relabel = false;

    VIR_FREE(p);
4887
    p = virXPathStringLimit("string(./@relabel)",
E
Eric Blake 已提交
4888
                            VIR_SECURITY_LABEL_BUFLEN-1, ctxt);
4889
    if (p) {
E
Eric Blake 已提交
4890
        if (STREQ(p, "yes")) {
4891
            seclabel->relabel = true;
E
Eric Blake 已提交
4892
        } else if (STREQ(p, "no")) {
4893
            seclabel->relabel = false;
E
Eric Blake 已提交
4894
        } else {
4895 4896
            virReportError(VIR_ERR_XML_ERROR,
                           _("invalid security relabel value %s"), p);
4897
            goto error;
E
Eric Blake 已提交
4898 4899
        }
    }
4900
    VIR_FREE(p);
E
Eric Blake 已提交
4901

4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913
    if (seclabel->type == VIR_DOMAIN_SECLABEL_DYNAMIC &&
        !seclabel->relabel) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       "%s", _("dynamic label type must use resource relabeling"));
        goto error;
    }
    if (seclabel->type == VIR_DOMAIN_SECLABEL_NONE &&
        seclabel->relabel) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       "%s", _("resource relabeling is not compatible with 'none' label type"));
        goto error;
    }
4914 4915 4916 4917

    /* For the model 'none' none of the following labels is going to be
     * present. Hence, return now. */

4918
    if (STREQ_NULLABLE(seclabel->model, "none")) {
4919 4920
        if (flags & VIR_DOMAIN_XML_INACTIVE) {
            /* Fix older configurations */
4921 4922
            seclabel->type = VIR_DOMAIN_SECLABEL_NONE;
            seclabel->relabel = false;
4923
        } else {
4924
            if (seclabel->type != VIR_DOMAIN_SECLABEL_NONE) {
4925 4926
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("unsupported type='%s' to model 'none'"),
4927
                               virDomainSeclabelTypeToString(seclabel->type));
4928 4929 4930 4931 4932
                goto error;
            }
            /* combination of relabel='yes' and type='static'
             * is checked a few lines above. */
        }
4933
        return seclabel;
4934
    }
4935

E
Eric Blake 已提交
4936
    /* Only parse label, if using static labels, or
4937
     * if the 'live' VM XML is requested
E
Eric Blake 已提交
4938
     */
4939
    if (seclabel->type == VIR_DOMAIN_SECLABEL_STATIC ||
E
Eric Blake 已提交
4940
        (!(flags & VIR_DOMAIN_XML_INACTIVE) &&
4941
         seclabel->type != VIR_DOMAIN_SECLABEL_NONE)) {
4942
        p = virXPathStringLimit("string(./label[1])",
E
Eric Blake 已提交
4943
                                VIR_SECURITY_LABEL_BUFLEN-1, ctxt);
4944
        if (p == NULL) {
4945 4946
            virReportError(VIR_ERR_XML_ERROR,
                           "%s", _("security label is missing"));
4947
            goto error;
E
Eric Blake 已提交
4948 4949
        }

4950
        seclabel->label = p;
4951
        p = NULL;
E
Eric Blake 已提交
4952 4953 4954
    }

    /* Only parse imagelabel, if requested live XML with relabeling */
4955
    if (seclabel->relabel &&
E
Eric Blake 已提交
4956
        (!(flags & VIR_DOMAIN_XML_INACTIVE) &&
4957
         seclabel->type != VIR_DOMAIN_SECLABEL_NONE)) {
4958
        p = virXPathStringLimit("string(./imagelabel[1])",
E
Eric Blake 已提交
4959 4960
                                VIR_SECURITY_LABEL_BUFLEN-1, ctxt);
        if (p == NULL) {
4961 4962
            virReportError(VIR_ERR_XML_ERROR,
                           "%s", _("security imagelabel is missing"));
E
Eric Blake 已提交
4963 4964
            goto error;
        }
4965
        seclabel->imagelabel = p;
4966
        p = NULL;
E
Eric Blake 已提交
4967 4968
    }

E
Eric Blake 已提交
4969
    /* Only parse baselabel for dynamic label type */
4970
    if (seclabel->type == VIR_DOMAIN_SECLABEL_DYNAMIC) {
4971
        p = virXPathStringLimit("string(./baselabel[1])",
E
Eric Blake 已提交
4972
                                VIR_SECURITY_LABEL_BUFLEN-1, ctxt);
4973
        seclabel->baselabel = p;
4974
        p = NULL;
E
Eric Blake 已提交
4975 4976
    }

4977
    return seclabel;
E
Eric Blake 已提交
4978

4979
 error:
4980 4981
    VIR_FREE(p);
    virSecurityLabelDefFree(seclabel);
4982
    return NULL;
E
Eric Blake 已提交
4983 4984
}

4985
static int
4986
virSecurityLabelDefsParseXML(virDomainDefPtr def,
4987 4988 4989
                             xmlXPathContextPtr ctxt,
                             virCapsPtr caps,
                             unsigned int flags)
4990
{
4991
    size_t i = 0, j;
4992
    int n;
4993
    xmlNodePtr *list = NULL, saved_node;
4994
    virCapsHostPtr host = &caps->host;
4995

4996 4997 4998 4999
    /* Check args and save context */
    if (def == NULL || ctxt == NULL)
        return 0;
    saved_node = ctxt->node;
5000

5001
    /* Allocate a security labels based on XML */
5002 5003 5004
    if ((n = virXPathNodeSet("./seclabel", ctxt, &list)) < 0)
        goto error;
    if (n == 0)
5005 5006
        return 0;

5007
    if (VIR_ALLOC_N(def->seclabels, n) < 0)
5008
        goto error;
5009

5010 5011
    /* Parse each "seclabel" tag */
    for (i = 0; i < n; i++) {
5012 5013
        virSecurityLabelDefPtr seclabel;

5014
        ctxt->node = list[i];
5015
        if (!(seclabel = virSecurityLabelDefParseXML(ctxt, flags)))
5016
            goto error;
5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028

        for (j = 0; j < i; j++) {
            if (STREQ_NULLABLE(seclabel->model, def->seclabels[j]->model)) {
                virReportError(VIR_ERR_XML_DETAIL,
                               _("seclablel for model %s is already provided"),
                               seclabel->model);
                virSecurityLabelDefFree(seclabel);
                goto error;
            }
        }

        def->seclabels[i] = seclabel;
5029
    }
5030 5031 5032
    def->nseclabels = n;
    ctxt->node = saved_node;
    VIR_FREE(list);
5033

5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 5049 5050
    /* libvirt versions prior to 0.10.0 support just a single seclabel element
     * in guest's XML and model attribute can be suppressed if type is none or
     * type is dynamic, baselabel is not defined and INACTIVE flag is set.
     *
     * To avoid compatibility issues, for this specific case the first model
     * defined in host's capabilities is used as model for the seclabel.
     */
    if (def->nseclabels == 1 &&
        !def->seclabels[0]->model &&
        host->nsecModels > 0) {
        if (def->seclabels[0]->type == VIR_DOMAIN_SECLABEL_NONE ||
            (def->seclabels[0]->type == VIR_DOMAIN_SECLABEL_DYNAMIC &&
             !def->seclabels[0]->baselabel &&
             (flags & VIR_DOMAIN_XML_INACTIVE))) {
            /* Copy model from host. */
            VIR_DEBUG("Found seclabel without a model, using '%s'",
                      host->secModels[0].model);
5051
            if (VIR_STRDUP(def->seclabels[0]->model, host->secModels[0].model) < 0)
5052
                goto error;
5053 5054 5055 5056 5057 5058 5059

            if (STREQ(def->seclabels[0]->model, "none") &&
                flags & VIR_DOMAIN_XML_INACTIVE) {
                /* Fix older configurations */
                def->seclabels[0]->type = VIR_DOMAIN_SECLABEL_NONE;
                def->seclabels[0]->relabel = false;
            }
5060 5061 5062 5063 5064 5065 5066 5067 5068
        } else {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("missing security model in domain seclabel"));
            goto error;
        }
    }

    /* Checking missing model information */
    if (def->nseclabels > 1) {
5069
        for (; n; n--) {
5070 5071
            if (def->seclabels[n - 1]->model == NULL) {
                virReportError(VIR_ERR_XML_ERROR, "%s",
5072 5073
                               _("missing security model "
                                 "when using multiple labels"));
5074 5075
                goto error;
            }
5076 5077
        }
    }
5078

5079
    return 0;
5080

5081
 error:
5082 5083 5084 5085 5086
    ctxt->node = saved_node;
    for (; i > 0; i--) {
        virSecurityLabelDefFree(def->seclabels[i - 1]);
    }
    VIR_FREE(def->seclabels);
5087
    def->nseclabels = 0;
5088 5089 5090
    VIR_FREE(list);
    return -1;
}
5091

5092
/* Parse the <seclabel> from a disk or character device. */
5093
static int
5094 5095
virSecurityDeviceLabelDefParseXML(virSecurityDeviceLabelDefPtr **seclabels_rtn,
                                  size_t *nseclabels_rtn,
5096
                                  virSecurityLabelDefPtr *vmSeclabels,
5097 5098
                                  int nvmSeclabels, xmlXPathContextPtr ctxt,
                                  unsigned int flags)
5099
{
5100
    virSecurityDeviceLabelDefPtr *seclabels = NULL;
5101
    size_t nseclabels = 0;
5102 5103
    int n;
    size_t i, j;
5104 5105
    xmlNodePtr *list = NULL;
    virSecurityLabelDefPtr vmDef = NULL;
5106
    char *model, *relabel, *label, *labelskip;
5107

5108 5109 5110
    if ((n = virXPathNodeSet("./seclabel", ctxt, &list)) < 0)
        goto error;
    if (n == 0)
5111 5112
        return 0;

5113
    if (VIR_ALLOC_N(seclabels, n) < 0)
5114
        goto error;
5115
    nseclabels = n;
5116
    for (i = 0; i < n; i++) {
5117
        if (VIR_ALLOC(seclabels[i]) < 0)
5118
            goto error;
5119 5120
    }

5121 5122 5123
    for (i = 0; i < n; i++) {
        /* get model associated to this override */
        model = virXMLPropString(list[i], "model");
5124 5125
        if (model) {
            /* find the security label that it's being overridden */
5126 5127 5128 5129 5130 5131
            for (j = 0; j < nvmSeclabels; j++) {
                if (STREQ(vmSeclabels[j]->model, model)) {
                    vmDef = vmSeclabels[j];
                    break;
                }
            }
5132
            seclabels[i]->model = model;
5133 5134 5135
        }

        /* Can't use overrides if top-level doesn't allow relabeling.  */
5136
        if (vmDef && !vmDef->relabel) {
5137 5138 5139 5140 5141 5142 5143 5144 5145
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("label overrides require relabeling to be "
                             "enabled at the domain level"));
            goto error;
        }

        relabel = virXMLPropString(list[i], "relabel");
        if (relabel != NULL) {
            if (STREQ(relabel, "yes")) {
5146
                seclabels[i]->relabel = true;
5147
            } else if (STREQ(relabel, "no")) {
5148
                seclabels[i]->relabel = false;
5149 5150 5151 5152 5153 5154 5155 5156 5157
            } else {
                virReportError(VIR_ERR_XML_ERROR,
                               _("invalid security relabel value %s"),
                               relabel);
                VIR_FREE(relabel);
                goto error;
            }
            VIR_FREE(relabel);
        } else {
5158
            seclabels[i]->relabel = true;
5159 5160
        }

5161 5162 5163 5164 5165 5166 5167
        /* labelskip is only parsed on live images */
        labelskip = virXMLPropString(list[i], "labelskip");
        seclabels[i]->labelskip = false;
        if (labelskip && !(flags & VIR_DOMAIN_XML_INACTIVE))
            seclabels[i]->labelskip = STREQ(labelskip, "yes");
        VIR_FREE(labelskip);

5168 5169 5170
        ctxt->node = list[i];
        label = virXPathStringLimit("string(./label)",
                                    VIR_SECURITY_LABEL_BUFLEN-1, ctxt);
5171
        seclabels[i]->label = label;
5172

5173
        if (label && !seclabels[i]->relabel) {
5174 5175 5176
            virReportError(VIR_ERR_XML_ERROR,
                           _("Cannot specify a label if relabelling is "
                             "turned off. model=%s"),
5177
                             NULLSTR(seclabels[i]->model));
5178 5179 5180 5181
            goto error;
        }
    }
    VIR_FREE(list);
5182 5183 5184 5185

    *nseclabels_rtn = nseclabels;
    *seclabels_rtn = seclabels;

5186
    return 0;
5187

5188
 error:
5189 5190
    for (i = 0; i < nseclabels; i++) {
        virSecurityDeviceLabelDefFree(seclabels[i]);
5191
    }
5192
    VIR_FREE(seclabels);
5193 5194
    VIR_FREE(list);
    return -1;
5195 5196 5197
}


5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 5209
/* Parse the XML definition for a lease
 */
static virDomainLeaseDefPtr
virDomainLeaseDefParseXML(xmlNodePtr node)
{
    virDomainLeaseDefPtr def;
    xmlNodePtr cur;
    char *lockspace = NULL;
    char *key = NULL;
    char *path = NULL;
    char *offset = NULL;

5210
    if (VIR_ALLOC(def) < 0)
5211 5212 5213 5214 5215
        return NULL;

    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
E
Eric Blake 已提交
5216
            if (!key && xmlStrEqual(cur->name, BAD_CAST "key")) {
5217
                key = (char *)xmlNodeGetContent(cur);
E
Eric Blake 已提交
5218 5219
            } else if (!lockspace &&
                       xmlStrEqual(cur->name, BAD_CAST "lockspace")) {
5220
                lockspace = (char *)xmlNodeGetContent(cur);
E
Eric Blake 已提交
5221 5222
            } else if (!path &&
                       xmlStrEqual(cur->name, BAD_CAST "target")) {
5223 5224 5225 5226 5227 5228 5229 5230
                path = virXMLPropString(cur, "path");
                offset = virXMLPropString(cur, "offset");
            }
        }
        cur = cur->next;
    }

    if (!key) {
5231 5232
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Missing 'key' element for lease"));
5233 5234 5235
        goto error;
    }
    if (!path) {
5236 5237
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Missing 'target' element for lease"));
5238 5239 5240 5241 5242
        goto error;
    }

    if (offset &&
        virStrToLong_ull(offset, NULL, 10, &def->offset) < 0) {
5243 5244
        virReportError(VIR_ERR_XML_ERROR,
                       _("Malformed lease target offset %s"), offset);
5245 5246 5247 5248 5249 5250 5251 5252
        goto error;
    }

    def->key = key;
    def->lockspace = lockspace;
    def->path = path;
    path = key = lockspace = NULL;

5253
 cleanup:
5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264 5265 5266
    VIR_FREE(lockspace);
    VIR_FREE(key);
    VIR_FREE(path);
    VIR_FREE(offset);

    return def;

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

5267 5268
static int
virDomainDiskSourcePoolDefParse(xmlNodePtr node,
5269
                                virStorageSourcePoolDefPtr *srcpool)
5270
{
5271
    char *mode = NULL;
5272
    virStorageSourcePoolDefPtr source;
5273 5274
    int ret = -1;

5275 5276 5277 5278 5279 5280 5281
    *srcpool = NULL;

    if (VIR_ALLOC(source) < 0)
        return -1;

    source->pool = virXMLPropString(node, "pool");
    source->volume = virXMLPropString(node, "volume");
5282
    mode = virXMLPropString(node, "mode");
5283 5284

    /* CD-ROM and Floppy allows no source */
5285 5286 5287 5288
    if (!source->pool && !source->volume) {
        ret = 0;
        goto cleanup;
    }
5289

5290
    if (!source->pool || !source->volume) {
5291 5292 5293 5294 5295 5296
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("'pool' and 'volume' must be specified together "
                         "for 'pool' type source"));
        goto cleanup;
    }

5297
    if (mode &&
5298
        (source->mode = virStorageSourcePoolModeTypeFromString(mode)) <= 0) {
5299
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
5300 5301 5302 5303 5304
                       _("unknown source mode '%s' for volume type disk"),
                       mode);
        goto cleanup;
    }

5305 5306
    *srcpool = source;
    source = NULL;
5307 5308
    ret = 0;

5309
 cleanup:
5310
    virStorageSourcePoolDefFree(source);
5311
    VIR_FREE(mode);
5312 5313 5314
    return ret;
}

5315

5316
int
5317 5318
virDomainDiskSourceParse(xmlNodePtr node,
                         virStorageSourcePtr src)
5319 5320
{
    int ret = -1;
5321
    char *protocol = NULL;
5322

5323
    switch ((virStorageType)src->type) {
E
Eric Blake 已提交
5324
    case VIR_STORAGE_TYPE_FILE:
5325
        src->path = virXMLPropString(node, "file");
5326
        break;
E
Eric Blake 已提交
5327
    case VIR_STORAGE_TYPE_BLOCK:
5328
        src->path = virXMLPropString(node, "dev");
5329
        break;
E
Eric Blake 已提交
5330
    case VIR_STORAGE_TYPE_DIR:
5331
        src->path = virXMLPropString(node, "dir");
5332
        break;
E
Eric Blake 已提交
5333
    case VIR_STORAGE_TYPE_NETWORK:
5334 5335 5336 5337
        if (!(protocol = virXMLPropString(node, "protocol"))) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("missing network source protocol type"));
            goto cleanup;
5338
        }
5339

5340
        if ((src->protocol = virStorageNetProtocolTypeFromString(protocol)) <= 0) {
5341
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
5342 5343
                           _("unknown protocol type '%s'"), protocol);
            goto cleanup;
5344 5345
        }

5346 5347
        if (!(src->path = virXMLPropString(node, "name")) &&
            src->protocol != VIR_STORAGE_NET_PROTOCOL_NBD) {
5348
            virReportError(VIR_ERR_XML_ERROR, "%s",
5349
                           _("missing name for disk source"));
5350
            goto cleanup;
5351
        }
5352

5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373
        /* for historical reasons the volume name for gluster volume is stored
         * as a part of the path. This is hard to work with when dealing with
         * relative names. Split out the volume into a separate variable */
        if (src->path && src->protocol == VIR_STORAGE_NET_PROTOCOL_GLUSTER) {
            char *tmp;
            if (!(tmp = strchr(src->path, '/')) ||
                tmp == src->path) {
                virReportError(VIR_ERR_XML_ERROR,
                               _("missing volume name or file name in "
                                 "gluster source path '%s'"), src->path);
                goto cleanup;
            }

            src->volume = src->path;

            if (VIR_STRDUP(src->path, tmp) < 0)
                goto cleanup;

            tmp[0] = '\0';
        }

5374 5375
        if (virDomainStorageHostParse(node, &src->hosts, &src->nhosts) < 0)
            goto cleanup;
5376
        break;
E
Eric Blake 已提交
5377
    case VIR_STORAGE_TYPE_VOLUME:
5378
        if (virDomainDiskSourcePoolDefParse(node, &src->srcpool) < 0)
5379
            goto cleanup;
5380
        break;
5381 5382
    case VIR_STORAGE_TYPE_NONE:
    case VIR_STORAGE_TYPE_LAST:
5383 5384
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected disk type %s"),
5385
                       virStorageTypeToString(src->type));
5386
        goto cleanup;
5387 5388
    }

5389 5390 5391
    /* People sometimes pass a bogus '' source path when they mean to omit the
     * source element completely (e.g. CDROM without media). This is just a
     * little compatibility check to help those broken apps */
5392 5393
    if (src->path && !*src->path)
        VIR_FREE(src->path);
5394 5395 5396

    ret = 0;

5397
 cleanup:
5398 5399 5400 5401 5402
    VIR_FREE(protocol);
    return ret;
}


5403 5404 5405 5406 5407 5408 5409 5410 5411 5412 5413 5414 5415 5416 5417 5418 5419 5420 5421 5422 5423 5424 5425 5426 5427 5428
static int
virDomainDiskBackingStoreParse(xmlXPathContextPtr ctxt,
                               virStorageSourcePtr src)
{
    virStorageSourcePtr backingStore = NULL;
    xmlNodePtr save_ctxt = ctxt->node;
    xmlNodePtr source;
    char *type = NULL;
    char *format = NULL;
    int ret = -1;

    if (!(ctxt->node = virXPathNode("./backingStore[*]", ctxt))) {
        ret = 0;
        goto cleanup;
    }

    if (VIR_ALLOC(backingStore) < 0)
        goto cleanup;

    if (!(type = virXMLPropString(ctxt->node, "type"))) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("missing disk backing store type"));
        goto cleanup;
    }

    backingStore->type = virStorageTypeFromString(type);
5429
    if (backingStore->type <= 0) {
5430 5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("unknown disk backing store type '%s'"), type);
        goto cleanup;
    }

    if (!(format = virXPathString("string(./format/@type)", ctxt))) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("missing disk backing store format"));
        goto cleanup;
    }

    backingStore->format = virStorageFileFormatTypeFromString(format);
5442
    if (backingStore->format <= 0) {
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
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("unknown disk backing store format '%s'"), format);
        goto cleanup;
    }

    if (!(source = virXPathNode("./source", ctxt))) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("missing disk backing store source"));
        goto cleanup;
    }

    if (virDomainDiskSourceParse(source, backingStore) < 0 ||
        virDomainDiskBackingStoreParse(ctxt, backingStore) < 0)
        goto cleanup;

    src->backingStore = backingStore;
    ret = 0;

 cleanup:
    if (ret < 0)
        virStorageSourceFree(backingStore);
    VIR_FREE(type);
    VIR_FREE(format);
    ctxt->node = save_ctxt;
    return ret;
}


5471 5472
#define VENDOR_LEN  8
#define PRODUCT_LEN 16
5473

5474 5475 5476 5477
/* Parse the XML definition for a disk
 * @param node XML nodeset to parse for disk definition
 */
static virDomainDiskDefPtr
5478
virDomainDiskDefParseXML(virDomainXMLOptionPtr xmlopt,
5479
                         xmlNodePtr node,
L
Lei Li 已提交
5480
                         xmlXPathContextPtr ctxt,
5481
                         virHashTablePtr bootHash,
5482 5483
                         virSecurityLabelDefPtr* vmSeclabels,
                         int nvmSeclabels,
E
Eric Blake 已提交
5484
                         unsigned int flags)
5485
{
5486
    virDomainDiskDefPtr def;
5487
    xmlNodePtr sourceNode = NULL;
5488
    xmlNodePtr cur;
L
Lei Li 已提交
5489
    xmlNodePtr save_ctxt = ctxt->node;
5490 5491
    char *type = NULL;
    char *device = NULL;
5492
    char *snapshot = NULL;
5493
    char *rawio = NULL;
O
Osier Yang 已提交
5494
    char *sgio = NULL;
5495 5496
    char *driverName = NULL;
    char *driverType = NULL;
5497
    const char *source = NULL;
5498
    char *target = NULL;
J
J.B. Joret 已提交
5499
    char *trans = NULL;
5500
    char *bus = NULL;
5501
    char *cachetag = NULL;
5502
    char *error_policy = NULL;
5503
    char *rerror_policy = NULL;
M
Matthias Dahl 已提交
5504
    char *iotag = NULL;
5505
    char *ioeventfd = NULL;
5506
    char *event_idx = NULL;
O
Osier Yang 已提交
5507
    char *copy_on_read = NULL;
5508
    char *driverIOThread = NULL;
5509
    char *devaddr = NULL;
5510
    virStorageEncryptionPtr encryption = NULL;
5511
    char *serial = NULL;
5512
    char *startupPolicy = NULL;
5513
    virStorageAuthDefPtr authdef = NULL;
5514
    char *tray = NULL;
5515
    char *removable = NULL;
5516 5517
    char *logical_block_size = NULL;
    char *physical_block_size = NULL;
O
Osier Yang 已提交
5518
    char *wwn = NULL;
5519 5520
    char *vendor = NULL;
    char *product = NULL;
O
Osier Yang 已提交
5521
    char *discard = NULL;
E
Eric Blake 已提交
5522 5523
    char *mirrorFormat = NULL;
    char *mirrorType = NULL;
5524 5525
    int expected_secret_usage = -1;
    int auth_secret_usage = -1;
5526
    int ret = 0;
5527

5528
    if (!(def = virDomainDiskDefNew()))
5529 5530
        return NULL;

J
J.B. Joret 已提交
5531 5532 5533 5534 5535
    def->geometry.cylinders = 0;
    def->geometry.heads = 0;
    def->geometry.sectors = 0;
    def->geometry.trans = VIR_DOMAIN_DISK_TRANS_DEFAULT;

V
Viktor Mihajlovski 已提交
5536 5537
    def->blockio.logical_block_size = 0;
    def->blockio.physical_block_size = 0;
5538

L
Lei Li 已提交
5539 5540
    ctxt->node = node;

5541 5542
    type = virXMLPropString(node, "type");
    if (type) {
5543
        if ((def->src->type = virStorageTypeFromString(type)) <= 0) {
5544
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
5545
                           _("unknown disk type '%s'"), type);
5546 5547 5548
            goto error;
        }
    } else {
5549
        def->src->type = VIR_STORAGE_TYPE_FILE;
5550 5551
    }

5552 5553
    snapshot = virXMLPropString(node, "snapshot");

5554
    rawio = virXMLPropString(node, "rawio");
O
Osier Yang 已提交
5555
    sgio = virXMLPropString(node, "sgio");
5556

5557 5558 5559
    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
5560
            if (!source && !def->src->hosts && !def->src->srcpool &&
E
Eric Blake 已提交
5561
                xmlStrEqual(cur->name, BAD_CAST "source")) {
5562 5563
                sourceNode = cur;

5564
                if (virDomainDiskSourceParse(cur, def->src) < 0)
5565
                    goto error;
5566
                source = def->src->path;
5567

5568 5569
                if (def->src->type == VIR_STORAGE_TYPE_NETWORK) {
                    if (def->src->protocol == VIR_STORAGE_NET_PROTOCOL_ISCSI)
5570
                        expected_secret_usage = VIR_SECRET_USAGE_TYPE_ISCSI;
5571
                    else if (def->src->protocol == VIR_STORAGE_NET_PROTOCOL_RBD)
5572
                        expected_secret_usage = VIR_SECRET_USAGE_TYPE_CEPH;
5573
                }
5574

5575 5576
                startupPolicy = virXMLPropString(cur, "startupPolicy");

E
Eric Blake 已提交
5577 5578
            } else if (!target &&
                       xmlStrEqual(cur->name, BAD_CAST "target")) {
5579 5580
                target = virXMLPropString(cur, "dev");
                bus = virXMLPropString(cur, "bus");
5581
                tray = virXMLPropString(cur, "tray");
5582
                removable = virXMLPropString(cur, "removable");
5583 5584 5585 5586 5587 5588

                /* HACK: Work around for compat with Xen
                 * driver in previous libvirt releases */
                if (target &&
                    STRPREFIX(target, "ioemu:"))
                    memmove(target, target+6, strlen(target)-5);
J
J.B. Joret 已提交
5589 5590 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608 5609 5610 5611
            } else if (xmlStrEqual(cur->name, BAD_CAST "geometry")) {
                if (virXPathUInt("string(./geometry/@cyls)",
                                 ctxt, &def->geometry.cylinders) < 0) {
                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                   _("invalid geometry settings (cyls)"));
                    goto error;
                }
                if (virXPathUInt("string(./geometry/@heads)",
                                 ctxt, &def->geometry.heads) < 0) {
                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                   _("invalid geometry settings (heads)"));
                    goto error;
                }
                if (virXPathUInt("string(./geometry/@secs)",
                                 ctxt, &def->geometry.sectors) < 0) {
                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                   _("invalid geometry settings (secs)"));
                    goto error;
                }
                trans = virXMLPropString(cur, "trans");
                if (trans) {
                    def->geometry.trans = virDomainDiskGeometryTransTypeFromString(trans);
                    if (def->geometry.trans <= 0) {
5612
                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
J
J.B. Joret 已提交
5613 5614 5615 5616 5617
                                       _("invalid translation value '%s'"),
                                       trans);
                        goto error;
                    }
                }
V
Viktor Mihajlovski 已提交
5618
            } else if (xmlStrEqual(cur->name, BAD_CAST "blockio")) {
5619 5620 5621 5622
                logical_block_size =
                    virXMLPropString(cur, "logical_block_size");
                if (logical_block_size &&
                    virStrToLong_ui(logical_block_size, NULL, 0,
V
Viktor Mihajlovski 已提交
5623
                                    &def->blockio.logical_block_size) < 0) {
5624 5625 5626 5627 5628 5629 5630 5631 5632
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("invalid logical block size '%s'"),
                                   logical_block_size);
                    goto error;
                }
                physical_block_size =
                    virXMLPropString(cur, "physical_block_size");
                if (physical_block_size &&
                    virStrToLong_ui(physical_block_size, NULL, 0,
V
Viktor Mihajlovski 已提交
5633
                                    &def->blockio.physical_block_size) < 0) {
5634 5635 5636 5637 5638
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("invalid physical block size '%s'"),
                                   physical_block_size);
                    goto error;
                }
E
Eric Blake 已提交
5639 5640
            } else if (!driverName &&
                       xmlStrEqual(cur->name, BAD_CAST "driver")) {
5641 5642
                driverName = virXMLPropString(cur, "name");
                driverType = virXMLPropString(cur, "type");
5643 5644 5645 5646 5647 5648
                if (STREQ_NULLABLE(driverType, "aio")) {
                    /* In-place conversion to "raw", for Xen back-compat */
                    driverType[0] = 'r';
                    driverType[1] = 'a';
                    driverType[2] = 'w';
                }
5649
                cachetag = virXMLPropString(cur, "cache");
5650
                error_policy = virXMLPropString(cur, "error_policy");
5651
                rerror_policy = virXMLPropString(cur, "rerror_policy");
M
Matthias Dahl 已提交
5652
                iotag = virXMLPropString(cur, "io");
5653
                ioeventfd = virXMLPropString(cur, "ioeventfd");
5654
                event_idx = virXMLPropString(cur, "event_idx");
O
Osier Yang 已提交
5655
                copy_on_read = virXMLPropString(cur, "copy_on_read");
O
Osier Yang 已提交
5656
                discard = virXMLPropString(cur, "discard");
5657
                driverIOThread = virXMLPropString(cur, "iothread");
5658 5659
            } else if (!def->mirror &&
                       xmlStrEqual(cur->name, BAD_CAST "mirror") &&
5660 5661
                       !(flags & VIR_DOMAIN_XML_INACTIVE)) {
                char *ready;
E
Eric Blake 已提交
5662
                char *blockJob;
5663 5664 5665

                if (VIR_ALLOC(def->mirror) < 0)
                    goto error;
E
Eric Blake 已提交
5666

E
Eric Blake 已提交
5667 5668 5669 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 5681
                blockJob = virXMLPropString(cur, "job");
                if (blockJob) {
                    def->mirrorJob = virDomainBlockJobTypeFromString(blockJob);
                    if (def->mirrorJob <= 0) {
                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                       _("unknown mirror job type '%s'"),
                                       blockJob);
                        VIR_FREE(blockJob);
                        goto error;
                    }
                    VIR_FREE(blockJob);
                } else {
                    def->mirrorJob = VIR_DOMAIN_BLOCK_JOB_TYPE_COPY;
                }

E
Eric Blake 已提交
5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 5698 5699 5700 5701 5702 5703
                mirrorType = virXMLPropString(cur, "type");
                if (mirrorType) {
                    def->mirror->type = virStorageTypeFromString(mirrorType);
                    if (def->mirror->type <= 0) {
                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                       _("unknown mirror backing store "
                                         "type '%s'"), mirrorType);
                        goto error;
                    }
                    mirrorFormat = virXPathString("string(./mirror/format/@type)",
                                                  ctxt);
                } else {
                    /* For back-compat reasons, we handle a file name
                     * encoded as attributes, even though we prefer
                     * modern output in the style of backingStore */
                    def->mirror->type = VIR_STORAGE_TYPE_FILE;
                    def->mirror->path = virXMLPropString(cur, "file");
                    if (!def->mirror->path) {
                        virReportError(VIR_ERR_XML_ERROR, "%s",
                                       _("mirror requires file name"));
                        goto error;
                    }
E
Eric Blake 已提交
5704 5705 5706 5707 5708 5709
                    if (def->mirrorJob != VIR_DOMAIN_BLOCK_JOB_TYPE_COPY) {
                        virReportError(VIR_ERR_XML_ERROR, "%s",
                                       _("mirror without type only supported "
                                         "by copy job"));
                        goto error;
                    }
E
Eric Blake 已提交
5710
                    mirrorFormat = virXMLPropString(cur, "format");
5711
                }
5712 5713 5714 5715 5716 5717 5718 5719 5720
                if (mirrorFormat) {
                    def->mirror->format =
                        virStorageFileFormatTypeFromString(mirrorFormat);
                    if (def->mirror->format <= 0) {
                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                       _("unknown mirror format value '%s'"),
                                       mirrorFormat);
                        goto error;
                    }
E
Eric Blake 已提交
5721 5722 5723 5724 5725 5726 5727 5728 5729 5730 5731
                }
                if (mirrorType) {
                    xmlNodePtr mirrorNode;

                    if (!(mirrorNode = virXPathNode("./mirror/source", ctxt))) {
                        virReportError(VIR_ERR_XML_ERROR, "%s",
                                       _("mirror requires source element"));
                        goto error;
                    }
                    if (virDomainDiskSourceParse(mirrorNode, def->mirror) < 0)
                        goto error;
5732
                }
5733 5734
                ready = virXMLPropString(cur, "ready");
                if (ready) {
5735 5736 5737 5738 5739 5740 5741 5742
                    if ((def->mirrorState =
                         virDomainDiskMirrorStateTypeFromString(ready)) < 0) {
                        virReportError(VIR_ERR_XML_ERROR,
                                       _("unknown mirror ready state %s"),
                                       ready);
                        VIR_FREE(ready);
                        goto error;
                    }
5743 5744
                    VIR_FREE(ready);
                }
5745 5746
            } else if (!authdef &&
                       xmlStrEqual(cur->name, BAD_CAST "auth")) {
5747 5748 5749 5750 5751 5752 5753
                if (!(authdef = virStorageAuthDefParse(node->doc, cur)))
                    goto error;
                if ((auth_secret_usage =
                     virSecretUsageTypeFromString(authdef->secrettype)) < 0) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("invalid secret type %s"),
                                   authdef->secrettype);
5754 5755
                    goto error;
                }
L
Lei Li 已提交
5756
            } else if (xmlStrEqual(cur->name, BAD_CAST "iotune")) {
5757 5758 5759 5760 5761 5762 5763 5764
                ret = virXPathULongLong("string(./iotune/total_bytes_sec)",
                                        ctxt,
                                        &def->blkdeviotune.total_bytes_sec);
                if (ret == -2) {
                    virReportError(VIR_ERR_XML_ERROR, "%s",
                                   _("total throughput limit must be an integer"));
                    goto error;
                } else if (ret < 0) {
L
Lei Li 已提交
5765 5766 5767
                    def->blkdeviotune.total_bytes_sec = 0;
                }

5768 5769 5770 5771 5772 5773 5774 5775
                ret = virXPathULongLong("string(./iotune/read_bytes_sec)",
                                        ctxt,
                                        &def->blkdeviotune.read_bytes_sec);
                if (ret == -2) {
                    virReportError(VIR_ERR_XML_ERROR, "%s",
                                   _("read throughput limit must be an integer"));
                    goto error;
                } else if (ret < 0) {
L
Lei Li 已提交
5776 5777 5778
                    def->blkdeviotune.read_bytes_sec = 0;
                }

5779 5780 5781 5782 5783 5784 5785 5786
                ret = virXPathULongLong("string(./iotune/write_bytes_sec)",
                                        ctxt,
                                        &def->blkdeviotune.write_bytes_sec);
                if (ret == -2) {
                    virReportError(VIR_ERR_XML_ERROR, "%s",
                                   _("write throughput limit must be an integer"));
                    goto error;
                } else if (ret < 0) {
L
Lei Li 已提交
5787 5788 5789
                    def->blkdeviotune.write_bytes_sec = 0;
                }

5790 5791 5792 5793 5794 5795 5796 5797
                ret = virXPathULongLong("string(./iotune/total_iops_sec)",
                                        ctxt,
                                        &def->blkdeviotune.total_iops_sec);
                if (ret == -2) {
                    virReportError(VIR_ERR_XML_ERROR, "%s",
                                   _("total I/O operations limit must be an integer"));
                    goto error;
                } else if (ret < 0) {
L
Lei Li 已提交
5798 5799 5800
                    def->blkdeviotune.total_iops_sec = 0;
                }

5801 5802 5803 5804 5805 5806 5807 5808
                ret = virXPathULongLong("string(./iotune/read_iops_sec)",
                                        ctxt,
                                        &def->blkdeviotune.read_iops_sec);
                if (ret == -2) {
                    virReportError(VIR_ERR_XML_ERROR, "%s",
                                   _("read I/O operations limit must be an integer"));
                    goto error;
                } else if (ret < 0) {
L
Lei Li 已提交
5809 5810 5811
                    def->blkdeviotune.read_iops_sec = 0;
                }

5812 5813 5814 5815 5816 5817 5818 5819
                ret = virXPathULongLong("string(./iotune/write_iops_sec)",
                                        ctxt,
                                        &def->blkdeviotune.write_iops_sec);
                if (ret == -2) {
                    virReportError(VIR_ERR_XML_ERROR, "%s",
                                   _("write I/O operations limit must be an integer"));
                    goto error;
                } else if (ret < 0) {
L
Lei Li 已提交
5820 5821 5822 5823 5824 5825 5826
                    def->blkdeviotune.write_iops_sec = 0;
                }

                if ((def->blkdeviotune.total_bytes_sec &&
                     def->blkdeviotune.read_bytes_sec) ||
                    (def->blkdeviotune.total_bytes_sec &&
                     def->blkdeviotune.write_bytes_sec)) {
5827
                    virReportError(VIR_ERR_XML_ERROR, "%s",
5828 5829
                                   _("total and read/write bytes_sec "
                                     "cannot be set at the same time"));
L
Lei Li 已提交
5830 5831 5832 5833 5834 5835 5836
                    goto error;
                }

                if ((def->blkdeviotune.total_iops_sec &&
                     def->blkdeviotune.read_iops_sec) ||
                    (def->blkdeviotune.total_iops_sec &&
                     def->blkdeviotune.write_iops_sec)) {
5837
                    virReportError(VIR_ERR_XML_ERROR, "%s",
5838 5839
                                   _("total and read/write iops_sec "
                                     "cannot be set at the same time"));
L
Lei Li 已提交
5840 5841
                    goto error;
                }
5842
            } else if (xmlStrEqual(cur->name, BAD_CAST "readonly")) {
5843
                def->src->readonly = true;
5844
            } else if (xmlStrEqual(cur->name, BAD_CAST "shareable")) {
5845
                def->src->shared = true;
5846
            } else if (xmlStrEqual(cur->name, BAD_CAST "transient")) {
5847
                def->transient = true;
5848 5849
            } else if ((flags & VIR_DOMAIN_XML_INTERNAL_STATUS) &&
                       xmlStrEqual(cur->name, BAD_CAST "state")) {
5850
                /* Legacy back-compat. Don't add any more attributes here */
5851
                devaddr = virXMLPropString(cur, "devaddr");
5852 5853
            } else if (encryption == NULL &&
                       xmlStrEqual(cur->name, BAD_CAST "encryption")) {
5854
                encryption = virStorageEncryptionParseNode(node->doc,
5855 5856 5857
                                                           cur);
                if (encryption == NULL)
                    goto error;
E
Eric Blake 已提交
5858 5859
            } else if (!serial &&
                       xmlStrEqual(cur->name, BAD_CAST "serial")) {
5860
                serial = (char *)xmlNodeGetContent(cur);
O
Osier Yang 已提交
5861 5862 5863 5864 5865 5866
            } else if (!wwn &&
                       xmlStrEqual(cur->name, BAD_CAST "wwn")) {
                wwn = (char *)xmlNodeGetContent(cur);

                if (!virValidateWWN(wwn))
                    goto error;
5867 5868 5869 5870 5871 5872 5873 5874 5875 5876 5877 5878 5879 5880 5881 5882 5883 5884 5885
            } else if (!vendor &&
                       xmlStrEqual(cur->name, BAD_CAST "vendor")) {
                vendor = (char *)xmlNodeGetContent(cur);

                if (strlen(vendor) > VENDOR_LEN) {
                    virReportError(VIR_ERR_XML_ERROR, "%s",
                                   _("disk vendor is more than 8 characters"));
                    goto error;
                }

                if (!virStrIsPrint(vendor)) {
                    virReportError(VIR_ERR_XML_ERROR, "%s",
                                   _("disk vendor is not printable string"));
                    goto error;
                }
            } else if (!product &&
                       xmlStrEqual(cur->name, BAD_CAST "product")) {
                product = (char *)xmlNodeGetContent(cur);

A
Alex Jia 已提交
5886
                if (strlen(product) > PRODUCT_LEN) {
5887 5888 5889 5890 5891 5892 5893 5894 5895 5896
                    virReportError(VIR_ERR_XML_ERROR, "%s",
                                   _("disk product is more than 16 characters"));
                    goto error;
                }

                if (!virStrIsPrint(product)) {
                    virReportError(VIR_ERR_XML_ERROR, "%s",
                                   _("disk product is not printable string"));
                    goto error;
                }
5897
            } else if (xmlStrEqual(cur->name, BAD_CAST "boot")) {
5898
                /* boot is parsed as part of virDomainDeviceInfoParseXML */
5899 5900 5901 5902 5903
            }
        }
        cur = cur->next;
    }

5904 5905 5906
    if (auth_secret_usage != -1 && auth_secret_usage != expected_secret_usage) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("invalid secret type '%s'"),
5907
                       virSecretUsageTypeToString(auth_secret_usage));
5908 5909 5910
        goto error;
    }

5911 5912 5913
    device = virXMLPropString(node, "device");
    if (device) {
        if ((def->device = virDomainDiskDeviceTypeFromString(device)) < 0) {
5914
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
5915
                           _("unknown disk device '%s'"), device);
5916 5917 5918 5919 5920 5921 5922
            goto error;
        }
    } else {
        def->device = VIR_DOMAIN_DISK_DEVICE_DISK;
    }

    /* Only CDROM and Floppy devices are allowed missing source path
5923 5924
     * to indicate no media present. LUN is for raw access CD-ROMs
     * that are not attached to a physical device presently */
5925
    if (source == NULL && def->src->hosts == NULL && !def->src->srcpool &&
5926 5927
        (def->device == VIR_DOMAIN_DISK_DEVICE_DISK ||
         (flags & VIR_DOMAIN_XML_INTERNAL_DISK_SOURCE))) {
5928 5929
        virReportError(VIR_ERR_NO_SOURCE,
                       target ? "%s" : NULL, target);
5930 5931 5932
        goto error;
    }

5933 5934 5935 5936
    /* If source is present, check for an optional seclabel override.  */
    if (sourceNode) {
        xmlNodePtr saved_node = ctxt->node;
        ctxt->node = sourceNode;
5937 5938
        if (virSecurityDeviceLabelDefParseXML(&def->src->seclabels,
                                              &def->src->nseclabels,
5939
                                              vmSeclabels,
5940
                                              nvmSeclabels,
5941 5942
                                              ctxt,
                                              flags) < 0)
5943 5944 5945 5946
            goto error;
        ctxt->node = saved_node;
    }

5947
    if (!target && !(flags & VIR_DOMAIN_XML_INTERNAL_DISK_SOURCE)) {
5948
        if (def->src->srcpool) {
5949 5950
            char *tmp;
            if (virAsprintf(&tmp, "pool = '%s', volume = '%s'",
5951
                def->src->srcpool->pool, def->src->srcpool->volume) < 0)
5952 5953 5954 5955 5956 5957 5958
                goto error;

            virReportError(VIR_ERR_NO_TARGET, "%s", tmp);
            VIR_FREE(tmp);
        } else {
            virReportError(VIR_ERR_NO_TARGET, source ? "%s" : NULL, source);
        }
5959 5960 5961
        goto error;
    }

5962 5963 5964 5965 5966 5967 5968
    if (!(flags & VIR_DOMAIN_XML_INTERNAL_DISK_SOURCE)) {
        if (def->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY &&
            !STRPREFIX(target, "fd")) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Invalid floppy device name: %s"), target);
            goto error;
        }
5969

5970 5971 5972
        /* Force CDROM to be listed as read only */
        if (def->device == VIR_DOMAIN_DISK_DEVICE_CDROM)
            def->src->readonly = true;
5973

5974 5975 5976 5977 5978 5979 5980 5981 5982 5983 5984
        if ((def->device == VIR_DOMAIN_DISK_DEVICE_DISK ||
             def->device == VIR_DOMAIN_DISK_DEVICE_LUN) &&
            !STRPREFIX((const char *)target, "hd") &&
            !STRPREFIX((const char *)target, "sd") &&
            !STRPREFIX((const char *)target, "vd") &&
            !STRPREFIX((const char *)target, "xvd") &&
            !STRPREFIX((const char *)target, "ubd")) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Invalid harddisk device name: %s"), target);
            goto error;
        }
5985 5986
    }

5987
    if (snapshot) {
E
Eric Blake 已提交
5988
        def->snapshot = virDomainSnapshotLocationTypeFromString(snapshot);
5989
        if (def->snapshot <= 0) {
5990
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
5991 5992
                           _("unknown disk snapshot setting '%s'"),
                           snapshot);
5993 5994
            goto error;
        }
5995
    } else if (def->src->readonly) {
E
Eric Blake 已提交
5996
        def->snapshot = VIR_DOMAIN_SNAPSHOT_LOCATION_NONE;
5997 5998
    }

O
Osier Yang 已提交
5999 6000 6001 6002 6003 6004 6005 6006
    if ((rawio || sgio) &&
        (def->device != VIR_DOMAIN_DISK_DEVICE_LUN)) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("rawio or sgio can be used only with "
                         "device='lun'"));
        goto error;
    }

6007
    if (rawio) {
6008
        if ((def->rawio = virTristateBoolTypeFromString(rawio)) <= 0) {
O
Osier Yang 已提交
6009 6010 6011 6012 6013 6014 6015 6016
            virReportError(VIR_ERR_XML_ERROR,
                           _("unknown disk rawio setting '%s'"),
                           rawio);
            goto error;
        }
    }

    if (sgio) {
6017
        if ((def->sgio = virDomainDeviceSGIOTypeFromString(sgio)) <= 0) {
6018
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
O
Osier Yang 已提交
6019
                           _("unknown disk sgio mode '%s'"), sgio);
6020 6021 6022 6023
            goto error;
        }
    }

6024 6025
    if (bus) {
        if ((def->bus = virDomainDiskBusTypeFromString(bus)) < 0) {
6026
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
6027
                           _("unknown disk bus type '%s'"), bus);
6028 6029 6030 6031 6032
            goto error;
        }
    } else {
        if (def->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
            def->bus = VIR_DOMAIN_DISK_BUS_FDC;
6033
        } else if (!(flags & VIR_DOMAIN_XML_INTERNAL_DISK_SOURCE)) {
6034 6035 6036 6037 6038 6039 6040 6041
            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;
6042 6043
            else if (STRPREFIX(target, "ubd"))
                def->bus = VIR_DOMAIN_DISK_BUS_UML;
6044 6045 6046 6047 6048
            else
                def->bus = VIR_DOMAIN_DISK_BUS_IDE;
        }
    }

6049 6050
    if (tray) {
        if ((def->tray_status = virDomainDiskTrayTypeFromString(tray)) < 0) {
6051
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
6052
                           _("unknown disk tray status '%s'"), tray);
6053 6054 6055 6056 6057
            goto error;
        }

        if (def->device != VIR_DOMAIN_DISK_DEVICE_FLOPPY &&
            def->device != VIR_DOMAIN_DISK_DEVICE_CDROM) {
6058 6059
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("tray is only valid for cdrom and floppy"));
6060 6061 6062 6063 6064 6065 6066 6067
            goto error;
        }
    } else {
        if (def->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY ||
            def->device == VIR_DOMAIN_DISK_DEVICE_CDROM)
            def->tray_status = VIR_DOMAIN_DISK_TRAY_CLOSED;
    }

6068
    if (removable) {
J
Ján Tomko 已提交
6069
        if ((def->removable = virTristateSwitchTypeFromString(removable)) < 0) {
6070
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
6071 6072 6073 6074 6075 6076 6077 6078 6079 6080 6081
                           _("unknown disk removable status '%s'"), removable);
            goto error;
        }

        if (def->bus != VIR_DOMAIN_DISK_BUS_USB) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("removable is only valid for usb disks"));
            goto error;
        }
    } else {
        if (def->bus == VIR_DOMAIN_DISK_BUS_USB) {
J
Ján Tomko 已提交
6082
            def->removable = VIR_TRISTATE_SWITCH_ABSENT;
6083 6084 6085
        }
    }

6086 6087
    if (def->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY &&
        def->bus != VIR_DOMAIN_DISK_BUS_FDC) {
6088 6089
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Invalid bus type '%s' for floppy disk"), bus);
6090 6091 6092 6093
        goto error;
    }
    if (def->device != VIR_DOMAIN_DISK_DEVICE_FLOPPY &&
        def->bus == VIR_DOMAIN_DISK_BUS_FDC) {
6094 6095
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Invalid bus type '%s' for disk"), bus);
6096 6097 6098
        goto error;
    }

6099 6100
    if (cachetag &&
        (def->cachemode = virDomainDiskCacheTypeFromString(cachetag)) < 0) {
6101
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
6102
                       _("unknown disk cache mode '%s'"), cachetag);
6103 6104 6105
        goto error;
    }

6106
    if (error_policy &&
6107
        (def->error_policy = virDomainDiskErrorPolicyTypeFromString(error_policy)) <= 0) {
6108
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
6109
                       _("unknown disk error policy '%s'"), error_policy);
6110 6111 6112
        goto error;
    }

6113 6114 6115 6116
    if (rerror_policy &&
        (((def->rerror_policy
           = virDomainDiskErrorPolicyTypeFromString(rerror_policy)) <= 0) ||
         (def->rerror_policy == VIR_DOMAIN_DISK_ERROR_POLICY_ENOSPACE))) {
6117
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
6118 6119
                       _("unknown disk read error policy '%s'"),
                       rerror_policy);
6120 6121 6122
        goto error;
    }

M
Matthias Dahl 已提交
6123 6124 6125
    if (iotag) {
        if ((def->iomode = virDomainDiskIoTypeFromString(iotag)) < 0 ||
            def->iomode == VIR_DOMAIN_DISK_IO_DEFAULT) {
6126
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
6127
                           _("unknown disk io mode '%s'"), iotag);
M
Matthias Dahl 已提交
6128 6129 6130 6131
            goto error;
        }
    }

6132
    if (ioeventfd) {
6133 6134
        int val;

6135
        if (def->bus != VIR_DOMAIN_DISK_BUS_VIRTIO) {
6136
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
6137 6138
                           _("disk ioeventfd mode supported "
                             "only for virtio bus"));
6139 6140 6141
            goto error;
        }

J
Ján Tomko 已提交
6142
        if ((val = virTristateSwitchTypeFromString(ioeventfd)) <= 0) {
6143 6144 6145
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown disk ioeventfd mode '%s'"),
                           ioeventfd);
6146 6147
            goto error;
        }
6148
        def->ioeventfd = val;
6149 6150
    }

6151 6152
    if (event_idx) {
        if (def->bus != VIR_DOMAIN_DISK_BUS_VIRTIO) {
6153
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
6154 6155
                           _("disk event_idx mode supported "
                             "only for virtio bus"));
6156 6157 6158 6159
            goto error;
        }

        int idx;
J
Ján Tomko 已提交
6160
        if ((idx = virTristateSwitchTypeFromString(event_idx)) <= 0) {
6161 6162 6163
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown disk event_idx mode '%s'"),
                           event_idx);
6164 6165 6166 6167 6168
            goto error;
        }
        def->event_idx = idx;
    }

O
Osier Yang 已提交
6169 6170
    if (copy_on_read) {
        int cor;
J
Ján Tomko 已提交
6171
        if ((cor = virTristateSwitchTypeFromString(copy_on_read)) <= 0) {
6172 6173 6174
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown disk copy_on_read mode '%s'"),
                           copy_on_read);
O
Osier Yang 已提交
6175 6176 6177 6178 6179
            goto error;
        }
        def->copy_on_read = cor;
    }

O
Osier Yang 已提交
6180 6181 6182 6183 6184 6185 6186 6187
    if (discard) {
        if ((def->discard = virDomainDiskDiscardTypeFromString(discard)) <= 0) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown disk discard mode '%s'"), discard);
            goto error;
        }
    }

6188 6189 6190 6191 6192 6193 6194 6195 6196
    if (driverIOThread) {
        if (virStrToLong_uip(driverIOThread, NULL, 10, &def->iothread) < 0) {
            virReportError(VIR_ERR_XML_ERROR,
                           _("Invalid iothread attribute in disk driver "
                             "element: %s"), driverIOThread);
            goto error;
        }
    }

6197
    if (devaddr) {
6198 6199
        if (virDomainParseLegacyDeviceAddress(devaddr,
                                              &def->info.addr.pci) < 0) {
6200 6201 6202
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unable to parse devaddr parameter '%s'"),
                           devaddr);
6203 6204 6205 6206
            goto error;
        }
        def->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
    } else {
6207
        if (virDomainDeviceInfoParseXML(node, bootHash, &def->info,
6208
                                        flags | VIR_DOMAIN_XML_INTERNAL_ALLOW_BOOT) < 0)
6209
            goto error;
6210 6211
    }

6212
    if (startupPolicy) {
6213
        int val;
6214

6215
        if ((val = virDomainStartupPolicyTypeFromString(startupPolicy)) <= 0) {
6216 6217 6218
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown startupPolicy value '%s'"),
                           startupPolicy);
6219 6220 6221
            goto error;
        }

6222
        if (def->src->type == VIR_STORAGE_TYPE_NETWORK) {
6223 6224 6225
            virReportError(VIR_ERR_XML_ERROR,
                           _("Setting disk %s is not allowed for "
                             "disk of network type"),
6226
                           startupPolicy);
6227 6228
            goto error;
        }
6229 6230 6231 6232 6233 6234 6235 6236 6237

        if (def->device != VIR_DOMAIN_DISK_DEVICE_CDROM &&
            def->device != VIR_DOMAIN_DISK_DEVICE_FLOPPY &&
            val == VIR_DOMAIN_STARTUP_POLICY_REQUISITE) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("Setting disk 'requisite' is allowed only for "
                             "cdrom or floppy"));
            goto error;
        }
6238
        def->startupPolicy = val;
6239 6240
    }

6241 6242
    def->dst = target;
    target = NULL;
6243 6244
    def->src->auth = authdef;
    authdef = NULL;
6245
    def->src->driverName = driverName;
6246
    driverName = NULL;
6247
    def->src->encryption = encryption;
6248
    encryption = NULL;
6249 6250
    def->serial = serial;
    serial = NULL;
O
Osier Yang 已提交
6251 6252
    def->wwn = wwn;
    wwn = NULL;
6253 6254 6255 6256
    def->vendor = vendor;
    vendor = NULL;
    def->product = product;
    product = NULL;
6257

6258
    if (driverType) {
6259 6260
        def->src->format = virStorageFileFormatTypeFromString(driverType);
        if (def->src->format <= 0) {
6261 6262 6263 6264 6265 6266
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown driver format value '%s'"),
                           driverType);
            goto error;
        }
    }
6267

6268 6269 6270 6271
    if (!(flags & VIR_DOMAIN_XML_INTERNAL_DISK_SOURCE)) {
        if (def->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE
            && virDomainDiskDefAssignAddress(xmlopt, def) < 0)
            goto error;
6272

6273 6274 6275
        if (virDomainDiskBackingStoreParse(ctxt, def->src) < 0)
            goto error;
    }
6276

6277
 cleanup:
6278 6279
    VIR_FREE(bus);
    VIR_FREE(type);
6280
    VIR_FREE(snapshot);
6281
    VIR_FREE(rawio);
O
Osier Yang 已提交
6282
    VIR_FREE(sgio);
6283
    VIR_FREE(target);
6284
    VIR_FREE(tray);
6285
    VIR_FREE(removable);
J
J.B. Joret 已提交
6286
    VIR_FREE(trans);
6287
    VIR_FREE(device);
6288
    virStorageAuthDefFree(authdef);
6289 6290
    VIR_FREE(driverType);
    VIR_FREE(driverName);
6291
    VIR_FREE(cachetag);
6292
    VIR_FREE(error_policy);
6293
    VIR_FREE(rerror_policy);
M
Matthias Dahl 已提交
6294
    VIR_FREE(iotag);
6295
    VIR_FREE(ioeventfd);
6296
    VIR_FREE(event_idx);
O
Osier Yang 已提交
6297
    VIR_FREE(copy_on_read);
O
Osier Yang 已提交
6298
    VIR_FREE(discard);
6299
    VIR_FREE(driverIOThread);
6300
    VIR_FREE(devaddr);
6301
    VIR_FREE(serial);
6302
    virStorageEncryptionFree(encryption);
6303
    VIR_FREE(startupPolicy);
6304 6305
    VIR_FREE(logical_block_size);
    VIR_FREE(physical_block_size);
O
Osier Yang 已提交
6306
    VIR_FREE(wwn);
6307 6308
    VIR_FREE(vendor);
    VIR_FREE(product);
E
Eric Blake 已提交
6309 6310
    VIR_FREE(mirrorType);
    VIR_FREE(mirrorFormat);
6311

L
Lei Li 已提交
6312
    ctxt->node = save_ctxt;
6313 6314
    return def;

6315
 error:
6316 6317 6318 6319 6320 6321
    virDomainDiskDefFree(def);
    def = NULL;
    goto cleanup;
}


6322 6323 6324 6325 6326 6327 6328 6329 6330 6331 6332 6333 6334 6335 6336
/* Parse a value located at XPATH within CTXT, and store the
 * result into val.  If REQUIRED, then the value must exist;
 * otherwise, the value is optional.  The value is in bytes.
 * Return 1 on success, 0 if the value was not present and
 * is not REQUIRED, -1 on failure after issuing error. */
static int
virDomainParseScaledValue(const char *xpath,
                          xmlXPathContextPtr ctxt,
                          unsigned long long *val,
                          unsigned long long scale,
                          unsigned long long max,
                          bool required)
{
    char *xpath_full = NULL;
    char *unit = NULL;
6337
    char *bytes_str = NULL;
6338 6339 6340 6341 6342 6343
    int ret = -1;
    unsigned long long bytes;

    *val = 0;
    if (virAsprintf(&xpath_full, "string(%s)", xpath) < 0)
        goto cleanup;
6344 6345 6346 6347 6348 6349

    bytes_str = virXPathString(xpath_full, ctxt);
    if (!bytes_str) {
        if (!required) {
            ret = 0;
        } else {
6350 6351 6352
            virReportError(VIR_ERR_XML_ERROR,
                           _("missing element %s"),
                           xpath);
6353
        }
6354 6355 6356 6357
        goto cleanup;
    }
    VIR_FREE(xpath_full);

6358 6359 6360 6361 6362 6363 6364
    if (virStrToLong_ullp(bytes_str, NULL, 10, &bytes) < 0) {
        virReportError(VIR_ERR_XML_ERROR,
                       _("Invalid value '%s' for element '%s'"),
                       bytes_str, xpath);
        goto cleanup;
    }

6365 6366 6367 6368 6369 6370 6371 6372 6373
    if (virAsprintf(&xpath_full, "string(%s/@unit)", xpath) < 0)
        goto cleanup;
    unit = virXPathString(xpath_full, ctxt);

    if (virScaleInteger(&bytes, unit, scale, max) < 0)
        goto cleanup;

    *val = bytes;
    ret = 1;
6374
 cleanup:
6375
    VIR_FREE(bytes_str);
6376 6377 6378 6379 6380 6381
    VIR_FREE(xpath_full);
    VIR_FREE(unit);
    return ret;
}


6382
/* Parse a memory element located at XPATH within CTXT, and store the
6383 6384 6385 6386 6387 6388
 * result into MEM, in blocks of 1024.  If REQUIRED, then the value
 * must exist; otherwise, the value is optional.  The value must not
 * exceed VIR_DOMAIN_MEMORY_PARAM_UNLIMITED once scaled; additionally,
 * if CAPPED is true, the value must fit within an unsigned long (only
 * matters on 32-bit platforms).
 *
6389 6390 6391
 * Return 0 on success, -1 on failure after issuing error.  */
static int
virDomainParseMemory(const char *xpath, xmlXPathContextPtr ctxt,
6392
                     unsigned long long *mem, bool required, bool capped)
6393 6394 6395 6396 6397 6398
{
    int ret = -1;
    unsigned long long bytes, max;

    /* On 32-bit machines, our bound is 0xffffffff * KiB. On 64-bit
     * machines, our bound is off_t (2^63).  */
6399
    if (capped && sizeof(unsigned long) < sizeof(long long))
6400 6401 6402 6403 6404 6405 6406 6407 6408 6409 6410 6411 6412 6413 6414 6415
        max = 1024ull * ULONG_MAX;
    else
        max = LLONG_MAX;

    ret = virDomainParseScaledValue(xpath, ctxt, &bytes, 1024, max, required);
    if (ret < 0)
        goto cleanup;

    /* Yes, we really do use kibibytes for our internal sizing.  */
    *mem = VIR_DIV_UP(bytes, 1024);
    ret = 0;
 cleanup:
    return ret;
}


6416
static int
6417
virDomainControllerModelTypeFromString(const virDomainControllerDef *def,
6418 6419 6420 6421
                                       const char *model)
{
    if (def->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI)
        return virDomainControllerModelSCSITypeFromString(model);
6422 6423
    else if (def->type == VIR_DOMAIN_CONTROLLER_TYPE_USB)
        return virDomainControllerModelUSBTypeFromString(model);
J
Ján Tomko 已提交
6424 6425
    else if (def->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI)
        return virDomainControllerModelPCITypeFromString(model);
6426 6427 6428 6429

    return -1;
}

6430 6431 6432 6433
/* Parse the XML definition for a controller
 * @param node XML nodeset to parse for controller definition
 */
static virDomainControllerDefPtr
6434
virDomainControllerDefParseXML(xmlNodePtr node,
6435
                               xmlXPathContextPtr ctxt,
E
Eric Blake 已提交
6436
                               unsigned int flags)
6437 6438
{
    virDomainControllerDefPtr def;
6439
    xmlNodePtr cur = NULL;
6440 6441
    char *type = NULL;
    char *idx = NULL;
6442
    char *model = NULL;
6443
    char *queues = NULL;
6444 6445
    char *cmd_per_lun = NULL;
    char *max_sectors = NULL;
6446
    xmlNodePtr saved = ctxt->node;
6447
    int rc;
6448 6449

    ctxt->node = node;
6450

6451
    if (VIR_ALLOC(def) < 0)
6452 6453 6454 6455
        return NULL;

    type = virXMLPropString(node, "type");
    if (type) {
6456
        if ((def->type = virDomainControllerTypeFromString(type)) < 0) {
6457
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
6458
                           _("Unknown controller type '%s'"), type);
6459 6460 6461 6462 6463 6464
            goto error;
        }
    }

    idx = virXMLPropString(node, "index");
    if (idx) {
6465 6466
        if (virStrToLong_ui(idx, NULL, 10, &def->idx) < 0 ||
            def->idx > INT_MAX) {
6467 6468
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Cannot parse controller index %s"), idx);
6469 6470 6471 6472
            goto error;
        }
    }

6473 6474
    model = virXMLPropString(node, "model");
    if (model) {
6475
        if ((def->model = virDomainControllerModelTypeFromString(def, model)) < 0) {
6476
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
6477
                           _("Unknown model type '%s'"), model);
6478 6479 6480 6481 6482 6483
            goto error;
        }
    } else {
        def->model = -1;
    }

6484 6485 6486
    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
6487
            if (xmlStrEqual(cur->name, BAD_CAST "driver")) {
6488
                queues = virXMLPropString(cur, "queues");
6489 6490
                cmd_per_lun = virXMLPropString(cur, "cmd_per_lun");
                max_sectors = virXMLPropString(cur, "max_sectors");
6491
            }
6492
        }
6493 6494 6495 6496 6497 6498 6499
        cur = cur->next;
    }

    if (queues && virStrToLong_ui(queues, NULL, 10, &def->queues) < 0) {
        virReportError(VIR_ERR_XML_ERROR,
                       _("Malformed 'queues' value '%s'"), queues);
        goto error;
6500 6501
    }

6502 6503 6504 6505 6506 6507 6508 6509 6510 6511 6512
    if (cmd_per_lun && virStrToLong_ui(cmd_per_lun, NULL, 10, &def->cmd_per_lun) < 0) {
        virReportError(VIR_ERR_XML_ERROR,
                       _("Malformed 'cmd_per_lun' value '%s'"), cmd_per_lun);
        goto error;
    }

    if (max_sectors && virStrToLong_ui(max_sectors, NULL, 10, &def->max_sectors) < 0) {
        virReportError(VIR_ERR_XML_ERROR,
                       _("Malformed 'max_sectors' value %s'"), max_sectors);
    }

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

6516 6517 6518 6519 6520 6521 6522
    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) {
6523 6524
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Invalid ports: %s"), ports);
6525 6526 6527 6528 6529 6530 6531 6532 6533 6534 6535 6536 6537
                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) {
6538 6539
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Invalid vectors: %s"), vectors);
6540 6541 6542 6543 6544 6545 6546 6547 6548
                VIR_FREE(vectors);
                goto error;
            }
        } else {
            def->opts.vioserial.vectors = -1;
        }
        VIR_FREE(vectors);
        break;
    }
6549 6550 6551 6552 6553 6554 6555 6556 6557 6558 6559 6560 6561 6562 6563 6564 6565 6566 6567 6568 6569 6570
    case VIR_DOMAIN_CONTROLLER_TYPE_USB: {
        /* If the XML has a uhci1, uhci2, uhci3 controller and no
         * master port was given, we should set a sensible one */
        int masterPort = -1;
        switch (def->model) {
        case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI1:
            masterPort = 0;
            break;
        case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI2:
            masterPort = 2;
            break;
        case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI3:
            masterPort = 4;
            break;
        }
        if (masterPort != -1 &&
            def->info.mastertype == VIR_DOMAIN_CONTROLLER_MASTER_NONE) {
            def->info.mastertype = VIR_DOMAIN_CONTROLLER_MASTER_USB;
            def->info.master.usb.startport = masterPort;
        }
        break;
    }
J
Ján Tomko 已提交
6571 6572 6573
    case VIR_DOMAIN_CONTROLLER_TYPE_PCI:
        switch (def->model) {
        case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT:
6574 6575
        case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT: {
            unsigned long long bytes;
J
Ján Tomko 已提交
6576 6577
            if (def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
                virReportError(VIR_ERR_XML_ERROR, "%s",
L
Laine Stump 已提交
6578
                               _("pci-root and pcie-root controllers should not "
J
Ján Tomko 已提交
6579 6580 6581
                                 "have an address"));
                goto error;
            }
6582 6583
            if (def->idx != 0) {
                virReportError(VIR_ERR_XML_ERROR, "%s",
L
Laine Stump 已提交
6584 6585
                               _("pci-root and pcie-root controllers "
                                 "should have index 0"));
6586 6587
                goto error;
            }
6588 6589 6590 6591
            if ((rc = virDomainParseScaledValue("./pcihole64", ctxt,
                                                &bytes, 1024,
                                                1024ULL * ULONG_MAX, false)) < 0)
                goto error;
6592

6593 6594 6595 6596
            if (rc == 1)
                def->opts.pciopts.pcihole64 = true;
            def->opts.pciopts.pcihole64size = VIR_DIV_UP(bytes, 1024);
        }
J
Ján Tomko 已提交
6597
        }
6598 6599 6600 6601 6602

    default:
        break;
    }

6603
    if (def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
6604
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO &&
6605
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW &&
6606
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390 &&
6607
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO &&
6608
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
6609 6610
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Controllers must use the 'pci' address type"));
6611 6612 6613
        goto error;
    }

6614
 cleanup:
6615
    ctxt->node = saved;
6616 6617
    VIR_FREE(type);
    VIR_FREE(idx);
6618
    VIR_FREE(model);
6619
    VIR_FREE(queues);
6620 6621
    VIR_FREE(cmd_per_lun);
    VIR_FREE(max_sectors);
6622 6623 6624 6625 6626 6627 6628 6629 6630

    return def;

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

6631

6632 6633 6634 6635 6636 6637 6638 6639
void
virDomainNetGenerateMAC(virDomainXMLOptionPtr xmlopt,
                        virMacAddrPtr mac)
{
    virMacAddrGenerate(xmlopt->config.macPrefix, mac);
}


6640 6641 6642 6643
/* Parse the XML definition for a disk
 * @param node XML nodeset to parse for disk definition
 */
static virDomainFSDefPtr
6644
virDomainFSDefParseXML(xmlNodePtr node,
6645
                       xmlXPathContextPtr ctxt,
6646 6647
                       unsigned int flags)
{
6648
    virDomainFSDefPtr def;
6649
    xmlNodePtr cur, save_node = ctxt->node;
6650
    char *type = NULL;
6651
    char *fsdriver = NULL;
6652 6653
    char *source = NULL;
    char *target = NULL;
6654
    char *format = NULL;
6655
    char *accessmode = NULL;
6656
    char *wrpolicy = NULL;
6657
    char *usage = NULL;
6658
    char *units = NULL;
6659

6660 6661
    ctxt->node = node;

6662
    if (VIR_ALLOC(def) < 0)
6663 6664 6665 6666 6667
        return NULL;

    type = virXMLPropString(node, "type");
    if (type) {
        if ((def->type = virDomainFSTypeFromString(type)) < 0) {
6668
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
6669
                           _("unknown filesystem type '%s'"), type);
6670 6671 6672 6673 6674 6675
            goto error;
        }
    } else {
        def->type = VIR_DOMAIN_FS_TYPE_MOUNT;
    }

6676 6677 6678
    accessmode = virXMLPropString(node, "accessmode");
    if (accessmode) {
        if ((def->accessmode = virDomainFSAccessModeTypeFromString(accessmode)) < 0) {
6679
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
6680
                           _("unknown accessmode '%s'"), accessmode);
6681 6682 6683 6684 6685 6686
            goto error;
        }
    } else {
        def->accessmode = VIR_DOMAIN_FS_ACCESSMODE_PASSTHROUGH;
    }

6687 6688
    if (virDomainParseScaledValue("./space_hard_limit[1]", ctxt,
                                  &def->space_hard_limit, 1,
6689
                                  ULLONG_MAX, false) < 0)
6690 6691 6692 6693
        goto error;

    if (virDomainParseScaledValue("./space_soft_limit[1]", ctxt,
                                  &def->space_soft_limit, 1,
6694
                                  ULLONG_MAX, false) < 0)
6695 6696
        goto error;

6697 6698 6699
    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
E
Eric Blake 已提交
6700 6701
            if (!source &&
                xmlStrEqual(cur->name, BAD_CAST "source")) {
6702

6703
                if (def->type == VIR_DOMAIN_FS_TYPE_MOUNT ||
6704
                    def->type == VIR_DOMAIN_FS_TYPE_BIND) {
6705
                    source = virXMLPropString(cur, "dir");
6706
                } else if (def->type == VIR_DOMAIN_FS_TYPE_FILE) {
6707
                    source = virXMLPropString(cur, "file");
6708
                } else if (def->type == VIR_DOMAIN_FS_TYPE_BLOCK) {
6709
                    source = virXMLPropString(cur, "dev");
6710
                } else if (def->type == VIR_DOMAIN_FS_TYPE_TEMPLATE) {
6711
                    source = virXMLPropString(cur, "name");
6712
                } else if (def->type == VIR_DOMAIN_FS_TYPE_RAM) {
6713
                    usage = virXMLPropString(cur, "usage");
6714
                    units = virXMLPropString(cur, "units");
6715
                }
E
Eric Blake 已提交
6716 6717
            } else if (!target &&
                       xmlStrEqual(cur->name, BAD_CAST "target")) {
6718 6719
                target = virXMLPropString(cur, "dir");
            } else if (xmlStrEqual(cur->name, BAD_CAST "readonly")) {
6720
                def->readonly = true;
6721 6722 6723 6724 6725 6726 6727
            } else if (xmlStrEqual(cur->name, BAD_CAST "driver")) {
                if (!fsdriver)
                    fsdriver = virXMLPropString(cur, "type");
                if (!wrpolicy)
                    wrpolicy = virXMLPropString(cur, "wrpolicy");
                if (!format)
                    format = virXMLPropString(cur, "format");
6728 6729 6730 6731 6732
            }
        }
        cur = cur->next;
    }

6733
    if (fsdriver) {
6734
        if ((def->fsdriver = virDomainFSDriverTypeFromString(fsdriver)) <= 0) {
6735
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
6736
                           _("unknown fs driver type '%s'"), fsdriver);
6737 6738 6739 6740
            goto error;
        }
    }

6741 6742 6743 6744 6745 6746 6747 6748
    if (format) {
        if ((def->format = virStorageFileFormatTypeFromString(format)) <= 0) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown driver format value '%s'"), format);
            goto error;
        }
    }

6749 6750
    if (wrpolicy) {
        if ((def->wrpolicy = virDomainFSWrpolicyTypeFromString(wrpolicy)) <= 0) {
6751 6752
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown filesystem write policy '%s'"), wrpolicy);
6753 6754 6755 6756 6757 6758
            goto error;
        }
    } else {
        def->wrpolicy = VIR_DOMAIN_FS_WRPOLICY_DEFAULT;
    }

6759 6760
    if (source == NULL &&
        def->type != VIR_DOMAIN_FS_TYPE_RAM) {
6761 6762
        virReportError(VIR_ERR_NO_SOURCE,
                       target ? "%s" : NULL, target);
6763 6764 6765 6766
        goto error;
    }

    if (target == NULL) {
6767 6768
        virReportError(VIR_ERR_NO_TARGET,
                       source ? "%s" : NULL, source);
6769 6770 6771
        goto error;
    }

6772 6773
    if (def->type == VIR_DOMAIN_FS_TYPE_RAM) {
        if (!usage) {
6774 6775
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("missing 'usage' attribute for RAM filesystem"));
6776 6777 6778
            goto error;
        }
        if (virStrToLong_ull(usage, NULL, 10, &def->usage) < 0) {
6779 6780 6781
            virReportError(VIR_ERR_XML_ERROR,
                           _("cannot parse usage '%s' for RAM filesystem"),
                           usage);
6782 6783
            goto error;
        }
6784
        if (virScaleInteger(&def->usage, units,
6785
                            1024, ULLONG_MAX) < 0)
6786 6787 6788
            goto error;
    }

6789 6790 6791 6792 6793
    def->src = source;
    source = NULL;
    def->dst = target;
    target = NULL;

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

6797
 cleanup:
6798
    ctxt->node = save_node;
6799
    VIR_FREE(type);
6800
    VIR_FREE(fsdriver);
6801 6802
    VIR_FREE(target);
    VIR_FREE(source);
6803
    VIR_FREE(accessmode);
6804
    VIR_FREE(wrpolicy);
6805
    VIR_FREE(usage);
6806
    VIR_FREE(units);
6807
    VIR_FREE(format);
6808 6809 6810 6811 6812 6813 6814 6815 6816

    return def;

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

6817 6818 6819
static int
virDomainActualNetDefParseXML(xmlNodePtr node,
                              xmlXPathContextPtr ctxt,
6820 6821 6822
                              virDomainNetDefPtr parent,
                              virDomainActualNetDefPtr *def,
                              unsigned int flags)
6823 6824 6825 6826
{
    virDomainActualNetDefPtr actual = NULL;
    int ret = -1;
    xmlNodePtr save_ctxt = ctxt->node;
6827
    xmlNodePtr bandwidth_node = NULL;
6828
    xmlNodePtr vlanNode;
6829
    xmlNodePtr virtPortNode;
6830 6831
    char *type = NULL;
    char *mode = NULL;
6832
    char *addrtype = NULL;
6833
    char *trustGuestRxFilters = NULL;
6834

6835
    if (VIR_ALLOC(actual) < 0)
6836 6837 6838 6839 6840 6841
        return -1;

    ctxt->node = node;

    type = virXMLPropString(node, "type");
    if (!type) {
6842 6843
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("missing type attribute in interface's <actual> element"));
6844 6845 6846
        goto error;
    }
    if ((actual->type = virDomainNetTypeFromString(type)) < 0) {
6847
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
6848
                       _("unknown type '%s' in interface's <actual> element"), type);
6849 6850 6851
        goto error;
    }
    if (actual->type != VIR_DOMAIN_NET_TYPE_BRIDGE &&
6852
        actual->type != VIR_DOMAIN_NET_TYPE_DIRECT &&
6853
        actual->type != VIR_DOMAIN_NET_TYPE_HOSTDEV &&
6854
        actual->type != VIR_DOMAIN_NET_TYPE_NETWORK) {
6855 6856 6857
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unsupported type '%s' in interface's <actual> element"),
                       type);
6858 6859 6860
        goto error;
    }

6861 6862 6863 6864 6865 6866 6867 6868 6869 6870
    trustGuestRxFilters = virXMLPropString(node, "trustGuestRxFilters");
    if (trustGuestRxFilters &&
        ((actual->trustGuestRxFilters
          = virTristateBoolTypeFromString(trustGuestRxFilters)) <= 0)) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("unknown trustGuestRxFilters value '%s'"),
                       trustGuestRxFilters);
        goto error;
    }

6871 6872 6873 6874 6875
    virtPortNode = virXPathNode("./virtualport", ctxt);
    if (virtPortNode) {
        if (actual->type == VIR_DOMAIN_NET_TYPE_BRIDGE ||
            actual->type == VIR_DOMAIN_NET_TYPE_DIRECT ||
            actual->type == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
6876 6877 6878
            /* the virtualport in <actual> should always already
             * have an instanceid/interfaceid if its required,
             * so don't let the parser generate one */
6879
            if (!(actual->virtPortProfile
6880 6881 6882
                  = virNetDevVPortProfileParse(virtPortNode,
                                               VIR_VPORT_XML_REQUIRE_ALL_ATTRIBUTES |
                                               VIR_VPORT_XML_REQUIRE_TYPE))) {
6883 6884 6885 6886 6887 6888
                goto error;
            }
        } else {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("<virtualport> element unsupported for type='%s'"
                             " in interface's <actual> element"), type);
A
Ansis Atteka 已提交
6889
            goto error;
6890 6891
        }
    }
6892

6893
    if (actual->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
6894 6895 6896 6897 6898
        actual->data.direct.linkdev = virXPathString("string(./source[1]/@dev)", ctxt);

        mode = virXPathString("string(./source[1]/@mode)", ctxt);
        if (mode) {
            int m;
6899
            if ((m = virNetDevMacVLanModeTypeFromString(mode)) < 0) {
6900
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
J
Ján Tomko 已提交
6901
                               _("Unknown mode '%s' in interface <actual> element"),
6902
                               mode);
6903 6904 6905 6906
                goto error;
            }
            actual->data.direct.mode = m;
        }
6907 6908 6909 6910 6911 6912 6913 6914 6915 6916 6917 6918
    } else if (actual->type == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
        virDomainHostdevDefPtr hostdev = &actual->data.hostdev.def;

        hostdev->parent.type = VIR_DOMAIN_DEVICE_NET;
        hostdev->parent.data.net = parent;
        hostdev->info = &parent->info;
        /* The helper function expects type to already be found and
         * passed in as a string, since it is in a different place in
         * NetDef vs HostdevDef.
         */
        addrtype = virXPathString("string(./source/address/@type)", ctxt);
        /* if not explicitly stated, source/vendor implies usb device */
E
Eric Blake 已提交
6919
        if (!addrtype && virXPathNode("./source/vendor", ctxt) &&
6920
            VIR_STRDUP(addrtype, "usb") < 0)
6921
            goto error;
6922 6923 6924
        hostdev->mode = VIR_DOMAIN_HOSTDEV_MODE_SUBSYS;
        if (virDomainHostdevDefParseXMLSubsys(node, ctxt, addrtype,
                                              hostdev, flags) < 0) {
6925 6926
            goto error;
        }
6927 6928 6929 6930 6931 6932 6933 6934 6935 6936 6937
    } else if (actual->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
        char *class_id = virXPathString("string(./class/@id)", ctxt);
        if (class_id &&
            virStrToLong_ui(class_id, NULL, 10, &actual->class_id) < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unable to parse class id '%s'"),
                           class_id);
            VIR_FREE(class_id);
            goto error;
        }
        VIR_FREE(class_id);
6938 6939 6940 6941 6942 6943 6944 6945 6946
    } else if (actual->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
        char *brname = virXPathString("string(./source/@bridge)", ctxt);
        if (!brname) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Missing <source> element with bridge name in "
                             "interface's <actual> element"));
            goto error;
        }
        actual->data.bridge.brname = brname;
6947 6948
    }

6949 6950
    bandwidth_node = virXPathNode("./bandwidth", ctxt);
    if (bandwidth_node &&
6951 6952
        !(actual->bandwidth = virNetDevBandwidthParse(bandwidth_node,
                                                      actual->type)))
6953 6954
        goto error;

6955 6956 6957 6958
    vlanNode = virXPathNode("./vlan", ctxt);
    if (vlanNode && virNetDevVlanParse(vlanNode, ctxt, &actual->vlan) < 0)
       goto error;

6959 6960 6961
    *def = actual;
    actual = NULL;
    ret = 0;
6962
 error:
6963 6964
    VIR_FREE(type);
    VIR_FREE(mode);
6965
    VIR_FREE(addrtype);
6966
    VIR_FREE(trustGuestRxFilters);
6967 6968 6969 6970 6971
    virDomainActualNetDefFree(actual);

    ctxt->node = save_ctxt;
    return ret;
}
6972

E
Eric Blake 已提交
6973
#define NET_MODEL_CHARS \
6974
    "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-"
E
Eric Blake 已提交
6975

6976 6977 6978 6979
/* Parse the XML definition for a network interface
 * @param node XML nodeset to parse for net definition
 * @return 0 on success, -1 on failure
 */
6980
static virDomainNetDefPtr
6981
virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt,
6982
                        xmlNodePtr node,
6983
                        xmlXPathContextPtr ctxt,
6984
                        virHashTablePtr bootHash,
E
Eric Blake 已提交
6985
                        unsigned int flags)
6986
{
6987
    virDomainNetDefPtr def;
6988
    virDomainHostdevDefPtr hostdev;
6989 6990 6991 6992
    xmlNodePtr cur;
    char *macaddr = NULL;
    char *type = NULL;
    char *network = NULL;
6993
    char *portgroup = NULL;
6994 6995 6996
    char *bridge = NULL;
    char *dev = NULL;
    char *ifname = NULL;
6997 6998
    char *ifname_guest = NULL;
    char *ifname_guest_actual = NULL;
6999 7000 7001 7002
    char *script = NULL;
    char *address = NULL;
    char *port = NULL;
    char *model = NULL;
7003
    char *backend = NULL;
7004
    char *txmode = NULL;
7005
    char *ioeventfd = NULL;
7006
    char *event_idx = NULL;
7007
    char *queues = NULL;
7008
    char *str = NULL;
7009
    char *filter = NULL;
D
Daniel Veillard 已提交
7010
    char *internal = NULL;
7011
    char *devaddr = NULL;
7012
    char *mode = NULL;
7013
    char *linkstate = NULL;
7014
    char *addrtype = NULL;
M
Michele Paolino 已提交
7015 7016 7017
    char *vhostuser_mode = NULL;
    char *vhostuser_path = NULL;
    char *vhostuser_type = NULL;
7018
    char *trustGuestRxFilters = NULL;
7019
    virNWFilterHashTablePtr filterparams = NULL;
7020
    virDomainActualNetDefPtr actual = NULL;
7021
    xmlNodePtr oldnode = ctxt->node;
7022
    int ret, val;
7023

7024
    if (VIR_ALLOC(def) < 0)
7025 7026
        return NULL;

7027 7028
    ctxt->node = node;

7029 7030
    type = virXMLPropString(node, "type");
    if (type != NULL) {
S
Stefan Berger 已提交
7031
        if ((int)(def->type = virDomainNetTypeFromString(type)) < 0) {
7032
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
7033
                           _("unknown interface type '%s'"), type);
7034 7035 7036 7037 7038 7039
            goto error;
        }
    } else {
        def->type = VIR_DOMAIN_NET_TYPE_USER;
    }

7040 7041 7042 7043 7044 7045 7046 7047 7048 7049
    trustGuestRxFilters = virXMLPropString(node, "trustGuestRxFilters");
    if (trustGuestRxFilters &&
        ((def->trustGuestRxFilters
          = virTristateBoolTypeFromString(trustGuestRxFilters)) <= 0)) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("unknown trustGuestRxFilters value '%s'"),
                       trustGuestRxFilters);
        goto error;
    }

7050 7051 7052
    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
E
Eric Blake 已提交
7053
            if (!macaddr && xmlStrEqual(cur->name, BAD_CAST "mac")) {
7054
                macaddr = virXMLPropString(cur, "address");
E
Eric Blake 已提交
7055 7056 7057
            } else if (!network &&
                       def->type == VIR_DOMAIN_NET_TYPE_NETWORK &&
                       xmlStrEqual(cur->name, BAD_CAST "source")) {
7058
                network = virXMLPropString(cur, "network");
7059
                portgroup = virXMLPropString(cur, "portgroup");
E
Eric Blake 已提交
7060 7061 7062
            } else if (!internal &&
                       def->type == VIR_DOMAIN_NET_TYPE_INTERNAL &&
                       xmlStrEqual(cur->name, BAD_CAST "source")) {
D
Daniel Veillard 已提交
7063
                internal = virXMLPropString(cur, "name");
G
Guannan Ren 已提交
7064
            } else if (!bridge &&
E
Eric Blake 已提交
7065 7066
                       def->type == VIR_DOMAIN_NET_TYPE_BRIDGE &&
                       xmlStrEqual(cur->name, BAD_CAST "source")) {
7067
                bridge = virXMLPropString(cur, "bridge");
E
Eric Blake 已提交
7068
            } else if (!dev &&
7069 7070
                       (def->type == VIR_DOMAIN_NET_TYPE_ETHERNET ||
                        def->type == VIR_DOMAIN_NET_TYPE_DIRECT) &&
7071
                       xmlStrEqual(cur->name, BAD_CAST "source")) {
7072 7073
                dev  = virXMLPropString(cur, "dev");
                mode = virXMLPropString(cur, "mode");
M
Michele Paolino 已提交
7074 7075 7076 7077 7078 7079
            } else if (!vhostuser_path && !vhostuser_mode && !vhostuser_type
                       && def->type == VIR_DOMAIN_NET_TYPE_VHOSTUSER &&
                       xmlStrEqual(cur->name, BAD_CAST "source")) {
                vhostuser_type = virXMLPropString(cur, "type");
                vhostuser_path = virXMLPropString(cur, "path");
                vhostuser_mode = virXMLPropString(cur, "mode");
7080 7081
            } else if (!def->virtPortProfile
                       && xmlStrEqual(cur->name, BAD_CAST "virtualport")) {
7082
                if (def->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
7083
                    if (!(def->virtPortProfile
7084 7085 7086 7087 7088 7089 7090 7091 7092 7093 7094 7095
                          = virNetDevVPortProfileParse(cur,
                                                       VIR_VPORT_XML_GENERATE_MISSING_DEFAULTS))) {
                        goto error;
                    }
                } else if (def->type == VIR_DOMAIN_NET_TYPE_BRIDGE ||
                           def->type == VIR_DOMAIN_NET_TYPE_DIRECT ||
                           def->type == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
                    if (!(def->virtPortProfile
                          = virNetDevVPortProfileParse(cur,
                                                       VIR_VPORT_XML_GENERATE_MISSING_DEFAULTS|
                                                       VIR_VPORT_XML_REQUIRE_ALL_ATTRIBUTES|
                                                       VIR_VPORT_XML_REQUIRE_TYPE))) {
7096 7097 7098 7099 7100 7101
                        goto error;
                    }
                } else {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("<virtualport> element unsupported for"
                                     " <interface type='%s'>"), type);
7102
                    goto error;
7103
                }
G
Guannan Ren 已提交
7104
            } else if (!address &&
E
Eric Blake 已提交
7105 7106 7107 7108
                       (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")) {
7109 7110
                address = virXMLPropString(cur, "address");
                port = virXMLPropString(cur, "port");
E
Eric Blake 已提交
7111
            } else if (!address &&
7112 7113
                       (def->type == VIR_DOMAIN_NET_TYPE_ETHERNET ||
                        def->type == VIR_DOMAIN_NET_TYPE_BRIDGE) &&
E
Eric Blake 已提交
7114
                       xmlStrEqual(cur->name, BAD_CAST "ip")) {
7115
                address = virXMLPropString(cur, "address");
E
Eric Blake 已提交
7116
            } else if (!ifname &&
7117 7118
                       xmlStrEqual(cur->name, BAD_CAST "target")) {
                ifname = virXMLPropString(cur, "dev");
E
Eric Blake 已提交
7119 7120 7121
                if (ifname &&
                    (flags & VIR_DOMAIN_XML_INACTIVE) &&
                    STRPREFIX(ifname, VIR_NET_GENERATED_PREFIX)) {
7122 7123 7124
                    /* An auto-generated target name, blank it out */
                    VIR_FREE(ifname);
                }
7125 7126 7127 7128
            } else if ((!ifname_guest || !ifname_guest_actual) &&
                       xmlStrEqual(cur->name, BAD_CAST "guest")) {
                ifname_guest = virXMLPropString(cur, "dev");
                ifname_guest_actual = virXMLPropString(cur, "actual");
E
Eric Blake 已提交
7129
            } else if (!linkstate &&
7130 7131
                       xmlStrEqual(cur->name, BAD_CAST "link")) {
                linkstate = virXMLPropString(cur, "state");
E
Eric Blake 已提交
7132
            } else if (!script &&
7133 7134
                       xmlStrEqual(cur->name, BAD_CAST "script")) {
                script = virXMLPropString(cur, "path");
7135
            } else if (xmlStrEqual(cur->name, BAD_CAST "model")) {
7136
                model = virXMLPropString(cur, "type");
7137
            } else if (xmlStrEqual(cur->name, BAD_CAST "driver")) {
7138
                backend = virXMLPropString(cur, "name");
7139
                txmode = virXMLPropString(cur, "txmode");
7140
                ioeventfd = virXMLPropString(cur, "ioeventfd");
7141
                event_idx = virXMLPropString(cur, "event_idx");
7142
                queues = virXMLPropString(cur, "queues");
7143
            } else if (xmlStrEqual(cur->name, BAD_CAST "filterref")) {
7144 7145 7146 7147 7148 7149
                if (filter) {
                    virReportError(VIR_ERR_XML_ERROR, "%s",
                                   _("Invalid specification of multiple <filterref>s "
                                     "in a single <interface>"));
                    goto error;
                }
7150
                filter = virXMLPropString(cur, "filter");
7151
                virNWFilterHashTableFree(filterparams);
7152
                filterparams = virNWFilterParseParamAttributes(cur);
7153 7154
            } else if ((flags & VIR_DOMAIN_XML_INTERNAL_STATUS) &&
                       xmlStrEqual(cur->name, BAD_CAST "state")) {
7155
                /* Legacy back-compat. Don't add any more attributes here */
7156
                devaddr = virXMLPropString(cur, "devaddr");
7157
            } else if (xmlStrEqual(cur->name, BAD_CAST "boot")) {
7158
                /* boot is parsed as part of virDomainDeviceInfoParseXML */
E
Eric Blake 已提交
7159
            } else if (!actual &&
7160
                       (flags & VIR_DOMAIN_XML_INTERNAL_ACTUAL_NET) &&
E
Eric Blake 已提交
7161
                       def->type == VIR_DOMAIN_NET_TYPE_NETWORK &&
7162
                       xmlStrEqual(cur->name, BAD_CAST "actual")) {
7163 7164
                if (virDomainActualNetDefParseXML(cur, ctxt, def,
                                                  &actual, flags) < 0) {
7165
                    goto error;
7166
                }
7167
            } else if (xmlStrEqual(cur->name, BAD_CAST "bandwidth")) {
7168 7169
                if (!(def->bandwidth = virNetDevBandwidthParse(cur,
                                                               def->type)))
7170
                    goto error;
7171 7172 7173
            } else if (xmlStrEqual(cur->name, BAD_CAST "vlan")) {
                if (virNetDevVlanParse(cur, ctxt, &def->vlan) < 0)
                    goto error;
7174
            } else if (xmlStrEqual(cur->name, BAD_CAST "backend")) {
7175 7176 7177 7178 7179 7180 7181 7182 7183
                char *tmp = NULL;

                if ((tmp = virXMLPropString(cur, "tap")))
                    def->backend.tap = virFileSanitizePath(tmp);
                VIR_FREE(tmp);

                if ((tmp = virXMLPropString(cur, "vhost")))
                    def->backend.vhost = virFileSanitizePath(tmp);
                VIR_FREE(tmp);
7184 7185 7186 7187 7188 7189
            }
        }
        cur = cur->next;
    }

    if (macaddr) {
7190
        if (virMacAddrParse((const char *)macaddr, &def->mac) < 0) {
7191 7192 7193
            virReportError(VIR_ERR_XML_ERROR,
                           _("unable to parse mac address '%s'"),
                           (const char *)macaddr);
7194 7195
            goto error;
        }
7196
        if (virMacAddrIsMulticast(&def->mac)) {
7197 7198 7199
            virReportError(VIR_ERR_XML_ERROR,
                           _("expected unicast mac address, found multicast '%s'"),
                           (const char *)macaddr);
7200 7201
            goto error;
        }
7202
    } else {
7203
        virDomainNetGenerateMAC(xmlopt, &def->mac);
7204 7205
    }

7206
    if (devaddr) {
7207 7208
        if (virDomainParseLegacyDeviceAddress(devaddr,
                                              &def->info.addr.pci) < 0) {
7209 7210 7211
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unable to parse devaddr parameter '%s'"),
                           devaddr);
7212 7213 7214 7215
            goto error;
        }
        def->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
    } else {
7216
        if (virDomainDeviceInfoParseXML(node, bootHash, &def->info,
7217 7218
                                        flags | VIR_DOMAIN_XML_INTERNAL_ALLOW_BOOT
                                        | VIR_DOMAIN_XML_INTERNAL_ALLOW_ROM) < 0)
7219 7220 7221 7222 7223 7224
            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 &&
7225
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO &&
7226
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW &&
7227
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390 &&
7228
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO &&
7229
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
7230 7231
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Network interfaces must use 'pci' address type"));
7232 7233 7234
        goto error;
    }

7235 7236 7237
    switch (def->type) {
    case VIR_DOMAIN_NET_TYPE_NETWORK:
        if (network == NULL) {
7238 7239 7240
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("No <source> 'network' attribute "
                             "specified with <interface type='network'/>"));
7241 7242 7243 7244
            goto error;
        }
        def->data.network.name = network;
        network = NULL;
7245 7246 7247 7248
        def->data.network.portgroup = portgroup;
        portgroup = NULL;
        def->data.network.actual = actual;
        actual = NULL;
7249 7250
        break;

M
Michele Paolino 已提交
7251 7252 7253 7254 7255 7256 7257 7258 7259 7260 7261 7262 7263 7264 7265 7266 7267 7268 7269 7270 7271 7272 7273 7274 7275 7276 7277 7278 7279 7280 7281 7282 7283 7284 7285 7286 7287 7288 7289 7290 7291 7292 7293 7294 7295 7296
    case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
        if (STRNEQ_NULLABLE(model, "virtio")) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Wrong or no <model> 'type' attribute "
                             "specified with <interface type='vhostuser'/>. "
                             "vhostuser requires the virtio-net* frontend"));
            goto error;
        }

        if (STRNEQ_NULLABLE(vhostuser_type, "unix")) {
            if (vhostuser_type)
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("Type='%s' unsupported for"
                                 " <interface type='vhostuser'>"),
                               vhostuser_type);
            else
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                               _("No <source> 'type' attribute "
                                 "specified for <interface "
                                 "type='vhostuser'>"));
            goto error;
        }

        if (vhostuser_path == NULL) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("No <source> 'path' attribute "
                             "specified with <interface "
                             "type='vhostuser'/>"));
            goto error;
        }

        if (vhostuser_mode == NULL) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("No <source> 'mode' attribute "
                             "specified with <interface "
                             "type='vhostuser'/>"));
            goto error;
        }

        if (VIR_ALLOC(def->data.vhostuser) < 0)
            goto error;

        def->data.vhostuser->type = VIR_DOMAIN_CHR_TYPE_UNIX;
        def->data.vhostuser->data.nix.path = vhostuser_path;
        vhostuser_path = NULL;

7297
        if (STREQ(vhostuser_mode, "server")) {
M
Michele Paolino 已提交
7298
            def->data.vhostuser->data.nix.listen = true;
7299
        } else if (STREQ(vhostuser_mode, "client")) {
M
Michele Paolino 已提交
7300
            def->data.vhostuser->data.nix.listen = false;
7301
        } else {
M
Michele Paolino 已提交
7302 7303 7304 7305 7306 7307 7308 7309
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("Wrong <source> 'mode' attribute "
                             "specified with <interface "
                             "type='vhostuser'/>"));
            goto error;
        }
        break;

7310 7311 7312 7313 7314 7315 7316 7317 7318 7319 7320 7321 7322
    case VIR_DOMAIN_NET_TYPE_ETHERNET:
        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) {
7323 7324 7325
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("No <source> 'bridge' attribute "
                             "specified with <interface type='bridge'/>"));
7326 7327 7328 7329
            goto error;
        }
        def->data.bridge.brname = bridge;
        bridge = NULL;
7330 7331 7332 7333
        if (address != NULL) {
            def->data.bridge.ipaddr = address;
            address = NULL;
        }
7334 7335 7336 7337 7338 7339
        break;

    case VIR_DOMAIN_NET_TYPE_CLIENT:
    case VIR_DOMAIN_NET_TYPE_SERVER:
    case VIR_DOMAIN_NET_TYPE_MCAST:
        if (port == NULL) {
7340 7341 7342
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("No <source> 'port' attribute "
                             "specified with socket interface"));
7343 7344 7345
            goto error;
        }
        if (virStrToLong_i(port, NULL, 10, &def->data.socket.port) < 0) {
7346 7347 7348
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Cannot parse <source> 'port' attribute "
                             "with socket interface"));
7349 7350 7351 7352 7353 7354
            goto error;
        }

        if (address == NULL) {
            if (def->type == VIR_DOMAIN_NET_TYPE_CLIENT ||
                def->type == VIR_DOMAIN_NET_TYPE_MCAST) {
7355 7356 7357
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("No <source> 'address' attribute "
                                 "specified with socket interface"));
7358 7359 7360 7361 7362 7363
                goto error;
            }
        } else {
            def->data.socket.address = address;
            address = NULL;
        }
7364 7365
        break;

D
Daniel Veillard 已提交
7366 7367
    case VIR_DOMAIN_NET_TYPE_INTERNAL:
        if (internal == NULL) {
7368 7369 7370
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("No <source> 'name' attribute specified "
                             "with <interface type='internal'/>"));
D
Daniel Veillard 已提交
7371 7372 7373 7374 7375
            goto error;
        }
        def->data.internal.name = internal;
        internal = NULL;
        break;
7376 7377 7378

    case VIR_DOMAIN_NET_TYPE_DIRECT:
        if (dev == NULL) {
7379 7380 7381
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("No <source> 'dev' attribute specified "
                             "with <interface type='direct'/>"));
7382 7383 7384 7385
            goto error;
        }

        if (mode != NULL) {
7386
            if ((val = virNetDevMacVLanModeTypeFromString(mode)) < 0) {
7387
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
J
Ján Tomko 已提交
7388
                               _("Unknown mode has been specified"));
7389 7390
                goto error;
            }
7391
            def->data.direct.mode = val;
E
Eric Blake 已提交
7392
        } else {
7393
            def->data.direct.mode = VIR_NETDEV_MACVLAN_MODE_VEPA;
E
Eric Blake 已提交
7394
        }
7395 7396 7397 7398

        def->data.direct.linkdev = dev;
        dev = NULL;

E
Eric Blake 已提交
7399
        if (flags & VIR_DOMAIN_XML_INACTIVE)
7400
            VIR_FREE(ifname);
7401

7402
        break;
S
Stefan Berger 已提交
7403

7404 7405 7406 7407 7408 7409 7410 7411 7412 7413 7414
    case VIR_DOMAIN_NET_TYPE_HOSTDEV:
        hostdev = &def->data.hostdev.def;
        hostdev->parent.type = VIR_DOMAIN_DEVICE_NET;
        hostdev->parent.data.net = def;
        hostdev->info = &def->info;
        /* The helper function expects type to already be found and
         * passed in as a string, since it is in a different place in
         * NetDef vs HostdevDef.
         */
        addrtype = virXPathString("string(./source/address/@type)", ctxt);
        /* if not explicitly stated, source/vendor implies usb device */
E
Eric Blake 已提交
7415
        if (!addrtype && virXPathNode("./source/vendor", ctxt) &&
7416
            VIR_STRDUP(addrtype, "usb") < 0)
7417
            goto error;
7418 7419 7420
        hostdev->mode = VIR_DOMAIN_HOSTDEV_MODE_SUBSYS;
        if (virDomainHostdevDefParseXMLSubsys(node, ctxt, addrtype,
                                              hostdev, flags) < 0) {
7421 7422 7423 7424
            goto error;
        }
        break;

S
Stefan Berger 已提交
7425 7426 7427
    case VIR_DOMAIN_NET_TYPE_USER:
    case VIR_DOMAIN_NET_TYPE_LAST:
        break;
7428 7429
    }

7430 7431 7432 7433
    if (script != NULL) {
        def->script = script;
        script = NULL;
    }
7434 7435 7436 7437
    if (ifname != NULL) {
        def->ifname = ifname;
        ifname = NULL;
    }
7438 7439 7440 7441 7442 7443 7444 7445
    if (ifname_guest != NULL) {
        def->ifname_guest = ifname_guest;
        ifname_guest = NULL;
    }
    if (ifname_guest_actual != NULL) {
        def->ifname_guest_actual = ifname_guest_actual;
        ifname_guest_actual = NULL;
    }
7446 7447 7448 7449 7450

    /* 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
E
Eric Blake 已提交
7451
     * QEMU PPC64 supports spapr-vlan
7452 7453
     */
    if (model != NULL) {
E
Eric Blake 已提交
7454
        if (strspn(model, NET_MODEL_CHARS) < strlen(model)) {
7455 7456
            virReportError(VIR_ERR_INVALID_ARG, "%s",
                           _("Model name contains invalid characters"));
E
Eric Blake 已提交
7457
            goto error;
7458 7459 7460 7461 7462
        }
        def->model = model;
        model = NULL;
    }

7463 7464
    if (def->type != VIR_DOMAIN_NET_TYPE_HOSTDEV &&
        STREQ_NULLABLE(def->model, "virtio")) {
7465
        if (backend != NULL) {
7466 7467
            if ((val = virDomainNetBackendTypeFromString(backend)) < 0 ||
                val == VIR_DOMAIN_NET_BACKEND_TYPE_DEFAULT) {
7468
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
7469 7470 7471
                               _("Unknown interface <driver name='%s'> "
                                 "has been specified"),
                               backend);
7472 7473
                goto error;
            }
7474
            def->driver.virtio.name = val;
7475
        }
7476
        if (txmode != NULL) {
7477 7478
            if ((val = virDomainNetVirtioTxModeTypeFromString(txmode)) < 0 ||
                val == VIR_DOMAIN_NET_VIRTIO_TX_MODE_DEFAULT) {
7479
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
7480 7481 7482
                               _("Unknown interface <driver txmode='%s'> "
                                 "has been specified"),
                               txmode);
7483 7484
                goto error;
            }
7485
            def->driver.virtio.txmode = val;
7486
        }
7487
        if (ioeventfd) {
J
Ján Tomko 已提交
7488
            if ((val = virTristateSwitchTypeFromString(ioeventfd)) <= 0) {
7489 7490 7491
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("unknown interface ioeventfd mode '%s'"),
                               ioeventfd);
7492 7493
                goto error;
            }
7494
            def->driver.virtio.ioeventfd = val;
7495
        }
7496
        if (event_idx) {
7497
            if ((val = virTristateSwitchTypeFromString(event_idx)) <= 0) {
7498 7499 7500
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("unknown interface event_idx mode '%s'"),
                               event_idx);
7501 7502
                goto error;
            }
7503
            def->driver.virtio.event_idx = val;
7504
        }
7505 7506
        if (queues) {
            unsigned int q;
7507
            if (virStrToLong_uip(queues, NULL, 10, &q) < 0) {
7508 7509 7510 7511 7512 7513 7514
                virReportError(VIR_ERR_XML_DETAIL,
                               _("'queues' attribute must be positive number: %s"),
                               queues);
                goto error;
            }
            def->driver.virtio.queues = q;
        }
7515 7516 7517 7518 7519 7520 7521 7522 7523 7524 7525 7526 7527 7528 7529 7530 7531 7532 7533 7534 7535 7536 7537 7538 7539 7540 7541 7542 7543 7544 7545 7546 7547 7548 7549 7550 7551 7552 7553 7554 7555 7556 7557 7558 7559 7560 7561 7562 7563 7564 7565 7566 7567 7568 7569 7570 7571 7572 7573 7574 7575 7576 7577 7578 7579 7580 7581 7582 7583 7584 7585 7586 7587 7588 7589 7590 7591 7592 7593 7594 7595 7596 7597 7598 7599 7600 7601 7602 7603 7604 7605 7606 7607 7608 7609 7610 7611 7612 7613 7614 7615 7616 7617 7618 7619 7620 7621 7622 7623
        if ((str = virXPathString("string(./driver/host/@csum)", ctxt))) {
            if ((val = virTristateSwitchTypeFromString(str)) <= 0) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("unknown host csum mode '%s'"),
                               str);
                goto error;
            }
            def->driver.virtio.host.csum = val;
        }
        VIR_FREE(str);
        if ((str = virXPathString("string(./driver/host/@gso)", ctxt))) {
            if ((val = virTristateSwitchTypeFromString(str)) <= 0) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("unknown host gso mode '%s'"),
                               str);
                goto error;
            }
            def->driver.virtio.host.gso = val;
        }
        VIR_FREE(str);
        if ((str = virXPathString("string(./driver/host/@tso4)", ctxt))) {
            if ((val = virTristateSwitchTypeFromString(str)) <= 0) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("unknown host tso4 mode '%s'"),
                               str);
                goto error;
            }
            def->driver.virtio.host.tso4 = val;
        }
        VIR_FREE(str);
        if ((str = virXPathString("string(./driver/host/@tso6)", ctxt))) {
            if ((val = virTristateSwitchTypeFromString(str)) <= 0) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("unknown host tso6 mode '%s'"),
                               str);
                goto error;
            }
            def->driver.virtio.host.tso6 = val;
        }
        VIR_FREE(str);
        if ((str = virXPathString("string(./driver/host/@ecn)", ctxt))) {
            if ((val = virTristateSwitchTypeFromString(str)) <= 0) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("unknown host ecn mode '%s'"),
                               str);
                goto error;
            }
            def->driver.virtio.host.ecn = val;
        }
        VIR_FREE(str);
        if ((str = virXPathString("string(./driver/host/@ufo)", ctxt))) {
            if ((val = virTristateSwitchTypeFromString(str)) <= 0) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("unknown host ufo mode '%s'"),
                               str);
                goto error;
            }
            def->driver.virtio.host.ufo = val;
        }
        VIR_FREE(str);
        if ((str = virXPathString("string(./driver/guest/@csum)", ctxt))) {
            if ((val = virTristateSwitchTypeFromString(str)) <= 0) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("unknown guest csum mode '%s'"),
                               str);
                goto error;
            }
            def->driver.virtio.guest.csum = val;
        }
        VIR_FREE(str);
        if ((str = virXPathString("string(./driver/guest/@tso4)", ctxt))) {
            if ((val = virTristateSwitchTypeFromString(str)) <= 0) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("unknown guest tso4 mode '%s'"),
                               str);
                goto error;
            }
            def->driver.virtio.guest.tso4 = val;
        }
        VIR_FREE(str);
        if ((str = virXPathString("string(./driver/guest/@tso6)", ctxt))) {
            if ((val = virTristateSwitchTypeFromString(str)) <= 0) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("unknown guest tso6 mode '%s'"),
                               str);
                goto error;
            }
            def->driver.virtio.guest.tso6 = val;
        }
        VIR_FREE(str);
        if ((str = virXPathString("string(./driver/guest/@ecn)", ctxt))) {
            if ((val = virTristateSwitchTypeFromString(str)) <= 0) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("unknown guest ecn mode '%s'"),
                               str);
                goto error;
            }
            def->driver.virtio.guest.ecn = val;
        }
        VIR_FREE(str);
        if ((str = virXPathString("string(./driver/guest/@ufo)", ctxt))) {
            if ((val = virTristateSwitchTypeFromString(str)) <= 0) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("unknown guest ufo mode '%s'"),
                               str);
                goto error;
            }
            def->driver.virtio.guest.ufo = val;
        }
7624
    }
7625

7626 7627 7628
    def->linkstate = VIR_DOMAIN_NET_INTERFACE_LINK_STATE_DEFAULT;
    if (linkstate != NULL) {
        if ((def->linkstate = virDomainNetInterfaceLinkStateTypeFromString(linkstate)) <= 0) {
7629 7630 7631
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown interface link state '%s'"),
                           linkstate);
7632 7633 7634 7635
            goto error;
        }
    }

7636 7637 7638 7639 7640 7641 7642 7643 7644 7645 7646 7647 7648 7649 7650
    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;
        }
    }

7651 7652 7653 7654
    ret = virXPathULong("string(./tune/sndbuf)", ctxt, &def->tune.sndbuf);
    if (ret >= 0) {
        def->tune.sndbuf_specified = true;
    } else if (ret == -2) {
7655 7656
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("sndbuf must be a positive integer"));
7657 7658 7659
        goto error;
    }

7660
 cleanup:
7661
    ctxt->node = oldnode;
7662 7663
    VIR_FREE(macaddr);
    VIR_FREE(network);
7664
    VIR_FREE(portgroup);
7665 7666
    VIR_FREE(address);
    VIR_FREE(port);
M
Michele Paolino 已提交
7667 7668 7669
    VIR_FREE(vhostuser_type);
    VIR_FREE(vhostuser_path);
    VIR_FREE(vhostuser_mode);
7670 7671
    VIR_FREE(ifname);
    VIR_FREE(dev);
7672
    virDomainActualNetDefFree(actual);
7673 7674 7675
    VIR_FREE(script);
    VIR_FREE(bridge);
    VIR_FREE(model);
7676
    VIR_FREE(backend);
7677
    VIR_FREE(txmode);
7678
    VIR_FREE(ioeventfd);
7679
    VIR_FREE(event_idx);
7680
    VIR_FREE(queues);
7681
    VIR_FREE(str);
7682
    VIR_FREE(filter);
7683
    VIR_FREE(type);
D
Daniel Veillard 已提交
7684
    VIR_FREE(internal);
7685
    VIR_FREE(devaddr);
S
Stefan Berger 已提交
7686
    VIR_FREE(mode);
7687
    VIR_FREE(linkstate);
7688
    VIR_FREE(addrtype);
7689
    VIR_FREE(trustGuestRxFilters);
7690
    virNWFilterHashTableFree(filterparams);
7691 7692 7693

    return def;

7694
 error:
7695 7696 7697 7698 7699
    virDomainNetDefFree(def);
    def = NULL;
    goto cleanup;
}

7700
static int
7701 7702
virDomainChrDefaultTargetType(int devtype)
{
7703
    switch ((virDomainChrDeviceType) devtype) {
7704
    case VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL:
7705 7706 7707
        virReportError(VIR_ERR_XML_ERROR,
                       _("target type must be specified for %s device"),
                       virDomainChrDeviceTypeToString(devtype));
7708
        return -1;
7709 7710

    case VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE:
7711
        return VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_NONE;
7712

7713
    case VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL:
7714
        return VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_ISA;
G
Guannan Ren 已提交
7715

7716
    case VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL:
7717
    case VIR_DOMAIN_CHR_DEVICE_TYPE_LAST:
7718 7719 7720 7721
        /* No target type yet*/
        break;
    }

7722
    return 0;
7723 7724 7725
}

static int
7726
virDomainChrTargetTypeFromString(virDomainChrDefPtr def,
7727
                                 int devtype,
7728 7729 7730 7731
                                 const char *targetType)
{
    int ret = -1;

7732 7733
    if (!targetType)
        return virDomainChrDefaultTargetType(devtype);
7734

7735
    switch ((virDomainChrDeviceType) devtype) {
7736
    case VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL:
7737
        ret = virDomainChrChannelTargetTypeFromString(targetType);
7738 7739
        break;

7740
    case VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE:
7741
        ret = virDomainChrConsoleTargetTypeFromString(targetType);
C
Cole Robinson 已提交
7742
        break;
7743

7744
    case VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL:
7745
        ret = virDomainChrSerialTargetTypeFromString(targetType);
G
Guannan Ren 已提交
7746 7747
        break;

7748
    case VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL:
7749
    case VIR_DOMAIN_CHR_DEVICE_TYPE_LAST:
7750
        /* No target type yet*/
7751
        ret = 0;
7752 7753 7754
        break;
    }

G
Guannan Ren 已提交
7755 7756
    def->targetTypeAttr = true;

7757 7758 7759 7760
    return ret;
}

static int
7761
virDomainChrDefParseTargetXML(virDomainChrDefPtr def,
E
Eric Blake 已提交
7762
                              xmlNodePtr cur)
7763 7764 7765
{
    int ret = -1;
    unsigned int port;
7766 7767 7768
    char *targetType = virXMLPropString(cur, "type");
    char *addrStr = NULL;
    char *portStr = NULL;
7769 7770

    if ((def->targetType =
7771 7772
         virDomainChrTargetTypeFromString(def, def->deviceType,
                                          targetType)) < 0) {
7773
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
7774 7775
                       _("unknown target type '%s' specified for character device"),
                       targetType);
7776 7777 7778 7779 7780 7781 7782 7783 7784 7785
        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");

7786
            if (VIR_ALLOC(def->target.addr) < 0)
7787 7788
                goto error;

7789
            if (addrStr == NULL) {
7790 7791 7792
                virReportError(VIR_ERR_XML_ERROR, "%s",
                               _("guestfwd channel does not "
                                 "define a target address"));
7793 7794 7795
                goto error;
            }

7796
            if (virSocketAddrParse(def->target.addr, addrStr, AF_UNSPEC) < 0)
7797 7798
                goto error;

7799
            if (def->target.addr->data.stor.ss_family != AF_INET) {
7800 7801 7802
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               "%s", _("guestfwd channel only supports "
                                       "IPv4 addresses"));
7803 7804 7805 7806
                goto error;
            }

            if (portStr == NULL) {
7807 7808 7809
                virReportError(VIR_ERR_XML_ERROR, "%s",
                               _("guestfwd channel does "
                                 "not define a target port"));
7810 7811 7812 7813
                goto error;
            }

            if (virStrToLong_ui(portStr, NULL, 10, &port) < 0) {
7814 7815 7816
                virReportError(VIR_ERR_XML_ERROR,
                               _("Invalid port number: %s"),
                               portStr);
7817 7818 7819
                goto error;
            }

7820
            virSocketAddrSetPort(def->target.addr, port);
7821 7822 7823 7824 7825 7826 7827 7828 7829 7830 7831
            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) {
7832 7833
            /* Set to negative value to indicate we should set it later */
            def->target.port = -1;
7834 7835 7836 7837
            break;
        }

        if (virStrToLong_ui(portStr, NULL, 10, &port) < 0) {
7838 7839 7840
            virReportError(VIR_ERR_XML_ERROR,
                           _("Invalid port number: %s"),
                           portStr);
7841 7842
            goto error;
        }
7843
        def->target.port = port;
7844 7845 7846 7847 7848
        break;
    }


    ret = 0;
7849
 error:
7850 7851 7852 7853 7854 7855 7856
    VIR_FREE(targetType);
    VIR_FREE(addrStr);
    VIR_FREE(portStr);

    return ret;
}

7857 7858 7859
#define SERIAL_CHANNEL_NAME_CHARS \
    "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-."

7860 7861 7862 7863 7864 7865 7866
/* 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,
7867 7868 7869 7870 7871
                              xmlNodePtr cur, unsigned int flags,
                              virDomainChrDefPtr chr_def,
                              xmlXPathContextPtr ctxt,
                              virSecurityLabelDefPtr* vmSeclabels,
                              int nvmSeclabels)
7872
{
7873 7874 7875 7876 7877 7878 7879
    char *bindHost = NULL;
    char *bindService = NULL;
    char *connectHost = NULL;
    char *connectService = NULL;
    char *path = NULL;
    char *mode = NULL;
    char *protocol = NULL;
7880
    char *channel = NULL;
7881 7882
    char *master = NULL;
    char *slave = NULL;
7883
    int remaining = 0;
7884 7885 7886 7887

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

7891
                switch ((virDomainChrType) def->type) {
7892 7893 7894 7895 7896
                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:
7897
                    /* PTY path is only parsed from live xml.  */
7898
                    if (!path  &&
7899 7900
                        (def->type != VIR_DOMAIN_CHR_TYPE_PTY ||
                         !(flags & VIR_DOMAIN_XML_INACTIVE)))
7901 7902 7903 7904 7905 7906
                        path = virXMLPropString(cur, "path");

                    break;

                case VIR_DOMAIN_CHR_TYPE_UDP:
                case VIR_DOMAIN_CHR_TYPE_TCP:
7907 7908
                    if (!mode || STREQ(mode, "connect")) {
                        if (!connectHost)
7909
                            connectHost = virXMLPropString(cur, "host");
7910
                        if (!connectService)
7911
                            connectService = virXMLPropString(cur, "service");
7912 7913
                    } else if (STREQ(mode, "bind")) {
                        if (!bindHost)
7914
                            bindHost = virXMLPropString(cur, "host");
7915
                        if (!bindService)
7916
                            bindService = virXMLPropString(cur, "service");
7917
                    } else {
7918
                        virReportError(VIR_ERR_INTERNAL_ERROR,
7919
                                       _("Unknown source mode '%s'"), mode);
7920
                        goto error;
7921 7922
                    }

7923
                    if (def->type == VIR_DOMAIN_CHR_TYPE_UDP)
7924
                        VIR_FREE(mode);
7925 7926
                    break;

7927 7928 7929 7930 7931
                case VIR_DOMAIN_CHR_TYPE_SPICEPORT:
                    if (!channel)
                        channel = virXMLPropString(cur, "channel");
                    break;

7932 7933 7934 7935 7936 7937 7938
                case VIR_DOMAIN_CHR_TYPE_NMDM:
                    if (!master)
                        master = virXMLPropString(cur, "master");
                    if (!slave)
                        slave = virXMLPropString(cur, "slave");
                    break;

7939 7940 7941 7942 7943 7944
                case VIR_DOMAIN_CHR_TYPE_LAST:
                case VIR_DOMAIN_CHR_TYPE_NULL:
                case VIR_DOMAIN_CHR_TYPE_VC:
                case VIR_DOMAIN_CHR_TYPE_STDIO:
                case VIR_DOMAIN_CHR_TYPE_SPICEVMC:
                    break;
7945
                }
7946 7947 7948 7949 7950 7951 7952 7953 7954

                /* Check for an optional seclabel override in <source/>. */
                if (chr_def) {
                    xmlNodePtr saved_node = ctxt->node;
                    ctxt->node = cur;
                    if (virSecurityDeviceLabelDefParseXML(&chr_def->seclabels,
                                                          &chr_def->nseclabels,
                                                          vmSeclabels,
                                                          nvmSeclabels,
7955 7956
                                                          ctxt,
                                                          flags) < 0) {
7957 7958 7959 7960 7961
                        ctxt->node = saved_node;
                        goto error;
                    }
                    ctxt->node = saved_node;
                }
7962
            } else if (xmlStrEqual(cur->name, BAD_CAST "protocol")) {
7963
                if (!protocol)
7964
                    protocol = virXMLPropString(cur, "type");
7965 7966
            } else {
                remaining++;
7967 7968 7969 7970 7971
            }
        }
        cur = cur->next;
    }

7972
    switch ((virDomainChrType) def->type) {
7973
    case VIR_DOMAIN_CHR_TYPE_NULL:
7974
    case VIR_DOMAIN_CHR_TYPE_VC:
7975 7976
    case VIR_DOMAIN_CHR_TYPE_STDIO:
    case VIR_DOMAIN_CHR_TYPE_SPICEVMC:
7977
    case VIR_DOMAIN_CHR_TYPE_LAST:
7978 7979 7980 7981 7982 7983
        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:
7984
        if (!path &&
7985
            def->type != VIR_DOMAIN_CHR_TYPE_PTY) {
7986 7987
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Missing source path attribute for char device"));
7988 7989 7990 7991 7992 7993 7994
            goto error;
        }

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

7995 7996 7997 7998 7999 8000 8001 8002 8003 8004 8005 8006 8007 8008 8009 8010 8011 8012 8013
    case VIR_DOMAIN_CHR_TYPE_NMDM:
        if (!master) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Missing master path attribute for nmdm device"));
            goto error;
        }

        if (!slave) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Missing slave path attribute for nmdm device"));
            goto error;
        }

        def->data.nmdm.master = master;
        def->data.nmdm.slave = slave;
        master = NULL;
        slave = NULL;
        break;

8014
    case VIR_DOMAIN_CHR_TYPE_TCP:
8015 8016
        if (!mode || STREQ(mode, "connect")) {
            if (!connectHost) {
8017 8018
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Missing source host attribute for char device"));
8019 8020
                goto error;
            }
8021 8022

            if (!connectService) {
8023 8024
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Missing source service attribute for char device"));
8025 8026 8027 8028 8029 8030 8031
                goto error;
            }

            def->data.tcp.host = connectHost;
            connectHost = NULL;
            def->data.tcp.service = connectService;
            connectService = NULL;
8032
            def->data.tcp.listen = false;
8033
        } else {
8034
            if (!bindHost) {
8035 8036
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Missing source host attribute for char device"));
8037 8038
                goto error;
            }
8039 8040

            if (!bindService) {
8041 8042
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Missing source service attribute for char device"));
8043 8044 8045 8046 8047 8048 8049
                goto error;
            }

            def->data.tcp.host = bindHost;
            bindHost = NULL;
            def->data.tcp.service = bindService;
            bindService = NULL;
8050
            def->data.tcp.listen = true;
8051
        }
8052

8053
        if (!protocol)
8054
            def->data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_RAW;
8055 8056
        else if ((def->data.tcp.protocol =
                  virDomainChrTcpProtocolTypeFromString(protocol)) < 0) {
8057
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
8058
                           _("Unknown protocol '%s'"), protocol);
8059 8060 8061
            goto error;
        }

8062 8063 8064
        break;

    case VIR_DOMAIN_CHR_TYPE_UDP:
8065
        if (!connectService) {
8066 8067
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Missing source service attribute for char device"));
8068 8069 8070 8071 8072 8073 8074 8075 8076 8077 8078 8079 8080 8081 8082
            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:
8083 8084
        /* path can be auto generated */
        if (!path &&
8085 8086
            (!chr_def ||
             chr_def->targetType != VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO)) {
8087 8088
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Missing source path attribute for char device"));
8089 8090 8091
            goto error;
        }

8092
        def->data.nix.listen = mode != NULL && STRNEQ(mode, "connect");
8093 8094 8095 8096

        def->data.nix.path = path;
        path = NULL;
        break;
8097 8098 8099 8100 8101 8102 8103 8104 8105 8106 8107 8108 8109 8110 8111

    case VIR_DOMAIN_CHR_TYPE_SPICEPORT:
        if (!channel) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("Missing source channel attribute for char device"));
            goto error;
        }
        if (strspn(channel, SERIAL_CHANNEL_NAME_CHARS) < strlen(channel)) {
            virReportError(VIR_ERR_INVALID_ARG, "%s",
                           _("Invalid character in source channel for char device"));
            goto error;
        }
        def->data.spiceport.channel = channel;
        channel = NULL;
        break;
8112 8113
    }

8114
 cleanup:
8115 8116 8117 8118 8119 8120 8121
    VIR_FREE(mode);
    VIR_FREE(protocol);
    VIR_FREE(bindHost);
    VIR_FREE(bindService);
    VIR_FREE(connectHost);
    VIR_FREE(connectService);
    VIR_FREE(path);
8122
    VIR_FREE(channel);
8123

8124 8125
    return remaining;

8126
 error:
8127 8128 8129 8130 8131
    virDomainChrSourceDefClear(def);
    remaining = -1;
    goto cleanup;
}

M
Michal Novotny 已提交
8132 8133 8134 8135
/* Create a new character device definition and set
 * default port.
 */
virDomainChrDefPtr
8136 8137
virDomainChrDefNew(void)
{
M
Michal Novotny 已提交
8138 8139
    virDomainChrDefPtr def = NULL;

8140
    if (VIR_ALLOC(def) < 0)
M
Michal Novotny 已提交
8141 8142 8143 8144 8145 8146
        return NULL;

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

8147 8148 8149 8150 8151 8152 8153 8154 8155 8156 8157 8158 8159 8160 8161 8162 8163 8164 8165 8166 8167 8168 8169 8170 8171 8172 8173 8174 8175 8176 8177 8178 8179 8180 8181 8182 8183
/* 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>
 *
8184 8185 8186 8187 8188
 * <serial type="nmdm">
 *   <source master="/dev/nmdm0A" slave="/dev/nmdm0B"/>
 *   <target port="1">
 * </serial>
 *
8189 8190
 */
static virDomainChrDefPtr
8191
virDomainChrDefParseXML(xmlXPathContextPtr ctxt,
8192
                        xmlNodePtr node,
8193 8194
                        virSecurityLabelDefPtr* vmSeclabels,
                        int nvmSeclabels,
E
Eric Blake 已提交
8195 8196
                        unsigned int flags)
{
8197 8198 8199 8200
    xmlNodePtr cur;
    char *type = NULL;
    const char *nodeName;
    virDomainChrDefPtr def;
8201
    bool seenTarget = false;
8202

M
Michal Novotny 已提交
8203
    if (!(def = virDomainChrDefNew()))
8204 8205 8206 8207 8208 8209
        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) {
8210
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
8211 8212
                       _("unknown type presented to host for character device: %s"),
                       type);
8213 8214 8215 8216 8217
        goto error;
    }

    nodeName = (const char *) node->name;
    if ((def->deviceType = virDomainChrDeviceTypeFromString(nodeName)) < 0) {
8218
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
8219 8220
                       _("unknown character device type: %s"),
                       nodeName);
8221 8222 8223
    }

    cur = node->children;
8224 8225 8226 8227 8228 8229
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
            if (xmlStrEqual(cur->name, BAD_CAST "target")) {
                seenTarget = true;
                if (virDomainChrDefParseTargetXML(def, cur) < 0) {
                    goto error;
8230 8231 8232
                }
            }
        }
8233
        cur = cur->next;
8234 8235
    }

8236
    if (!seenTarget &&
8237
        ((def->targetType = virDomainChrDefaultTargetType(def->deviceType)) < 0))
8238 8239
        goto cleanup;

8240 8241 8242 8243
    if (virDomainChrSourceDefParseXML(&def->source, node->children, flags, def,
                                      ctxt, vmSeclabels, nvmSeclabels) < 0)
        goto error;

E
Eric Blake 已提交
8244 8245
    if (def->source.type == VIR_DOMAIN_CHR_TYPE_SPICEVMC) {
        if (def->targetType != VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO) {
8246 8247 8248
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("spicevmc device type only supports "
                             "virtio"));
E
Eric Blake 已提交
8249 8250 8251 8252
            goto error;
        } else {
            def->source.data.spicevmc = VIR_DOMAIN_CHR_SPICEVMC_VDAGENT;
        }
8253 8254
    }

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

G
Guannan Ren 已提交
8258 8259 8260 8261 8262 8263 8264 8265 8266
    if (def->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL &&
        def->targetType == VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_USB &&
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("usb-serial requires address of usb type"));
        goto error;
    }

8267
 cleanup:
8268 8269
    VIR_FREE(type);

8270 8271
    return def;

8272
 error:
8273 8274 8275 8276 8277
    virDomainChrDefFree(def);
    def = NULL;
    goto cleanup;
}

E
Eric Blake 已提交
8278 8279
static virDomainSmartcardDefPtr
virDomainSmartcardDefParseXML(xmlNodePtr node,
E
Eric Blake 已提交
8280
                              unsigned int flags)
E
Eric Blake 已提交
8281 8282 8283 8284 8285
{
    xmlNodePtr cur;
    char *mode = NULL;
    char *type = NULL;
    virDomainSmartcardDefPtr def;
8286
    size_t i;
E
Eric Blake 已提交
8287

8288
    if (VIR_ALLOC(def) < 0)
E
Eric Blake 已提交
8289 8290 8291 8292
        return NULL;

    mode = virXMLPropString(node, "mode");
    if (mode == NULL) {
8293 8294
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("missing smartcard device mode"));
E
Eric Blake 已提交
8295 8296 8297
        goto error;
    }
    if ((def->type = virDomainSmartcardTypeFromString(mode)) < 0) {
8298
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
8299 8300
                       _("unknown smartcard device mode: %s"),
                       mode);
E
Eric Blake 已提交
8301 8302 8303 8304 8305 8306 8307 8308 8309 8310 8311 8312 8313 8314
        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) {
8315 8316 8317
                    virReportError(VIR_ERR_XML_ERROR, "%s",
                                   _("host-certificates mode needs "
                                     "exactly three certificates"));
E
Eric Blake 已提交
8318 8319 8320 8321 8322 8323 8324 8325 8326 8327 8328 8329 8330 8331 8332 8333 8334
                    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 != '/') {
8335 8336 8337
                    virReportError(VIR_ERR_XML_ERROR,
                                   _("expecting absolute path: %s"),
                                   def->data.cert.database);
E
Eric Blake 已提交
8338 8339 8340 8341 8342 8343
                    goto error;
                }
            }
            cur = cur->next;
        }
        if (i < 3) {
8344 8345 8346
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("host-certificates mode needs "
                             "exactly three certificates"));
E
Eric Blake 已提交
8347 8348 8349 8350 8351 8352 8353
            goto error;
        }
        break;

    case VIR_DOMAIN_SMARTCARD_TYPE_PASSTHROUGH:
        type = virXMLPropString(node, "type");
        if (type == NULL) {
8354 8355 8356
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("passthrough mode requires a character "
                             "device type attribute"));
E
Eric Blake 已提交
8357 8358 8359
            goto error;
        }
        if ((def->data.passthru.type = virDomainChrTypeFromString(type)) < 0) {
8360
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
8361 8362
                           _("unknown type presented to host for "
                             "character device: %s"), type);
E
Eric Blake 已提交
8363 8364 8365 8366
            goto error;
        }

        cur = node->children;
8367 8368
        if (virDomainChrSourceDefParseXML(&def->data.passthru, cur, flags,
                                          NULL, NULL, NULL, 0) < 0)
E
Eric Blake 已提交
8369
            goto error;
8370 8371

        if (def->data.passthru.type == VIR_DOMAIN_CHR_TYPE_SPICEVMC) {
E
Eric Blake 已提交
8372 8373
            def->data.passthru.data.spicevmc
                = VIR_DOMAIN_CHR_SPICEVMC_SMARTCARD;
8374
        }
E
Eric Blake 已提交
8375

E
Eric Blake 已提交
8376 8377 8378
        break;

    default:
8379 8380
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("unknown smartcard mode"));
E
Eric Blake 已提交
8381 8382 8383
        goto error;
    }

8384
    if (virDomainDeviceInfoParseXML(node, NULL, &def->info, flags) < 0)
E
Eric Blake 已提交
8385 8386 8387
        goto error;
    if (def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCID) {
8388 8389
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Controllers must use the 'ccid' address type"));
E
Eric Blake 已提交
8390 8391 8392
        goto error;
    }

8393
 cleanup:
E
Eric Blake 已提交
8394 8395 8396 8397 8398
    VIR_FREE(mode);
    VIR_FREE(type);

    return def;

8399
 error:
E
Eric Blake 已提交
8400 8401 8402 8403 8404
    virDomainSmartcardDefFree(def);
    def = NULL;
    goto cleanup;
}

8405 8406 8407 8408 8409 8410 8411 8412 8413 8414 8415 8416
/* Parse the XML definition for a TPM device
 *
 * The XML looks like this:
 *
 * <tpm model='tpm-tis'>
 *   <backend type='passthrough'>
 *     <device path='/dev/tpm0'/>
 *   </backend>
 * </tpm>
 *
 */
static virDomainTPMDefPtr
8417
virDomainTPMDefParseXML(xmlNodePtr node,
8418 8419 8420 8421 8422 8423 8424 8425 8426 8427 8428 8429
                        xmlXPathContextPtr ctxt,
                        unsigned int flags)
{
    char *type = NULL;
    char *path = NULL;
    char *model = NULL;
    char *backend = NULL;
    virDomainTPMDefPtr def;
    xmlNodePtr save = ctxt->node;
    xmlNodePtr *backends = NULL;
    int nbackends;

8430
    if (VIR_ALLOC(def) < 0)
8431 8432 8433 8434 8435
        return NULL;

    model = virXMLPropString(node, "model");
    if (model != NULL &&
        (int)(def->model = virDomainTPMModelTypeFromString(model)) < 0) {
8436
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
8437 8438 8439 8440 8441 8442 8443 8444 8445 8446 8447 8448 8449 8450 8451 8452 8453
                       _("Unknown TPM frontend model '%s'"), model);
        goto error;
    } else {
        def->model = VIR_DOMAIN_TPM_MODEL_TIS;
    }

    ctxt->node = node;

    if ((nbackends = virXPathNodeSet("./backend", ctxt, &backends)) < 0)
        goto error;

    if (nbackends > 1) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("only one TPM backend is supported"));
        goto error;
    }

8454 8455 8456 8457 8458 8459
    if (nbackends == 0) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("missing TPM device backend"));
        goto error;
    }

8460 8461 8462 8463 8464 8465 8466
    if (!(backend = virXMLPropString(backends[0], "type"))) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("missing TPM device backend type"));
        goto error;
    }

    if ((int)(def->type = virDomainTPMBackendTypeFromString(backend)) < 0) {
8467
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
8468 8469 8470 8471 8472 8473 8474 8475
                       _("Unknown TPM backend type '%s'"),
                       backend);
        goto error;
    }

    switch (def->type) {
    case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH:
        path = virXPathString("string(./backend/device/@path)", ctxt);
8476
        if (!path && VIR_STRDUP(path, VIR_DOMAIN_TPM_DEFAULT_DEVICE) < 0)
8477 8478 8479 8480 8481 8482 8483 8484 8485 8486 8487 8488
            goto error;
        def->data.passthrough.source.data.file.path = path;
        def->data.passthrough.source.type = VIR_DOMAIN_CHR_TYPE_DEV;
        path = NULL;
        break;
    case VIR_DOMAIN_TPM_TYPE_LAST:
        goto error;
    }

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

8489
 cleanup:
8490 8491 8492 8493 8494 8495 8496 8497
    VIR_FREE(type);
    VIR_FREE(path);
    VIR_FREE(model);
    VIR_FREE(backend);
    VIR_FREE(backends);
    ctxt->node = save;
    return def;

8498
 error:
8499 8500 8501 8502 8503
    virDomainTPMDefFree(def);
    def = NULL;
    goto cleanup;
}

8504
/* Parse the XML definition for an input device */
8505
static virDomainInputDefPtr
L
Li Zhang 已提交
8506
virDomainInputDefParseXML(const virDomainDef *dom,
8507
                          xmlNodePtr node,
E
Eric Blake 已提交
8508 8509
                          unsigned int flags)
{
8510 8511 8512 8513
    virDomainInputDefPtr def;
    char *type = NULL;
    char *bus = NULL;

8514
    if (VIR_ALLOC(def) < 0)
8515 8516 8517 8518 8519 8520
        return NULL;

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

    if (!type) {
8521 8522
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing input device type"));
8523 8524 8525 8526
        goto error;
    }

    if ((def->type = virDomainInputTypeFromString(type)) < 0) {
8527
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
8528
                       _("unknown input device type '%s'"), type);
8529 8530 8531 8532 8533
        goto error;
    }

    if (bus) {
        if ((def->bus = virDomainInputBusTypeFromString(bus)) < 0) {
8534
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
8535
                           _("unknown input bus type '%s'"), bus);
8536 8537 8538
            goto error;
        }

L
Li Zhang 已提交
8539 8540 8541 8542
        if (STREQ(dom->os.type, "hvm")) {
            if (def->bus == VIR_DOMAIN_INPUT_BUS_PS2 &&
                def->type != VIR_DOMAIN_INPUT_TYPE_MOUSE &&
                def->type != VIR_DOMAIN_INPUT_TYPE_KBD) {
8543 8544 8545
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("ps2 bus does not support %s input device"),
                               type);
8546 8547 8548
                goto error;
            }
            if (def->bus == VIR_DOMAIN_INPUT_BUS_XEN) {
8549 8550 8551
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unsupported input bus %s"),
                               bus);
8552 8553 8554 8555
                goto error;
            }
        } else {
            if (def->bus != VIR_DOMAIN_INPUT_BUS_XEN) {
8556 8557 8558
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unsupported input bus %s"),
                               bus);
8559
            }
L
Li Zhang 已提交
8560 8561
            if (def->type != VIR_DOMAIN_INPUT_TYPE_MOUSE &&
                def->type != VIR_DOMAIN_INPUT_TYPE_KBD) {
8562 8563 8564
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("xen bus does not support %s input device"),
                               type);
8565 8566 8567 8568
                goto error;
            }
        }
    } else {
L
Li Zhang 已提交
8569 8570
        if (STREQ(dom->os.type, "hvm")) {
            if ((def->type == VIR_DOMAIN_INPUT_TYPE_MOUSE ||
8571 8572
                def->type == VIR_DOMAIN_INPUT_TYPE_KBD) &&
                (ARCH_IS_X86(dom->os.arch) || dom->os.arch == VIR_ARCH_NONE)) {
8573
                def->bus = VIR_DOMAIN_INPUT_BUS_PS2;
8574
            } else {
8575
                def->bus = VIR_DOMAIN_INPUT_BUS_USB;
8576
            }
8577 8578 8579 8580 8581
        } else {
            def->bus = VIR_DOMAIN_INPUT_BUS_XEN;
        }
    }

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

8585 8586 8587
    if (def->bus == VIR_DOMAIN_INPUT_BUS_USB &&
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB) {
8588 8589
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Invalid address for a USB device"));
8590 8591 8592
        goto error;
    }

8593
 cleanup:
8594 8595 8596 8597 8598
    VIR_FREE(type);
    VIR_FREE(bus);

    return def;

8599
 error:
8600 8601 8602 8603 8604 8605
    virDomainInputDefFree(def);
    def = NULL;
    goto cleanup;
}


E
Eric Blake 已提交
8606
/* Parse the XML definition for a hub device */
M
Marc-André Lureau 已提交
8607 8608 8609 8610 8611 8612
static virDomainHubDefPtr
virDomainHubDefParseXML(xmlNodePtr node, unsigned int flags)
{
    virDomainHubDefPtr def;
    char *type = NULL;

8613
    if (VIR_ALLOC(def) < 0)
M
Marc-André Lureau 已提交
8614 8615 8616 8617 8618
        return NULL;

    type = virXMLPropString(node, "type");

    if (!type) {
8619 8620
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing hub device type"));
M
Marc-André Lureau 已提交
8621 8622 8623 8624
        goto error;
    }

    if ((def->type = virDomainHubTypeFromString(type)) < 0) {
8625
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
8626
                       _("unknown hub device type '%s'"), type);
M
Marc-André Lureau 已提交
8627 8628 8629
        goto error;
    }

8630
    if (virDomainDeviceInfoParseXML(node, NULL, &def->info, flags) < 0)
M
Marc-André Lureau 已提交
8631 8632
        goto error;

8633
 cleanup:
M
Marc-André Lureau 已提交
8634 8635 8636 8637
    VIR_FREE(type);

    return def;

8638
 error:
M
Marc-André Lureau 已提交
8639 8640 8641 8642 8643 8644
    virDomainHubDefFree(def);
    def = NULL;
    goto cleanup;
}


8645 8646
/* Parse the XML definition for a clock timer */
static virDomainTimerDefPtr
8647
virDomainTimerDefParseXML(xmlNodePtr node,
E
Eric Blake 已提交
8648
                          xmlXPathContextPtr ctxt)
8649 8650 8651 8652
{
    char *name = NULL;
    char *present = NULL;
    char *tickpolicy = NULL;
8653
    char *track = NULL;
8654 8655 8656 8657
    char *mode = NULL;

    virDomainTimerDefPtr def;
    xmlNodePtr oldnode = ctxt->node;
8658 8659
    xmlNodePtr catchup;
    int ret;
8660

8661
    if (VIR_ALLOC(def) < 0)
8662 8663 8664 8665 8666 8667
        return NULL;

    ctxt->node = node;

    name = virXMLPropString(node, "name");
    if (name == NULL) {
8668 8669
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing timer name"));
8670 8671 8672
        goto error;
    }
    if ((def->name = virDomainTimerNameTypeFromString(name)) < 0) {
8673
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
8674
                       _("unknown timer name '%s'"), name);
8675 8676 8677 8678 8679 8680 8681 8682 8683 8684
        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 {
8685 8686
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown timer present value '%s'"), present);
8687 8688 8689 8690 8691 8692 8693 8694
            goto error;
        }
    }

    def->tickpolicy = -1;
    tickpolicy = virXMLPropString(node, "tickpolicy");
    if (tickpolicy != NULL) {
        if ((def->tickpolicy = virDomainTimerTickpolicyTypeFromString(tickpolicy)) < 0) {
8695
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
8696
                           _("unknown timer tickpolicy '%s'"), tickpolicy);
8697 8698 8699 8700
            goto error;
        }
    }

8701 8702 8703 8704
    def->track = -1;
    track = virXMLPropString(node, "track");
    if (track != NULL) {
        if ((def->track = virDomainTimerTrackTypeFromString(track)) < 0) {
8705
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
8706
                           _("unknown timer track '%s'"), track);
8707 8708 8709 8710
            goto error;
        }
    }

8711
    ret = virXPathULong("string(./frequency)", ctxt, &def->frequency);
8712 8713
    if (ret == -1) {
        def->frequency = 0;
8714
    } else if (ret < 0) {
8715 8716
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("invalid timer frequency"));
8717 8718 8719 8720 8721 8722 8723
        goto error;
    }

    def->mode = -1;
    mode = virXMLPropString(node, "mode");
    if (mode != NULL) {
        if ((def->mode = virDomainTimerModeTypeFromString(mode)) < 0) {
8724
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
8725
                           _("unknown timer mode '%s'"), mode);
8726 8727 8728 8729
            goto error;
        }
    }

8730
    catchup = virXPathNode("./catchup", ctxt);
8731 8732 8733 8734 8735 8736
    if (catchup != NULL) {
        ret = virXPathULong("string(./catchup/@threshold)", ctxt,
                            &def->catchup.threshold);
        if (ret == -1) {
            def->catchup.threshold = 0;
        } else if (ret < 0) {
8737 8738
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("invalid catchup threshold"));
8739 8740 8741 8742 8743 8744 8745
            goto error;
        }

        ret = virXPathULong("string(./catchup/@slew)", ctxt, &def->catchup.slew);
        if (ret == -1) {
            def->catchup.slew = 0;
        } else if (ret < 0) {
8746 8747
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("invalid catchup slew"));
8748 8749 8750 8751 8752 8753 8754
            goto error;
        }

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

8761
 cleanup:
8762 8763 8764
    VIR_FREE(name);
    VIR_FREE(present);
    VIR_FREE(tickpolicy);
8765
    VIR_FREE(track);
8766 8767 8768 8769 8770
    VIR_FREE(mode);
    ctxt->node = oldnode;

    return def;

8771
 error:
8772 8773 8774 8775
    VIR_FREE(def);
    goto cleanup;
}

8776 8777

static int
8778 8779 8780
virDomainGraphicsAuthDefParseXML(xmlNodePtr node,
                                 virDomainGraphicsAuthDefPtr def,
                                 int type)
8781 8782
{
    char *validTo = NULL;
8783
    char *connected = virXMLPropString(node, "connected");
8784 8785 8786 8787 8788 8789 8790 8791 8792 8793 8794 8795 8796 8797 8798 8799 8800 8801 8802 8803 8804 8805 8806 8807

    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') {
8808 8809 8810
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot parse password validity time '%s', expect YYYY-MM-DDTHH:MM:SS"),
                           validTo);
8811 8812 8813 8814 8815 8816 8817 8818 8819 8820
            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);
8821
        def->expires = true;
8822 8823
    }

8824 8825 8826
    if (connected) {
        int action = virDomainGraphicsAuthConnectedTypeFromString(connected);
        if (action <= 0) {
8827 8828 8829
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown connected value %s"),
                           connected);
8830 8831 8832 8833 8834 8835 8836 8837
            VIR_FREE(connected);
            return -1;
        }
        VIR_FREE(connected);

        /* VNC supports connected='keep' only */
        if (type == VIR_DOMAIN_GRAPHICS_TYPE_VNC &&
            action != VIR_DOMAIN_GRAPHICS_AUTH_CONNECTED_KEEP) {
8838 8839
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("VNC supports connected='keep' only"));
8840 8841 8842 8843 8844 8845
            return -1;
        }

        def->connected = action;
    }

8846 8847 8848
    return 0;
}

8849 8850 8851 8852 8853 8854 8855 8856 8857
static int
virDomainGraphicsListenDefParseXML(virDomainGraphicsListenDefPtr def,
                                   xmlNodePtr node,
                                   unsigned int flags)
{
    int ret = -1;
    char *type     = virXMLPropString(node, "type");
    char *address  = virXMLPropString(node, "address");
    char *network  = virXMLPropString(node, "network");
8858 8859
    char *fromConfig = virXMLPropString(node, "fromConfig");
    int tmp;
8860 8861

    if (!type) {
8862 8863
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("graphics listen type must be specified"));
8864 8865 8866 8867
        goto error;
    }

    if ((def->type = virDomainGraphicsListenTypeFromString(type)) < 0) {
8868
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
8869
                       _("unknown graphics listen type '%s'"), type);
8870 8871 8872 8873 8874 8875 8876
        goto error;
    }

    /* address is recognized if either type='address', or if
     * type='network' and we're looking at live XML (i.e. *not*
     * inactive). It is otherwise ignored. */
    if (address && address[0] &&
E
Eric Blake 已提交
8877 8878
        (def->type == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS ||
         (def->type == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NETWORK &&
8879 8880 8881 8882 8883 8884 8885 8886
          !(flags & VIR_DOMAIN_XML_INACTIVE)))) {
        def->address = address;
        address = NULL;
    }

    if (network && network[0]) {
        if (def->type != VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NETWORK) {
            /* network='xxx' never makes sense with anything except
8887
             * type='network' */
8888 8889
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("network attribute not allowed when listen type is not network"));
8890 8891 8892 8893 8894 8895
            goto error;
        }
        def->network = network;
        network = NULL;
    }

8896 8897 8898 8899 8900 8901 8902 8903 8904 8905 8906
    if (fromConfig &&
        flags & VIR_DOMAIN_XML_INTERNAL_STATUS) {
        if (virStrToLong_i(fromConfig, NULL, 10, &tmp) < 0) {
            virReportError(VIR_ERR_XML_ERROR,
                           _("Invalid fromConfig value: %s"),
                           fromConfig);
            goto error;
        }
        def->fromConfig = tmp != 0;
    }

8907
    ret = 0;
8908
 error:
8909 8910 8911 8912 8913
    if (ret < 0)
        virDomainGraphicsListenDefClear(def);
    VIR_FREE(type);
    VIR_FREE(address);
    VIR_FREE(network);
8914
    VIR_FREE(fromConfig);
8915 8916 8917
    return ret;
}

8918

8919 8920
/* Parse the XML definition for a graphics device */
static virDomainGraphicsDefPtr
8921 8922 8923
virDomainGraphicsDefParseXML(xmlNodePtr node,
                             xmlXPathContextPtr ctxt,
                             unsigned int flags)
E
Eric Blake 已提交
8924
{
8925 8926
    virDomainGraphicsDefPtr def;
    char *type = NULL;
8927 8928 8929 8930
    int nListens;
    xmlNodePtr *listenNodes = NULL;
    char *listenAddr = NULL;
    xmlNodePtr save = ctxt->node;
8931

8932
    if (VIR_ALLOC(def) < 0)
8933 8934
        return NULL;

8935 8936
    ctxt->node = node;

8937 8938 8939
    type = virXMLPropString(node, "type");

    if (!type) {
8940 8941
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing graphics device type"));
8942 8943 8944 8945
        goto error;
    }

    if ((def->type = virDomainGraphicsTypeFromString(type)) < 0) {
8946
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
8947
                       _("unknown graphics device type '%s'"), type);
8948 8949 8950
        goto error;
    }

E
Eric Blake 已提交
8951 8952 8953
    if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC ||
        def->type == VIR_DOMAIN_GRAPHICS_TYPE_RDP ||
        def->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) {
8954 8955 8956 8957 8958 8959 8960

        /* parse the <listen> subelements for graphics types that support it */
        nListens = virXPathNodeSet("./listen", ctxt, &listenNodes);
        if (nListens < 0)
            goto error;

        if (nListens > 0) {
8961
            size_t i;
8962

8963
            if (VIR_ALLOC_N(def->listens, nListens) < 0)
8964 8965
                goto error;

8966 8967 8968
            for (i = 0; i < nListens; i++) {
                int ret = virDomainGraphicsListenDefParseXML(&def->listens[i],
                                                             listenNodes[i],
8969 8970 8971 8972 8973 8974 8975 8976 8977 8978 8979 8980 8981 8982 8983 8984 8985 8986 8987 8988 8989 8990 8991 8992 8993 8994 8995 8996 8997
                                                             flags);
                if (ret < 0)
                    goto error;
                def->nListens++;
            }
            VIR_FREE(listenNodes);
        }

        /* listen attribute of <graphics> is also supported by these,
         * but must match the 'address' attribute of the first listen
         * that is type='address' (if present) */
        listenAddr = virXMLPropString(node, "listen");
        if (listenAddr && !listenAddr[0])
            VIR_FREE(listenAddr);

        if (listenAddr) {
            if (def->nListens == 0) {
                /* There were no <listen> elements, so we can just
                 * directly set listenAddr as listens[0]->address */
                if (virDomainGraphicsListenSetAddress(def, 0, listenAddr,
                                                      -1, true) < 0)
                    goto error;
            } else {
                /* There is at least 1 listen element, so we look for
                 * the first listen of type='address', and make sure
                 * its address matches the listen attribute from
                 * graphics. */
                bool matched = false;
                const char *found = NULL;
8998
                size_t i;
8999

9000 9001
                for (i = 0; i < nListens; i++) {
                    if (virDomainGraphicsListenGetType(def, i)
9002
                        == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS) {
9003
                        found = virDomainGraphicsListenGetAddress(def, i);
9004 9005 9006 9007 9008 9009 9010
                        if (STREQ_NULLABLE(found, listenAddr)) {
                            matched = true;
                        }
                        break;
                    }
                }
                if (!matched) {
9011 9012 9013 9014
                    virReportError(VIR_ERR_XML_ERROR,
                                   _("graphics listen attribute %s must match address "
                                     "attribute of first listen element (found %s)"),
                                   listenAddr, found ? found : "none");
9015 9016 9017 9018 9019 9020
                    goto error;
                }
            }
        }
    }

9021 9022
    if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
        char *port = virXMLPropString(node, "port");
M
Martin Kletzander 已提交
9023
        char *websocket = virXMLPropString(node, "websocket");
9024
        char *sharePolicy = virXMLPropString(node, "sharePolicy");
9025 9026 9027 9028
        char *autoport;

        if (port) {
            if (virStrToLong_i(port, NULL, 10, &def->data.vnc.port) < 0) {
9029 9030
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("cannot parse vnc port %s"), port);
9031 9032 9033 9034 9035 9036
                VIR_FREE(port);
                goto error;
            }
            VIR_FREE(port);
            /* Legacy compat syntax, used -1 for auto-port */
            if (def->data.vnc.port == -1) {
9037 9038
                if (flags & VIR_DOMAIN_XML_INACTIVE)
                    def->data.vnc.port = 0;
9039
                def->data.vnc.autoport = true;
9040 9041 9042
            }
        } else {
            def->data.vnc.port = 0;
9043
            def->data.vnc.autoport = true;
9044 9045 9046 9047
        }

        if ((autoport = virXMLPropString(node, "autoport")) != NULL) {
            if (STREQ(autoport, "yes")) {
9048 9049
                if (flags & VIR_DOMAIN_XML_INACTIVE)
                    def->data.vnc.port = 0;
9050
                def->data.vnc.autoport = true;
9051 9052 9053 9054
            }
            VIR_FREE(autoport);
        }

M
Martin Kletzander 已提交
9055 9056 9057 9058 9059 9060 9061 9062 9063 9064 9065 9066
        if (websocket) {
            if (virStrToLong_i(websocket,
                               NULL, 10,
                               &def->data.vnc.websocket) < 0) {
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("cannot parse vnc WebSocket port %s"), websocket);
                VIR_FREE(websocket);
                goto error;
            }
            VIR_FREE(websocket);
        }

9067 9068 9069 9070 9071 9072 9073 9074 9075 9076 9077 9078 9079 9080 9081
        if (sharePolicy) {
            int policy =
               virDomainGraphicsVNCSharePolicyTypeFromString(sharePolicy);

            if (policy < 0) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("unknown vnc display sharing policy '%s'"), sharePolicy);
                VIR_FREE(sharePolicy);
                goto error;
            } else {
                def->data.vnc.sharePolicy = policy;
            }
            VIR_FREE(sharePolicy);
        }

9082
        def->data.vnc.socket = virXMLPropString(node, "socket");
9083
        def->data.vnc.keymap = virXMLPropString(node, "keymap");
9084

9085 9086
        if (virDomainGraphicsAuthDefParseXML(node, &def->data.vnc.auth,
                                             def->type) < 0)
9087
            goto error;
9088
    } else if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) {
9089 9090 9091 9092
        char *fullscreen = virXMLPropString(node, "fullscreen");

        if (fullscreen != NULL) {
            if (STREQ(fullscreen, "yes")) {
9093
                def->data.sdl.fullscreen = true;
9094
            } else if (STREQ(fullscreen, "no")) {
9095
                def->data.sdl.fullscreen = false;
9096
            } else {
9097 9098
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unknown fullscreen value '%s'"), fullscreen);
9099 9100 9101 9102
                VIR_FREE(fullscreen);
                goto error;
            }
            VIR_FREE(fullscreen);
E
Eric Blake 已提交
9103
        } else {
9104
            def->data.sdl.fullscreen = false;
E
Eric Blake 已提交
9105
        }
9106 9107
        def->data.sdl.xauth = virXMLPropString(node, "xauth");
        def->data.sdl.display = virXMLPropString(node, "display");
9108 9109 9110 9111 9112 9113 9114 9115
    } 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) {
9116 9117
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("cannot parse rdp port %s"), port);
9118 9119 9120
                VIR_FREE(port);
                goto error;
            }
M
Michal Privoznik 已提交
9121 9122
            /* Legacy compat syntax, used -1 for auto-port */
            if (def->data.rdp.port == -1)
9123
                def->data.rdp.autoport = true;
M
Michal Privoznik 已提交
9124

9125 9126 9127
            VIR_FREE(port);
        } else {
            def->data.rdp.port = 0;
9128
            def->data.rdp.autoport = true;
9129 9130 9131
        }

        if ((autoport = virXMLPropString(node, "autoport")) != NULL) {
M
Michal Privoznik 已提交
9132
            if (STREQ(autoport, "yes"))
9133
                def->data.rdp.autoport = true;
M
Michal Privoznik 已提交
9134

9135 9136 9137
            VIR_FREE(autoport);
        }

M
Michal Privoznik 已提交
9138 9139 9140
        if (def->data.rdp.autoport && (flags & VIR_DOMAIN_XML_INACTIVE))
            def->data.rdp.port = 0;

9141 9142
        if ((replaceUser = virXMLPropString(node, "replaceUser")) != NULL) {
            if (STREQ(replaceUser, "yes")) {
9143
                def->data.rdp.replaceUser = true;
9144 9145 9146 9147 9148 9149
            }
            VIR_FREE(replaceUser);
        }

        if ((multiUser = virXMLPropString(node, "multiUser")) != NULL) {
            if (STREQ(multiUser, "yes")) {
9150
                def->data.rdp.multiUser = true;
9151 9152 9153 9154 9155 9156 9157 9158 9159
            }
            VIR_FREE(multiUser);
        }

    } else if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP) {
        char *fullscreen = virXMLPropString(node, "fullscreen");

        if (fullscreen != NULL) {
            if (STREQ(fullscreen, "yes")) {
9160
                def->data.desktop.fullscreen = true;
9161
            } else if (STREQ(fullscreen, "no")) {
9162
                def->data.desktop.fullscreen = false;
9163
            } else {
9164 9165
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unknown fullscreen value '%s'"), fullscreen);
9166 9167 9168 9169
                VIR_FREE(fullscreen);
                goto error;
            }
            VIR_FREE(fullscreen);
E
Eric Blake 已提交
9170
        } else {
9171
            def->data.desktop.fullscreen = false;
E
Eric Blake 已提交
9172
        }
9173 9174

        def->data.desktop.display = virXMLPropString(node, "display");
9175
    } else if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) {
9176
        xmlNodePtr cur;
9177 9178 9179
        char *port = virXMLPropString(node, "port");
        char *tlsPort;
        char *autoport;
9180 9181
        char *defaultMode;
        int defaultModeVal;
9182 9183 9184

        if (port) {
            if (virStrToLong_i(port, NULL, 10, &def->data.spice.port) < 0) {
9185 9186
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("cannot parse spice port %s"), port);
9187 9188 9189 9190 9191
                VIR_FREE(port);
                goto error;
            }
            VIR_FREE(port);
        } else {
9192
            def->data.spice.port = 0;
9193 9194 9195 9196 9197
        }

        tlsPort = virXMLPropString(node, "tlsPort");
        if (tlsPort) {
            if (virStrToLong_i(tlsPort, NULL, 10, &def->data.spice.tlsPort) < 0) {
9198 9199
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("cannot parse spice tlsPort %s"), tlsPort);
9200 9201 9202 9203 9204 9205 9206 9207 9208
                VIR_FREE(tlsPort);
                goto error;
            }
            VIR_FREE(tlsPort);
        } else {
            def->data.spice.tlsPort = 0;
        }

        if ((autoport = virXMLPropString(node, "autoport")) != NULL) {
M
Michal Privoznik 已提交
9209
            if (STREQ(autoport, "yes"))
9210
                def->data.spice.autoport = true;
9211 9212 9213
            VIR_FREE(autoport);
        }

9214 9215 9216 9217
        def->data.spice.defaultMode = VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_ANY;

        if ((defaultMode = virXMLPropString(node, "defaultMode")) != NULL) {
            if ((defaultModeVal = virDomainGraphicsSpiceChannelModeTypeFromString(defaultMode)) < 0) {
9218
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
9219 9220
                               _("unknown default spice channel mode %s"),
                               defaultMode);
9221 9222 9223 9224 9225 9226 9227
                VIR_FREE(defaultMode);
                goto error;
            }
            def->data.spice.defaultMode = defaultModeVal;
            VIR_FREE(defaultMode);
        }

M
Michal Privoznik 已提交
9228 9229
        if (def->data.spice.port == -1 && def->data.spice.tlsPort == -1) {
            /* Legacy compat syntax, used -1 for auto-port */
9230
            def->data.spice.autoport = true;
M
Michal Privoznik 已提交
9231 9232 9233 9234 9235 9236 9237
        }

        if (def->data.spice.autoport && (flags & VIR_DOMAIN_XML_INACTIVE)) {
            def->data.spice.port = 0;
            def->data.spice.tlsPort = 0;
        }

9238
        def->data.spice.keymap = virXMLPropString(node, "keymap");
9239

9240 9241
        if (virDomainGraphicsAuthDefParseXML(node, &def->data.spice.auth,
                                             def->type) < 0)
9242
            goto error;
9243 9244 9245 9246 9247

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

                    if (!name || !mode) {
9254 9255
                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                       _("spice channel missing name/mode"));
E
Eric Blake 已提交
9256 9257
                        VIR_FREE(name);
                        VIR_FREE(mode);
9258 9259 9260 9261
                        goto error;
                    }

                    if ((nameval = virDomainGraphicsSpiceChannelNameTypeFromString(name)) < 0) {
9262
                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
9263 9264
                                       _("unknown spice channel name %s"),
                                       name);
E
Eric Blake 已提交
9265 9266
                        VIR_FREE(name);
                        VIR_FREE(mode);
9267 9268 9269
                        goto error;
                    }
                    if ((modeval = virDomainGraphicsSpiceChannelModeTypeFromString(mode)) < 0) {
9270
                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
9271 9272
                                       _("unknown spice channel mode %s"),
                                       mode);
E
Eric Blake 已提交
9273 9274
                        VIR_FREE(name);
                        VIR_FREE(mode);
9275 9276
                        goto error;
                    }
E
Eric Blake 已提交
9277 9278
                    VIR_FREE(name);
                    VIR_FREE(mode);
9279 9280

                    def->data.spice.channels[nameval] = modeval;
9281
                } else if (xmlStrEqual(cur->name, BAD_CAST "image")) {
9282
                    char *compression = virXMLPropString(cur, "compression");
9283 9284 9285
                    int compressionVal;

                    if (!compression) {
9286 9287
                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                       _("spice image missing compression"));
9288 9289 9290 9291 9292
                        goto error;
                    }

                    if ((compressionVal =
                         virDomainGraphicsSpiceImageCompressionTypeFromString(compression)) <= 0) {
9293 9294 9295
                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                       _("unknown spice image compression %s"),
                                       compression);
9296 9297 9298 9299 9300 9301 9302
                        VIR_FREE(compression);
                        goto error;
                    }
                    VIR_FREE(compression);

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

                    if (!compression) {
9307 9308
                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                       _("spice jpeg missing compression"));
9309 9310 9311 9312 9313
                        goto error;
                    }

                    if ((compressionVal =
                         virDomainGraphicsSpiceJpegCompressionTypeFromString(compression)) <= 0) {
9314 9315 9316
                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                       _("unknown spice jpeg compression %s"),
                                       compression);
9317 9318 9319 9320 9321 9322 9323
                        VIR_FREE(compression);
                        goto error;
                    }
                    VIR_FREE(compression);

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

                    if (!compression) {
9328 9329
                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                       _("spice zlib missing compression"));
9330 9331 9332 9333 9334
                        goto error;
                    }

                    if ((compressionVal =
                         virDomainGraphicsSpiceZlibCompressionTypeFromString(compression)) <= 0) {
9335 9336 9337
                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                       _("unknown spice zlib compression %s"),
                                       compression);
9338 9339 9340
                        VIR_FREE(compression);
                        goto error;
                    }
9341
                    VIR_FREE(compression);
9342 9343 9344

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

                    if (!compression) {
9349 9350
                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                       _("spice playback missing compression"));
9351 9352 9353 9354
                        goto error;
                    }

                    if ((compressionVal =
J
Ján Tomko 已提交
9355
                         virTristateSwitchTypeFromString(compression)) <= 0) {
9356
                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
9357
                                       _("unknown spice playback compression"));
9358 9359 9360 9361 9362 9363 9364
                        VIR_FREE(compression);
                        goto error;

                    }
                    VIR_FREE(compression);

                    def->data.spice.playback = compressionVal;
9365
                } else if (xmlStrEqual(cur->name, BAD_CAST "streaming")) {
9366
                    char *mode = virXMLPropString(cur, "mode");
9367 9368 9369
                    int modeVal;

                    if (!mode) {
9370 9371
                        virReportError(VIR_ERR_XML_ERROR, "%s",
                                       _("spice streaming missing mode"));
9372 9373 9374 9375
                        goto error;
                    }
                    if ((modeVal =
                         virDomainGraphicsSpiceStreamingModeTypeFromString(mode)) <= 0) {
9376
                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
9377
                                       _("unknown spice streaming mode"));
9378 9379 9380 9381 9382 9383 9384
                        VIR_FREE(mode);
                        goto error;

                    }
                    VIR_FREE(mode);

                    def->data.spice.streaming = modeVal;
9385
                } else if (xmlStrEqual(cur->name, BAD_CAST "clipboard")) {
9386
                    char *copypaste = virXMLPropString(cur, "copypaste");
9387 9388 9389
                    int copypasteVal;

                    if (!copypaste) {
9390 9391
                        virReportError(VIR_ERR_XML_ERROR, "%s",
                                       _("spice clipboard missing copypaste"));
9392 9393 9394 9395
                        goto error;
                    }

                    if ((copypasteVal =
J
Ján Tomko 已提交
9396
                         virTristateBoolTypeFromString(copypaste)) <= 0) {
9397
                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
9398
                                       _("unknown copypaste value '%s'"), copypaste);
9399 9400 9401 9402 9403 9404
                        VIR_FREE(copypaste);
                        goto error;
                    }
                    VIR_FREE(copypaste);

                    def->data.spice.copypaste = copypasteVal;
9405 9406 9407 9408 9409 9410 9411 9412 9413 9414 9415
                } else if (xmlStrEqual(cur->name, BAD_CAST "filetransfer")) {
                    char *enable = virXMLPropString(cur, "enable");
                    int enableVal;

                    if (!enable) {
                        virReportError(VIR_ERR_XML_ERROR, "%s",
                                       _("spice filetransfer missing enable"));
                        goto error;
                    }

                    if ((enableVal =
J
Ján Tomko 已提交
9416
                         virTristateBoolTypeFromString(enable)) <= 0) {
9417 9418 9419 9420 9421 9422 9423 9424
                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                       _("unknown enable value '%s'"), enable);
                        VIR_FREE(enable);
                        goto error;
                    }
                    VIR_FREE(enable);

                    def->data.spice.filetransfer = enableVal;
P
Peng Zhou 已提交
9425
                } else if (xmlStrEqual(cur->name, BAD_CAST "mouse")) {
9426
                    char *mode = virXMLPropString(cur, "mode");
P
Peng Zhou 已提交
9427 9428 9429
                    int modeVal;

                    if (!mode) {
9430 9431
                        virReportError(VIR_ERR_XML_ERROR, "%s",
                                       _("spice mouse missing mode"));
P
Peng Zhou 已提交
9432 9433 9434 9435
                        goto error;
                    }

                    if ((modeVal = virDomainGraphicsSpiceMouseModeTypeFromString(mode)) <= 0) {
9436
                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
9437 9438
                                       _("unknown mouse mode value '%s'"),
                                       mode);
P
Peng Zhou 已提交
9439 9440 9441 9442 9443 9444
                        VIR_FREE(mode);
                        goto error;
                    }
                    VIR_FREE(mode);

                    def->data.spice.mousemode = modeVal;
9445 9446 9447 9448
                }
            }
            cur = cur->next;
        }
9449 9450
    }

9451
 cleanup:
9452
    VIR_FREE(type);
9453 9454
    VIR_FREE(listenNodes);
    VIR_FREE(listenAddr);
9455

9456
    ctxt->node = save;
9457 9458
    return def;

9459
 error:
9460 9461 9462 9463 9464 9465
    virDomainGraphicsDefFree(def);
    def = NULL;
    goto cleanup;
}


9466
static virDomainSoundCodecDefPtr
9467
virDomainSoundCodecDefParseXML(xmlNodePtr node)
9468 9469 9470 9471
{
    char *type;
    virDomainSoundCodecDefPtr def;

9472
    if (VIR_ALLOC(def) < 0)
9473 9474 9475 9476
        return NULL;

    type = virXMLPropString(node, "type");
    if ((def->type = virDomainSoundCodecTypeFromString(type)) < 0) {
9477
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
9478
                       _("unknown codec type '%s'"), type);
9479 9480 9481
        goto error;
    }

9482
 cleanup:
9483 9484 9485 9486
    VIR_FREE(type);

    return def;

9487
 error:
9488 9489 9490 9491 9492 9493
    virDomainSoundCodecDefFree(def);
    def = NULL;
    goto cleanup;
}


9494
static virDomainSoundDefPtr
9495
virDomainSoundDefParseXML(xmlNodePtr node,
9496
                          xmlXPathContextPtr ctxt,
E
Eric Blake 已提交
9497
                          unsigned int flags)
9498
{
9499 9500
    char *model;
    virDomainSoundDefPtr def;
9501
    xmlNodePtr save = ctxt->node;
9502

9503
    if (VIR_ALLOC(def) < 0)
9504 9505
        return NULL;

9506 9507
    ctxt->node = node;

9508 9509
    model = virXMLPropString(node, "model");
    if ((def->model = virDomainSoundModelTypeFromString(model)) < 0) {
9510
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
9511
                       _("unknown sound model '%s'"), model);
9512 9513 9514
        goto error;
    }

9515 9516
    if (def->model == VIR_DOMAIN_SOUND_MODEL_ICH6 ||
        def->model == VIR_DOMAIN_SOUND_MODEL_ICH9) {
9517 9518 9519 9520 9521 9522 9523 9524 9525
        int ncodecs;
        xmlNodePtr *codecNodes = NULL;

        /* parse the <codec> subelements for sound models that support it */
        ncodecs = virXPathNodeSet("./codec", ctxt, &codecNodes);
        if (ncodecs < 0)
            goto error;

        if (ncodecs > 0) {
9526
            size_t i;
9527 9528 9529 9530 9531 9532

            if (VIR_ALLOC_N(def->codecs, ncodecs) < 0) {
                VIR_FREE(codecNodes);
                goto error;
            }

9533 9534
            for (i = 0; i < ncodecs; i++) {
                virDomainSoundCodecDefPtr codec = virDomainSoundCodecDefParseXML(codecNodes[i]);
9535 9536
                if (codec == NULL) {
                    VIR_FREE(codecNodes);
9537
                    goto error;
9538
                }
9539 9540 9541 9542 9543 9544 9545 9546

                codec->cad = def->ncodecs; /* that will do for now */
                def->codecs[def->ncodecs++] = codec;
            }
            VIR_FREE(codecNodes);
        }
    }

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

9550
 cleanup:
9551 9552
    VIR_FREE(model);

9553
    ctxt->node = save;
9554 9555
    return def;

9556
 error:
9557 9558 9559 9560 9561
    virDomainSoundDefFree(def);
    def = NULL;
    goto cleanup;
}

9562

R
Richard Jones 已提交
9563
static virDomainWatchdogDefPtr
9564
virDomainWatchdogDefParseXML(xmlNodePtr node,
E
Eric Blake 已提交
9565
                             unsigned int flags)
9566
{
R
Richard Jones 已提交
9567 9568 9569 9570 9571

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

9572
    if (VIR_ALLOC(def) < 0)
R
Richard Jones 已提交
9573 9574
        return NULL;

9575
    model = virXMLPropString(node, "model");
R
Richard Jones 已提交
9576
    if (model == NULL) {
9577 9578
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("watchdog must contain model name"));
R
Richard Jones 已提交
9579 9580
        goto error;
    }
9581
    def->model = virDomainWatchdogModelTypeFromString(model);
R
Richard Jones 已提交
9582
    if (def->model < 0) {
9583
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
9584
                       _("unknown watchdog model '%s'"), model);
R
Richard Jones 已提交
9585 9586 9587
        goto error;
    }

9588
    action = virXMLPropString(node, "action");
9589
    if (action == NULL) {
R
Richard Jones 已提交
9590
        def->action = VIR_DOMAIN_WATCHDOG_ACTION_RESET;
9591
    } else {
9592
        def->action = virDomainWatchdogActionTypeFromString(action);
R
Richard Jones 已提交
9593
        if (def->action < 0) {
9594
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
9595
                           _("unknown watchdog action '%s'"), action);
R
Richard Jones 已提交
9596 9597 9598 9599
            goto error;
        }
    }

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

9603
 cleanup:
9604 9605
    VIR_FREE(action);
    VIR_FREE(model);
R
Richard Jones 已提交
9606 9607 9608

    return def;

9609
 error:
9610
    virDomainWatchdogDefFree(def);
R
Richard Jones 已提交
9611 9612 9613 9614 9615
    def = NULL;
    goto cleanup;
}


9616
static virDomainRNGDefPtr
9617
virDomainRNGDefParseXML(xmlNodePtr node,
9618 9619 9620
                        xmlXPathContextPtr ctxt,
                        unsigned int flags)
{
9621 9622 9623
    char *model = NULL;
    char *backend = NULL;
    char *type = NULL;
9624 9625 9626 9627 9628
    virDomainRNGDefPtr def;
    xmlNodePtr save = ctxt->node;
    xmlNodePtr *backends = NULL;
    int nbackends;

9629
    if (VIR_ALLOC(def) < 0)
9630 9631 9632 9633 9634 9635 9636 9637
        return NULL;

    if (!(model = virXMLPropString(node, "model"))) {
        virReportError(VIR_ERR_XML_ERROR, "%s", _("missing RNG device model"));
        goto error;
    }

    if ((def->model = virDomainRNGModelTypeFromString(model)) < 0) {
9638
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("unknown RNG model '%s'"), model);
9639 9640 9641 9642 9643
        goto error;
    }

    ctxt->node = node;

9644 9645 9646 9647 9648 9649 9650 9651 9652 9653 9654 9655 9656
    if (virXPathUInt("string(./rate/@bytes)", ctxt, &def->rate) < -1) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("invalid RNG rate bytes value"));
        goto error;
    }

    if (def->rate > 0 &&
        virXPathUInt("string(./rate/@period)", ctxt, &def->period) < -1) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("invalid RNG rate period value"));
        goto error;
    }

9657 9658 9659 9660 9661 9662 9663 9664 9665 9666 9667 9668 9669 9670 9671 9672
    if ((nbackends = virXPathNodeSet("./backend", ctxt, &backends)) < 0)
        goto error;

    if (nbackends != 1) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("only one RNG backend is supported"));
        goto error;
    }

    if (!(backend = virXMLPropString(backends[0], "model"))) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("missing RNG device backend model"));
        goto error;
    }

    if ((def->backend = virDomainRNGBackendTypeFromString(backend)) < 0) {
9673
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
9674 9675 9676 9677
                       _("unknown RNG backend model '%s'"), backend);
        goto error;
    }

9678
    switch ((virDomainRNGBackend) def->backend) {
9679 9680
    case VIR_DOMAIN_RNG_BACKEND_RANDOM:
        def->source.file = virXPathString("string(./backend)", ctxt);
9681 9682
        if (def->source.file &&
            STRNEQ(def->source.file, "/dev/random") &&
9683 9684 9685 9686 9687 9688
            STRNEQ(def->source.file, "/dev/hwrng")) {
            virReportError(VIR_ERR_XML_ERROR,
                           _("file '%s' is not a supported random source"),
                           def->source.file);
            goto error;
        }
9689 9690 9691 9692 9693 9694 9695 9696 9697
        break;

    case VIR_DOMAIN_RNG_BACKEND_EGD:
        if (!(type = virXMLPropString(backends[0], "type"))) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("missing EGD backend type"));
            goto error;
        }

9698
        if (VIR_ALLOC(def->source.chardev) < 0)
9699 9700 9701 9702
            goto error;

        def->source.chardev->type = virDomainChrTypeFromString(type);
        if (def->source.chardev->type < 0) {
9703
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
9704 9705 9706 9707 9708 9709 9710 9711 9712 9713 9714 9715 9716 9717 9718 9719 9720 9721
                           _("unknown backend type '%s' for egd"),
                           type);
            goto error;
        }

        if (virDomainChrSourceDefParseXML(def->source.chardev,
                                          backends[0]->children, flags,
                                          NULL, ctxt, NULL, 0) < 0)
            goto error;
        break;

    case VIR_DOMAIN_RNG_BACKEND_LAST:
        break;
    }

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

9722
 cleanup:
9723 9724 9725 9726 9727 9728 9729
    VIR_FREE(model);
    VIR_FREE(backend);
    VIR_FREE(type);
    VIR_FREE(backends);
    ctxt->node = save;
    return def;

9730
 error:
9731 9732 9733 9734 9735 9736
    virDomainRNGDefFree(def);
    def = NULL;
    goto cleanup;
}


9737
static virDomainMemballoonDefPtr
9738
virDomainMemballoonDefParseXML(xmlNodePtr node,
9739
                               xmlXPathContextPtr ctxt,
E
Eric Blake 已提交
9740
                               unsigned int flags)
9741 9742 9743
{
    char *model;
    virDomainMemballoonDefPtr def;
9744
    xmlNodePtr save = ctxt->node;
9745

9746
    if (VIR_ALLOC(def) < 0)
9747 9748 9749
        return NULL;

    model = virXMLPropString(node, "model");
9750
    if (model == NULL) {
9751
        virReportError(VIR_ERR_XML_ERROR, "%s",
9752
                       _("balloon memory must contain model name"));
9753 9754
        goto error;
    }
9755

9756
    if ((def->model = virDomainMemballoonModelTypeFromString(model)) < 0) {
9757
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
9758
                       _("unknown memory balloon model '%s'"), model);
9759 9760 9761
        goto error;
    }

9762 9763 9764 9765 9766 9767 9768
    ctxt->node = node;
    if (virXPathUInt("string(./stats/@period)", ctxt, &def->period) < -1) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("invalid statistics collection period"));
        goto error;
    }

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

9772
 cleanup:
9773 9774
    VIR_FREE(model);

9775
    ctxt->node = save;
9776 9777
    return def;

9778
 error:
9779 9780 9781 9782 9783
    virDomainMemballoonDefFree(def);
    def = NULL;
    goto cleanup;
}

L
Li Zhang 已提交
9784
static virDomainNVRAMDefPtr
9785
virDomainNVRAMDefParseXML(xmlNodePtr node,
L
Li Zhang 已提交
9786 9787 9788 9789
                          unsigned int flags)
{
   virDomainNVRAMDefPtr def;

9790
    if (VIR_ALLOC(def) < 0)
L
Li Zhang 已提交
9791 9792 9793 9794 9795 9796 9797
        return NULL;

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

    return def;

9798
 error:
L
Li Zhang 已提交
9799 9800 9801 9802
    virDomainNVRAMDefFree(def);
    return NULL;
}

9803 9804 9805 9806 9807 9808 9809 9810 9811 9812 9813 9814 9815 9816 9817 9818 9819 9820 9821 9822 9823 9824 9825 9826 9827 9828 9829 9830
static virDomainShmemDefPtr
virDomainShmemDefParseXML(xmlNodePtr node,
                          xmlXPathContextPtr ctxt,
                          unsigned int flags)
{
    char *tmp = NULL;
    virDomainShmemDefPtr def = NULL;
    virDomainShmemDefPtr ret = NULL;
    xmlNodePtr msi = NULL;
    xmlNodePtr save = ctxt->node;
    xmlNodePtr server = NULL;


    if (VIR_ALLOC(def) < 0)
        return NULL;

    ctxt->node = node;

    if (!(def->name = virXMLPropString(node, "name"))) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("shmem element must contain 'name' attribute"));
        goto cleanup;
    }

    if (virDomainParseScaledValue("./size[1]", ctxt, &def->size,
                                    1, ULLONG_MAX, false) < 0)
        goto cleanup;

9831
    if ((server = virXPathNode("./server[1]", ctxt))) {
9832 9833 9834 9835 9836 9837 9838
        def->server.enabled = true;

        if ((tmp = virXMLPropString(server, "path")))
            def->server.path = virFileSanitizePath(tmp);
        VIR_FREE(tmp);
    }

9839
    if ((msi = virXPathNode("./msi[1]", ctxt))) {
9840 9841 9842 9843 9844 9845 9846 9847 9848 9849 9850 9851 9852 9853 9854 9855 9856 9857 9858 9859 9860 9861 9862 9863 9864 9865 9866 9867 9868 9869 9870 9871 9872 9873 9874 9875 9876 9877 9878 9879 9880
        def->msi.enabled = true;

        if ((tmp = virXMLPropString(msi, "vectors")) &&
            virStrToLong_uip(tmp, NULL, 0, &def->msi.vectors) < 0) {
            virReportError(VIR_ERR_XML_ERROR,
                           _("invalid number of vectors for shmem: '%s'"),
                           tmp);
            goto cleanup;
        }
        VIR_FREE(tmp);

        if ((tmp = virXMLPropString(msi, "ioeventfd")) &&
            (def->msi.ioeventfd = virTristateSwitchTypeFromString(tmp)) <= 0) {
            virReportError(VIR_ERR_XML_ERROR,
                           _("invalid msi ioeventfd setting for shmem: '%s'"),
                           tmp);
            goto cleanup;
        }
        VIR_FREE(tmp);
    }

    /* msi option is only relevant with a server */
    if (def->msi.enabled && !def->server.enabled) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("msi option is only supported with a server"));
        goto cleanup;
    }

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


    ret = def;
    def = NULL;
 cleanup:
    ctxt->node = save;
    VIR_FREE(tmp);
    virDomainShmemDefFree(def);
    return ret;
}

9881
static virSysinfoDefPtr
9882
virSysinfoParseXML(xmlNodePtr node,
9883 9884 9885
                  xmlXPathContextPtr ctxt,
                  unsigned char *domUUID,
                  bool uuid_generated)
9886 9887 9888
{
    virSysinfoDefPtr def;
    char *type;
9889
    char *tmpUUID = NULL;
9890 9891

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

9897
    if (VIR_ALLOC(def) < 0)
9898
        return NULL;
9899 9900 9901

    type = virXMLPropString(node, "type");
    if (type == NULL) {
9902 9903
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("sysinfo must contain a type attribute"));
9904 9905
        goto error;
    }
9906
    if ((def->type = virSysinfoTypeFromString(type)) < 0) {
9907
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
9908
                       _("unknown sysinfo type '%s'"), type);
9909 9910 9911 9912 9913 9914 9915 9916 9917 9918 9919
        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);
9920 9921 9922 9923 9924 9925 9926 9927 9928 9929 9930 9931 9932 9933 9934 9935 9936 9937 9938 9939 9940 9941 9942
    if (def->bios_date != NULL) {
        char *ptr;
        int month, day, year;

        /* Validate just the format of the date
         * Expect mm/dd/yyyy or mm/dd/yy,
         * where yy must be 00->99 and would be assumed to be 19xx
         * a yyyy date should be 1900 and beyond
         */
        if (virStrToLong_i(def->bios_date, &ptr, 10, &month) < 0 ||
            *ptr != '/' ||
            virStrToLong_i(ptr + 1, &ptr, 10, &day) < 0 ||
            *ptr != '/' ||
            virStrToLong_i(ptr + 1, &ptr, 10, &year) < 0 ||
            *ptr != '\0' ||
            (month < 1 || month > 12) ||
            (day < 1 || day > 31) ||
            (year < 0 || (year >= 100 && year < 1900))) {
            virReportError(VIR_ERR_XML_DETAIL, "%s",
                           _("Invalid BIOS 'date' format"));
            goto error;
        }
    }
9943 9944 9945 9946 9947 9948 9949 9950 9951 9952 9953 9954
    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);
9955 9956 9957 9958 9959 9960 9961 9962 9963
    tmpUUID = virXPathString("string(system/entry[@name='uuid'])", ctxt);
    if (tmpUUID) {
        unsigned char uuidbuf[VIR_UUID_BUFLEN];
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        if (virUUIDParse(tmpUUID, uuidbuf) < 0) {
            virReportError(VIR_ERR_XML_DETAIL,
                           "%s", _("malformed <sysinfo> uuid element"));
            goto error;
        }
9964
        if (uuid_generated) {
9965
            memcpy(domUUID, uuidbuf, VIR_UUID_BUFLEN);
9966
        } else if (memcmp(domUUID, uuidbuf, VIR_UUID_BUFLEN) != 0) {
9967 9968 9969 9970 9971 9972 9973 9974 9975 9976 9977 9978 9979 9980 9981
            virReportError(VIR_ERR_XML_DETAIL, "%s",
                           _("UUID mismatch between <uuid> and "
                             "<sysinfo>"));
            goto error;
        }
        /* Although we've validated the UUID as good, virUUIDParse() is
         * lax with respect to allowing extraneous "-" and " ", but the
         * underlying hypervisor may be less forgiving. Use virUUIDFormat()
         * to validate format in xml is right. If not, then format it
         * properly so that it's used correctly later.
         */
        virUUIDFormat(uuidbuf, uuidstr);
        if (VIR_STRDUP(def->system_uuid, uuidstr) < 0)
            goto error;
    }
9982 9983
    def->system_sku =
        virXPathString("string(system/entry[@name='sku'])", ctxt);
E
Eric Blake 已提交
9984 9985
    def->system_family =
        virXPathString("string(system/entry[@name='family'])", ctxt);
9986

9987
 cleanup:
9988
    VIR_FREE(type);
9989
    VIR_FREE(tmpUUID);
9990
    return def;
9991

9992
 error:
9993 9994 9995 9996
    virSysinfoDefFree(def);
    def = NULL;
    goto cleanup;
}
9997

9998
int
9999
virDomainVideoDefaultRAM(const virDomainDef *def,
10000 10001
                         int type)
{
10002 10003 10004 10005
    /* Defer setting default vram to the Xen drivers */
    if (def->virtType == VIR_DOMAIN_VIRT_XEN)
        return 0;

10006
    switch (type) {
J
Ján Tomko 已提交
10007
        /* Weird, QEMU defaults to 9 MB ??! */
10008 10009 10010 10011 10012
    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 已提交
10013 10014
        else if (def->virtType == VIR_DOMAIN_VIRT_VMWARE)
            return 4 * 1024;
10015 10016 10017 10018 10019 10020 10021 10022
        else
            return 9 * 1024;
        break;

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

10023 10024 10025 10026
    case VIR_DOMAIN_VIDEO_TYPE_QXL:
        /* QEMU use 64M as the minimal video video memory for qxl device */
        return 64 * 1024;

10027 10028 10029 10030 10031 10032 10033
    default:
        return 0;
    }
}


int
10034
virDomainVideoDefaultType(const virDomainDef *def)
10035 10036 10037 10038 10039 10040 10041 10042 10043 10044 10045
{
    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;
10046
        else if ARCH_IS_PPC64(def->os.arch)
10047
            return VIR_DOMAIN_VIDEO_TYPE_VGA;
10048 10049 10050 10051 10052 10053
        else
            return VIR_DOMAIN_VIDEO_TYPE_CIRRUS;

    case VIR_DOMAIN_VIRT_VBOX:
        return VIR_DOMAIN_VIDEO_TYPE_VBOX;

M
Matthias Bolte 已提交
10054 10055 10056
    case VIR_DOMAIN_VIRT_VMWARE:
        return VIR_DOMAIN_VIDEO_TYPE_VMVGA;

10057 10058 10059 10060 10061
    default:
        return -1;
    }
}

10062
static virDomainVideoAccelDefPtr
10063 10064
virDomainVideoAccelDefParseXML(xmlNodePtr node)
{
10065 10066 10067 10068 10069 10070 10071 10072
    xmlNodePtr cur;
    virDomainVideoAccelDefPtr def;
    char *support3d = NULL;
    char *support2d = NULL;

    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
E
Eric Blake 已提交
10073
            if (!support3d && !support2d &&
10074 10075 10076 10077 10078 10079 10080 10081
                xmlStrEqual(cur->name, BAD_CAST "acceleration")) {
                support3d = virXMLPropString(cur, "accel3d");
                support2d = virXMLPropString(cur, "accel2d");
            }
        }
        cur = cur->next;
    }

E
Eric Blake 已提交
10082
    if (!support3d && !support2d)
10083
        return NULL;
10084

10085
    if (VIR_ALLOC(def) < 0)
10086 10087 10088 10089
        return NULL;

    if (support3d) {
        if (STREQ(support3d, "yes"))
10090
            def->support3d = true;
10091
        else
10092
            def->support3d = false;
10093 10094 10095 10096 10097
        VIR_FREE(support3d);
    }

    if (support2d) {
        if (STREQ(support2d, "yes"))
10098
            def->support2d = true;
10099
        else
10100
            def->support2d = false;
10101 10102 10103 10104 10105 10106
        VIR_FREE(support2d);
    }

    return def;
}

10107
static virDomainVideoDefPtr
10108 10109
virDomainVideoDefParseXML(xmlNodePtr node,
                          const virDomainDef *dom,
E
Eric Blake 已提交
10110 10111
                          unsigned int flags)
{
10112 10113 10114 10115 10116
    virDomainVideoDefPtr def;
    xmlNodePtr cur;
    char *type = NULL;
    char *heads = NULL;
    char *vram = NULL;
10117
    char *ram = NULL;
10118
    char *primary = NULL;
10119

10120
    if (VIR_ALLOC(def) < 0)
10121 10122 10123 10124 10125
        return NULL;

    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
10126
            if (!type && !vram && !ram && !heads &&
10127 10128
                xmlStrEqual(cur->name, BAD_CAST "model")) {
                type = virXMLPropString(cur, "type");
10129
                ram = virXMLPropString(cur, "ram");
10130 10131
                vram = virXMLPropString(cur, "vram");
                heads = virXMLPropString(cur, "heads");
10132

10133
                if ((primary = virXMLPropString(cur, "primary")) != NULL) {
10134 10135
                    if (STREQ(primary, "yes"))
                        def->primary = 1;
10136 10137
                    VIR_FREE(primary);
                }
10138

10139
                def->accel = virDomainVideoAccelDefParseXML(cur);
10140 10141 10142 10143 10144 10145 10146
            }
        }
        cur = cur->next;
    }

    if (type) {
        if ((def->type = virDomainVideoTypeFromString(type)) < 0) {
10147
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
10148
                           _("unknown video model '%s'"), type);
10149 10150 10151 10152
            goto error;
        }
    } else {
        if ((def->type = virDomainVideoDefaultType(dom)) < 0) {
10153 10154
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("missing video model and cannot determine default"));
10155 10156 10157 10158
            goto error;
        }
    }

10159 10160 10161 10162 10163 10164 10165 10166 10167 10168 10169 10170 10171 10172 10173
    if (ram) {
        if (def->type != VIR_DOMAIN_VIDEO_TYPE_QXL) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("ram attribute only supported for type of qxl"));
            goto error;
        }
        if (virStrToLong_ui(ram, NULL, 10, &def->ram) < 0) {
            virReportError(VIR_ERR_XML_ERROR,
                           _("cannot parse video ram '%s'"), ram);
            goto error;
        }
    } else if (def->type == VIR_DOMAIN_VIDEO_TYPE_QXL) {
        def->ram = virDomainVideoDefaultRAM(dom, def->type);
    }

10174 10175
    if (vram) {
        if (virStrToLong_ui(vram, NULL, 10, &def->vram) < 0) {
10176
            virReportError(VIR_ERR_XML_ERROR,
10177
                           _("cannot parse video ram '%s'"), vram);
10178 10179 10180 10181 10182 10183 10184 10185
            goto error;
        }
    } else {
        def->vram = virDomainVideoDefaultRAM(dom, def->type);
    }

    if (heads) {
        if (virStrToLong_ui(heads, NULL, 10, &def->heads) < 0) {
10186 10187
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot parse video heads '%s'"), heads);
10188 10189 10190 10191 10192 10193
            goto error;
        }
    } else {
        def->heads = 1;
    }

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

10197
    VIR_FREE(type);
10198
    VIR_FREE(ram);
10199 10200 10201 10202 10203
    VIR_FREE(vram);
    VIR_FREE(heads);

    return def;

10204
 error:
10205 10206
    virDomainVideoDefFree(def);
    VIR_FREE(type);
10207
    VIR_FREE(ram);
10208 10209 10210 10211 10212
    VIR_FREE(vram);
    VIR_FREE(heads);
    return NULL;
}

10213
static virDomainHostdevDefPtr
10214
virDomainHostdevDefParseXML(virDomainXMLOptionPtr xmlopt,
10215 10216
                            const virDomainDef *vmdef,
                            xmlNodePtr node,
10217
                            xmlXPathContextPtr ctxt,
10218
                            virHashTablePtr bootHash,
E
Eric Blake 已提交
10219
                            unsigned int flags)
10220
{
10221
    virDomainHostdevDefPtr def;
10222 10223 10224
    xmlNodePtr save = ctxt->node;
    char *mode = virXMLPropString(node, "mode");
    char *type = virXMLPropString(node, "type");
10225

10226
    ctxt->node = node;
10227

10228
    if (!(def = virDomainHostdevDefAlloc()))
10229 10230
        goto error;

10231 10232
    if (mode) {
        if ((def->mode = virDomainHostdevModeTypeFromString(mode)) < 0) {
10233
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
10234 10235 10236 10237 10238 10239 10240 10241 10242 10243 10244 10245 10246
                           _("unknown hostdev mode '%s'"), mode);
            goto error;
        }
    } else {
        def->mode = VIR_DOMAIN_HOSTDEV_MODE_SUBSYS;
    }

    switch (def->mode) {
    case VIR_DOMAIN_HOSTDEV_MODE_SUBSYS:
        /* parse managed/mode/type, and the <source> element */
        if (virDomainHostdevDefParseXMLSubsys(node, ctxt, type, def, flags) < 0)
            goto error;
        break;
10247 10248 10249 10250 10251
    case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
        /* parse managed/mode/type, and the <source> element */
        if (virDomainHostdevDefParseXMLCaps(node, ctxt, type, def) < 0)
            goto error;
        break;
10252 10253 10254
    default:
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unexpected hostdev mode %d"), def->mode);
10255
        goto error;
10256
    }
10257

10258
    if (def->info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
10259
        if (virDomainDeviceInfoParseXML(node, bootHash, def->info,
10260 10261
                                        flags  | VIR_DOMAIN_XML_INTERNAL_ALLOW_BOOT
                                        | VIR_DOMAIN_XML_INTERNAL_ALLOW_ROM) < 0)
10262 10263 10264 10265 10266 10267
            goto error;
    }

    if (def->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
        switch (def->source.subsys.type) {
        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
10268 10269
            if (def->info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
                def->info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
10270 10271
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("PCI host devices must use 'pci' address type"));
10272 10273 10274
                goto error;
            }
            break;
H
Han Cheng 已提交
10275
        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
10276 10277 10278
            if (def->info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
                virDomainHostdevAssignAddress(xmlopt, vmdef, def) < 0) {

H
Han Cheng 已提交
10279 10280 10281 10282
                virReportError(VIR_ERR_XML_ERROR, "%s",
                               _("SCSI host devices must have address specified"));
                goto error;
            }
O
Osier Yang 已提交
10283 10284 10285

            if (virXPathBoolean("boolean(./readonly)", ctxt))
                def->readonly = true;
10286 10287
            if (virXPathBoolean("boolean(./shareable)", ctxt))
                def->shareable = true;
H
Han Cheng 已提交
10288
            break;
10289 10290 10291
        }
    }

10292
 cleanup:
10293 10294
    VIR_FREE(type);
    VIR_FREE(mode);
10295
    ctxt->node = save;
10296 10297
    return def;

10298
 error:
10299 10300 10301 10302 10303
    virDomainHostdevDefFree(def);
    def = NULL;
    goto cleanup;
}

10304

10305
static virDomainRedirdevDefPtr
10306
virDomainRedirdevDefParseXML(xmlNodePtr node,
10307
                             virHashTablePtr bootHash,
10308 10309 10310 10311 10312
                             unsigned int flags)
{
    xmlNodePtr cur;
    virDomainRedirdevDefPtr def;
    char *bus, *type = NULL;
10313
    int remaining;
10314

10315
    if (VIR_ALLOC(def) < 0)
10316 10317 10318 10319 10320
        return NULL;

    bus = virXMLPropString(node, "bus");
    if (bus) {
        if ((def->bus = virDomainRedirdevBusTypeFromString(bus)) < 0) {
10321
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
10322
                           _("unknown redirdev bus '%s'"), bus);
10323 10324 10325 10326 10327 10328 10329 10330 10331
            goto error;
        }
    } else {
        def->bus = VIR_DOMAIN_REDIRDEV_BUS_USB;
    }

    type = virXMLPropString(node, "type");
    if (type) {
        if ((def->source.chr.type = virDomainChrTypeFromString(type)) < 0) {
10332
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
10333
                           _("unknown redirdev character device type '%s'"), type);
10334 10335 10336
            goto error;
        }
    } else {
10337 10338
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing type in redirdev"));
10339 10340 10341 10342
        goto error;
    }

    cur = node->children;
10343 10344 10345 10346 10347 10348 10349
    /* boot gets parsed in virDomainDeviceInfoParseXML
     * source gets parsed in virDomainChrSourceDefParseXML
     * we don't know any of the elements that might remain */
    remaining = virDomainChrSourceDefParseXML(&def->source.chr, cur, flags,
                                              NULL, NULL, NULL, 0);
    if (remaining < 0)
        goto error;
10350

10351 10352 10353 10354
    if (def->source.chr.type == VIR_DOMAIN_CHR_TYPE_SPICEVMC) {
        def->source.chr.data.spicevmc = VIR_DOMAIN_CHR_SPICEVMC_USBREDIR;
    }

10355
    if (virDomainDeviceInfoParseXML(node, bootHash, &def->info,
10356
                                    flags | VIR_DOMAIN_XML_INTERNAL_ALLOW_BOOT) < 0)
10357 10358 10359 10360 10361
        goto error;

    if (def->bus == VIR_DOMAIN_REDIRDEV_BUS_USB &&
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB) {
10362 10363
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Invalid address for a USB device"));
10364 10365 10366 10367
        goto error;
    }


10368
 cleanup:
10369 10370 10371 10372
    VIR_FREE(bus);
    VIR_FREE(type);
    return def;

10373
 error:
10374 10375 10376 10377 10378
    virDomainRedirdevDefFree(def);
    def = NULL;
    goto cleanup;
}

10379 10380 10381 10382 10383 10384 10385 10386 10387
/*
 * This is the helper function to convert USB version from a
 * format of JJ.MN to a format of 0xJJMN where JJ is the major
 * version number, M is the minor version number and N is the
 * sub minor version number.
 * e.g. USB 2.0 is reported as 0x0200,
 *      USB 1.1 as 0x0110 and USB 1.0 as 0x0100.
 */
static int
10388 10389
virDomainRedirFilterUSBVersionHelper(const char *version,
                                     virDomainRedirFilterUSBDevDefPtr def)
10390 10391 10392 10393 10394 10395 10396 10397 10398 10399
{
    char *version_copy = NULL;
    char *temp = NULL;
    int ret = -1;
    size_t len;
    size_t fraction_len;
    unsigned int major;
    unsigned int minor;
    unsigned int hex;

10400
    if (VIR_STRDUP(version_copy, version) < 0)
10401 10402 10403 10404 10405 10406 10407 10408 10409 10410 10411 10412 10413 10414 10415 10416 10417 10418 10419 10420 10421 10422 10423 10424 10425 10426 10427 10428 10429 10430 10431 10432 10433 10434 10435 10436
        return -1;

    len = strlen(version_copy);
    /*
     * The valid format of version is like 01.10, 1.10, 1.1, etc.
     */
    if (len > 5 ||
        !(temp = strchr(version_copy, '.')) ||
        temp - version_copy < 1 ||
        temp - version_copy > 2 ||
        !(fraction_len = strlen(temp + 1)) ||
        fraction_len > 2) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Incorrect USB version format %s"), version);
        goto cleanup;
    }

    *temp = '\0';
    temp++;

    if ((virStrToLong_ui(version_copy, NULL, 0, &major)) < 0 ||
        (virStrToLong_ui(temp, NULL, 0, &minor)) < 0) {
        virReportError(VIR_ERR_XML_ERROR,
                       _("Cannot parse USB version %s"), version);
        goto cleanup;
    }

    hex = (major / 10) << 12 | (major % 10) << 8;
    if (fraction_len == 1)
        hex |= (minor % 10) << 4;
    else
        hex |= (minor / 10) << 4 | (minor % 10) << 0;

    def->version = hex;
    ret = 0;

10437
 cleanup:
10438 10439 10440 10441
    VIR_FREE(version_copy);
    return ret;
}

10442 10443
static virDomainRedirFilterUSBDevDefPtr
virDomainRedirFilterUSBDevDefParseXML(xmlNodePtr node)
10444 10445 10446 10447
{
    char *class;
    char *vendor = NULL, *product = NULL;
    char *version = NULL, *allow = NULL;
10448
    virDomainRedirFilterUSBDevDefPtr def;
10449

10450
    if (VIR_ALLOC(def) < 0)
10451 10452 10453 10454 10455 10456 10457 10458 10459 10460 10461 10462 10463 10464 10465 10466 10467 10468 10469 10470 10471 10472 10473 10474 10475 10476 10477 10478 10479 10480 10481 10482 10483 10484 10485 10486 10487 10488 10489 10490 10491 10492 10493 10494 10495
        return NULL;

    class = virXMLPropString(node, "class");
    if (class) {
        if ((virStrToLong_i(class, NULL, 0, &def->usbClass)) < 0) {
            virReportError(VIR_ERR_XML_ERROR,
                           _("Cannot parse USB Class code %s"), class);
            goto error;
        }

        if (def->usbClass != -1 && def->usbClass &~ 0xFF) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Invalid USB Class code %s"), class);
            goto error;
        }
    } else {
        def->usbClass = -1;
    }

    vendor = virXMLPropString(node, "vendor");
    if (vendor) {
        if ((virStrToLong_i(vendor, NULL, 0, &def->vendor)) < 0) {
            virReportError(VIR_ERR_XML_ERROR,
                           _("Cannot parse USB vendor ID %s"), vendor);
            goto error;
        }
    } else {
        def->vendor = -1;
    }

    product = virXMLPropString(node, "product");
    if (product) {
        if ((virStrToLong_i(product, NULL, 0, &def->product)) < 0) {
            virReportError(VIR_ERR_XML_ERROR,
                           _("Cannot parse USB product ID %s"), product);
            goto error;
        }
    } else {
        def->product = -1;
    }

    version = virXMLPropString(node, "version");
    if (version) {
        if (STREQ(version, "-1"))
            def->version = -1;
10496
        else if ((virDomainRedirFilterUSBVersionHelper(version, def)) < 0)
10497 10498 10499 10500 10501 10502 10503
            goto error;
    } else {
        def->version = -1;
    }

    allow = virXMLPropString(node, "allow");
    if (allow) {
10504
        if (STREQ(allow, "yes")) {
10505
            def->allow = true;
10506
        } else if (STREQ(allow, "no")) {
10507
            def->allow = false;
10508
        } else {
10509 10510 10511 10512 10513 10514 10515 10516 10517 10518
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Invalid allow value, either 'yes' or 'no'"));
            goto error;
        }
    } else {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Missing allow attribute for USB redirection filter"));
        goto error;
    }

10519
 cleanup:
10520 10521 10522 10523 10524 10525 10526
    VIR_FREE(class);
    VIR_FREE(vendor);
    VIR_FREE(product);
    VIR_FREE(version);
    VIR_FREE(allow);
    return def;

10527
 error:
10528 10529 10530 10531 10532 10533
    VIR_FREE(def);
    def = NULL;
    goto cleanup;
}

static virDomainRedirFilterDefPtr
10534
virDomainRedirFilterDefParseXML(xmlNodePtr node,
10535 10536 10537 10538 10539 10540 10541 10542 10543
                                xmlXPathContextPtr ctxt)
{
    int n;
    size_t i;
    xmlNodePtr *nodes = NULL;
    xmlNodePtr save = ctxt->node;
    virDomainRedirFilterDefPtr def = NULL;

    if (VIR_ALLOC(def) < 0)
10544
        goto error;
10545 10546 10547 10548 10549 10550 10551

    ctxt->node = node;
    if ((n = virXPathNodeSet("./usbdev", ctxt, &nodes)) < 0) {
        goto error;
    }

    if (n && VIR_ALLOC_N(def->usbdevs, n) < 0)
10552
        goto error;
10553 10554

    for (i = 0; i < n; i++) {
10555 10556
        virDomainRedirFilterUSBDevDefPtr usbdev =
            virDomainRedirFilterUSBDevDefParseXML(nodes[i]);
10557 10558 10559 10560 10561 10562 10563 10564 10565 10566

        if (!usbdev)
            goto error;
        def->usbdevs[def->nusbdevs++] = usbdev;
    }
    VIR_FREE(nodes);

    ctxt->node = save;
    return def;

10567
 error:
10568 10569 10570 10571 10572
    VIR_FREE(nodes);
    virDomainRedirFilterDefFree(def);
    return NULL;
}

10573 10574 10575 10576 10577 10578 10579
static int
virDomainEventActionParseXML(xmlXPathContextPtr ctxt,
                             const char *name,
                             const char *xpath,
                             int *val,
                             int defaultVal,
                             virEventActionFromStringFunc convFunc)
10580
{
10581
    char *tmp = virXPathString(xpath, ctxt);
10582 10583 10584
    if (tmp == NULL) {
        *val = defaultVal;
    } else {
10585
        *val = convFunc(tmp);
10586
        if (*val < 0) {
10587
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
10588
                           _("unknown %s action: %s"), name, tmp);
10589 10590 10591 10592 10593 10594 10595 10596
            VIR_FREE(tmp);
            return -1;
        }
        VIR_FREE(tmp);
    }
    return 0;
}

10597 10598 10599 10600 10601 10602 10603 10604
static int
virDomainPMStateParseXML(xmlXPathContextPtr ctxt,
                         const char *xpath,
                         int *val)
{
    int ret = -1;
    char *tmp = virXPathString(xpath, ctxt);
    if (tmp) {
J
Ján Tomko 已提交
10605
        *val = virTristateBoolTypeFromString(tmp);
10606 10607 10608 10609 10610 10611 10612 10613 10614 10615 10616 10617 10618
        if (*val < 0) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown PM state value %s"), tmp);
            goto cleanup;
        }
    }

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

10619
virDomainDeviceDefPtr
10620
virDomainDeviceDefParse(const char *xmlStr,
10621
                        const virDomainDef *def,
10622 10623
                        virCapsPtr caps,
                        virDomainXMLOptionPtr xmlopt,
10624
                        unsigned int flags)
10625 10626 10627
{
    xmlDocPtr xml;
    xmlNodePtr node;
10628
    xmlXPathContextPtr ctxt = NULL;
10629 10630
    virDomainDeviceDefPtr dev = NULL;

10631
    if (!(xml = virXMLParseStringCtxt(xmlStr, _("(device_definition)"), &ctxt)))
10632
        goto error;
10633

10634
    node = ctxt->node;
10635

10636
    if (VIR_ALLOC(dev) < 0)
10637 10638
        goto error;

10639 10640 10641 10642 10643 10644 10645 10646 10647
    if ((dev->type = virDomainDeviceTypeFromString((const char *) node->name)) < 0) {
        /* Some crazy mapping of serial, parallel, console and channel to
         * VIR_DOMAIN_DEVICE_CHR. */
        if (xmlStrEqual(node->name, BAD_CAST "channel") ||
            xmlStrEqual(node->name, BAD_CAST "console") ||
            xmlStrEqual(node->name, BAD_CAST "parallel") ||
            xmlStrEqual(node->name, BAD_CAST "serial")) {
            dev->type = VIR_DOMAIN_DEVICE_CHR;
        } else {
10648
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
10649 10650 10651 10652 10653 10654 10655 10656
                           _("unknown device type '%s'"),
                           node->name);
            goto error;
        }
    }

    switch ((virDomainDeviceType) dev->type) {
    case VIR_DOMAIN_DEVICE_DISK:
10657
        if (!(dev->data.disk = virDomainDiskDefParseXML(xmlopt, node, ctxt,
10658 10659
                                                        NULL, def->seclabels,
                                                        def->nseclabels,
10660
                                                        flags)))
10661
            goto error;
10662 10663
        break;
    case VIR_DOMAIN_DEVICE_LEASE:
10664 10665
        if (!(dev->data.lease = virDomainLeaseDefParseXML(node)))
            goto error;
10666 10667
        break;
    case VIR_DOMAIN_DEVICE_FS:
10668
        if (!(dev->data.fs = virDomainFSDefParseXML(node, ctxt, flags)))
10669
            goto error;
10670 10671
        break;
    case VIR_DOMAIN_DEVICE_NET:
10672
        if (!(dev->data.net = virDomainNetDefParseXML(xmlopt, node, ctxt,
10673
                                                      NULL, flags)))
10674
            goto error;
10675 10676
        break;
    case VIR_DOMAIN_DEVICE_INPUT:
L
Li Zhang 已提交
10677
        if (!(dev->data.input = virDomainInputDefParseXML(def,
10678
                                                          node, flags)))
10679
            goto error;
10680 10681
        break;
    case VIR_DOMAIN_DEVICE_SOUND:
10682
        if (!(dev->data.sound = virDomainSoundDefParseXML(node, ctxt, flags)))
10683
            goto error;
10684 10685
        break;
    case VIR_DOMAIN_DEVICE_WATCHDOG:
10686
        if (!(dev->data.watchdog = virDomainWatchdogDefParseXML(node, flags)))
R
Richard Jones 已提交
10687
            goto error;
10688 10689
        break;
    case VIR_DOMAIN_DEVICE_VIDEO:
10690
        if (!(dev->data.video = virDomainVideoDefParseXML(node, def, flags)))
10691
            goto error;
10692 10693
        break;
    case VIR_DOMAIN_DEVICE_HOSTDEV:
10694 10695
        if (!(dev->data.hostdev = virDomainHostdevDefParseXML(xmlopt, def, node,
                                                              ctxt, NULL, flags)))
10696
            goto error;
10697 10698
        break;
    case VIR_DOMAIN_DEVICE_CONTROLLER:
10699 10700
        if (!(dev->data.controller = virDomainControllerDefParseXML(node, ctxt,
                                                                    flags)))
10701
            goto error;
10702 10703
        break;
    case VIR_DOMAIN_DEVICE_GRAPHICS:
10704
        if (!(dev->data.graphics = virDomainGraphicsDefParseXML(node, ctxt, flags)))
10705
            goto error;
10706 10707
        break;
    case VIR_DOMAIN_DEVICE_HUB:
M
Marc-André Lureau 已提交
10708 10709
        if (!(dev->data.hub = virDomainHubDefParseXML(node, flags)))
            goto error;
10710 10711
        break;
    case VIR_DOMAIN_DEVICE_REDIRDEV:
10712
        if (!(dev->data.redirdev = virDomainRedirdevDefParseXML(node, NULL, flags)))
10713
            goto error;
10714 10715
        break;
    case VIR_DOMAIN_DEVICE_RNG:
10716 10717
        if (!(dev->data.rng = virDomainRNGDefParseXML(node, ctxt, flags)))
            goto error;
10718 10719
        break;
    case VIR_DOMAIN_DEVICE_CHR:
10720 10721 10722 10723 10724 10725
        if (!(dev->data.chr = virDomainChrDefParseXML(ctxt,
                                                      node,
                                                      def->seclabels,
                                                      def->nseclabels,
                                                      flags)))
            goto error;
10726 10727
        break;
    case VIR_DOMAIN_DEVICE_SMARTCARD:
10728 10729
        if (!(dev->data.smartcard = virDomainSmartcardDefParseXML(node, flags)))
            goto error;
10730 10731
        break;
    case VIR_DOMAIN_DEVICE_MEMBALLOON:
10732 10733 10734
        if (!(dev->data.memballoon = virDomainMemballoonDefParseXML(node,
                                                                    ctxt,
                                                                    flags)))
10735
            goto error;
10736 10737
        break;
    case VIR_DOMAIN_DEVICE_NVRAM:
10738 10739
        if (!(dev->data.nvram = virDomainNVRAMDefParseXML(node, flags)))
            goto error;
10740
        break;
10741 10742 10743 10744
    case VIR_DOMAIN_DEVICE_SHMEM:
        if (!(dev->data.shmem = virDomainShmemDefParseXML(node, ctxt, flags)))
            goto error;
        break;
10745 10746 10747
    case VIR_DOMAIN_DEVICE_NONE:
    case VIR_DOMAIN_DEVICE_LAST:
        break;
10748 10749
    }

10750
    /* callback to fill driver specific device aspects */
10751
    if (virDomainDeviceDefPostParse(dev, def, caps, xmlopt) < 0)
10752 10753
        goto error;

10754
 cleanup:
10755
    xmlFreeDoc(xml);
10756
    xmlXPathFreeContext(ctxt);
10757 10758
    return dev;

10759
 error:
10760
    VIR_FREE(dev);
10761
    goto cleanup;
10762
}
M
Matthias Bolte 已提交
10763 10764


10765 10766 10767 10768 10769 10770 10771 10772 10773 10774 10775 10776 10777 10778 10779 10780 10781 10782 10783 10784 10785 10786 10787 10788 10789 10790 10791 10792 10793 10794 10795 10796 10797 10798 10799 10800 10801 10802 10803 10804 10805
virStorageSourcePtr
virDomainDiskDefSourceParse(const char *xmlStr,
                            const virDomainDef *def,
                            virDomainXMLOptionPtr xmlopt,
                            unsigned int flags)
{
    xmlDocPtr xml;
    xmlNodePtr node;
    xmlXPathContextPtr ctxt = NULL;
    virDomainDiskDefPtr disk = NULL;
    virStorageSourcePtr ret = NULL;

    if (!(xml = virXMLParseStringCtxt(xmlStr, _("(disk_definition)"), &ctxt)))
        goto cleanup;
    node = ctxt->node;

    if (!xmlStrEqual(node->name, BAD_CAST "disk")) {
        virReportError(VIR_ERR_XML_ERROR,
                       _("expecting root element of 'disk', not '%s'"),
                       node->name);
        goto cleanup;
    }

    flags |= VIR_DOMAIN_XML_INTERNAL_DISK_SOURCE;
    if (!(disk = virDomainDiskDefParseXML(xmlopt, node, ctxt,
                                          NULL, def->seclabels,
                                          def->nseclabels,
                                          flags)))
        goto cleanup;

    ret = disk->src;
    disk->src = NULL;

 cleanup:
    virDomainDiskDefFree(disk);
    xmlFreeDoc(xml);
    xmlXPathFreeContext(ctxt);
    return ret;
}


10806 10807 10808 10809 10810 10811 10812 10813 10814 10815 10816 10817 10818
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;
G
Guannan Ren 已提交
10819 10820 10821
    case VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL:
        type = virDomainChrSerialTargetTypeToString(targetType);
        break;
10822 10823 10824 10825 10826 10827 10828
    default:
        break;
    }

    return type;
}

L
Laine Stump 已提交
10829 10830 10831
int
virDomainHostdevInsert(virDomainDefPtr def, virDomainHostdevDefPtr hostdev)
{
10832 10833

    return VIR_APPEND_ELEMENT(def->hostdevs, def->nhostdevs, hostdev);
L
Laine Stump 已提交
10834 10835
}

10836
virDomainHostdevDefPtr
L
Laine Stump 已提交
10837 10838
virDomainHostdevRemove(virDomainDefPtr def, size_t i)
{
10839 10840
    virDomainHostdevDefPtr hostdev = def->hostdevs[i];

10841
    VIR_DELETE_ELEMENT(def->hostdevs, i, def->nhostdevs);
10842
    return hostdev;
L
Laine Stump 已提交
10843 10844
}

10845 10846

static int
10847 10848
virDomainHostdevMatchSubsysUSB(virDomainHostdevDefPtr first,
                               virDomainHostdevDefPtr second)
10849
{
10850 10851 10852 10853
    virDomainHostdevSubsysUSBPtr first_usbsrc = &first->source.subsys.u.usb;
    virDomainHostdevSubsysUSBPtr second_usbsrc = &second->source.subsys.u.usb;

    if (first_usbsrc->bus && first_usbsrc->device) {
10854
        /* specified by bus location on host */
10855 10856
        if (first_usbsrc->bus == second_usbsrc->bus &&
            first_usbsrc->device == second_usbsrc->device)
10857 10858 10859
            return 1;
    } else {
        /* specified by product & vendor id */
10860 10861
        if (first_usbsrc->product == second_usbsrc->product &&
            first_usbsrc->vendor == second_usbsrc->vendor)
10862 10863 10864 10865 10866 10867
            return 1;
    }
    return 0;
}

static int
10868 10869
virDomainHostdevMatchSubsysPCI(virDomainHostdevDefPtr first,
                               virDomainHostdevDefPtr second)
10870
{
10871 10872 10873 10874 10875 10876 10877
    virDomainHostdevSubsysPCIPtr first_pcisrc = &first->source.subsys.u.pci;
    virDomainHostdevSubsysPCIPtr second_pcisrc = &second->source.subsys.u.pci;

    if (first_pcisrc->addr.domain == second_pcisrc->addr.domain &&
        first_pcisrc->addr.bus == second_pcisrc->addr.bus &&
        first_pcisrc->addr.slot == second_pcisrc->addr.slot &&
        first_pcisrc->addr.function == second_pcisrc->addr.function)
10878 10879 10880 10881
        return 1;
    return 0;
}

H
Han Cheng 已提交
10882
static int
10883 10884 10885 10886 10887 10888 10889 10890 10891 10892 10893 10894
virDomainHostdevMatchSubsysSCSIHost(virDomainHostdevDefPtr first,
                                    virDomainHostdevDefPtr second)
{
    virDomainHostdevSubsysSCSIHostPtr first_scsihostsrc =
        &first->source.subsys.u.scsi.u.host;
    virDomainHostdevSubsysSCSIHostPtr second_scsihostsrc =
        &second->source.subsys.u.scsi.u.host;

    if (STREQ(first_scsihostsrc->adapter, second_scsihostsrc->adapter) &&
        first_scsihostsrc->bus == second_scsihostsrc->bus &&
        first_scsihostsrc->target == second_scsihostsrc->target &&
        first_scsihostsrc->unit == second_scsihostsrc->unit)
H
Han Cheng 已提交
10895 10896 10897
        return 1;
    return 0;
}
10898

10899 10900 10901 10902 10903 10904 10905 10906 10907 10908 10909 10910 10911 10912 10913 10914
static int
virDomainHostdevMatchSubsysSCSIiSCSI(virDomainHostdevDefPtr first,
                                     virDomainHostdevDefPtr second)
{
    virDomainHostdevSubsysSCSIiSCSIPtr first_iscsisrc =
        &first->source.subsys.u.scsi.u.iscsi;
    virDomainHostdevSubsysSCSIiSCSIPtr second_iscsisrc =
        &second->source.subsys.u.scsi.u.iscsi;

    if (STREQ(first_iscsisrc->hosts[0].name, second_iscsisrc->hosts[0].name) &&
        STREQ(first_iscsisrc->hosts[0].port, second_iscsisrc->hosts[0].port) &&
        STREQ(first_iscsisrc->path, second_iscsisrc->path))
        return 1;
    return 0;
}

10915 10916 10917 10918 10919 10920 10921 10922 10923 10924 10925 10926
static int
virDomainHostdevMatchSubsys(virDomainHostdevDefPtr a,
                            virDomainHostdevDefPtr b)
{
    if (a->source.subsys.type != b->source.subsys.type)
        return 0;

    switch (a->source.subsys.type) {
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
        return virDomainHostdevMatchSubsysPCI(a, b);
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
        return virDomainHostdevMatchSubsysUSB(a, b);
H
Han Cheng 已提交
10927
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
10928 10929 10930 10931 10932
        if (a->source.subsys.u.scsi.protocol ==
            VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_ISCSI)
            return virDomainHostdevMatchSubsysSCSIiSCSI(a, b);
        else
            return virDomainHostdevMatchSubsysSCSIHost(a, b);
10933 10934 10935 10936 10937
    }
    return 0;
}


10938 10939 10940 10941 10942 10943 10944 10945 10946 10947 10948 10949 10950 10951 10952 10953 10954
static int
virDomainHostdevMatchCapsStorage(virDomainHostdevDefPtr a,
                                 virDomainHostdevDefPtr b)
{
    return STREQ_NULLABLE(a->source.caps.u.storage.block,
                          b->source.caps.u.storage.block);
}


static int
virDomainHostdevMatchCapsMisc(virDomainHostdevDefPtr a,
                              virDomainHostdevDefPtr b)
{
    return STREQ_NULLABLE(a->source.caps.u.misc.chardev,
                          b->source.caps.u.misc.chardev);
}

10955 10956 10957 10958 10959 10960 10961 10962
static int
virDomainHostdevMatchCapsNet(virDomainHostdevDefPtr a,
                              virDomainHostdevDefPtr b)
{
    return STREQ_NULLABLE(a->source.caps.u.net.iface,
                          b->source.caps.u.net.iface);
}

10963 10964 10965 10966 10967 10968 10969 10970 10971 10972 10973 10974 10975

static int
virDomainHostdevMatchCaps(virDomainHostdevDefPtr a,
                          virDomainHostdevDefPtr b)
{
    if (a->source.caps.type != b->source.caps.type)
        return 0;

    switch (a->source.caps.type) {
    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_STORAGE:
        return virDomainHostdevMatchCapsStorage(a, b);
    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_MISC:
        return virDomainHostdevMatchCapsMisc(a, b);
10976 10977
    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_NET:
        return virDomainHostdevMatchCapsNet(a, b);
10978 10979 10980 10981 10982
    }
    return 0;
}


10983 10984 10985 10986 10987 10988 10989 10990 10991 10992
static int
virDomainHostdevMatch(virDomainHostdevDefPtr a,
                      virDomainHostdevDefPtr b)
{
    if (a->mode != b->mode)
        return 0;

    switch (a->mode) {
    case VIR_DOMAIN_HOSTDEV_MODE_SUBSYS:
        return virDomainHostdevMatchSubsys(a, b);
10993 10994
    case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
        return virDomainHostdevMatchCaps(a, b);
10995 10996 10997 10998
    }
    return 0;
}

L
Laine Stump 已提交
10999 11000 11001 11002 11003 11004 11005 11006 11007 11008 11009
/* Find an entry in hostdevs that matches the source spec in
 * @match. return pointer to the entry in @found (if found is
 * non-NULL). Returns index (within hostdevs) of matched entry, or -1
 * if no match was found.
 */
int
virDomainHostdevFind(virDomainDefPtr def,
                     virDomainHostdevDefPtr match,
                     virDomainHostdevDefPtr *found)
{
    virDomainHostdevDefPtr local_found;
11010
    size_t i;
L
Laine Stump 已提交
11011 11012 11013 11014 11015

    if (!found)
        found = &local_found;
    *found = NULL;

11016
    for (i = 0; i < def->nhostdevs; i++) {
11017 11018
        if (virDomainHostdevMatch(match, def->hostdevs[i])) {
            *found = def->hostdevs[i];
L
Laine Stump 已提交
11019 11020 11021 11022 11023 11024
            break;
        }
    }
    return *found ? i : -1;
}

11025 11026 11027
int
virDomainDiskIndexByName(virDomainDefPtr def, const char *name,
                         bool allow_ambiguous)
11028 11029
{
    virDomainDiskDefPtr vdisk;
11030
    size_t i;
11031
    int candidate = -1;
11032

11033 11034 11035 11036
    /* We prefer the <target dev='name'/> name (it's shorter, required
     * for all disks, and should be unambiguous), but also support
     * <source file='name'/> (if unambiguous).  Assume dst if there is
     * no leading slash, source name otherwise.  */
11037 11038
    for (i = 0; i < def->ndisks; i++) {
        vdisk = def->disks[i];
11039 11040 11041
        if (*name != '/') {
            if (STREQ(vdisk->dst, name))
                return i;
11042
        } else if (STREQ_NULLABLE(virDomainDiskGetSource(vdisk), name)) {
11043 11044 11045 11046 11047 11048
            if (allow_ambiguous)
                return i;
            if (candidate >= 0)
                return -1;
            candidate = i;
        }
11049
    }
11050 11051 11052 11053 11054 11055 11056 11057 11058
    return candidate;
}

/* Return the path to a disk image if a string identifies at least one
 * disk belonging to the domain (both device strings 'vda' and paths
 * '/path/to/file' are converted into '/path/to/file').  */
const char *
virDomainDiskPathByName(virDomainDefPtr def, const char *name)
{
11059
    int idx = virDomainDiskIndexByName(def, name, true);
11060

11061
    return idx < 0 ? NULL : virDomainDiskGetSource(def->disks[idx]);
11062 11063
}

11064 11065
int virDomainDiskInsert(virDomainDefPtr def,
                        virDomainDiskDefPtr disk)
11066 11067
{

11068 11069 11070 11071 11072 11073
    if (VIR_REALLOC_N(def->disks, def->ndisks+1) < 0)
        return -1;

    virDomainDiskInsertPreAlloced(def, disk);

    return 0;
11074 11075
}

11076 11077 11078
void virDomainDiskInsertPreAlloced(virDomainDefPtr def,
                                   virDomainDiskDefPtr disk)
{
11079
    int idx;
11080 11081 11082 11083 11084 11085 11086 11087
    /* 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
     */
11088
    for (idx = (def->ndisks - 1); idx >= 0; idx--) {
11089 11090
        /* If bus matches and current disk is after
         * new disk, then new disk should go here */
11091 11092
        if (def->disks[idx]->bus == disk->bus &&
            (virDiskNameToIndex(def->disks[idx]->dst) >
11093
             virDiskNameToIndex(disk->dst))) {
11094 11095
            insertAt = idx;
        } else if (def->disks[idx]->bus == disk->bus &&
11096 11097 11098 11099
                   insertAt == -1) {
            /* Last disk with match bus is before the
             * new disk, then put new disk just after
             */
11100
            insertAt = idx + 1;
11101 11102 11103
        }
    }

11104 11105 11106
    /* VIR_INSERT_ELEMENT_INPLACE will never return an error here. */
    ignore_value(VIR_INSERT_ELEMENT_INPLACE(def->disks, insertAt,
                                            def->ndisks, disk));
11107 11108 11109
}


11110 11111
virDomainDiskDefPtr
virDomainDiskRemove(virDomainDefPtr def, size_t i)
11112
{
11113
    virDomainDiskDefPtr disk = def->disks[i];
11114

11115
    VIR_DELETE_ELEMENT(def->disks, i, def->ndisks);
11116
    return disk;
11117 11118
}

11119 11120
virDomainDiskDefPtr
virDomainDiskRemoveByName(virDomainDefPtr def, const char *name)
11121
{
11122 11123
    int idx = virDomainDiskIndexByName(def, name, false);
    if (idx < 0)
11124
        return NULL;
11125
    return virDomainDiskRemove(def, idx);
11126 11127
}

E
Eric Blake 已提交
11128
/* Return true if VM has at least one disk involved in a current block
11129
 * copy/commit job (that is, with a <mirror> element in the disk xml).  */
E
Eric Blake 已提交
11130 11131 11132
bool
virDomainHasDiskMirror(virDomainObjPtr vm)
{
11133
    size_t i;
E
Eric Blake 已提交
11134 11135 11136 11137 11138 11139
    for (i = 0; i < vm->def->ndisks; i++)
        if (vm->def->disks[i]->mirror)
            return true;
    return false;
}

11140 11141
int virDomainNetInsert(virDomainDefPtr def, virDomainNetDefPtr net)
{
11142 11143 11144 11145 11146 11147 11148 11149 11150 11151
    /* hostdev net devices must also exist in the hostdevs array */
    if (net->type == VIR_DOMAIN_NET_TYPE_HOSTDEV &&
        virDomainHostdevInsert(def, &net->data.hostdev.def) < 0)
        return -1;

    if (VIR_APPEND_ELEMENT(def->nets, def->nnets, net) < 0) {
        /* virDomainHostdevInsert just appends new hostdevs, so we are sure
         * that the hostdev we've added a few lines above is at the end of
         * array. Although, devices are indexed from zero ... */
        virDomainHostdevRemove(def, def->nhostdevs - 1);
11152
        return -1;
11153
    }
11154 11155 11156
    return 0;
}

11157 11158 11159 11160
/* virDomainNetFindIdx: search according to mac address and guest side
 *                      PCI address (if specified)
 *
 * Return: index of match if unique match found
11161
 *         -1 otherwise and an error is logged
11162 11163 11164
 */
int
virDomainNetFindIdx(virDomainDefPtr def, virDomainNetDefPtr net)
11165
{
11166 11167
    size_t i;
    int matchidx = -1;
11168
    char mac[VIR_MAC_STRING_BUFLEN];
11169 11170
    bool PCIAddrSpecified = virDomainDeviceAddressIsValid(&net->info,
                                                          VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI);
11171

11172 11173
    for (i = 0; i < def->nnets; i++) {
        if (virMacAddrCmp(&def->nets[i]->mac, &net->mac))
11174 11175 11176 11177 11178 11179 11180 11181 11182
            continue;

        if ((matchidx >= 0) && !PCIAddrSpecified) {
            /* there were multiple matches on mac address, and no
             * qualifying guest-side PCI address was given, so we must
             * fail (NB: a USB address isn't adequate, since it may
             * specify only vendor and product ID, and there may be
             * multiples of those.
             */
11183 11184 11185 11186
            virReportError(VIR_ERR_OPERATION_FAILED,
                           _("multiple devices matching mac address %s found"),
                           virMacAddrFormat(&net->mac, mac));
            return -1;
11187 11188
        }
        if (PCIAddrSpecified) {
11189
            if (virDevicePCIAddressEqual(&def->nets[i]->info.addr.pci,
11190 11191 11192 11193
                                         &net->info.addr.pci)) {
                /* exit early if the pci address was specified and
                 * it matches, as this guarantees no duplicates.
                 */
11194
                matchidx = i;
11195 11196 11197 11198
                break;
            }
        } else {
            /* no PCI address given, so there may be multiple matches */
11199
            matchidx = i;
11200 11201
        }
    }
11202
    if (matchidx < 0) {
11203 11204 11205 11206 11207 11208 11209 11210 11211 11212 11213 11214 11215 11216
        if (PCIAddrSpecified) {
            virReportError(VIR_ERR_OPERATION_FAILED,
                           _("no device matching mac address %s found on "
                             "%.4x:%.2x:%.2x.%.1x"),
                           virMacAddrFormat(&net->mac, mac),
                           net->info.addr.pci.domain,
                           net->info.addr.pci.bus,
                           net->info.addr.pci.slot,
                           net->info.addr.pci.function);
        } else {
            virReportError(VIR_ERR_OPERATION_FAILED,
                           _("no device matching mac address %s found"),
                           virMacAddrFormat(&net->mac, mac));
        }
11217
    }
11218
    return matchidx;
11219 11220
}

11221

11222 11223 11224 11225
void
virDomainNetRemoveHostdev(virDomainDefPtr def,
                          virDomainNetDefPtr net)
{
11226 11227 11228 11229 11230 11231
    /* hostdev net devices are normally also be in the hostdevs
     * array, but might have already been removed by the time we
     * get here.
     */
    virDomainHostdevDefPtr hostdev = virDomainNetGetActualHostdev(net);
    size_t i;
11232

11233
    if (hostdev) {
11234 11235 11236
        for (i = 0; i < def->nhostdevs; i++) {
            if (def->hostdevs[i] == hostdev) {
                virDomainHostdevRemove(def, i);
11237 11238 11239 11240
                break;
            }
        }
    }
11241 11242 11243 11244 11245 11246 11247 11248 11249
}


virDomainNetDefPtr
virDomainNetRemove(virDomainDefPtr def, size_t i)
{
    virDomainNetDefPtr net = def->nets[i];

    virDomainNetRemoveHostdev(def, net);
11250
    VIR_DELETE_ELEMENT(def->nets, i, def->nnets);
11251
    return net;
11252 11253
}

11254 11255 11256 11257 11258 11259 11260 11261 11262 11263 11264 11265 11266 11267 11268
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)
{
11269
    int idx;
11270 11271 11272 11273 11274 11275 11276 11277
    /* 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
     */
11278
    for (idx = (def->ncontrollers - 1); idx >= 0; idx--) {
11279 11280
        /* If bus matches and current controller is after
         * new controller, then new controller should go here */
11281 11282 11283 11284
        if (def->controllers[idx]->type == controller->type &&
            def->controllers[idx]->idx > controller->idx) {
            insertAt = idx;
        } else if (def->controllers[idx]->type == controller->type &&
11285 11286 11287 11288
                   insertAt == -1) {
            /* Last controller with match bus is before the
             * new controller, then put new controller just after
             */
11289
            insertAt = idx + 1;
11290 11291 11292
        }
    }

11293 11294 11295
    /* VIR_INSERT_ELEMENT_INPLACE will never return an error here. */
    ignore_value(VIR_INSERT_ELEMENT_INPLACE(def->controllers, insertAt,
                                            def->ncontrollers, controller));
11296 11297
}

11298 11299 11300 11301
int
virDomainControllerFind(virDomainDefPtr def,
                        int type, int idx)
{
11302
    size_t i;
11303

11304
    for (i = 0; i < def->ncontrollers; i++) {
11305 11306 11307 11308 11309 11310 11311 11312 11313 11314 11315 11316 11317 11318
        if ((def->controllers[i]->type == type) &&
            (def->controllers[i]->idx == idx)) {
            return i;
        }
    }

    return -1;
}

virDomainControllerDefPtr
virDomainControllerRemove(virDomainDefPtr def, size_t i)
{
    virDomainControllerDefPtr controller = def->controllers[i];

11319
    VIR_DELETE_ELEMENT(def->controllers, i, def->ncontrollers);
11320 11321
    return controller;
}
11322

11323 11324 11325 11326
int virDomainLeaseIndex(virDomainDefPtr def,
                        virDomainLeaseDefPtr lease)
{
    virDomainLeaseDefPtr vlease;
11327
    size_t i;
11328 11329 11330 11331 11332 11333 11334 11335 11336 11337 11338 11339 11340 11341 11342 11343 11344 11345 11346

    for (i = 0; i < def->nleases; i++) {
        vlease = def->leases[i];
        /* Either both must have lockspaces present which  match.. */
        if (vlease->lockspace && lease->lockspace &&
            STRNEQ(vlease->lockspace, lease->lockspace))
            continue;
        /* ...or neither must have a lockspace present */
        if (vlease->lockspace || lease->lockspace)
            continue;
        if (STREQ(vlease->key, lease->key))
            return i;
    }
    return -1;
}


int virDomainLeaseInsertPreAlloc(virDomainDefPtr def)
{
11347
    return VIR_EXPAND_N(def->leases, def->nleases, 1);
11348 11349 11350 11351 11352 11353 11354 11355 11356 11357 11358 11359 11360 11361 11362 11363 11364 11365 11366 11367 11368 11369 11370
}

int virDomainLeaseInsert(virDomainDefPtr def,
                         virDomainLeaseDefPtr lease)
{
    if (virDomainLeaseInsertPreAlloc(def) < 0)
        return -1;

    virDomainLeaseInsertPreAlloced(def, lease);
    return 0;
}


void virDomainLeaseInsertPreAlloced(virDomainDefPtr def,
                                    virDomainLeaseDefPtr lease)
{
    if (lease == NULL)
        VIR_SHRINK_N(def->leases, def->nleases, 1);
    else
        def->leases[def->nleases-1] = lease;
}


11371 11372
virDomainLeaseDefPtr
virDomainLeaseRemoveAt(virDomainDefPtr def, size_t i)
11373
{
11374 11375 11376

    virDomainLeaseDefPtr lease = def->leases[i];

11377
    VIR_DELETE_ELEMENT(def->leases, i, def->nleases);
11378
    return lease;
11379 11380 11381
}


11382 11383 11384
virDomainLeaseDefPtr
virDomainLeaseRemove(virDomainDefPtr def,
                     virDomainLeaseDefPtr lease)
11385
{
11386 11387
    int idx = virDomainLeaseIndex(def, lease);
    if (idx < 0)
11388
        return NULL;
11389
    return virDomainLeaseRemoveAt(def, idx);
11390 11391
}

11392
bool
11393 11394 11395 11396 11397 11398 11399 11400 11401 11402
virDomainChrEquals(virDomainChrDefPtr src,
                   virDomainChrDefPtr tgt)
{
    if (!src || !tgt)
        return src == tgt;

    if (src->deviceType != tgt->deviceType ||
        !virDomainChrSourceDefIsEqual(&src->source, &tgt->source))
        return false;

11403
    switch ((virDomainChrDeviceType) src->deviceType) {
11404 11405 11406
    case VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL:
        if (src->targetType != tgt->targetType)
            return false;
11407
        switch ((virDomainChrChannelTargetType) src->targetType) {
11408 11409 11410 11411 11412 11413 11414 11415 11416 11417 11418 11419 11420 11421 11422 11423 11424 11425 11426 11427 11428 11429 11430 11431 11432 11433 11434 11435 11436 11437 11438 11439 11440 11441 11442
        case VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO:
            return STREQ_NULLABLE(src->target.name, tgt->target.name);
            break;
        case VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_GUESTFWD:
            if (!src->target.addr || !tgt->target.addr)
                return src->target.addr == tgt->target.addr;
            return memcmp(src->target.addr, tgt->target.addr,
                          sizeof(*src->target.addr)) == 0;
            break;

        case VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_NONE:
        case VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_LAST:
            /* shouldn't happen */
            break;
        }
        break;

    case VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL:
        if (src->targetTypeAttr != tgt->targetTypeAttr)
            return false;
    case VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE:
    case VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL:
        return src->target.port == tgt->target.port;
        break;
    case VIR_DOMAIN_CHR_DEVICE_TYPE_LAST:
        /* shouldn't happen */
        break;
    }
    return false;
}

virDomainChrDefPtr
virDomainChrFind(virDomainDefPtr def,
                 virDomainChrDefPtr target)
{
11443 11444 11445
    virDomainChrDefPtr chr;
    const virDomainChrDef **arrPtr;
    size_t i, cnt;
11446

11447
    virDomainChrGetDomainPtrs(def, target->deviceType, &arrPtr, &cnt);
11448

11449 11450 11451
    for (i = 0; i < cnt; i++) {
        /* Cast away const */
        chr = (virDomainChrDefPtr) arrPtr[i];
11452 11453 11454 11455 11456 11457
        if (virDomainChrEquals(chr, target))
            return chr;
    }
    return NULL;
}

11458 11459 11460 11461 11462

/* Return the address within vmdef to be modified when working with a
 * chrdefptr of the given type.  */
static void
virDomainChrGetDomainPtrsInternal(virDomainDefPtr vmdef,
11463
                                  virDomainChrDeviceType type,
11464 11465
                                  virDomainChrDefPtr ***arrPtr,
                                  size_t **cntPtr)
11466
{
11467
    switch (type) {
11468 11469 11470 11471 11472 11473 11474 11475 11476 11477 11478 11479 11480 11481 11482 11483 11484 11485 11486 11487 11488
    case VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL:
        *arrPtr = &vmdef->parallels;
        *cntPtr = &vmdef->nparallels;
        break;

    case VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL:
        *arrPtr = &vmdef->serials;
        *cntPtr = &vmdef->nserials;
        break;

    case VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE:
        *arrPtr = &vmdef->consoles;
        *cntPtr = &vmdef->nconsoles;
        break;

    case VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL:
        *arrPtr = &vmdef->channels;
        *cntPtr = &vmdef->nchannels;
        break;

    case VIR_DOMAIN_CHR_DEVICE_TYPE_LAST:
11489 11490
        *arrPtr = NULL;
        *cntPtr = NULL;
11491 11492 11493 11494
        break;
    }
}

11495

11496 11497 11498 11499
/* Return the array within vmdef that can contain a chrdefptr of the
 * given type.  */
void
virDomainChrGetDomainPtrs(const virDomainDef *vmdef,
11500
                          virDomainChrDeviceType type,
11501 11502 11503
                          const virDomainChrDef ***arrPtr,
                          size_t *cntPtr)
{
11504 11505
    virDomainChrDef ***arrVar = NULL;
    size_t *cntVar = NULL;
11506 11507 11508 11509 11510 11511 11512 11513 11514 11515 11516 11517 11518

    /* Cast away const; we add it back in the final assignment.  */
    virDomainChrGetDomainPtrsInternal((virDomainDefPtr) vmdef, type,
                                      &arrVar, &cntVar);
    if (arrVar) {
        *arrPtr = (const virDomainChrDef **) *arrVar;
        *cntPtr = *cntVar;
    } else {
        *arrPtr = NULL;
        *cntPtr = 0;
    }
}

11519

11520 11521 11522 11523
int
virDomainChrInsert(virDomainDefPtr vmdef,
                   virDomainChrDefPtr chr)
{
11524 11525
    virDomainChrDefPtr **arrPtr = NULL;
    size_t *cntPtr = NULL;
11526

11527
    virDomainChrGetDomainPtrsInternal(vmdef, chr->deviceType, &arrPtr, &cntPtr);
11528 11529 11530 11531 11532 11533 11534 11535

    return VIR_APPEND_ELEMENT(*arrPtr, *cntPtr, chr);
}

virDomainChrDefPtr
virDomainChrRemove(virDomainDefPtr vmdef,
                   virDomainChrDefPtr chr)
{
11536 11537
    virDomainChrDefPtr ret, **arrPtr = NULL;
    size_t i, *cntPtr = NULL;
11538

11539
    virDomainChrGetDomainPtrsInternal(vmdef, chr->deviceType, &arrPtr, &cntPtr);
11540 11541 11542 11543 11544 11545 11546 11547 11548 11549 11550 11551 11552 11553

    for (i = 0; i < *cntPtr; i++) {
        ret = (*arrPtr)[i];

        if (virDomainChrEquals(ret, chr))
            break;
    }

    if (i == *cntPtr)
        return NULL;

    VIR_DELETE_ELEMENT(*arrPtr, i, *cntPtr);
    return ret;
}
11554

11555 11556 11557 11558
char *
virDomainDefGetDefaultEmulator(virDomainDefPtr def,
                               virCapsPtr caps)
{
11559 11560 11561 11562 11563 11564
    const char *type;
    const char *emulator;
    char *retemu;

    type = virDomainVirtTypeToString(def->virtType);
    if (!type) {
11565 11566
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("unknown virt type"));
11567 11568 11569 11570 11571 11572 11573 11574 11575
        return NULL;
    }

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

    if (!emulator) {
11576
        virReportError(VIR_ERR_INTERNAL_ERROR,
11577 11578
                       _("no emulator for domain %s os type %s "
                         "on architecture %s"),
11579
                       type, def->os.type, virArchToString(def->os.arch));
11580 11581 11582
        return NULL;
    }

11583
    ignore_value(VIR_STRDUP(retemu, emulator));
11584 11585 11586
    return retemu;
}

11587 11588
static int
virDomainDefParseBootXML(xmlXPathContextPtr ctxt,
11589
                         virDomainDefPtr def)
11590 11591
{
    xmlNodePtr *nodes = NULL;
11592 11593
    size_t i;
    int n;
M
Martin Kletzander 已提交
11594
    char *tmp = NULL;
11595
    int ret = -1;
M
Michal Privoznik 已提交
11596
    unsigned long deviceBoot, serialPorts;
11597 11598

    if (virXPathULong("count(./devices/disk[boot]"
11599
                      "|./devices/interface[boot]"
11600 11601
                      "|./devices/hostdev[boot]"
                      "|./devices/redirdev[boot])", ctxt, &deviceBoot) < 0) {
11602 11603
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("cannot count boot devices"));
11604 11605
        goto cleanup;
    }
11606 11607 11608 11609 11610 11611

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

11612
    if (n > 0 && deviceBoot) {
11613 11614 11615
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("per-device boot elements cannot be used"
                         " together with os/boot elements"));
11616 11617 11618
        goto cleanup;
    }

11619
    for (i = 0; i < n && i < VIR_DOMAIN_BOOT_LAST; i++) {
11620 11621 11622
        int val;
        char *dev = virXMLPropString(nodes[i], "dev");
        if (!dev) {
11623 11624
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("missing boot device"));
11625 11626 11627
            goto cleanup;
        }
        if ((val = virDomainBootTypeFromString(dev)) < 0) {
11628
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
11629 11630
                           _("unknown boot device '%s'"),
                           dev);
11631 11632 11633 11634 11635 11636
            VIR_FREE(dev);
            goto cleanup;
        }
        VIR_FREE(dev);
        def->os.bootDevs[def->os.nBootDevs++] = val;
    }
11637
    if (def->os.nBootDevs == 0 && !deviceBoot) {
11638 11639 11640 11641
        def->os.nBootDevs = 1;
        def->os.bootDevs[0] = VIR_DOMAIN_BOOT_DISK;
    }

M
Martin Kletzander 已提交
11642 11643
    tmp = virXPathString("string(./os/bootmenu[1]/@enable)", ctxt);
    if (tmp) {
J
Ján Tomko 已提交
11644
        def->os.bootmenu = virTristateBoolTypeFromString(tmp);
11645 11646 11647 11648 11649
        if (def->os.bootmenu <= 0) {
            /* In order not to break misconfigured machines, this
             * should not emit an error, but rather set the bootmenu
             * to disabled */
            VIR_WARN("disabling bootmenu due to unknown option '%s'",
M
Martin Kletzander 已提交
11650
                     tmp);
J
Ján Tomko 已提交
11651
            def->os.bootmenu = VIR_TRISTATE_BOOL_NO;
11652
        }
M
Martin Kletzander 已提交
11653
        VIR_FREE(tmp);
11654 11655
    }

11656 11657 11658 11659 11660 11661 11662 11663 11664 11665 11666 11667 11668
    tmp = virXPathString("string(./os/bootmenu[1]/@timeout)", ctxt);
    if (tmp && def->os.bootmenu == VIR_TRISTATE_BOOL_YES) {
        if (virStrToLong_uip(tmp, NULL, 0, &def->os.bm_timeout) < 0 ||
            def->os.bm_timeout > 65535) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("invalid value for boot menu timeout, "
                             "must be in range [0,65535]"));
            goto cleanup;
        }
        def->os.bm_timeout_set = true;
    }
    VIR_FREE(tmp);

M
Martin Kletzander 已提交
11669 11670 11671
    tmp = virXPathString("string(./os/bios[1]/@useserial)", ctxt);
    if (tmp) {
        if (STREQ(tmp, "yes")) {
M
Michal Privoznik 已提交
11672 11673
            if (virXPathULong("count(./devices/serial)",
                              ctxt, &serialPorts) < 0) {
11674 11675 11676
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                               _("need at least one serial port "
                                 "for useserial"));
M
Michal Privoznik 已提交
11677 11678
                goto cleanup;
            }
J
Ján Tomko 已提交
11679
            def->os.bios.useserial = VIR_TRISTATE_BOOL_YES;
M
Michal Privoznik 已提交
11680
        } else {
J
Ján Tomko 已提交
11681
            def->os.bios.useserial = VIR_TRISTATE_BOOL_NO;
M
Michal Privoznik 已提交
11682
        }
M
Martin Kletzander 已提交
11683
        VIR_FREE(tmp);
M
Michal Privoznik 已提交
11684 11685
    }

11686 11687 11688 11689 11690 11691 11692 11693 11694 11695 11696 11697 11698 11699
    tmp = virXPathString("string(./os/bios[1]/@rebootTimeout)", ctxt);
    if (tmp) {
        /* that was really just for the check if it is there */

        if (virStrToLong_i(tmp, NULL, 0, &def->os.bios.rt_delay) < 0 ||
            def->os.bios.rt_delay < -1 || def->os.bios.rt_delay > 65535) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("invalid value for rebootTimeout, "
                             "must be in range [-1,65535]"));
            goto cleanup;
        }
        def->os.bios.rt_set = true;
    }

11700 11701
    ret = 0;

11702
 cleanup:
11703
    VIR_FREE(tmp);
11704 11705 11706 11707
    VIR_FREE(nodes);
    return ret;
}

11708

G
Gao feng 已提交
11709 11710
static int virDomainIdMapEntrySort(const void *a, const void *b)
{
11711 11712
    const virDomainIdMapEntry *entrya = a;
    const virDomainIdMapEntry *entryb = b;
G
Gao feng 已提交
11713 11714 11715 11716 11717 11718 11719 11720 11721

    if (entrya->start > entryb->start)
        return 1;
    else if (entrya->start < entryb->start)
        return -1;
    else
        return 0;
}

11722 11723 11724 11725 11726 11727 11728 11729 11730
/* Parse the XML definition for user namespace id map.
 *
 * idmap has the form of
 *
 *   <uid start='0' target='1000' count='10'/>
 *   <gid start='0' target='1000' count='10'/>
 */
static virDomainIdMapEntryPtr
virDomainIdmapDefParseXML(xmlXPathContextPtr ctxt,
11731
                          xmlNodePtr *node,
11732 11733 11734 11735 11736 11737
                          size_t num)
{
    size_t i;
    virDomainIdMapEntryPtr idmap = NULL;
    xmlNodePtr save_ctxt = ctxt->node;

11738
    if (VIR_ALLOC_N(idmap, num) < 0)
11739 11740 11741 11742 11743 11744 11745
        goto cleanup;

    for (i = 0; i < num; i++) {
        ctxt->node = node[i];
        if (virXPathUInt("string(./@start)", ctxt, &idmap[i].start) < 0 ||
            virXPathUInt("string(./@target)", ctxt, &idmap[i].target) < 0 ||
            virXPathUInt("string(./@count)", ctxt, &idmap[i].count) < 0) {
11746 11747
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("invalid idmap start/target/count settings"));
11748 11749 11750 11751 11752
            VIR_FREE(idmap);
            goto cleanup;
        }
    }

G
Gao feng 已提交
11753 11754 11755 11756 11757 11758 11759 11760 11761 11762 11763
    qsort(idmap, num, sizeof(idmap[0]), virDomainIdMapEntrySort);

    if (idmap[0].start != 0) {
        /* Root user of container hasn't been mapped to any user of host,
         * return error. */
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("You must map the root user of container"));
        VIR_FREE(idmap);
        goto cleanup;
    }

11764
 cleanup:
11765 11766 11767 11768
    ctxt->node = save_ctxt;
    return idmap;
}

H
Hu Tao 已提交
11769 11770 11771 11772 11773 11774 11775 11776 11777 11778 11779 11780
static virDomainPanicDefPtr
virDomainPanicDefParseXML(xmlNodePtr node)
{
    virDomainPanicDefPtr panic;

    if (VIR_ALLOC(panic) < 0)
        return NULL;

    if (virDomainDeviceInfoParseXML(node, NULL, &panic->info, 0) < 0)
        goto error;

    return panic;
11781
 error:
H
Hu Tao 已提交
11782 11783 11784
    virDomainPanicDefFree(panic);
    return NULL;
}
11785

11786 11787 11788 11789 11790 11791 11792 11793
/* Parse the XML definition for a vcpupin or emulatorpin.
 *
 * vcpupin has the form of
 *   <vcpupin vcpu='0' cpuset='0'/>
 *
 * and emulatorpin has the form of
 *   <emulatorpin cpuset='0'/>
 *
11794 11795 11796
 * and an iothreadspin has the form
 *   <iothreadpin iothread='1' cpuset='2'/>
 *
11797 11798 11799
 * A vcpuid of -1 is valid and only valid for emulatorpin. So callers
 * have to check the returned cpuid for validity.
 */
E
Eric Blake 已提交
11800
static virDomainVcpuPinDefPtr
11801
virDomainVcpuPinDefParseXML(xmlNodePtr node,
11802
                            xmlXPathContextPtr ctxt,
11803
                            int maxvcpus,
11804 11805
                            bool emulator,
                            bool iothreads)
11806
{
E
Eric Blake 已提交
11807
    virDomainVcpuPinDefPtr def;
11808
    xmlNodePtr oldnode = ctxt->node;
11809
    int vcpuid = -1;
11810
    unsigned int iothreadid;
11811 11812 11813
    char *tmp = NULL;
    int ret;

11814
    if (VIR_ALLOC(def) < 0)
11815 11816 11817 11818
        return NULL;

    ctxt->node = node;

11819
    if (!emulator && !iothreads) {
11820 11821
        ret = virXPathInt("string(./@vcpu)", ctxt, &vcpuid);
        if ((ret == -2) || (vcpuid < -1)) {
11822 11823
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("vcpu id must be an unsigned integer or -1"));
11824 11825
            goto error;
        } else if (vcpuid == -1) {
11826 11827
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("vcpu id value -1 is not allowed for vcpupin"));
11828 11829
            goto error;
        }
11830

11831 11832 11833 11834 11835
        if (vcpuid >= maxvcpus) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("vcpu id must be less than maxvcpus"));
            goto error;
        }
11836

11837 11838
        def->vcpuid = vcpuid;
    }
11839

11840 11841 11842 11843 11844 11845 11846 11847 11848 11849 11850 11851 11852 11853 11854 11855 11856 11857 11858 11859 11860 11861 11862 11863 11864 11865 11866 11867
    if (iothreads && (tmp = virXPathString("string(./@iothread)", ctxt))) {
        if (virStrToLong_uip(tmp, NULL, 10, &iothreadid) < 0) {
            virReportError(VIR_ERR_XML_ERROR,
                           _("invalid setting for iothread '%s'"), tmp);
            goto error;
        }
        VIR_FREE(tmp);

        if (iothreadid == 0) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("zero is an invalid iothread id value"));
            goto error;
        }

        /* NB: maxvcpus is actually def->iothreads
         * IOThreads are numbered "iothread1...iothread<n>", where
         * "n" is the iothreads value
         */
        if (iothreadid > maxvcpus) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("iothread id must not exceed iothreads"));
            goto error;
        }

        /* Rather than creating our own structure we are reusing the vCPU */
        def->vcpuid = iothreadid;
    }

11868 11869 11870 11871
    if (!(tmp = virXMLPropString(node, "cpuset"))) {
        if (emulator)
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("missing cpuset for emulatorpin"));
11872 11873 11874
        else if (iothreads)
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("missing cpuset for iothreadpin"));
11875 11876 11877
        else
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("missing cpuset for vcpupin"));
11878 11879 11880 11881

        goto error;
    }

11882 11883 11884
    if (virBitmapParse(tmp, 0, &def->cpumask, VIR_DOMAIN_CPUMASK_LEN) < 0)
        goto error;

11885
 cleanup:
11886
    VIR_FREE(tmp);
11887 11888 11889
    ctxt->node = oldnode;
    return def;

11890
 error:
11891 11892 11893 11894
    VIR_FREE(def);
    goto cleanup;
}

11895

11896
int
11897 11898 11899 11900
virDomainDefMaybeAddController(virDomainDefPtr def,
                               int type,
                               int idx,
                               int model)
11901
{
11902
    size_t i;
11903 11904
    virDomainControllerDefPtr cont;

11905
    for (i = 0; i < def->ncontrollers; i++) {
11906 11907
        if (def->controllers[i]->type == type &&
            def->controllers[i]->idx == idx)
11908
            return 0;
11909 11910
    }

11911
    if (VIR_ALLOC(cont) < 0)
11912 11913 11914 11915
        return -1;

    cont->type = type;
    cont->idx = idx;
11916
    cont->model = model;
11917 11918 11919 11920 11921 11922

    if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL) {
        cont->opts.vioserial.ports = -1;
        cont->opts.vioserial.vectors = -1;
    }

11923
    if (VIR_APPEND_ELEMENT(def->controllers, def->ncontrollers, cont) < 0) {
11924 11925 11926 11927 11928 11929 11930
        VIR_FREE(cont);
        return -1;
    }

    return 0;
}

E
Eric Blake 已提交
11931

11932 11933 11934 11935 11936 11937 11938 11939 11940 11941 11942 11943 11944 11945 11946 11947 11948 11949 11950 11951 11952 11953 11954 11955 11956 11957 11958 11959 11960
int
virDomainDefMaybeAddInput(virDomainDefPtr def,
                          int type,
                          int bus)
{
    size_t i;
    virDomainInputDefPtr input;

    for (i = 0; i < def->ninputs; i++) {
        if (def->inputs[i]->type == type &&
            def->inputs[i]->bus == bus)
            return 0;
    }

    if (VIR_ALLOC(input) < 0)
        return -1;

    input->type = type;
    input->bus = bus;

    if (VIR_APPEND_ELEMENT(def->inputs, def->ninputs, input) < 0) {
        VIR_FREE(input);
        return -1;
    }

    return 0;
}


11961 11962 11963 11964 11965 11966 11967 11968 11969 11970 11971 11972 11973 11974 11975 11976 11977 11978 11979 11980 11981 11982 11983 11984 11985 11986 11987 11988 11989 11990 11991 11992 11993 11994 11995 11996 11997 11998 11999 12000 12001 12002 12003 12004 12005 12006 12007 12008 12009 12010 12011
static int
virDomainHugepagesParseXML(xmlNodePtr node,
                           xmlXPathContextPtr ctxt,
                           virDomainHugePagePtr hugepage)
{
    int ret = -1;
    xmlNodePtr oldnode = ctxt->node;
    unsigned long long bytes, max;
    char *unit = NULL, *nodeset = NULL;

    ctxt->node = node;

    /* On 32-bit machines, our bound is 0xffffffff * KiB. On 64-bit
     * machines, our bound is off_t (2^63).  */
    if (sizeof(unsigned long) < sizeof(long long))
        max = 1024ull * ULONG_MAX;
    else
        max = LLONG_MAX;

    if (virXPathULongLong("string(./@size)", ctxt, &bytes) < 0) {
        virReportError(VIR_ERR_XML_DETAIL, "%s",
                       _("unable to parse size attribute"));
        goto cleanup;
    }

    unit = virXPathString("string(./@unit)", ctxt);

    if (virScaleInteger(&bytes, unit, 1024, max) < 0)
        goto cleanup;

    if (!(hugepage->size = VIR_DIV_UP(bytes, 1024))) {
        virReportError(VIR_ERR_XML_DETAIL, "%s",
                       _("hugepage size can't be zero"));
        goto cleanup;
    }

    if ((nodeset = virXMLPropString(node, "nodeset"))) {
        if (virBitmapParse(nodeset, 0, &hugepage->nodemask,
                           VIR_DOMAIN_CPUMASK_LEN) < 0)
            goto cleanup;
    }

    ret = 0;
 cleanup:
    VIR_FREE(unit);
    VIR_FREE(nodeset);
    ctxt->node = oldnode;
    return ret;
}


12012 12013 12014 12015 12016 12017 12018 12019 12020
static virDomainResourceDefPtr
virDomainResourceDefParse(xmlNodePtr node,
                          xmlXPathContextPtr ctxt)
{
    virDomainResourceDefPtr def = NULL;
    xmlNodePtr tmp = ctxt->node;

    ctxt->node = node;

12021
    if (VIR_ALLOC(def) < 0)
12022 12023 12024 12025 12026 12027 12028 12029 12030 12031 12032 12033
        goto error;

    /* Find out what type of virtualization to use */
    if (!(def->partition = virXPathString("string(./partition)", ctxt))) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing resource partition attribute"));
        goto error;
    }

    ctxt->node = tmp;
    return def;

12034
 error:
12035 12036 12037 12038 12039
    ctxt->node = tmp;
    virDomainResourceDefFree(def);
    return NULL;
}

12040 12041 12042 12043
static int
virDomainDefMaybeAddHostdevSCSIcontroller(virDomainDefPtr def)
{
    /* Look for any hostdev scsi dev */
12044
    size_t i;
12045 12046 12047 12048 12049 12050 12051 12052 12053 12054 12055 12056
    int maxController = -1;
    virDomainHostdevDefPtr hostdev;

    for (i = 0; i < def->nhostdevs; i++) {
        hostdev = def->hostdevs[i];
        if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
            hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI &&
            (int)hostdev->info->addr.drive.controller > maxController) {
            maxController = hostdev->info->addr.drive.controller;
        }
    }

12057 12058 12059
    if (maxController == -1)
        return 0;

12060 12061 12062 12063 12064 12065 12066
    for (i = 0; i <= maxController; i++) {
        if (virDomainDefMaybeAddController(def, VIR_DOMAIN_CONTROLLER_TYPE_SCSI, i, -1) < 0)
            return -1;
    }

    return 0;
}
12067

12068 12069 12070 12071 12072 12073 12074 12075 12076 12077 12078 12079 12080 12081 12082 12083 12084 12085 12086 12087 12088 12089 12090 12091 12092 12093 12094 12095 12096 12097 12098 12099 12100 12101 12102 12103
static int
virDomainLoaderDefParseXML(xmlNodePtr node,
                           virDomainLoaderDefPtr loader)
{
    int ret = -1;
    char *readonly_str = NULL;
    char *type_str = NULL;

    readonly_str = virXMLPropString(node, "readonly");
    type_str = virXMLPropString(node, "type");
    loader->path = (char *) xmlNodeGetContent(node);

    if (readonly_str &&
        (loader->readonly = virTristateBoolTypeFromString(readonly_str)) <= 0) {
        virReportError(VIR_ERR_XML_DETAIL,
                       _("unknown readonly value: %s"), readonly_str);
        goto cleanup;
    }

    if (type_str) {
        int type;
        if ((type = virDomainLoaderTypeFromString(type_str)) < 0) {
            virReportError(VIR_ERR_XML_DETAIL,
                           _("unknown type value: %s"), type_str);
            goto cleanup;
        }
        loader->type = type;
    }

    ret = 0;
 cleanup:
    VIR_FREE(readonly_str);
    VIR_FREE(type_str);
    return ret;
}

12104
static virDomainDefPtr
12105
virDomainDefParseXML(xmlDocPtr xml,
12106 12107
                     xmlNodePtr root,
                     xmlXPathContextPtr ctxt,
12108 12109
                     virCapsPtr caps,
                     virDomainXMLOptionPtr xmlopt,
12110 12111
                     unsigned int expectedVirtTypes,
                     unsigned int flags)
12112 12113 12114
{
    xmlNodePtr *nodes = NULL, node = NULL;
    char *tmp = NULL;
12115
    size_t i, j;
12116
    int n;
12117
    long id = -1;
12118
    virDomainDefPtr def;
E
Eric Blake 已提交
12119
    unsigned long count;
12120
    bool uuid_generated = false;
12121
    virHashTablePtr bootHash = NULL;
12122 12123
    bool usb_none = false;
    bool usb_other = false;
12124
    bool usb_master = false;
12125
    bool primaryVideo = false;
12126

12127
    if (VIR_ALLOC(def) < 0)
12128
        return NULL;
12129 12130

    if (!(flags & VIR_DOMAIN_XML_INACTIVE))
E
Eric Blake 已提交
12131
        if (virXPathLong("string(./@id)", ctxt, &id) < 0)
12132 12133
            id = -1;
    def->id = (int)id;
12134

12135
    /* Find out what type of virtualization to use */
12136
    if (!(tmp = virXPathString("string(./@type)", ctxt))) {
12137 12138
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing domain type attribute"));
12139 12140 12141 12142
        goto error;
    }

    if ((def->virtType = virDomainVirtTypeFromString(tmp)) < 0) {
12143
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
12144
                       _("invalid domain type %s"), tmp);
12145 12146 12147 12148
        goto error;
    }
    VIR_FREE(tmp);

M
Matthias Bolte 已提交
12149 12150
    if ((expectedVirtTypes & (1 << def->virtType)) == 0) {
        if (count_one_bits(expectedVirtTypes) == 1) {
12151 12152 12153 12154
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected domain type %s, expecting %s"),
                           virDomainVirtTypeToString(def->virtType),
                           virDomainVirtTypeToString(ffs(expectedVirtTypes) - 1));
M
Matthias Bolte 已提交
12155 12156 12157 12158 12159 12160 12161 12162 12163 12164 12165 12166 12167
        } else {
            virBuffer buffer = VIR_BUFFER_INITIALIZER;
            char *string;

            for (i = 0; i < VIR_DOMAIN_VIRT_LAST; ++i) {
                if ((expectedVirtTypes & (1 << i)) != 0) {
                    if (virBufferUse(&buffer) > 0)
                        virBufferAddLit(&buffer, ", ");

                    virBufferAdd(&buffer, virDomainVirtTypeToString(i), -1);
                }
            }

12168
            if (virBufferCheckError(&buffer) < 0)
M
Matthias Bolte 已提交
12169 12170 12171 12172
                goto error;

            string = virBufferContentAndReset(&buffer);

12173 12174 12175 12176 12177
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected domain type %s, "
                             "expecting one of these: %s"),
                           virDomainVirtTypeToString(def->virtType),
                           string);
M
Matthias Bolte 已提交
12178 12179 12180 12181 12182 12183 12184

            VIR_FREE(string);
        }

        goto error;
    }

12185
    /* Extract domain name */
12186
    if (!(def->name = virXPathString("string(./name[1])", ctxt))) {
12187
        virReportError(VIR_ERR_NO_NAME, NULL);
12188 12189 12190
        goto error;
    }

12191 12192 12193
    /* 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. */
12194
    tmp = virXPathString("string(./uuid[1])", ctxt);
12195
    if (!tmp) {
12196
        if (virUUIDGenerate(def->uuid)) {
12197 12198
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("Failed to generate UUID"));
12199 12200
            goto error;
        }
12201
        uuid_generated = true;
12202 12203
    } else {
        if (virUUIDParse(tmp, def->uuid) < 0) {
12204 12205
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("malformed uuid element"));
12206 12207 12208 12209 12210
            goto error;
        }
        VIR_FREE(tmp);
    }

12211 12212 12213
    /* Extract short description of domain (title) */
    def->title = virXPathString("string(./title[1])", ctxt);
    if (def->title && strchr(def->title, '\n')) {
12214 12215
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Domain title can't contain newlines"));
12216 12217 12218
        goto error;
    }

12219
    /* Extract documentation if present */
12220
    def->description = virXPathString("string(./description[1])", ctxt);
12221

E
Eric Blake 已提交
12222 12223
    /* analysis of security label, done early even though we format it
     * late, so devices can refer to this for defaults */
12224
    if (virSecurityLabelDefsParseXML(def, ctxt, caps, flags) == -1)
E
Eric Blake 已提交
12225 12226
        goto error;

12227
    /* Extract domain memory */
E
Eric Blake 已提交
12228
    if (virDomainParseMemory("./memory[1]", ctxt,
12229
                             &def->mem.max_balloon, true, true) < 0)
12230 12231
        goto error;

E
Eric Blake 已提交
12232
    if (virDomainParseMemory("./currentMemory[1]", ctxt,
12233
                             &def->mem.cur_balloon, false, true) < 0)
E
Eric Blake 已提交
12234
        goto error;
12235

12236
    /* and info about it */
12237
    if ((tmp = virXPathString("string(./memory[1]/@dumpCore)", ctxt)) &&
J
Ján Tomko 已提交
12238
        (def->mem.dump_core = virTristateSwitchTypeFromString(tmp)) <= 0) {
12239
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
12240 12241
                       _("Invalid memory core dump attribute value '%s'"), tmp);
        goto error;
12242
    }
12243
    VIR_FREE(tmp);
12244

12245
    if (def->mem.cur_balloon > def->mem.max_balloon) {
12246
        /* Older libvirt could get into this situation due to
12247
         * rounding; if the discrepancy is less than 4MiB, we silently
12248
         * round down, otherwise we flag the issue.  */
12249 12250
        if (VIR_DIV_UP(def->mem.cur_balloon, 4096) >
            VIR_DIV_UP(def->mem.max_balloon, 4096)) {
12251 12252 12253 12254
            virReportError(VIR_ERR_XML_ERROR,
                           _("current memory '%lluk' exceeds "
                             "maximum '%lluk'"),
                           def->mem.cur_balloon, def->mem.max_balloon);
12255 12256 12257 12258 12259 12260
            goto error;
        } else {
            VIR_DEBUG("Truncating current %lluk to maximum %lluk",
                      def->mem.cur_balloon, def->mem.max_balloon);
            def->mem.cur_balloon = def->mem.max_balloon;
        }
E
Eric Blake 已提交
12261 12262
    } else if (def->mem.cur_balloon == 0) {
        def->mem.cur_balloon = def->mem.max_balloon;
12263 12264
    }

12265 12266 12267 12268 12269 12270 12271 12272 12273 12274 12275 12276 12277 12278 12279 12280 12281 12282 12283 12284 12285 12286 12287 12288 12289 12290 12291 12292 12293 12294 12295 12296 12297 12298 12299 12300 12301 12302 12303 12304 12305 12306 12307 12308 12309 12310 12311 12312 12313

    if ((n = virXPathNodeSet("./memoryBacking/hugepages/page", ctxt, &nodes)) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("cannot extract hugepages nodes"));
        goto error;
    }

    if (n) {
        if (VIR_ALLOC_N(def->mem.hugepages, n) < 0)
            goto error;

        for (i = 0; i < n; i++) {
            if (virDomainHugepagesParseXML(nodes[i], ctxt,
                                           &def->mem.hugepages[i]) < 0)
                goto error;
            def->mem.nhugepages++;

            for (j = 0; j < i; j++) {
                if (def->mem.hugepages[i].nodemask &&
                    def->mem.hugepages[j].nodemask &&
                    virBitmapOverlaps(def->mem.hugepages[i].nodemask,
                                      def->mem.hugepages[j].nodemask)) {
                    virReportError(VIR_ERR_XML_DETAIL,
                                   _("nodeset attribute of hugepages "
                                     "of sizes %llu and %llu intersect"),
                                   def->mem.hugepages[i].size,
                                   def->mem.hugepages[j].size);
                    goto error;
                } else if (!def->mem.hugepages[i].nodemask &&
                           !def->mem.hugepages[j].nodemask) {
                    virReportError(VIR_ERR_XML_DETAIL,
                                   _("two master hugepages detected: "
                                     "%llu and %llu"),
                                   def->mem.hugepages[i].size,
                                   def->mem.hugepages[j].size);
                    goto error;
                }
            }
        }

        VIR_FREE(nodes);
    } else {
        if ((node = virXPathNode("./memoryBacking/hugepages", ctxt))) {
            if (VIR_ALLOC(def->mem.hugepages) < 0)
                goto error;

            def->mem.nhugepages = 1;
        }
    }
12314

12315 12316 12317
    if ((node = virXPathNode("./memoryBacking/nosharepages", ctxt)))
        def->mem.nosharepages = true;

12318 12319 12320
    if (virXPathBoolean("boolean(./memoryBacking/locked)", ctxt))
        def->mem.locked = true;

12321 12322 12323 12324 12325
    /* Extract blkio cgroup tunables */
    if (virXPathUInt("string(./blkiotune/weight)", ctxt,
                     &def->blkio.weight) < 0)
        def->blkio.weight = 0;

12326
    if ((n = virXPathNodeSet("./blkiotune/device", ctxt, &nodes)) < 0) {
12327 12328
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("cannot extract blkiotune nodes"));
12329 12330 12331
        goto error;
    }
    if (n && VIR_ALLOC_N(def->blkio.devices, n) < 0)
12332
        goto error;
12333 12334

    for (i = 0; i < n; i++) {
12335 12336
        if (virDomainBlkioDeviceParseXML(nodes[i],
                                         &def->blkio.devices[i]) < 0)
12337 12338
            goto error;
        def->blkio.ndevices++;
12339 12340 12341
        for (j = 0; j < i; j++) {
            if (STREQ(def->blkio.devices[j].path,
                      def->blkio.devices[i].path)) {
12342
                virReportError(VIR_ERR_XML_ERROR,
12343
                               _("duplicate blkio device path '%s'"),
12344
                               def->blkio.devices[i].path);
12345 12346 12347
                goto error;
            }
        }
12348 12349 12350
    }
    VIR_FREE(nodes);

12351
    /* Extract other memory tunables */
E
Eric Blake 已提交
12352
    if (virDomainParseMemory("./memtune/hard_limit[1]", ctxt,
12353
                             &def->mem.hard_limit, false, false) < 0)
E
Eric Blake 已提交
12354
        goto error;
12355

E
Eric Blake 已提交
12356
    if (virDomainParseMemory("./memtune/soft_limit[1]", ctxt,
12357
                             &def->mem.soft_limit, false, false) < 0)
E
Eric Blake 已提交
12358
        goto error;
12359

E
Eric Blake 已提交
12360
    if (virDomainParseMemory("./memtune/min_guarantee[1]", ctxt,
12361
                             &def->mem.min_guarantee, false, false) < 0)
E
Eric Blake 已提交
12362
        goto error;
12363

E
Eric Blake 已提交
12364
    if (virDomainParseMemory("./memtune/swap_hard_limit[1]", ctxt,
12365
                             &def->mem.swap_hard_limit, false, false) < 0)
E
Eric Blake 已提交
12366
        goto error;
12367

E
Eric Blake 已提交
12368 12369
    n = virXPathULong("string(./vcpu[1])", ctxt, &count);
    if (n == -2) {
12370 12371
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("maximum vcpus must be an integer"));
E
Eric Blake 已提交
12372 12373 12374 12375 12376
        goto error;
    } else if (n < 0) {
        def->maxvcpus = 1;
    } else {
        def->maxvcpus = count;
12377
        if (count == 0 || (unsigned short) count != count) {
12378
            virReportError(VIR_ERR_XML_ERROR,
12379
                           _("invalid maximum number of vCPUs '%lu'"), count);
E
Eric Blake 已提交
12380 12381 12382 12383 12384 12385
            goto error;
        }
    }

    n = virXPathULong("string(./vcpu[1]/@current)", ctxt, &count);
    if (n == -2) {
12386 12387
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("current vcpus must be an integer"));
E
Eric Blake 已提交
12388 12389 12390 12391 12392
        goto error;
    } else if (n < 0) {
        def->vcpus = def->maxvcpus;
    } else {
        def->vcpus = count;
12393
        if (count == 0 || (unsigned short) count != count) {
12394
            virReportError(VIR_ERR_XML_ERROR,
12395
                           _("invalid current number of vCPUs '%lu'"), count);
E
Eric Blake 已提交
12396 12397
            goto error;
        }
12398 12399

        if (def->maxvcpus < count) {
12400
            virReportError(VIR_ERR_INTERNAL_ERROR,
12401 12402
                           _("maxvcpus must not be less than current vcpus "
                             "(%d < %lu)"),
12403
                           def->maxvcpus, count);
12404 12405
            goto error;
        }
E
Eric Blake 已提交
12406
    }
12407

O
Osier Yang 已提交
12408 12409 12410 12411
    tmp = virXPathString("string(./vcpu[1]/@placement)", ctxt);
    if (tmp) {
        if ((def->placement_mode =
             virDomainCpuPlacementModeTypeFromString(tmp)) < 0) {
12412
             virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
12413 12414
                            _("Unsupported CPU placement mode '%s'"),
                            tmp);
O
Osier Yang 已提交
12415 12416 12417 12418
             goto error;
        }
        VIR_FREE(tmp);
    } else {
12419
        def->placement_mode = VIR_DOMAIN_CPU_PLACEMENT_MODE_STATIC;
O
Osier Yang 已提交
12420 12421
    }

12422
    if (def->placement_mode != VIR_DOMAIN_CPU_PLACEMENT_MODE_AUTO) {
12423 12424
        tmp = virXPathString("string(./vcpu[1]/@cpuset)", ctxt);
        if (tmp) {
H
Hu Tao 已提交
12425
            if (virBitmapParse(tmp, 0, &def->cpumask,
12426
                               VIR_DOMAIN_CPUMASK_LEN) < 0)
12427
                goto error;
12428
            VIR_FREE(tmp);
12429 12430 12431
        }
    }

12432 12433 12434 12435 12436 12437 12438 12439 12440
    /* Optional - iothreads */
    tmp = virXPathString("string(./iothreads[1])", ctxt);
    if (tmp && virStrToLong_uip(tmp, NULL, 10, &def->iothreads) < 0) {
        virReportError(VIR_ERR_XML_ERROR,
                       _("invalid iothreads count '%s'"), tmp);
        goto error;
    }
    VIR_FREE(tmp);

12441
    /* Extract cpu tunables. */
12442 12443
    if ((n = virXPathULong("string(./cputune/shares[1])", ctxt,
                           &def->cputune.shares)) < -1) {
12444 12445 12446
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("can't parse cputune shares value"));
        goto error;
12447 12448
    } else if (n == 0) {
        def->cputune.sharesSpecified = true;
12449
    }
12450

12451
    if (virXPathULongLong("string(./cputune/period[1])", ctxt,
12452 12453 12454 12455 12456
                          &def->cputune.period) < -1) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("can't parse cputune period value"));
        goto error;
    }
12457

12458 12459 12460 12461 12462 12463 12464 12465
    if (def->cputune.period > 0 &&
        (def->cputune.period < 1000 || def->cputune.period > 1000000)) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Value of cputune period must be in range "
                         "[1000, 1000000]"));
        goto error;
    }

12466
    if (virXPathLongLong("string(./cputune/quota[1])", ctxt,
12467 12468 12469 12470 12471
                         &def->cputune.quota) < -1) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("can't parse cputune quota value"));
        goto error;
    }
12472

12473 12474
    if (def->cputune.quota > 0 &&
        (def->cputune.quota < 1000 ||
E
Eric Blake 已提交
12475
         def->cputune.quota > 18446744073709551LL)) {
12476 12477 12478 12479 12480 12481
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Value of cputune quota must be in range "
                         "[1000, 18446744073709551]"));
        goto error;
    }

12482
    if (virXPathULongLong("string(./cputune/emulator_period[1])", ctxt,
12483 12484 12485 12486 12487
                          &def->cputune.emulator_period) < -1) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("can't parse cputune emulator period value"));
        goto error;
    }
12488

12489 12490 12491 12492 12493 12494 12495 12496 12497
    if (def->cputune.emulator_period > 0 &&
        (def->cputune.emulator_period < 1000 ||
         def->cputune.emulator_period > 1000000)) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Value of cputune emulator_period must be in range "
                         "[1000, 1000000]"));
        goto error;
    }

12498
    if (virXPathLongLong("string(./cputune/emulator_quota[1])", ctxt,
12499 12500 12501
                         &def->cputune.emulator_quota) < -1) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("can't parse cputune emulator quota value"));
12502 12503 12504
        goto error;
    }

12505 12506
    if (def->cputune.emulator_quota > 0 &&
        (def->cputune.emulator_quota < 1000 ||
E
Eric Blake 已提交
12507
         def->cputune.emulator_quota > 18446744073709551LL)) {
12508 12509 12510 12511 12512 12513
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Value of cputune emulator_quota must be in range "
                         "[1000, 18446744073709551]"));
        goto error;
    }

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

12517
    if (n && VIR_ALLOC_N(def->cputune.vcpupin, n) < 0)
12518
        goto error;
12519

12520
    for (i = 0; i < n; i++) {
E
Eric Blake 已提交
12521
        virDomainVcpuPinDefPtr vcpupin = NULL;
12522
        vcpupin = virDomainVcpuPinDefParseXML(nodes[i], ctxt,
12523
                                              def->maxvcpus, false, false);
12524 12525 12526 12527

        if (!vcpupin)
            goto error;

E
Eric Blake 已提交
12528
        if (virDomainVcpuPinIsDuplicate(def->cputune.vcpupin,
12529 12530
                                        def->cputune.nvcpupin,
                                        vcpupin->vcpuid)) {
12531 12532
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("duplicate vcpupin for same vcpu"));
12533
            virDomainVcpuPinDefFree(vcpupin);
12534 12535 12536
            goto error;
        }

12537
        if (vcpupin->vcpuid >= def->vcpus) {
12538 12539 12540 12541 12542 12543
            /* To avoid the regression when daemon loading
             * domain confs, we can't simply error out if
             * <vcpupin> nodes greater than current vcpus,
             * ignoring them instead.
             */
            VIR_WARN("Ignore vcpupin for not onlined vcpus");
12544 12545
            virDomainVcpuPinDefFree(vcpupin);
        } else {
12546
            def->cputune.vcpupin[def->cputune.nvcpupin++] = vcpupin;
12547
        }
12548 12549 12550
    }
    VIR_FREE(nodes);

12551 12552 12553 12554
    /* Initialize the pinning policy for vcpus which doesn't has
     * the policy specified explicitly as def->cpuset.
     */
    if (def->cpumask) {
12555
        if (VIR_REALLOC_N(def->cputune.vcpupin, def->vcpus) < 0)
12556
            goto error;
12557 12558

        for (i = 0; i < def->vcpus; i++) {
12559 12560 12561 12562
            if (virDomainVcpuPinIsDuplicate(def->cputune.vcpupin,
                                            def->cputune.nvcpupin,
                                            i))
                continue;
12563

12564
            virDomainVcpuPinDefPtr vcpupin = NULL;
12565

12566
            if (VIR_ALLOC(vcpupin) < 0)
12567 12568
                goto error;

12569 12570
            if (!(vcpupin->cpumask = virBitmapNew(VIR_DOMAIN_CPUMASK_LEN))) {
                VIR_FREE(vcpupin);
12571
                goto error;
12572
            }
12573 12574 12575
            virBitmapCopy(vcpupin->cpumask, def->cpumask);
            vcpupin->vcpuid = i;
            def->cputune.vcpupin[def->cputune.nvcpupin++] = vcpupin;
12576 12577 12578
        }
    }

T
Tang Chen 已提交
12579 12580 12581 12582 12583 12584
    if ((n = virXPathNodeSet("./cputune/emulatorpin", ctxt, &nodes)) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("cannot extract emulatorpin nodes"));
        goto error;
    }

12585 12586 12587 12588
    /* Ignore emulatorpin if <vcpu> placement is "auto", they
     * conflicts with each other, and <vcpu> placement can't be
     * simply ignored, as <numatune>'s placement defaults to it.
     */
T
Tang Chen 已提交
12589
    if (n) {
12590 12591 12592 12593 12594 12595 12596
        if (def->placement_mode != VIR_DOMAIN_CPU_PLACEMENT_MODE_AUTO) {
            if (n > 1) {
                virReportError(VIR_ERR_XML_ERROR, "%s",
                               _("only one emulatorpin is supported"));
                VIR_FREE(nodes);
                goto error;
            }
T
Tang Chen 已提交
12597

12598 12599 12600
            def->cputune.emulatorpin = virDomainVcpuPinDefParseXML(nodes[0],
                                                                   ctxt, 0,
                                                                   true, false);
T
Tang Chen 已提交
12601

12602 12603 12604 12605 12606
            if (!def->cputune.emulatorpin)
                goto error;
        } else {
            VIR_WARN("Ignore emulatorpin for <vcpu> placement is 'auto'");
        }
T
Tang Chen 已提交
12607 12608 12609
    }
    VIR_FREE(nodes);

12610 12611 12612 12613 12614 12615 12616 12617 12618 12619 12620 12621 12622 12623 12624 12625 12626 12627 12628 12629 12630 12631 12632 12633 12634 12635 12636 12637 12638 12639 12640 12641 12642 12643 12644 12645 12646 12647 12648 12649 12650 12651 12652

    if ((n = virXPathNodeSet("./cputune/iothreadpin", ctxt, &nodes)) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("cannot extract iothreadpin nodes"));
        goto error;
    }

    /* Ignore iothreadpin if <vcpu> placement is "auto", they
     * conflict with each other, and <vcpu> placement can't be
     * simply ignored, as <numatune>'s placement defaults to it.
     */
    if (n) {
        if (def->placement_mode != VIR_DOMAIN_CPU_PLACEMENT_MODE_AUTO) {
            if (VIR_ALLOC_N(def->cputune.iothreadspin, n) < 0)
                goto error;

            for (i = 0; i < n; i++) {
                virDomainVcpuPinDefPtr iothreadpin = NULL;
                iothreadpin = virDomainVcpuPinDefParseXML(nodes[i], ctxt,
                                                          def->iothreads,
                                                          false, true);
                if (!iothreadpin)
                    goto error;

                if (virDomainVcpuPinIsDuplicate(def->cputune.iothreadspin,
                                                def->cputune.niothreadspin,
                                                iothreadpin->vcpuid)) {
                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                   _("duplicate iothreadpin for same iothread"));
                    virDomainVcpuPinDefFree(iothreadpin);
                    goto error;
                }

                def->cputune.iothreadspin[def->cputune.niothreadspin++] =
                    iothreadpin;
            }
        } else {
            VIR_WARN("Ignore iothreadpin for <vcpu> placement is 'auto'");
        }
    }
    VIR_FREE(nodes);


M
Martin Kletzander 已提交
12653 12654 12655 12656 12657 12658 12659 12660 12661 12662 12663 12664 12665 12666 12667 12668 12669 12670 12671 12672 12673 12674 12675 12676 12677 12678
    /* analysis of cpu handling */
    if ((node = virXPathNode("./cpu[1]", ctxt)) != NULL) {
        xmlNodePtr oldnode = ctxt->node;
        ctxt->node = node;
        def->cpu = virCPUDefParseXML(node, ctxt, VIR_CPU_TYPE_GUEST);
        ctxt->node = oldnode;

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

        if (def->cpu->sockets &&
            def->maxvcpus >
            def->cpu->sockets * def->cpu->cores * def->cpu->threads) {
            virReportError(VIR_ERR_XML_DETAIL, "%s",
                           _("Maximum CPUs greater than topology limit"));
            goto error;
        }

        if (def->cpu->cells_cpus > def->maxvcpus) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Number of CPUs in <numa> exceeds the"
                             " <vcpu> count"));
            goto error;
        }
    }

12679 12680 12681 12682 12683
    if (virDomainNumatuneParseXML(&def->numatune,
                                  def->placement_mode ==
                                  VIR_DOMAIN_CPU_PLACEMENT_MODE_STATIC,
                                  def->cpu ? def->cpu->ncells : 0,
                                  ctxt) < 0)
12684 12685
        goto error;

12686 12687 12688
    if (virDomainNumatuneHasPlacementAuto(def->numatune) && !def->cpumask)
        def->placement_mode = VIR_DOMAIN_CPU_PLACEMENT_MODE_AUTO;

12689 12690 12691 12692 12693 12694 12695 12696 12697 12698 12699 12700 12701 12702 12703 12704 12705
    if ((n = virXPathNodeSet("./resource", ctxt, &nodes)) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("cannot extract resource nodes"));
        goto error;
    }

    if (n > 1) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("only one resource element is supported"));
        goto error;
    }

    if (n &&
        !(def->resource = virDomainResourceDefParse(nodes[0], ctxt)))
        goto error;
    VIR_FREE(nodes);

12706
    if ((n = virXPathNodeSet("./features/*", ctxt, &nodes)) < 0)
12707
        goto error;
12708

12709
    for (i = 0; i < n; i++) {
12710 12711
        int val = virDomainFeatureTypeFromString((const char *)nodes[i]->name);
        if (val < 0) {
12712
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
12713
                           _("unexpected feature '%s'"), nodes[i]->name);
12714 12715
            goto error;
        }
12716

12717
        switch ((virDomainFeature) val) {
12718 12719
        case VIR_DOMAIN_FEATURE_APIC:
            if ((tmp = virXPathString("string(./features/apic/@eoi)", ctxt))) {
12720
                int eoi;
J
Ján Tomko 已提交
12721
                if ((eoi = virTristateSwitchTypeFromString(tmp)) <= 0) {
12722
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
12723
                                   _("unknown value for attribute eoi: '%s'"),
12724 12725
                                   tmp);
                    goto error;
12726
                }
12727 12728
                def->apic_eoi = eoi;
                VIR_FREE(tmp);
12729
            }
12730 12731 12732 12733 12734 12735 12736
            /* fallthrough */
        case VIR_DOMAIN_FEATURE_ACPI:
        case VIR_DOMAIN_FEATURE_PAE:
        case VIR_DOMAIN_FEATURE_HAP:
        case VIR_DOMAIN_FEATURE_VIRIDIAN:
        case VIR_DOMAIN_FEATURE_PRIVNET:
        case VIR_DOMAIN_FEATURE_HYPERV:
12737
        case VIR_DOMAIN_FEATURE_KVM:
J
Ján Tomko 已提交
12738
            def->features[val] = VIR_TRISTATE_SWITCH_ON;
12739 12740
            break;

12741 12742 12743 12744 12745 12746 12747 12748 12749 12750 12751 12752
        case VIR_DOMAIN_FEATURE_CAPABILITIES:
            node = ctxt->node;
            ctxt->node = nodes[i];
            if ((tmp = virXPathString("string(./@policy)", ctxt))) {
                if ((def->features[val] = virDomainCapabilitiesPolicyTypeFromString(tmp)) == -1) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("unknown state attribute '%s' of feature '%s'"),
                                   tmp, virDomainFeatureTypeToString(val));
                    goto error;
                }
                VIR_FREE(tmp);
            } else {
J
Ján Tomko 已提交
12753
                def->features[val] = VIR_TRISTATE_SWITCH_ABSENT;
12754 12755 12756
            }
            ctxt->node = node;
            break;
12757 12758 12759 12760
        case VIR_DOMAIN_FEATURE_PVSPINLOCK:
            node = ctxt->node;
            ctxt->node = nodes[i];
            if ((tmp = virXPathString("string(./@state)", ctxt))) {
J
Ján Tomko 已提交
12761
                if ((def->features[val] = virTristateSwitchTypeFromString(tmp)) == -1) {
12762
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
Y
Yuri Chornoivan 已提交
12763
                                   _("unknown state attribute '%s' of feature '%s'"),
12764 12765 12766
                                   tmp, virDomainFeatureTypeToString(val));
                    goto error;
                }
12767
                VIR_FREE(tmp);
12768
            } else {
J
Ján Tomko 已提交
12769
                def->features[val] = VIR_TRISTATE_SWITCH_ON;
12770 12771 12772 12773
            }
            ctxt->node = node;
            break;

12774
        /* coverity[dead_error_begin] */
12775 12776
        case VIR_DOMAIN_FEATURE_LAST:
            break;
12777 12778
        }
    }
12779
    VIR_FREE(nodes);
12780

J
Ján Tomko 已提交
12781
    if (def->features[VIR_DOMAIN_FEATURE_HYPERV] == VIR_TRISTATE_SWITCH_ON) {
12782 12783 12784 12785 12786 12787 12788 12789 12790
        int feature;
        int value;
        node = ctxt->node;
        if ((n = virXPathNodeSet("./features/hyperv/*", ctxt, &nodes)) < 0)
            goto error;

        for (i = 0; i < n; i++) {
            feature = virDomainHypervTypeFromString((const char *)nodes[i]->name);
            if (feature < 0) {
12791
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
12792 12793 12794 12795 12796 12797 12798
                               _("unsupported HyperV Enlightenment feature: %s"),
                               nodes[i]->name);
                goto error;
            }

            ctxt->node = nodes[i];

12799
            switch ((virDomainHyperv) feature) {
12800
                case VIR_DOMAIN_HYPERV_RELAXED:
12801
                case VIR_DOMAIN_HYPERV_VAPIC:
12802 12803 12804 12805 12806 12807 12808 12809
                    if (!(tmp = virXPathString("string(./@state)", ctxt))) {
                        virReportError(VIR_ERR_XML_ERROR,
                                       _("missing 'state' attribute for "
                                         "HyperV Enlightenment feature '%s'"),
                                       nodes[i]->name);
                        goto error;
                    }

J
Ján Tomko 已提交
12810
                    if ((value = virTristateSwitchTypeFromString(tmp)) < 0) {
12811
                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
12812 12813 12814 12815 12816 12817
                                       _("invalid value of state argument "
                                         "for HyperV Enlightenment feature '%s'"),
                                       nodes[i]->name);
                        goto error;
                    }

12818
                    VIR_FREE(tmp);
12819 12820 12821
                    def->hyperv_features[feature] = value;
                    break;

12822 12823 12824 12825 12826 12827 12828 12829 12830
                case VIR_DOMAIN_HYPERV_SPINLOCKS:
                    if (!(tmp = virXPathString("string(./@state)", ctxt))) {
                        virReportError(VIR_ERR_XML_ERROR,
                                       _("missing 'state' attribute for "
                                         "HyperV Enlightenment feature '%s'"),
                                       nodes[i]->name);
                        goto error;
                    }

J
Ján Tomko 已提交
12831
                    if ((value = virTristateSwitchTypeFromString(tmp)) < 0) {
12832
                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
12833 12834 12835 12836 12837 12838 12839
                                       _("invalid value of state argument "
                                         "for HyperV Enlightenment feature '%s'"),
                                       nodes[i]->name);
                        goto error;
                    }

                    VIR_FREE(tmp);
J
Ján Tomko 已提交
12840
                    if (value == VIR_TRISTATE_SWITCH_ON) {
12841 12842 12843 12844 12845 12846
                        if (virXPathUInt("string(./@retries)", ctxt,
                                     &def->hyperv_spinlocks) < 0) {
                            virReportError(VIR_ERR_XML_ERROR, "%s",
                                           _("invalid HyperV spinlock retry count"));
                            goto error;
                        }
12847

12848 12849 12850 12851 12852 12853
                        if (def->hyperv_spinlocks < 0xFFF) {
                            virReportError(VIR_ERR_XML_ERROR, "%s",
                                           _("HyperV spinlock retry count must be "
                                             "at least 4095"));
                            goto error;
                        }
12854 12855 12856 12857
                    }
                    def->hyperv_features[feature] = value;
                    break;

12858
                /* coverity[dead_error_begin] */
12859 12860 12861 12862 12863 12864 12865 12866
                case VIR_DOMAIN_HYPERV_LAST:
                    break;
            }
        }
        VIR_FREE(nodes);
        ctxt->node = node;
    }

12867 12868 12869 12870 12871 12872 12873 12874 12875 12876 12877 12878 12879 12880 12881 12882 12883 12884 12885 12886 12887 12888 12889 12890 12891 12892 12893 12894 12895 12896 12897 12898 12899 12900 12901 12902 12903 12904 12905 12906
    if (def->features[VIR_DOMAIN_FEATURE_KVM] == VIR_TRISTATE_SWITCH_ON) {
        int feature;
        int value;
        node = ctxt->node;
        if ((n = virXPathNodeSet("./features/kvm/*", ctxt, &nodes)) < 0)
            goto error;

        for (i = 0; i < n; i++) {
            feature = virDomainKVMTypeFromString((const char *)nodes[i]->name);
            if (feature < 0) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("unsupported KVM feature: %s"),
                               nodes[i]->name);
                goto error;
            }

            ctxt->node = nodes[i];

            switch ((virDomainKVM) feature) {
                case VIR_DOMAIN_KVM_HIDDEN:
                    if (!(tmp = virXPathString("string(./@state)", ctxt))) {
                        virReportError(VIR_ERR_XML_ERROR,
                                       _("missing 'state' attribute for "
                                         "KVM feature '%s'"),
                                       nodes[i]->name);
                        goto error;
                    }

                    if ((value = virTristateSwitchTypeFromString(tmp)) < 0) {
                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                       _("invalid value of state argument "
                                         "for KVM feature '%s'"),
                                       nodes[i]->name);
                        goto error;
                    }

                    VIR_FREE(tmp);
                    def->kvm_features[feature] = value;
                    break;

12907
                /* coverity[dead_error_begin] */
12908 12909 12910 12911 12912 12913 12914 12915
                case VIR_DOMAIN_KVM_LAST:
                    break;
            }
        }
        VIR_FREE(nodes);
        ctxt->node = node;
    }

12916 12917 12918 12919 12920 12921 12922 12923 12924 12925 12926 12927 12928 12929 12930 12931
    if ((n = virXPathNodeSet("./features/capabilities/*", ctxt, &nodes)) < 0)
        goto error;

    for (i = 0; i < n; i++) {
        int val = virDomainCapsFeatureTypeFromString((const char *)nodes[i]->name);
        if (val < 0) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unexpected capability feature '%s'"), nodes[i]->name);
            goto error;
        }

        if (val >= 0 && val < VIR_DOMAIN_CAPS_FEATURE_LAST) {
            node = ctxt->node;
            ctxt->node = nodes[i];

            if ((tmp = virXPathString("string(./@state)", ctxt))) {
J
Ján Tomko 已提交
12932
                if ((def->caps_features[val] = virTristateSwitchTypeFromString(tmp)) == -1) {
12933 12934 12935 12936 12937 12938 12939
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("unknown state attribute '%s' of feature capability '%s'"),
                                   tmp, virDomainFeatureTypeToString(val));
                    goto error;
                }
                VIR_FREE(tmp);
            } else {
J
Ján Tomko 已提交
12940
                def->caps_features[val] = VIR_TRISTATE_SWITCH_ON;
12941 12942 12943 12944 12945 12946
            }
            ctxt->node = node;
        }
    }
    VIR_FREE(nodes);

12947 12948 12949 12950 12951
    if (virDomainEventActionParseXML(ctxt, "on_reboot",
                                     "string(./on_reboot[1])",
                                     &def->onReboot,
                                     VIR_DOMAIN_LIFECYCLE_RESTART,
                                     virDomainLifecycleTypeFromString) < 0)
12952 12953
        goto error;

12954 12955 12956 12957 12958
    if (virDomainEventActionParseXML(ctxt, "on_poweroff",
                                     "string(./on_poweroff[1])",
                                     &def->onPoweroff,
                                     VIR_DOMAIN_LIFECYCLE_DESTROY,
                                     virDomainLifecycleTypeFromString) < 0)
12959 12960
        goto error;

12961 12962 12963 12964 12965
    if (virDomainEventActionParseXML(ctxt, "on_crash",
                                     "string(./on_crash[1])",
                                     &def->onCrash,
                                     VIR_DOMAIN_LIFECYCLE_CRASH_DESTROY,
                                     virDomainLifecycleCrashTypeFromString) < 0)
12966 12967
        goto error;

12968 12969 12970 12971 12972 12973 12974
    if (virDomainEventActionParseXML(ctxt, "on_lockfailure",
                                     "string(./on_lockfailure[1])",
                                     &def->onLockFailure,
                                     VIR_DOMAIN_LOCK_FAILURE_DEFAULT,
                                     virDomainLockFailureTypeFromString) < 0)
        goto error;

12975 12976 12977 12978 12979 12980 12981 12982 12983 12984
    if (virDomainPMStateParseXML(ctxt,
                                 "string(./pm/suspend-to-mem/@enabled)",
                                 &def->pm.s3) < 0)
        goto error;

    if (virDomainPMStateParseXML(ctxt,
                                 "string(./pm/suspend-to-disk/@enabled)",
                                 &def->pm.s4) < 0)
        goto error;

12985 12986
    if ((tmp = virXPathString("string(./clock/@offset)", ctxt)) &&
        (def->clock.offset = virDomainClockOffsetTypeFromString(tmp)) < 0) {
12987
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
12988 12989
                       _("unknown clock offset '%s'"), tmp);
        goto error;
12990
    }
12991 12992
    VIR_FREE(tmp);

12993
    switch (def->clock.offset) {
12994 12995 12996 12997 12998 12999 13000
    case VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME:
    case VIR_DOMAIN_CLOCK_OFFSET_UTC:
        tmp = virXPathString("string(./clock/@adjustment)", ctxt);
        if (tmp) {
            if (STREQ(tmp, "reset")) {
                def->clock.data.utc_reset = true;
            } else {
13001 13002
                if (virStrToLong_ll(tmp, NULL, 10,
                                    &def->clock.data.variable.adjustment) < 0) {
13003 13004 13005
                    virReportError(VIR_ERR_XML_ERROR,
                                   _("unknown clock adjustment '%s'"),
                                   tmp);
13006 13007 13008 13009 13010 13011 13012 13013 13014 13015 13016 13017 13018 13019 13020 13021 13022 13023
                    goto error;
                }
                switch (def->clock.offset) {
                case VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME:
                    def->clock.data.variable.basis = VIR_DOMAIN_CLOCK_BASIS_LOCALTIME;
                    break;
                case VIR_DOMAIN_CLOCK_OFFSET_UTC:
                    def->clock.data.variable.basis = VIR_DOMAIN_CLOCK_BASIS_UTC;
                    break;
                }
                def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_VARIABLE;
            }
            VIR_FREE(tmp);
        } else {
            def->clock.data.utc_reset = false;
        }
        break;

13024 13025
    case VIR_DOMAIN_CLOCK_OFFSET_VARIABLE:
        if (virXPathLongLong("number(./clock/@adjustment)", ctxt,
13026 13027
                             &def->clock.data.variable.adjustment) < 0)
            def->clock.data.variable.adjustment = 0;
13028 13029 13030
        if (virXPathLongLong("number(./clock/@adjustment0)", ctxt,
                             &def->clock.data.variable.adjustment0) < 0)
            def->clock.data.variable.adjustment0 = 0;
13031 13032 13033
        tmp = virXPathString("string(./clock/@basis)", ctxt);
        if (tmp) {
            if ((def->clock.data.variable.basis = virDomainClockBasisTypeFromString(tmp)) < 0) {
13034
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
13035
                               _("unknown clock basis '%s'"), tmp);
13036 13037 13038 13039 13040 13041
                goto error;
            }
            VIR_FREE(tmp);
        } else {
            def->clock.data.variable.basis = VIR_DOMAIN_CLOCK_BASIS_UTC;
        }
13042 13043 13044 13045 13046
        break;

    case VIR_DOMAIN_CLOCK_OFFSET_TIMEZONE:
        def->clock.data.timezone = virXPathString("string(./clock/@timezone)", ctxt);
        if (!def->clock.data.timezone) {
13047 13048
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("missing 'timezone' attribute for clock with offset='timezone'"));
13049 13050
            goto error;
        }
13051 13052
        break;
    }
13053

13054
    if ((n = virXPathNodeSet("./clock/timer", ctxt, &nodes)) < 0)
13055
        goto error;
13056

13057
    if (n && VIR_ALLOC_N(def->clock.timers, n) < 0)
13058
        goto error;
13059

13060
    for (i = 0; i < n; i++) {
13061
        virDomainTimerDefPtr timer = virDomainTimerDefParseXML(nodes[i],
E
Eric Blake 已提交
13062
                                                               ctxt);
13063 13064 13065 13066 13067 13068 13069
        if (!timer)
            goto error;

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

13070 13071
    def->os.bootloader = virXPathString("string(./bootloader)", ctxt);
    def->os.bootloaderArgs = virXPathString("string(./bootloader_args)", ctxt);
13072

13073
    def->os.type = virXPathString("string(./os/type[1])", ctxt);
13074 13075
    if (!def->os.type) {
        if (def->os.bootloader) {
13076 13077
            if (VIR_STRDUP(def->os.type, "xen") < 0)
                goto error;
13078
        } else {
13079 13080
            virReportError(VIR_ERR_OS_TYPE,
                           "%s", _("no OS type"));
13081 13082 13083 13084 13085 13086 13087 13088 13089 13090 13091
            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);
13092 13093
        if (VIR_STRDUP(def->os.type, "xen") < 0)
            goto error;
13094 13095 13096
    }

    if (!virCapabilitiesSupportsGuestOSType(caps, def->os.type)) {
13097 13098
        virReportError(VIR_ERR_OS_TYPE,
                       "%s", def->os.type);
13099 13100 13101
        goto error;
    }

13102 13103
    tmp = virXPathString("string(./os/type[1]/@arch)", ctxt);
    if (tmp) {
13104 13105
        def->os.arch = virArchFromString(tmp);
        if (!def->os.arch) {
13106 13107 13108 13109 13110 13111 13112
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unknown architecture %s"),
                           tmp);
            goto error;
        }
        VIR_FREE(tmp);

13113
        if (!virCapabilitiesSupportsGuestArch(caps, def->os.arch)) {
13114 13115
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("No guest options available for arch '%s'"),
13116
                           virArchToString(def->os.arch));
13117 13118 13119 13120 13121 13122
            goto error;
        }

        if (!virCapabilitiesSupportsGuestOSTypeArch(caps,
                                                    def->os.type,
                                                    def->os.arch)) {
13123 13124
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("No os type '%s' available for arch '%s'"),
13125
                           def->os.type, virArchToString(def->os.arch));
13126 13127 13128
            goto error;
        }
    } else {
13129 13130 13131 13132 13133
        def->os.arch =
            virCapabilitiesDefaultGuestArch(caps,
                                            def->os.type,
                                            virDomainVirtTypeToString(def->virtType));
        if (!def->os.arch) {
13134 13135 13136
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("no supported architecture for os type '%s'"),
                           def->os.type);
13137 13138 13139 13140
            goto error;
        }
    }

13141
    def->os.machine = virXPathString("string(./os/type[1]/@machine)", ctxt);
13142 13143 13144
    if (!def->os.machine) {
        const char *defaultMachine = virCapabilitiesDefaultGuestMachine(caps,
                                                                        def->os.type,
13145 13146
                                                                        def->os.arch,
                                                                        virDomainVirtTypeToString(def->virtType));
13147 13148
        if (VIR_STRDUP(def->os.machine, defaultMachine) < 0)
            goto error;
13149 13150
    }

13151 13152 13153 13154 13155 13156 13157 13158 13159 13160
    /*
     * 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")) {
13161
        def->os.init = virXPathString("string(./os/init[1])", ctxt);
13162
        def->os.cmdline = virXPathString("string(./os/cmdline[1])", ctxt);
13163 13164 13165 13166 13167 13168

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

        if (VIR_ALLOC_N(def->os.initargv, n+1) < 0)
13169
            goto error;
13170
        for (i = 0; i < n; i++) {
13171 13172
            if (!nodes[i]->children ||
                !nodes[i]->children->content) {
13173 13174
                virReportError(VIR_ERR_XML_ERROR, "%s",
                               _("No data supplied for <initarg> element"));
13175 13176
                goto error;
            }
13177 13178 13179
            if (VIR_STRDUP(def->os.initargv[i],
                           (const char*) nodes[i]->children->content) < 0)
                goto error;
13180 13181 13182
        }
        def->os.initargv[n] = NULL;
        VIR_FREE(nodes);
13183 13184 13185
    }

    if (STREQ(def->os.type, "xen") ||
13186 13187
        STREQ(def->os.type, "hvm") ||
        STREQ(def->os.type, "uml")) {
13188 13189
        xmlNodePtr loader_node;

13190 13191 13192
        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);
13193
        def->os.dtb = virXPathString("string(./os/dtb[1])", ctxt);
13194
        def->os.root = virXPathString("string(./os/root[1])", ctxt);
13195 13196 13197 13198 13199 13200 13201 13202
        if ((loader_node = virXPathNode("./os/loader[1]", ctxt))) {
            if (VIR_ALLOC(def->os.loader) < 0)
                goto error;

            if (virDomainLoaderDefParseXML(loader_node, def->os.loader) < 0)
                goto error;

            def->os.loader->nvram = virXPathString("string(./os/nvram[1])", ctxt);
13203
            def->os.loader->templt = virXPathString("string(./os/nvram[1]/@template)", ctxt);
13204
        }
13205
    }
13206

13207
    if (STREQ(def->os.type, "hvm")) {
13208 13209 13210
        if (virDomainDefParseBootXML(ctxt, def) < 0)
            goto error;
        if (!(bootHash = virHashCreate(5, NULL)))
13211
            goto error;
13212 13213
    }

13214
    def->emulator = virXPathString("string(./devices/emulator[1])", ctxt);
13215 13216

    /* analysis of the disk devices */
13217
    if ((n = virXPathNodeSet("./devices/disk", ctxt, &nodes)) < 0)
13218
        goto error;
13219

13220
    if (n && VIR_ALLOC_N(def->disks, n) < 0)
13221
        goto error;
13222

13223
    for (i = 0; i < n; i++) {
13224
        virDomainDiskDefPtr disk = virDomainDiskDefParseXML(xmlopt,
13225
                                                            nodes[i],
L
Lei Li 已提交
13226
                                                            ctxt,
13227
                                                            bootHash,
13228 13229
                                                            def->seclabels,
                                                            def->nseclabels,
13230
                                                            flags);
13231 13232 13233
        if (!disk)
            goto error;

13234
        virDomainDiskInsertPreAlloced(def, disk);
13235 13236 13237
    }
    VIR_FREE(nodes);

13238
    /* analysis of the controller devices */
13239
    if ((n = virXPathNodeSet("./devices/controller", ctxt, &nodes)) < 0)
13240
        goto error;
13241

13242
    if (n && VIR_ALLOC_N(def->controllers, n) < 0)
13243
        goto error;
13244

13245
    for (i = 0; i < n; i++) {
13246
        virDomainControllerDefPtr controller = virDomainControllerDefParseXML(nodes[i],
13247
                                                                              ctxt,
13248 13249 13250 13251
                                                                              flags);
        if (!controller)
            goto error;

13252 13253 13254 13255
        /* sanitize handling of "none" usb controller */
        if (controller->type == VIR_DOMAIN_CONTROLLER_TYPE_USB) {
            if (controller->model == VIR_DOMAIN_CONTROLLER_MODEL_USB_NONE) {
                if (usb_other || usb_none) {
13256
                    virDomainControllerDefFree(controller);
13257 13258 13259 13260 13261 13262 13263 13264
                    virReportError(VIR_ERR_XML_DETAIL, "%s",
                                   _("Can't add another USB controller: "
                                     "USB is disabled for this domain"));
                    goto error;
                }
                usb_none = true;
            } else {
                if (usb_none) {
13265
                    virDomainControllerDefFree(controller);
13266 13267 13268 13269 13270 13271 13272
                    virReportError(VIR_ERR_XML_DETAIL, "%s",
                                   _("Can't add another USB controller: "
                                     "USB is disabled for this domain"));
                    goto error;
                }
                usb_other = true;
            }
13273 13274 13275

            if (controller->info.mastertype == VIR_DOMAIN_CONTROLLER_MASTER_NONE)
                usb_master = true;
13276 13277
        }

13278
        virDomainControllerInsertPreAlloced(def, controller);
13279 13280 13281
    }
    VIR_FREE(nodes);

13282 13283 13284 13285 13286 13287
    if (usb_other && !usb_master) {
        virReportError(VIR_ERR_XML_DETAIL, "%s",
                       _("No master USB controller specified"));
        goto error;
    }

13288 13289
    /* analysis of the resource leases */
    if ((n = virXPathNodeSet("./devices/lease", ctxt, &nodes)) < 0) {
13290 13291
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("cannot extract device leases"));
13292 13293 13294
        goto error;
    }
    if (n && VIR_ALLOC_N(def->leases, n) < 0)
13295
        goto error;
13296
    for (i = 0; i < n; i++) {
13297 13298 13299 13300 13301 13302 13303 13304
        virDomainLeaseDefPtr lease = virDomainLeaseDefParseXML(nodes[i]);
        if (!lease)
            goto error;

        def->leases[def->nleases++] = lease;
    }
    VIR_FREE(nodes);

13305
    /* analysis of the filesystems */
13306
    if ((n = virXPathNodeSet("./devices/filesystem", ctxt, &nodes)) < 0) {
13307 13308
        goto error;
    }
13309
    if (n && VIR_ALLOC_N(def->fss, n) < 0)
13310
        goto error;
13311
    for (i = 0; i < n; i++) {
13312
        virDomainFSDefPtr fs = virDomainFSDefParseXML(nodes[i], ctxt,
13313
                                                      flags);
13314 13315 13316
        if (!fs)
            goto error;

13317
        def->fss[def->nfss++] = fs;
13318 13319 13320
    }
    VIR_FREE(nodes);

13321
    /* analysis of the network devices */
13322
    if ((n = virXPathNodeSet("./devices/interface", ctxt, &nodes)) < 0) {
13323 13324
        goto error;
    }
13325
    if (n && VIR_ALLOC_N(def->nets, n) < 0)
13326
        goto error;
13327
    for (i = 0; i < n; i++) {
13328
        virDomainNetDefPtr net = virDomainNetDefParseXML(xmlopt,
13329
                                                         nodes[i],
13330
                                                         ctxt,
13331
                                                         bootHash,
13332
                                                         flags);
13333 13334 13335
        if (!net)
            goto error;

13336
        def->nets[def->nnets++] = net;
13337

13338 13339 13340 13341 13342 13343
        /* <interface type='hostdev'> (and <interface type='net'>
         * where the actual network type is already known to be
         * hostdev) must also be in the hostdevs array.
         */
        if (virDomainNetGetActualType(net) == VIR_DOMAIN_NET_TYPE_HOSTDEV &&
            virDomainHostdevInsert(def, virDomainNetGetActualHostdev(net)) < 0) {
13344
            goto error;
13345
        }
13346 13347 13348 13349
    }
    VIR_FREE(nodes);


E
Eric Blake 已提交
13350 13351 13352 13353 13354
    /* analysis of the smartcard devices */
    if ((n = virXPathNodeSet("./devices/smartcard", ctxt, &nodes)) < 0) {
        goto error;
    }
    if (n && VIR_ALLOC_N(def->smartcards, n) < 0)
13355
        goto error;
E
Eric Blake 已提交
13356

13357
    for (i = 0; i < n; i++) {
E
Eric Blake 已提交
13358 13359 13360 13361 13362 13363 13364 13365 13366 13367
        virDomainSmartcardDefPtr card = virDomainSmartcardDefParseXML(nodes[i],
                                                                      flags);
        if (!card)
            goto error;

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


13368
    /* analysis of the character devices */
13369
    if ((n = virXPathNodeSet("./devices/parallel", ctxt, &nodes)) < 0) {
13370 13371
        goto error;
    }
13372
    if (n && VIR_ALLOC_N(def->parallels, n) < 0)
13373
        goto error;
13374

13375
    for (i = 0; i < n; i++) {
13376
        virDomainChrDefPtr chr = virDomainChrDefParseXML(ctxt,
13377
                                                         nodes[i],
13378 13379
                                                         def->seclabels,
                                                         def->nseclabels,
13380
                                                         flags);
13381 13382 13383
        if (!chr)
            goto error;

13384 13385
        if (chr->target.port == -1) {
            int maxport = -1;
13386
            for (j = 0; j < i; j++) {
13387 13388 13389 13390 13391
                if (def->parallels[j]->target.port > maxport)
                    maxport = def->parallels[j]->target.port;
            }
            chr->target.port = maxport + 1;
        }
13392
        def->parallels[def->nparallels++] = chr;
13393 13394 13395
    }
    VIR_FREE(nodes);

13396
    if ((n = virXPathNodeSet("./devices/serial", ctxt, &nodes)) < 0)
13397
        goto error;
13398

13399
    if (n && VIR_ALLOC_N(def->serials, n) < 0)
13400
        goto error;
13401

13402
    for (i = 0; i < n; i++) {
13403
        virDomainChrDefPtr chr = virDomainChrDefParseXML(ctxt,
13404
                                                         nodes[i],
13405 13406
                                                         def->seclabels,
                                                         def->nseclabels,
13407
                                                         flags);
13408 13409 13410
        if (!chr)
            goto error;

13411 13412
        if (chr->target.port == -1) {
            int maxport = -1;
13413
            for (j = 0; j < i; j++) {
13414 13415 13416 13417 13418
                if (def->serials[j]->target.port > maxport)
                    maxport = def->serials[j]->target.port;
            }
            chr->target.port = maxport + 1;
        }
13419
        def->serials[def->nserials++] = chr;
13420 13421 13422
    }
    VIR_FREE(nodes);

13423
    if ((n = virXPathNodeSet("./devices/console", ctxt, &nodes)) < 0) {
13424 13425
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("cannot extract console devices"));
13426 13427 13428
        goto error;
    }
    if (n && VIR_ALLOC_N(def->consoles, n) < 0)
13429
        goto error;
13430

13431
    for (i = 0; i < n; i++) {
13432
        virDomainChrDefPtr chr = virDomainChrDefParseXML(ctxt,
13433
                                                         nodes[i],
13434 13435
                                                         def->seclabels,
                                                         def->nseclabels,
13436
                                                         flags);
13437 13438
        if (!chr)
            goto error;
13439

13440 13441
        chr->target.port = i;
        def->consoles[def->nconsoles++] = chr;
13442
    }
13443
    VIR_FREE(nodes);
13444

13445
    if ((n = virXPathNodeSet("./devices/channel", ctxt, &nodes)) < 0) {
13446 13447 13448
        goto error;
    }
    if (n && VIR_ALLOC_N(def->channels, n) < 0)
13449
        goto error;
13450

13451
    for (i = 0; i < n; i++) {
13452
        virDomainChrDefPtr chr = virDomainChrDefParseXML(ctxt,
13453
                                                         nodes[i],
13454 13455
                                                         def->seclabels,
                                                         def->nseclabels,
13456 13457 13458 13459 13460
                                                         flags);
        if (!chr)
            goto error;

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

13462 13463
        if (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL &&
            chr->targetType == VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO &&
13464 13465 13466
            chr->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
            chr->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL;

13467 13468
        if (chr->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL &&
            chr->info.addr.vioserial.port == 0) {
13469
            int maxport = 0;
13470
            for (j = 0; j < i; j++) {
13471 13472 13473 13474 13475 13476 13477 13478 13479
                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;
        }
13480 13481 13482
    }
    VIR_FREE(nodes);

13483 13484

    /* analysis of the input devices */
13485
    if ((n = virXPathNodeSet("./devices/input", ctxt, &nodes)) < 0) {
13486 13487
        goto error;
    }
13488
    if (n && VIR_ALLOC_N(def->inputs, n) < 0)
13489
        goto error;
13490

13491
    for (i = 0; i < n; i++) {
L
Li Zhang 已提交
13492
        virDomainInputDefPtr input = virDomainInputDefParseXML(def,
13493 13494
                                                               nodes[i],
                                                               flags);
13495 13496 13497
        if (!input)
            goto error;

13498 13499
        /* Check if USB bus is required */
        if (input->bus == VIR_DOMAIN_INPUT_BUS_USB && usb_none) {
13500
            virDomainInputDefFree(input);
13501 13502 13503 13504 13505
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("Can't add USB input device. "
                             "USB bus is disabled"));
            goto error;
        }
13506 13507 13508 13509 13510 13511

        /* 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 &&
L
Li Zhang 已提交
13512 13513
             (input->type == VIR_DOMAIN_INPUT_TYPE_MOUSE ||
              input->type == VIR_DOMAIN_INPUT_TYPE_KBD)) ||
13514 13515
            (STRNEQ(def->os.type, "hvm") &&
             input->bus == VIR_DOMAIN_INPUT_BUS_XEN &&
L
Li Zhang 已提交
13516 13517
             (input->type == VIR_DOMAIN_INPUT_TYPE_MOUSE ||
              input->type == VIR_DOMAIN_INPUT_TYPE_KBD))) {
13518 13519 13520 13521
            virDomainInputDefFree(input);
            continue;
        }

13522
        def->inputs[def->ninputs++] = input;
13523 13524 13525
    }
    VIR_FREE(nodes);

13526
    /* analysis of the graphics devices */
13527
    if ((n = virXPathNodeSet("./devices/graphics", ctxt, &nodes)) < 0) {
13528 13529
        goto error;
    }
13530
    if (n && VIR_ALLOC_N(def->graphics, n) < 0)
13531
        goto error;
13532
    for (i = 0; i < n; i++) {
13533
        virDomainGraphicsDefPtr graphics = virDomainGraphicsDefParseXML(nodes[i],
13534
                                                                        ctxt,
13535
                                                                        flags);
13536 13537 13538
        if (!graphics)
            goto error;

13539
        def->graphics[def->ngraphics++] = graphics;
13540 13541 13542 13543
    }
    VIR_FREE(nodes);

    /* If graphics are enabled, there's an implicit PS2 mouse */
13544 13545
    if (def->ngraphics > 0 &&
        (ARCH_IS_X86(def->os.arch) || def->os.arch == VIR_ARCH_NONE)) {
13546
        int input_bus = VIR_DOMAIN_INPUT_BUS_XEN;
13547

13548 13549
        if (STREQ(def->os.type, "hvm"))
            input_bus = VIR_DOMAIN_INPUT_BUS_PS2;
13550

13551 13552 13553
        if (virDomainDefMaybeAddInput(def,
                                      VIR_DOMAIN_INPUT_TYPE_MOUSE,
                                      input_bus) < 0)
13554
            goto error;
13555

L
Li Zhang 已提交
13556 13557 13558 13559 13560
        if (virDomainDefMaybeAddInput(def,
                                      VIR_DOMAIN_INPUT_TYPE_KBD,
                                      input_bus) < 0)
            goto error;
    }
13561 13562

    /* analysis of the sound devices */
13563
    if ((n = virXPathNodeSet("./devices/sound", ctxt, &nodes)) < 0) {
13564 13565
        goto error;
    }
13566
    if (n && VIR_ALLOC_N(def->sounds, n) < 0)
13567
        goto error;
13568
    for (i = 0; i < n; i++) {
13569
        virDomainSoundDefPtr sound = virDomainSoundDefParseXML(nodes[i],
13570
                                                               ctxt,
13571
                                                               flags);
13572 13573 13574
        if (!sound)
            goto error;

13575
        def->sounds[def->nsounds++] = sound;
13576 13577 13578
    }
    VIR_FREE(nodes);

13579
    /* analysis of the video devices */
13580
    if ((n = virXPathNodeSet("./devices/video", ctxt, &nodes)) < 0) {
13581 13582 13583
        goto error;
    }
    if (n && VIR_ALLOC_N(def->videos, n) < 0)
13584
        goto error;
13585
    for (i = 0; i < n; i++) {
13586
        j = def->nvideos;
13587
        virDomainVideoDefPtr video = virDomainVideoDefParseXML(nodes[j],
13588 13589 13590 13591
                                                               def,
                                                               flags);
        if (!video)
            goto error;
13592 13593 13594

        if (video->primary) {
            if (primaryVideo) {
13595
                virDomainVideoDefFree(video);
13596 13597 13598 13599 13600
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                               _("Only one primary video device is supported"));
                goto error;
            }

13601
            j = 0;
13602 13603
            primaryVideo = true;
        }
13604
        if (VIR_INSERT_ELEMENT_INPLACE(def->videos,
13605
                                       j,
13606 13607
                                       def->nvideos,
                                       video) < 0) {
13608
            virDomainVideoDefFree(video);
13609
            goto error;
13610
        }
13611 13612 13613
    }
    VIR_FREE(nodes);

13614
    /* For backwards compatibility, if no <video> tag is set but there
13615 13616 13617 13618
     * is a <graphics> tag, then we add a single video tag */
    if (def->ngraphics && !def->nvideos) {
        virDomainVideoDefPtr video;
        if (VIR_ALLOC(video) < 0)
13619
            goto error;
13620 13621
        video->type = virDomainVideoDefaultType(def);
        if (video->type < 0) {
13622 13623
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("cannot determine default video type"));
13624 13625 13626 13627 13628 13629 13630
            VIR_FREE(video);
            goto error;
        }
        video->vram = virDomainVideoDefaultRAM(def, video->type);
        video->heads = 1;
        if (VIR_ALLOC_N(def->videos, 1) < 0) {
            virDomainVideoDefFree(video);
13631
            goto error;
13632 13633 13634 13635
        }
        def->videos[def->nvideos++] = video;
    }

13636
    /* analysis of the host devices */
13637
    if ((n = virXPathNodeSet("./devices/hostdev", ctxt, &nodes)) < 0) {
13638 13639
        goto error;
    }
13640
    if (n && VIR_REALLOC_N(def->hostdevs, def->nhostdevs + n) < 0)
13641
        goto error;
13642
    for (i = 0; i < n; i++) {
13643 13644
        virDomainHostdevDefPtr hostdev;

13645 13646
        hostdev = virDomainHostdevDefParseXML(xmlopt, def, nodes[i],
                                              ctxt, bootHash, flags);
13647 13648 13649
        if (!hostdev)
            goto error;

13650 13651 13652 13653 13654
        if (hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB &&
            usb_none) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("Can't add host USB device: "
                             "USB is disabled in this host"));
13655
            virDomainHostdevDefFree(hostdev);
13656 13657 13658
            goto error;
        }

13659
        def->hostdevs[def->nhostdevs++] = hostdev;
13660 13661 13662

        if (virDomainDefMaybeAddHostdevSCSIcontroller(def) < 0)
            goto error;
13663 13664 13665
    }
    VIR_FREE(nodes);

R
Richard Jones 已提交
13666 13667
    /* analysis of the watchdog devices */
    def->watchdog = NULL;
13668
    if ((n = virXPathNodeSet("./devices/watchdog", ctxt, &nodes)) < 0) {
R
Richard Jones 已提交
13669 13670 13671
        goto error;
    }
    if (n > 1) {
13672 13673
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("only a single watchdog device is supported"));
R
Richard Jones 已提交
13674 13675 13676 13677
        goto error;
    }
    if (n > 0) {
        virDomainWatchdogDefPtr watchdog =
13678
            virDomainWatchdogDefParseXML(nodes[0], flags);
R
Richard Jones 已提交
13679 13680 13681 13682 13683 13684 13685
        if (!watchdog)
            goto error;

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

13686 13687 13688 13689 13690 13691
    /* analysis of the memballoon devices */
    def->memballoon = NULL;
    if ((n = virXPathNodeSet("./devices/memballoon", ctxt, &nodes)) < 0) {
        goto error;
    }
    if (n > 1) {
13692 13693
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("only a single memory balloon device is supported"));
13694 13695 13696 13697
        goto error;
    }
    if (n > 0) {
        virDomainMemballoonDefPtr memballoon =
13698
            virDomainMemballoonDefParseXML(nodes[0], ctxt, flags);
13699 13700 13701 13702 13703 13704 13705
        if (!memballoon)
            goto error;

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

13706
    /* Parse the RNG devices */
13707 13708
    if ((n = virXPathNodeSet("./devices/rng", ctxt, &nodes)) < 0)
        goto error;
13709
    if (n && VIR_ALLOC_N(def->rngs, n) < 0)
13710
        goto error;
13711 13712 13713 13714 13715
    for (i = 0; i < n; i++) {
        virDomainRNGDefPtr rng = virDomainRNGDefParseXML(nodes[i],
                                                         ctxt,
                                                         flags);
        if (!rng)
13716
            goto error;
13717 13718

        def->rngs[def->nrngs++] = rng;
13719
    }
13720 13721 13722 13723 13724 13725 13726 13727 13728 13729 13730 13731 13732 13733 13734 13735 13736
    VIR_FREE(nodes);

    /* Parse the TPM devices */
    if ((n = virXPathNodeSet("./devices/tpm", ctxt, &nodes)) < 0)
        goto error;

    if (n > 1) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("only a single TPM device is supported"));
        goto error;
    }

    if (n > 0) {
        if (!(def->tpm = virDomainTPMDefParseXML(nodes[0], ctxt, flags)))
            goto error;
    }
    VIR_FREE(nodes);
13737

L
Li Zhang 已提交
13738 13739 13740 13741 13742 13743 13744 13745 13746 13747 13748 13749 13750 13751 13752 13753 13754
    if ((n = virXPathNodeSet("./devices/nvram", ctxt, &nodes)) < 0) {
        goto error;
    }

    if (n > 1) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("only a single nvram device is supported"));
        goto error;
    } else if (n == 1) {
        virDomainNVRAMDefPtr nvram =
            virDomainNVRAMDefParseXML(nodes[0], flags);
        if (!nvram)
            goto error;
        def->nvram = nvram;
        VIR_FREE(nodes);
    }

M
Marc-André Lureau 已提交
13755 13756 13757 13758 13759
    /* analysis of the hub devices */
    if ((n = virXPathNodeSet("./devices/hub", ctxt, &nodes)) < 0) {
        goto error;
    }
    if (n && VIR_ALLOC_N(def->hubs, n) < 0)
13760
        goto error;
13761
    for (i = 0; i < n; i++) {
M
Marc-André Lureau 已提交
13762 13763 13764 13765
        virDomainHubDefPtr hub = virDomainHubDefParseXML(nodes[i], flags);
        if (!hub)
            goto error;

13766
        if (hub->type == VIR_DOMAIN_HUB_TYPE_USB && usb_none) {
13767
            virDomainHubDefFree(hub);
13768 13769 13770 13771 13772 13773
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("Can't add USB hub: "
                             "USB is disabled for this domain"));
            goto error;
        }

M
Marc-André Lureau 已提交
13774 13775 13776 13777
        def->hubs[def->nhubs++] = hub;
    }
    VIR_FREE(nodes);

13778 13779 13780 13781 13782
    /* analysis of the redirected devices */
    if ((n = virXPathNodeSet("./devices/redirdev", ctxt, &nodes)) < 0) {
        goto error;
    }
    if (n && VIR_ALLOC_N(def->redirdevs, n) < 0)
13783
        goto error;
13784
    for (i = 0; i < n; i++) {
13785
        virDomainRedirdevDefPtr redirdev = virDomainRedirdevDefParseXML(nodes[i],
13786
                                                                        bootHash,
13787 13788 13789 13790
                                                                        flags);
        if (!redirdev)
            goto error;

13791 13792 13793 13794
        if (redirdev->bus == VIR_DOMAIN_REDIRDEV_BUS_USB && usb_none) {
             virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                            _("Can't add redirected USB device: "
                              "USB is disabled for this domain"));
13795
            virDomainRedirdevDefFree(redirdev);
13796 13797 13798
            goto error;
        }

13799 13800 13801 13802
        def->redirdevs[def->nredirdevs++] = redirdev;
    }
    VIR_FREE(nodes);

13803 13804 13805 13806 13807 13808 13809 13810 13811 13812 13813 13814 13815 13816 13817 13818 13819 13820 13821 13822
    /* analysis of the redirection filter rules */
    if ((n = virXPathNodeSet("./devices/redirfilter", ctxt, &nodes)) < 0) {
        goto error;
    }
    if (n > 1) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("only one set of redirection filter rule is supported"));
        goto error;
    }

    if (n) {
        virDomainRedirFilterDefPtr redirfilter =
            virDomainRedirFilterDefParseXML(nodes[0], ctxt);
        if (!redirfilter)
            goto error;

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

H
Hu Tao 已提交
13823 13824 13825 13826 13827 13828 13829 13830 13831 13832 13833 13834 13835 13836 13837 13838 13839 13840 13841 13842
    /* analysis of the panic devices */
    def->panic = NULL;
    if ((n = virXPathNodeSet("./devices/panic", ctxt, &nodes)) < 0) {
        goto error;
    }
    if (n > 1) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("only a single panic device is supported"));
        goto error;
    }
    if (n > 0) {
        virDomainPanicDefPtr panic =
            virDomainPanicDefParseXML(nodes[0]);
        if (!panic)
            goto error;

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

13843 13844 13845 13846 13847 13848 13849 13850 13851 13852 13853 13854 13855 13856 13857 13858 13859 13860 13861
    /* analysis of the shmem devices */
    if ((n = virXPathNodeSet("./devices/shmem", ctxt, &nodes)) < 0) {
        goto error;
    }
    if (n && VIR_ALLOC_N(def->shmems, n) < 0)
        goto error;

    node = ctxt->node;
    for (i = 0; i < n; i++) {
        virDomainShmemDefPtr shmem;
        ctxt->node = nodes[i];
        shmem = virDomainShmemDefParseXML(nodes[i], ctxt, flags);
        if (!shmem)
            goto error;

        def->shmems[def->nshmems++] = shmem;
    }
    ctxt->node = node;
    VIR_FREE(nodes);
H
Hu Tao 已提交
13862

13863 13864 13865 13866 13867 13868 13869 13870 13871 13872 13873 13874 13875 13876 13877 13878 13879 13880 13881 13882 13883 13884 13885 13886 13887 13888 13889 13890 13891 13892 13893 13894
    /* analysis of the user namespace mapping */
    if ((n = virXPathNodeSet("./idmap/uid", ctxt, &nodes)) < 0)
        goto error;

    if (n) {
        def->idmap.uidmap = virDomainIdmapDefParseXML(ctxt, nodes, n);
        if (!def->idmap.uidmap)
            goto error;

        def->idmap.nuidmap = n;
    }
    VIR_FREE(nodes);

    if  ((n = virXPathNodeSet("./idmap/gid", ctxt, &nodes)) < 0)
        goto error;

    if (n) {
        def->idmap.gidmap =  virDomainIdmapDefParseXML(ctxt, nodes, n);
        if (!def->idmap.gidmap)
            goto error;

        def->idmap.ngidmap = n;
    }
    VIR_FREE(nodes);

    if ((def->idmap.uidmap && !def->idmap.gidmap) ||
        (!def->idmap.uidmap && def->idmap.gidmap)) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("uid and gid should be mapped both"));
            goto error;
    }

13895 13896 13897
    if ((node = virXPathNode("./sysinfo[1]", ctxt)) != NULL) {
        xmlNodePtr oldnode = ctxt->node;
        ctxt->node = node;
13898 13899
        def->sysinfo = virSysinfoParseXML(node, ctxt,
                                          def->uuid, uuid_generated);
13900 13901 13902 13903 13904
        ctxt->node = oldnode;

        if (def->sysinfo == NULL)
            goto error;
    }
13905 13906

    if ((tmp = virXPathString("string(./os/smbios/@mode)", ctxt))) {
13907 13908 13909
        int mode;

        if ((mode = virDomainSmbiosModeTypeFromString(tmp)) < 0) {
13910
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
13911
                           _("unknown smbios mode '%s'"), tmp);
13912 13913 13914 13915 13916
            goto error;
        }
        def->os.smbios_mode = mode;
        VIR_FREE(tmp);
    }
13917

13918
    /* Extract custom metadata */
13919
    if ((node = virXPathNode("./metadata[1]", ctxt)) != NULL)
13920 13921
        def->metadata = xmlCopyNode(node, 1);

13922 13923 13924
    /* we have to make a copy of all of the callback pointers here since
     * we won't have the virCaps structure available during free
     */
13925
    def->ns = xmlopt->ns;
13926

13927 13928 13929
    if (def->ns.parse &&
        (def->ns.parse)(xml, root, ctxt, &def->namespaceData) < 0)
        goto error;
13930

13931 13932 13933 13934
    /* callback to fill driver specific domain aspects */
    if (virDomainDefPostParse(def, caps, xmlopt) < 0)
        goto error;

13935 13936 13937 13938
    /* Auto-add any implied controllers which aren't present */
    if (virDomainDefAddImplicitControllers(def) < 0)
        goto error;

13939
    virHashFree(bootHash);
13940

13941 13942
    return def;

13943
 error:
13944 13945
    VIR_FREE(tmp);
    VIR_FREE(nodes);
13946
    virHashFree(bootHash);
13947 13948 13949 13950
    virDomainDefFree(def);
    return NULL;
}

13951

13952
static virDomainObjPtr
13953
virDomainObjParseXML(xmlDocPtr xml,
13954
                     xmlXPathContextPtr ctxt,
13955 13956
                     virCapsPtr caps,
                     virDomainXMLOptionPtr xmlopt,
13957 13958
                     unsigned int expectedVirtTypes,
                     unsigned int flags)
13959 13960 13961 13962 13963 13964
{
    char *tmp = NULL;
    long val;
    xmlNodePtr config;
    xmlNodePtr oldnode;
    virDomainObjPtr obj;
13965
    xmlNodePtr *nodes = NULL;
13966 13967
    size_t i;
    int n;
J
Jiri Denemark 已提交
13968 13969
    int state;
    int reason = 0;
13970

13971
    if (!(obj = virDomainObjNew(xmlopt)))
13972 13973
        return NULL;

13974
    if (!(config = virXPathNode("./domain", ctxt))) {
13975 13976
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("no domain config"));
13977 13978 13979 13980 13981
        goto error;
    }

    oldnode = ctxt->node;
    ctxt->node = config;
13982 13983
    obj->def = virDomainDefParseXML(xml, config, ctxt, caps, xmlopt,
                                    expectedVirtTypes, flags);
13984 13985 13986 13987
    ctxt->node = oldnode;
    if (!obj->def)
        goto error;

13988
    if (!(tmp = virXPathString("string(./@state)", ctxt))) {
13989 13990
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing domain state"));
13991 13992
        goto error;
    }
J
Jiri Denemark 已提交
13993
    if ((state = virDomainStateTypeFromString(tmp)) < 0) {
13994
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
13995
                       _("invalid domain state '%s'"), tmp);
13996 13997 13998 13999 14000
        VIR_FREE(tmp);
        goto error;
    }
    VIR_FREE(tmp);

J
Jiri Denemark 已提交
14001 14002
    if ((tmp = virXPathString("string(./@reason)", ctxt))) {
        if ((reason = virDomainStateReasonFromString(state, tmp)) < 0) {
14003
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
14004
                           _("invalid domain state reason '%s'"), tmp);
J
Jiri Denemark 已提交
14005 14006 14007 14008 14009 14010 14011 14012
            VIR_FREE(tmp);
            goto error;
        }
        VIR_FREE(tmp);
    }

    virDomainObjSetState(obj, state, reason);

E
Eric Blake 已提交
14013
    if (virXPathLong("string(./@pid)", ctxt, &val) < 0) {
14014 14015
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("invalid pid"));
14016 14017 14018 14019
        goto error;
    }
    obj->pid = (pid_t)val;

14020 14021 14022
    if ((n = virXPathNodeSet("./taint", ctxt, &nodes)) < 0) {
        goto error;
    }
14023
    for (i = 0; i < n; i++) {
14024 14025 14026 14027
        char *str = virXMLPropString(nodes[i], "flag");
        if (str) {
            int flag = virDomainTaintTypeFromString(str);
            if (flag < 0) {
14028
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
14029
                               _("Unknown taint flag %s"), str);
14030
                VIR_FREE(str);
14031 14032
                goto error;
            }
14033
            VIR_FREE(str);
14034 14035 14036 14037 14038
            virDomainObjTaint(obj, flag);
        }
    }
    VIR_FREE(nodes);

14039 14040
    if (xmlopt->privateData.parse &&
        ((xmlopt->privateData.parse)(ctxt, obj->privateData)) < 0)
14041
        goto error;
14042

14043 14044
    return obj;

14045
 error:
14046
    virObjectUnref(obj);
14047
    VIR_FREE(nodes);
14048 14049 14050 14051
    return NULL;
}


J
Jiri Denemark 已提交
14052 14053 14054 14055
static virDomainDefPtr
virDomainDefParse(const char *xmlStr,
                  const char *filename,
                  virCapsPtr caps,
14056
                  virDomainXMLOptionPtr xmlopt,
M
Matthias Bolte 已提交
14057
                  unsigned int expectedVirtTypes,
E
Eric Blake 已提交
14058
                  unsigned int flags)
14059
{
J
Jiri Denemark 已提交
14060 14061
    xmlDocPtr xml;
    virDomainDefPtr def = NULL;
14062
    int keepBlanksDefault = xmlKeepBlanksDefault(0);
J
Jiri Denemark 已提交
14063

14064
    if ((xml = virXMLParse(filename, xmlStr, _("(domain_definition)")))) {
14065 14066
        def = virDomainDefParseNode(xml, xmlDocGetRootElement(xml), caps,
                                    xmlopt, expectedVirtTypes, flags);
J
Jiri Denemark 已提交
14067
        xmlFreeDoc(xml);
14068
    }
J
Jiri Denemark 已提交
14069

14070
    xmlKeepBlanksDefault(keepBlanksDefault);
J
Jiri Denemark 已提交
14071
    return def;
14072
}
14073

14074
virDomainDefPtr
14075 14076
virDomainDefParseString(const char *xmlStr,
                        virCapsPtr caps,
14077
                        virDomainXMLOptionPtr xmlopt,
14078 14079
                        unsigned int expectedVirtTypes,
                        unsigned int flags)
14080
{
14081
    return virDomainDefParse(xmlStr, NULL, caps, xmlopt,
14082
                             expectedVirtTypes, flags);
14083 14084
}

14085
virDomainDefPtr
14086 14087
virDomainDefParseFile(const char *filename,
                      virCapsPtr caps,
14088
                      virDomainXMLOptionPtr xmlopt,
14089 14090
                      unsigned int expectedVirtTypes,
                      unsigned int flags)
14091
{
14092
    return virDomainDefParse(NULL, filename, caps, xmlopt,
14093
                             expectedVirtTypes, flags);
14094 14095 14096
}


14097
virDomainDefPtr
14098
virDomainDefParseNode(xmlDocPtr xml,
14099
                      xmlNodePtr root,
14100 14101
                      virCapsPtr caps,
                      virDomainXMLOptionPtr xmlopt,
14102 14103
                      unsigned int expectedVirtTypes,
                      unsigned int flags)
14104 14105 14106 14107 14108
{
    xmlXPathContextPtr ctxt = NULL;
    virDomainDefPtr def = NULL;

    if (!xmlStrEqual(root->name, BAD_CAST "domain")) {
14109 14110 14111 14112
        virReportError(VIR_ERR_XML_ERROR,
                       _("unexpected root element <%s>, "
                         "expecting <domain>"),
                       root->name);
14113 14114 14115 14116 14117
        goto cleanup;
    }

    ctxt = xmlXPathNewContext(xml);
    if (ctxt == NULL) {
14118
        virReportOOMError();
14119 14120 14121 14122
        goto cleanup;
    }

    ctxt->node = root;
14123
    def = virDomainDefParseXML(xml, root, ctxt, caps, xmlopt,
14124
                               expectedVirtTypes, flags);
14125

14126
 cleanup:
14127 14128 14129
    xmlXPathFreeContext(ctxt);
    return def;
}
14130 14131


H
Hu Tao 已提交
14132
static virDomainObjPtr
14133
virDomainObjParseNode(xmlDocPtr xml,
L
Laine Stump 已提交
14134
                      xmlNodePtr root,
14135 14136
                      virCapsPtr caps,
                      virDomainXMLOptionPtr xmlopt,
M
Matthias Bolte 已提交
14137
                      unsigned int expectedVirtTypes,
L
Laine Stump 已提交
14138
                      unsigned int flags)
14139 14140 14141 14142 14143
{
    xmlXPathContextPtr ctxt = NULL;
    virDomainObjPtr obj = NULL;

    if (!xmlStrEqual(root->name, BAD_CAST "domstatus")) {
14144 14145 14146 14147
        virReportError(VIR_ERR_XML_ERROR,
                       _("unexpected root element <%s>, "
                         "expecting <domstatus>"),
                       root->name);
14148 14149 14150
        goto cleanup;
    }

14151
    if (!(ctxt = xmlXPathNewContext(xml))) {
14152
        virReportOOMError();
14153 14154 14155 14156
        goto cleanup;
    }

    ctxt->node = root;
14157
    obj = virDomainObjParseXML(xml, ctxt, caps, xmlopt, expectedVirtTypes, flags);
14158

14159
 cleanup:
14160 14161 14162 14163
    xmlXPathFreeContext(ctxt);
    return obj;
}

H
Hu Tao 已提交
14164

14165
static virDomainObjPtr
14166 14167
virDomainObjParseFile(const char *filename,
                      virCapsPtr caps,
14168
                      virDomainXMLOptionPtr xmlopt,
14169 14170
                      unsigned int expectedVirtTypes,
                      unsigned int flags)
H
Hu Tao 已提交
14171 14172 14173
{
    xmlDocPtr xml;
    virDomainObjPtr obj = NULL;
14174
    int keepBlanksDefault = xmlKeepBlanksDefault(0);
H
Hu Tao 已提交
14175 14176

    if ((xml = virXMLParseFile(filename))) {
14177 14178
        obj = virDomainObjParseNode(xml, xmlDocGetRootElement(xml),
                                    caps, xmlopt,
M
Matthias Bolte 已提交
14179
                                    expectedVirtTypes, flags);
H
Hu Tao 已提交
14180 14181 14182
        xmlFreeDoc(xml);
    }

14183
    xmlKeepBlanksDefault(keepBlanksDefault);
H
Hu Tao 已提交
14184 14185 14186 14187
    return obj;
}


14188 14189 14190
static bool
virDomainTimerDefCheckABIStability(virDomainTimerDefPtr src,
                                   virDomainTimerDefPtr dst)
14191 14192
{
    if (src->name != dst->name) {
14193 14194 14195 14196
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target timer %s does not match source %s"),
                       virDomainTimerNameTypeToString(dst->name),
                       virDomainTimerNameTypeToString(src->name));
14197
        return false;
14198 14199 14200
    }

    if (src->present != dst->present) {
14201 14202 14203
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target timer presence %d does not match source %d"),
                       dst->present, src->present);
14204
        return false;
14205 14206 14207 14208
    }

    if (src->name == VIR_DOMAIN_TIMER_NAME_TSC) {
        if (src->frequency != dst->frequency) {
14209 14210 14211
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Target TSC frequency %lu does not match source %lu"),
                           dst->frequency, src->frequency);
14212
            return false;
14213 14214 14215
        }

        if (src->mode != dst->mode) {
14216 14217 14218 14219
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Target TSC mode %s does not match source %s"),
                           virDomainTimerModeTypeToString(dst->mode),
                           virDomainTimerModeTypeToString(src->mode));
14220
            return false;
14221 14222 14223
        }
    }

14224
    return true;
14225 14226 14227
}


14228 14229 14230
static bool
virDomainDeviceInfoCheckABIStability(virDomainDeviceInfoPtr src,
                                     virDomainDeviceInfoPtr dst)
14231 14232
{
    if (src->type != dst->type) {
14233 14234 14235 14236
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target device address type %s does not match source %s"),
                       virDomainDeviceAddressTypeToString(dst->type),
                       virDomainDeviceAddressTypeToString(src->type));
14237
        return false;
14238 14239
    }

14240
    switch ((virDomainDeviceAddressType) src->type) {
14241 14242 14243 14244 14245
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI:
        if (src->addr.pci.domain != dst->addr.pci.domain ||
            src->addr.pci.bus != dst->addr.pci.bus ||
            src->addr.pci.slot != dst->addr.pci.slot ||
            src->addr.pci.function != dst->addr.pci.function) {
14246
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
14247 14248
                           _("Target device PCI address %04x:%02x:%02x.%02x "
                             "does not match source %04x:%02x:%02x.%02x"),
14249 14250 14251 14252
                           dst->addr.pci.domain, dst->addr.pci.bus,
                           dst->addr.pci.slot, dst->addr.pci.function,
                           src->addr.pci.domain, src->addr.pci.bus,
                           src->addr.pci.slot, src->addr.pci.function);
14253
            return false;
14254 14255 14256 14257 14258 14259 14260
        }
        break;

    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE:
        if (src->addr.drive.controller != dst->addr.drive.controller ||
            src->addr.drive.bus != dst->addr.drive.bus ||
            src->addr.drive.unit != dst->addr.drive.unit) {
14261
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
14262 14263
                           _("Target device drive address %d:%d:%d "
                             "does not match source %d:%d:%d"),
14264 14265 14266 14267
                           dst->addr.drive.controller, dst->addr.drive.bus,
                           dst->addr.drive.unit,
                           src->addr.drive.controller, src->addr.drive.bus,
                           src->addr.drive.unit);
14268
            return false;
14269 14270 14271 14272 14273 14274 14275
        }
        break;

    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL:
        if (src->addr.vioserial.controller != dst->addr.vioserial.controller ||
            src->addr.vioserial.bus != dst->addr.vioserial.bus ||
            src->addr.vioserial.port != dst->addr.vioserial.port) {
14276
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
14277 14278
                           _("Target device virtio serial address %d:%d:%d "
                             "does not match source %d:%d:%d"),
14279 14280 14281 14282
                           dst->addr.vioserial.controller, dst->addr.vioserial.bus,
                           dst->addr.vioserial.port,
                           src->addr.vioserial.controller, src->addr.vioserial.bus,
                           src->addr.vioserial.port);
14283
            return false;
14284 14285 14286 14287 14288 14289
        }
        break;

    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCID:
        if (src->addr.ccid.controller != dst->addr.ccid.controller ||
            src->addr.ccid.slot != dst->addr.ccid.slot) {
14290
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
14291 14292
                           _("Target device ccid address %d:%d "
                             "does not match source %d:%d"),
14293 14294 14295 14296
                           dst->addr.ccid.controller,
                           dst->addr.ccid.slot,
                           src->addr.ccid.controller,
                           src->addr.ccid.slot);
14297
            return false;
14298 14299
        }
        break;
H
Hu Tao 已提交
14300 14301 14302 14303 14304 14305 14306 14307 14308 14309 14310 14311 14312 14313

    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_ISA:
        if (src->addr.isa.iobase != dst->addr.isa.iobase ||
            src->addr.isa.irq != dst->addr.isa.irq) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Target device isa address %d:%d "
                             "does not match source %d:%d"),
                           dst->addr.isa.iobase,
                           dst->addr.isa.irq,
                           src->addr.isa.iobase,
                           src->addr.isa.irq);
            return false;
        }
        break;
14314 14315 14316 14317 14318 14319 14320 14321 14322

    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB:
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO:
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390:
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW:
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO:
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE:
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST:
        break;
14323 14324
    }

14325
    return true;
14326 14327 14328
}


14329 14330 14331
static bool
virDomainDiskDefCheckABIStability(virDomainDiskDefPtr src,
                                  virDomainDiskDefPtr dst)
14332 14333
{
    if (src->device != dst->device) {
14334 14335 14336 14337
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target disk device %s does not match source %s"),
                       virDomainDiskDeviceTypeToString(dst->device),
                       virDomainDiskDeviceTypeToString(src->device));
14338
        return false;
14339 14340 14341
    }

    if (src->bus != dst->bus) {
14342 14343 14344 14345
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target disk bus %s does not match source %s"),
                       virDomainDiskBusTypeToString(dst->bus),
                       virDomainDiskBusTypeToString(src->bus));
14346
        return false;
14347 14348 14349
    }

    if (STRNEQ(src->dst, dst->dst)) {
14350 14351 14352
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target disk %s does not match source %s"),
                       dst->dst, src->dst);
14353
        return false;
14354 14355 14356
    }

    if (STRNEQ_NULLABLE(src->serial, dst->serial)) {
14357 14358 14359
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target disk serial %s does not match source %s"),
                       NULLSTR(dst->serial), NULLSTR(src->serial));
14360
        return false;
14361 14362
    }

14363 14364
    if (src->src->readonly != dst->src->readonly ||
        src->src->shared != dst->src->shared) {
14365 14366
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Target disk access mode does not match source"));
14367
        return false;
14368 14369 14370
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
14371
        return false;
14372

14373
    return true;
14374 14375 14376
}


14377 14378 14379
static bool
virDomainControllerDefCheckABIStability(virDomainControllerDefPtr src,
                                        virDomainControllerDefPtr dst)
14380 14381
{
    if (src->type != dst->type) {
14382 14383 14384 14385
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target controller type %s does not match source %s"),
                       virDomainControllerTypeToString(dst->type),
                       virDomainControllerTypeToString(src->type));
14386
        return false;
14387 14388 14389
    }

    if (src->idx != dst->idx) {
14390 14391 14392
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target controller index %d does not match source %d"),
                       dst->idx, src->idx);
14393
        return false;
14394 14395 14396
    }

    if (src->model != dst->model) {
14397 14398 14399
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target controller model %d does not match source %d"),
                       dst->model, src->model);
14400
        return false;
14401 14402 14403 14404
    }

    if (src->type == VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL) {
        if (src->opts.vioserial.ports != dst->opts.vioserial.ports) {
14405 14406 14407
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Target controller ports %d does not match source %d"),
                           dst->opts.vioserial.ports, src->opts.vioserial.ports);
14408
            return false;
14409 14410 14411
        }

        if (src->opts.vioserial.vectors != dst->opts.vioserial.vectors) {
14412 14413 14414
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Target controller vectors %d does not match source %d"),
                           dst->opts.vioserial.vectors, src->opts.vioserial.vectors);
14415
            return false;
14416 14417 14418 14419
        }
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
14420
        return false;
14421

14422
    return true;
14423 14424 14425
}


14426 14427 14428
static bool
virDomainFsDefCheckABIStability(virDomainFSDefPtr src,
                                virDomainFSDefPtr dst)
14429 14430
{
    if (STRNEQ(src->dst, dst->dst)) {
14431 14432 14433
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target filesystem guest target %s does not match source %s"),
                       dst->dst, src->dst);
14434
        return false;
14435 14436 14437
    }

    if (src->readonly != dst->readonly) {
14438 14439
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Target filesystem access mode does not match source"));
14440
        return false;
14441 14442 14443
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
14444
        return false;
14445

14446
    return true;
14447 14448 14449
}


14450 14451 14452
static bool
virDomainNetDefCheckABIStability(virDomainNetDefPtr src,
                                 virDomainNetDefPtr dst)
14453
{
14454 14455 14456
    char srcmac[VIR_MAC_STRING_BUFLEN];
    char dstmac[VIR_MAC_STRING_BUFLEN];

14457
    if (virMacAddrCmp(&src->mac, &dst->mac) != 0) {
14458
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
14459 14460 14461 14462
                       _("Target network card mac %s"
                         " does not match source %s"),
                       virMacAddrFormat(&dst->mac, dstmac),
                       virMacAddrFormat(&src->mac, srcmac));
14463
        return false;
14464 14465 14466
    }

    if (STRNEQ_NULLABLE(src->model, dst->model)) {
14467 14468 14469
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target network card model %s does not match source %s"),
                       NULLSTR(dst->model), NULLSTR(src->model));
14470
        return false;
14471 14472 14473
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
14474
        return false;
14475

14476
    return true;
14477 14478 14479
}


14480 14481 14482
static bool
virDomainInputDefCheckABIStability(virDomainInputDefPtr src,
                                   virDomainInputDefPtr dst)
14483 14484
{
    if (src->type != dst->type) {
14485 14486 14487 14488
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target input device type %s does not match source %s"),
                       virDomainInputTypeToString(dst->type),
                       virDomainInputTypeToString(src->type));
14489
        return false;
14490 14491 14492
    }

    if (src->bus != dst->bus) {
14493 14494 14495 14496
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target input device bus %s does not match source %s"),
                       virDomainInputBusTypeToString(dst->bus),
                       virDomainInputBusTypeToString(src->bus));
14497
        return false;
14498 14499 14500
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
14501
        return false;
14502

14503
    return true;
14504 14505 14506
}


14507 14508 14509
static bool
virDomainSoundDefCheckABIStability(virDomainSoundDefPtr src,
                                   virDomainSoundDefPtr dst)
14510 14511
{
    if (src->model != dst->model) {
14512 14513 14514 14515
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target sound card model %s does not match source %s"),
                       virDomainSoundModelTypeToString(dst->model),
                       virDomainSoundModelTypeToString(src->model));
14516
        return false;
14517 14518 14519
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
14520
        return false;
14521

14522
    return true;
14523 14524 14525
}


14526 14527 14528
static bool
virDomainVideoDefCheckABIStability(virDomainVideoDefPtr src,
                                   virDomainVideoDefPtr dst)
14529 14530
{
    if (src->type != dst->type) {
14531 14532 14533 14534
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target video card model %s does not match source %s"),
                       virDomainVideoTypeToString(dst->type),
                       virDomainVideoTypeToString(src->type));
14535
        return false;
14536 14537
    }

14538 14539 14540 14541 14542 14543 14544
    if (src->ram != dst->ram) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target video card ram %u does not match source %u"),
                       dst->ram, src->ram);
        return false;
    }

14545
    if (src->vram != dst->vram) {
14546 14547 14548
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target video card vram %u does not match source %u"),
                       dst->vram, src->vram);
14549
        return false;
14550 14551 14552
    }

    if (src->heads != dst->heads) {
14553 14554 14555
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target video card heads %u does not match source %u"),
                       dst->heads, src->heads);
14556
        return false;
14557 14558 14559 14560
    }

    if ((src->accel && !dst->accel) ||
        (!src->accel && dst->accel)) {
14561 14562
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Target video card acceleration does not match source"));
14563
        return false;
14564 14565 14566 14567
    }

    if (src->accel) {
        if (src->accel->support2d != dst->accel->support2d) {
14568 14569 14570
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Target video card 2d accel %u does not match source %u"),
                           dst->accel->support2d, src->accel->support2d);
14571
            return false;
14572 14573 14574
        }

        if (src->accel->support3d != dst->accel->support3d) {
14575 14576 14577
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Target video card 3d accel %u does not match source %u"),
                           dst->accel->support3d, src->accel->support3d);
14578
            return false;
14579 14580 14581 14582
        }
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
14583
        return false;
14584

14585
    return true;
14586 14587 14588
}


14589 14590 14591
static bool
virDomainHostdevDefCheckABIStability(virDomainHostdevDefPtr src,
                                     virDomainHostdevDefPtr dst)
14592 14593
{
    if (src->mode != dst->mode) {
14594 14595 14596 14597
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target host device mode %s does not match source %s"),
                       virDomainHostdevModeTypeToString(dst->mode),
                       virDomainHostdevModeTypeToString(src->mode));
14598
        return false;
14599 14600
    }

14601 14602 14603 14604 14605 14606 14607
    if (src->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
        src->source.subsys.type != dst->source.subsys.type) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target host device subsystem %s does not match source %s"),
                       virDomainHostdevSubsysTypeToString(dst->source.subsys.type),
                       virDomainHostdevSubsysTypeToString(src->source.subsys.type));
        return false;
14608 14609
    }

14610
    if (!virDomainDeviceInfoCheckABIStability(src->info, dst->info))
14611
        return false;
14612

14613
    return true;
14614 14615 14616
}


14617 14618 14619
static bool
virDomainSmartcardDefCheckABIStability(virDomainSmartcardDefPtr src,
                                       virDomainSmartcardDefPtr dst)
14620 14621
{
    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
14622
        return false;
14623

14624
    return true;
14625 14626 14627
}


14628 14629 14630
static bool
virDomainSerialDefCheckABIStability(virDomainChrDefPtr src,
                                    virDomainChrDefPtr dst)
14631 14632
{
    if (src->target.port != dst->target.port) {
14633 14634 14635
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target serial port %d does not match source %d"),
                       dst->target.port, src->target.port);
14636
        return false;
14637 14638 14639
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
14640
        return false;
14641

14642
    return true;
14643 14644 14645
}


14646 14647 14648
static bool
virDomainParallelDefCheckABIStability(virDomainChrDefPtr src,
                                      virDomainChrDefPtr dst)
14649 14650
{
    if (src->target.port != dst->target.port) {
14651
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
14652
                       _("Target parallel port %d does not match source %d"),
14653
                       dst->target.port, src->target.port);
14654
        return false;
14655 14656 14657
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
14658
        return false;
14659

14660
    return true;
14661 14662 14663
}


14664 14665 14666
static bool
virDomainChannelDefCheckABIStability(virDomainChrDefPtr src,
                                     virDomainChrDefPtr dst)
14667 14668
{
    if (src->targetType != dst->targetType) {
14669 14670 14671 14672
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target channel type %s does not match source %s"),
                       virDomainChrChannelTargetTypeToString(dst->targetType),
                       virDomainChrChannelTargetTypeToString(src->targetType));
14673
        return false;
14674 14675 14676 14677
    }

    switch (src->targetType) {
    case VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO:
14678
        if (STRNEQ_NULLABLE(src->target.name, dst->target.name)) {
14679 14680 14681
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Target channel name %s does not match source %s"),
                           NULLSTR(dst->target.name), NULLSTR(src->target.name));
14682
            return false;
14683
        }
14684 14685 14686 14687 14688 14689 14690
        if (src->source.type != dst->source.type &&
            (src->source.type == VIR_DOMAIN_CHR_TYPE_SPICEVMC ||
             dst->source.type == VIR_DOMAIN_CHR_TYPE_SPICEVMC) &&
            !src->target.name) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("Changing device type to/from spicevmc would"
                             " change default target channel name"));
14691
            return false;
14692
        }
14693 14694
        break;
    case VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_GUESTFWD:
E
Eric Blake 已提交
14695 14696
        if (memcmp(src->target.addr, dst->target.addr,
                   sizeof(*src->target.addr)) != 0) {
14697 14698
            char *saddr = virSocketAddrFormatFull(src->target.addr, true, ":");
            char *daddr = virSocketAddrFormatFull(dst->target.addr, true, ":");
14699 14700 14701
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Target channel addr %s does not match source %s"),
                           NULLSTR(daddr), NULLSTR(saddr));
14702 14703
            VIR_FREE(saddr);
            VIR_FREE(daddr);
14704
            return false;
14705 14706 14707 14708 14709
        }
        break;
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
14710
        return false;
14711

14712
    return true;
14713 14714 14715
}


14716 14717 14718
static bool
virDomainConsoleDefCheckABIStability(virDomainChrDefPtr src,
                                     virDomainChrDefPtr dst)
14719 14720
{
    if (src->targetType != dst->targetType) {
14721 14722 14723 14724
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target console type %s does not match source %s"),
                       virDomainChrConsoleTargetTypeToString(dst->targetType),
                       virDomainChrConsoleTargetTypeToString(src->targetType));
14725
        return false;
14726 14727 14728
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
14729
        return false;
14730

14731
    return true;
14732 14733 14734
}


14735 14736 14737
static bool
virDomainWatchdogDefCheckABIStability(virDomainWatchdogDefPtr src,
                                      virDomainWatchdogDefPtr dst)
14738 14739
{
    if (src->model != dst->model) {
14740 14741 14742 14743
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target watchdog model %s does not match source %s"),
                       virDomainWatchdogModelTypeToString(dst->model),
                       virDomainWatchdogModelTypeToString(src->model));
14744
        return false;
14745 14746 14747
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
14748
        return false;
14749

14750
    return true;
14751 14752 14753
}


14754 14755 14756
static bool
virDomainMemballoonDefCheckABIStability(virDomainMemballoonDefPtr src,
                                        virDomainMemballoonDefPtr dst)
14757 14758
{
    if (src->model != dst->model) {
14759 14760 14761 14762
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target balloon model %s does not match source %s"),
                       virDomainMemballoonModelTypeToString(dst->model),
                       virDomainMemballoonModelTypeToString(src->model));
14763
        return false;
14764 14765 14766
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
14767
        return false;
14768

14769
    return true;
14770 14771 14772
}


14773 14774 14775 14776 14777 14778 14779 14780 14781 14782 14783 14784 14785 14786 14787 14788 14789 14790 14791
static bool
virDomainRNGDefCheckABIStability(virDomainRNGDefPtr src,
                                 virDomainRNGDefPtr dst)
{
    if (src->model != dst->model) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target RNG model '%s' does not match source '%s'"),
                       virDomainRNGModelTypeToString(dst->model),
                       virDomainRNGModelTypeToString(src->model));
        return false;
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
        return false;

    return true;
}


14792 14793 14794
static bool
virDomainHubDefCheckABIStability(virDomainHubDefPtr src,
                                 virDomainHubDefPtr dst)
M
Marc-André Lureau 已提交
14795 14796
{
    if (src->type != dst->type) {
14797 14798 14799 14800
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target hub device type %s does not match source %s"),
                       virDomainHubTypeToString(dst->type),
                       virDomainHubTypeToString(src->type));
14801
        return false;
M
Marc-André Lureau 已提交
14802 14803 14804
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
14805
        return false;
M
Marc-André Lureau 已提交
14806

14807
    return true;
M
Marc-André Lureau 已提交
14808 14809
}

14810 14811 14812 14813 14814 14815 14816 14817 14818 14819 14820 14821 14822 14823

static bool
virDomainRedirdevDefCheckABIStability(virDomainRedirdevDefPtr src,
                                      virDomainRedirdevDefPtr dst)
{
    if (src->bus != dst->bus) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target redirected device bus %s does not match "
                         "source %s"),
                       virDomainRedirdevBusTypeToString(dst->bus),
                       virDomainRedirdevBusTypeToString(src->bus));
        return false;
    }

14824
    switch ((virDomainRedirdevBus) src->bus) {
14825 14826 14827 14828 14829 14830 14831 14832 14833 14834 14835 14836 14837 14838 14839 14840 14841 14842 14843 14844 14845
    case VIR_DOMAIN_REDIRDEV_BUS_USB:
        if (src->source.chr.type != dst->source.chr.type) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Target redirected device source type %s does "
                             "not match source device source type %s"),
                           virDomainChrTypeToString(dst->source.chr.type),
                           virDomainChrTypeToString(src->source.chr.type));
            return false;
        }
        break;
    case VIR_DOMAIN_REDIRDEV_BUS_LAST:
        break;
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
        return false;

    return true;
}


14846 14847 14848 14849
static bool
virDomainRedirFilterDefCheckABIStability(virDomainRedirFilterDefPtr src,
                                         virDomainRedirFilterDefPtr dst)
{
14850
    size_t i;
14851 14852 14853 14854 14855 14856

    if (src->nusbdevs != dst->nusbdevs) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target USB redirection filter rule "
                         "count %zu does not match source %zu"),
                         dst->nusbdevs, src->nusbdevs);
14857
        return false;
14858 14859 14860
    }

    for (i = 0; i < src->nusbdevs; i++) {
14861 14862 14863
        virDomainRedirFilterUSBDevDefPtr srcUSBDev = src->usbdevs[i];
        virDomainRedirFilterUSBDevDefPtr dstUSBDev = dst->usbdevs[i];
        if (srcUSBDev->usbClass != dstUSBDev->usbClass) {
14864 14865
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           "%s", _("Target USB Class code does not match source"));
14866
            return false;
14867 14868
        }

14869
        if (srcUSBDev->vendor != dstUSBDev->vendor) {
14870 14871
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           "%s", _("Target USB vendor ID does not match source"));
14872
            return false;
14873 14874
        }

14875
        if (srcUSBDev->product != dstUSBDev->product) {
14876 14877
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           "%s", _("Target USB product ID does not match source"));
14878
            return false;
14879 14880
        }

14881
        if (srcUSBDev->version != dstUSBDev->version) {
14882 14883
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           "%s", _("Target USB version does not match source"));
14884
            return false;
14885 14886
        }

14887
        if (srcUSBDev->allow != dstUSBDev->allow) {
14888 14889
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Target USB allow '%s' does not match source '%s'"),
14890 14891
                             dstUSBDev->allow ? "yes" : "no",
                             srcUSBDev->allow ? "yes" : "no");
14892
            return false;
14893 14894 14895
        }
    }

14896
    return true;
14897
}
M
Marc-André Lureau 已提交
14898

14899 14900 14901 14902 14903 14904 14905

static bool
virDomainDefFeaturesCheckABIStability(virDomainDefPtr src,
                                      virDomainDefPtr dst)
{
    size_t i;

14906 14907 14908 14909 14910 14911
    for (i = 0; i < VIR_DOMAIN_FEATURE_LAST; i++) {
        if (src->features[i] != dst->features[i]) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("State of feature '%s' differs: "
                             "source: '%s', destination: '%s'"),
                           virDomainFeatureTypeToString(i),
J
Ján Tomko 已提交
14912 14913
                           virTristateSwitchTypeToString(src->features[i]),
                           virTristateSwitchTypeToString(dst->features[i]));
14914 14915
            return false;
        }
14916 14917 14918 14919 14920 14921 14922
    }

    /* APIC EOI */
    if (src->apic_eoi != dst->apic_eoi) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("State of APIC EOI differs: "
                         "source: '%s', destination: '%s'"),
J
Ján Tomko 已提交
14923 14924
                       virTristateSwitchTypeToString(src->apic_eoi),
                       virTristateSwitchTypeToString(dst->apic_eoi));
14925 14926 14927 14928
        return false;
    }

    /* hyperv */
J
Ján Tomko 已提交
14929
    if (src->features[VIR_DOMAIN_FEATURE_HYPERV] == VIR_TRISTATE_SWITCH_ON) {
14930
        for (i = 0; i < VIR_DOMAIN_HYPERV_LAST; i++) {
14931
            switch ((virDomainHyperv) i) {
14932 14933 14934 14935 14936 14937 14938 14939
            case VIR_DOMAIN_HYPERV_RELAXED:
            case VIR_DOMAIN_HYPERV_VAPIC:
                if (src->hyperv_features[i] != dst->hyperv_features[i]) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("State of HyperV enlightenment "
                                     "feature '%s' differs: "
                                     "source: '%s', destination: '%s'"),
                                   virDomainHypervTypeToString(i),
J
Ján Tomko 已提交
14940 14941
                                   virTristateSwitchTypeToString(src->hyperv_features[i]),
                                   virTristateSwitchTypeToString(dst->hyperv_features[i]));
14942 14943 14944 14945 14946 14947 14948 14949 14950 14951 14952 14953 14954 14955 14956 14957 14958
                    return false;
                }

                break;

            case VIR_DOMAIN_HYPERV_SPINLOCKS:
                /* spinlock count matters! */
                if (src->hyperv_spinlocks != dst->hyperv_spinlocks) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("HyperV spinlock retry count differs: "
                                     "source: '%u', destination: '%u'"),
                                   src->hyperv_spinlocks,
                                   dst->hyperv_spinlocks);
                    return false;
                }
                break;

14959
            /* coverity[dead_error_begin] */
14960 14961 14962 14963 14964 14965
            case VIR_DOMAIN_HYPERV_LAST:
                break;
            }
        }
    }

14966 14967 14968 14969 14970 14971 14972 14973 14974 14975 14976 14977 14978 14979 14980 14981 14982
    /* kvm */
    if (src->features[VIR_DOMAIN_FEATURE_KVM] == VIR_TRISTATE_SWITCH_ON) {
        for (i = 0; i < VIR_DOMAIN_KVM_LAST; i++) {
            switch ((virDomainKVM) i) {
            case VIR_DOMAIN_KVM_HIDDEN:
                if (src->kvm_features[i] != dst->kvm_features[i]) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("State of KVM feature '%s' differs: "
                                     "source: '%s', destination: '%s'"),
                                   virDomainKVMTypeToString(i),
                                   virTristateSwitchTypeToString(src->kvm_features[i]),
                                   virTristateSwitchTypeToString(dst->kvm_features[i]));
                    return false;
                }

                break;

14983
            /* coverity[dead_error_begin] */
14984 14985 14986 14987 14988 14989
            case VIR_DOMAIN_KVM_LAST:
                break;
            }
        }
    }

14990 14991 14992
    return true;
}

H
Hu Tao 已提交
14993 14994 14995 14996
static bool
virDomainPanicCheckABIStability(virDomainPanicDefPtr src,
                                virDomainPanicDefPtr dst)
{
14997 14998 14999 15000 15001 15002 15003 15004 15005 15006 15007
    if (!src && !dst)
        return true;

    if (!src || !dst) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target domain panic device count '%d' "
                         "does not match source count '%d'"),
                       src ? 1 : 0, dst ? 1 : 0);
        return false;
    }

H
Hu Tao 已提交
15008 15009 15010
    return virDomainDeviceInfoCheckABIStability(&src->info, &dst->info);
}

15011

15012 15013 15014 15015 15016 15017 15018 15019 15020 15021 15022 15023 15024 15025 15026 15027 15028 15029 15030 15031 15032 15033 15034 15035 15036 15037 15038 15039 15040 15041 15042 15043 15044 15045 15046 15047 15048 15049
static bool
virDomainShmemDefCheckABIStability(virDomainShmemDefPtr src,
                                   virDomainShmemDefPtr dst)
{
    if (STRNEQ_NULLABLE(src->name, dst->name)) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target shared memory name '%s' does not match source "
                         "'%s'"), dst->name, src->name);
        return false;
    }

    if (src->size != dst->size) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target shared memory size '%llu' does not match "
                         "source size '%llu'"), dst->size, src->size);
        return false;
    }

    if (src->server.enabled != dst->server.enabled) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Target shared memory server usage doesn't match "
                         "source"));
        return false;
    }

    if (src->msi.vectors != dst->msi.vectors ||
        src->msi.enabled != dst->msi.enabled ||
        src->msi.ioeventfd != dst->msi.ioeventfd) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Target shared memory MSI configuration doesn't match "
                         "source"));
        return false;
    }

    return virDomainDeviceInfoCheckABIStability(&src->info, &dst->info);
}


15050 15051 15052 15053
/* This compares two configurations and looks for any differences
 * which will affect the guest ABI. This is primarily to allow
 * validation of custom XML config passed in during migration
 */
15054 15055 15056
bool
virDomainDefCheckABIStability(virDomainDefPtr src,
                              virDomainDefPtr dst)
15057
{
15058
    size_t i;
15059 15060 15061
    virErrorPtr err;
    char *strSrc;
    char *strDst;
15062 15063

    if (src->virtType != dst->virtType) {
15064 15065 15066 15067
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target domain virt type %s does not match source %s"),
                       virDomainVirtTypeToString(dst->virtType),
                       virDomainVirtTypeToString(src->virtType));
15068
        goto error;
15069 15070 15071 15072 15073 15074 15075
    }

    if (memcmp(src->uuid, dst->uuid, VIR_UUID_BUFLEN) != 0) {
        char uuidsrc[VIR_UUID_STRING_BUFLEN];
        char uuiddst[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(src->uuid, uuidsrc);
        virUUIDFormat(dst->uuid, uuiddst);
15076 15077 15078
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target domain uuid %s does not match source %s"),
                       uuiddst, uuidsrc);
15079
        goto error;
15080 15081
    }

15082 15083 15084 15085
    /* Not strictly ABI related, but we want to make sure domains
     * don't get silently re-named through the backdoor when passing
     * custom XML into various APIs, since this would create havoc
     */
15086
    if (STRNEQ_NULLABLE(src->name, dst->name)) {
15087 15088 15089
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target domain name '%s' does not match source '%s'"),
                       dst->name, src->name);
15090
        goto error;
15091 15092
    }

15093
    if (src->mem.max_balloon != dst->mem.max_balloon) {
15094 15095 15096
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target domain max memory %lld does not match source %lld"),
                       dst->mem.max_balloon, src->mem.max_balloon);
15097
        goto error;
15098 15099
    }
    if (src->mem.cur_balloon != dst->mem.cur_balloon) {
15100 15101 15102
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target domain current memory %lld does not match source %lld"),
                       dst->mem.cur_balloon, src->mem.cur_balloon);
15103
        goto error;
15104
    }
15105
    if (src->mem.nhugepages != dst->mem.nhugepages) {
15106
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
15107 15108
                       _("Target domain huge pages count %zu does not match source %zu"),
                       dst->mem.nhugepages, src->mem.nhugepages);
15109
        goto error;
15110
    }
15111 15112 15113 15114 15115 15116 15117 15118 15119 15120 15121 15122 15123 15124 15125 15126 15127 15128 15129 15130 15131 15132 15133 15134 15135 15136
    for (i = 0; i < src->mem.nhugepages; i++) {
        virDomainHugePagePtr src_huge = &src->mem.hugepages[i];
        virDomainHugePagePtr dst_huge = &dst->mem.hugepages[i];

        if (src_huge->size != dst_huge->size) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Target domain huge page size %llu "
                             "does not match source %llu"),
                           dst_huge->size, src_huge->size);
            goto error;
        }

        if (src_huge->nodemask && dst_huge->nodemask) {
            if (!virBitmapEqual(src_huge->nodemask, dst_huge->nodemask)) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                               _("Target huge page nodemask does not match source"));
                goto error;
            }
        } else {
            if (src_huge->nodemask || dst_huge->nodemask) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                               _("Target huge page nodemask does not match source"));
                goto error;
            }
        }
    }
15137

15138
    if (src->vcpus != dst->vcpus) {
15139
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
15140
                       _("Target domain vCPU count %d does not match source %d"),
15141
                       dst->vcpus, src->vcpus);
15142
        goto error;
15143 15144
    }
    if (src->maxvcpus != dst->maxvcpus) {
15145
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
15146
                       _("Target domain vCPU max %d does not match source %d"),
15147
                       dst->maxvcpus, src->maxvcpus);
15148
        goto error;
15149 15150
    }

15151 15152 15153 15154 15155 15156 15157 15158
    if (src->iothreads != dst->iothreads) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target domain iothreads count %u does not "
                         "match source %u"),
                       dst->iothreads, src->iothreads);
        goto error;
    }

15159
    if (STRNEQ(src->os.type, dst->os.type)) {
15160 15161 15162
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target domain OS type %s does not match source %s"),
                       dst->os.type, src->os.type);
15163
        goto error;
15164
    }
15165
    if (src->os.arch != dst->os.arch) {
15166 15167
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target domain architecture %s does not match source %s"),
15168 15169
                       virArchToString(dst->os.arch),
                       virArchToString(src->os.arch));
15170
        goto error;
15171
    }
15172
    if (STRNEQ_NULLABLE(src->os.machine, dst->os.machine)) {
15173 15174 15175
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target domain OS type %s does not match source %s"),
                       dst->os.machine, src->os.machine);
15176
        goto error;
15177 15178 15179
    }

    if (src->os.smbios_mode != dst->os.smbios_mode) {
15180 15181 15182 15183
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target domain SMBIOS mode %s does not match source %s"),
                       virDomainSmbiosModeTypeToString(dst->os.smbios_mode),
                       virDomainSmbiosModeTypeToString(src->os.smbios_mode));
15184
        goto error;
15185 15186
    }

15187
    if (!virDomainDefFeaturesCheckABIStability(src, dst))
15188
        goto error;
15189 15190

    if (src->clock.ntimers != dst->clock.ntimers) {
15191 15192
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Target domain timers do not match source"));
15193
        goto error;
15194 15195
    }

15196
    for (i = 0; i < src->clock.ntimers; i++) {
15197 15198
        if (!virDomainTimerDefCheckABIStability(src->clock.timers[i],
                                                dst->clock.timers[i]))
15199
            goto error;
15200 15201 15202
    }

    if (!virCPUDefIsEqual(src->cpu, dst->cpu))
15203
        goto error;
15204 15205

    if (!virSysinfoIsEqual(src->sysinfo, dst->sysinfo))
15206
        goto error;
15207 15208

    if (src->ndisks != dst->ndisks) {
15209
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
15210
                       _("Target domain disk count %zu does not match source %zu"),
15211
                       dst->ndisks, src->ndisks);
15212
        goto error;
15213 15214
    }

15215
    for (i = 0; i < src->ndisks; i++)
15216
        if (!virDomainDiskDefCheckABIStability(src->disks[i], dst->disks[i]))
15217
            goto error;
15218 15219

    if (src->ncontrollers != dst->ncontrollers) {
15220
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
15221
                       _("Target domain controller count %zu "
15222
                         "does not match source %zu"),
15223
                       dst->ncontrollers, src->ncontrollers);
15224
        goto error;
15225 15226
    }

15227
    for (i = 0; i < src->ncontrollers; i++)
15228 15229
        if (!virDomainControllerDefCheckABIStability(src->controllers[i],
                                                     dst->controllers[i]))
15230
            goto error;
15231 15232

    if (src->nfss != dst->nfss) {
15233
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
15234 15235
                       _("Target domain filesystem count %zu "
                         "does not match source %zu"),
15236
                       dst->nfss, src->nfss);
15237
        goto error;
15238 15239
    }

15240
    for (i = 0; i < src->nfss; i++)
15241
        if (!virDomainFsDefCheckABIStability(src->fss[i], dst->fss[i]))
15242
            goto error;
15243 15244

    if (src->nnets != dst->nnets) {
15245
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
15246 15247
                       _("Target domain net card count %zu "
                         "does not match source %zu"),
15248
                       dst->nnets, src->nnets);
15249
        goto error;
15250 15251
    }

15252
    for (i = 0; i < src->nnets; i++)
15253
        if (!virDomainNetDefCheckABIStability(src->nets[i], dst->nets[i]))
15254
            goto error;
15255 15256

    if (src->ninputs != dst->ninputs) {
15257
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
15258 15259
                       _("Target domain input device count %zu "
                         "does not match source %zu"),
15260
                       dst->ninputs, src->ninputs);
15261
        goto error;
15262 15263
    }

15264
    for (i = 0; i < src->ninputs; i++)
15265
        if (!virDomainInputDefCheckABIStability(src->inputs[i], dst->inputs[i]))
15266
            goto error;
15267 15268

    if (src->nsounds != dst->nsounds) {
15269
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
15270 15271
                       _("Target domain sound card count %zu "
                         "does not match source %zu"),
15272
                       dst->nsounds, src->nsounds);
15273
        goto error;
15274 15275
    }

15276
    for (i = 0; i < src->nsounds; i++)
15277
        if (!virDomainSoundDefCheckABIStability(src->sounds[i], dst->sounds[i]))
15278
            goto error;
15279 15280

    if (src->nvideos != dst->nvideos) {
15281
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
15282 15283
                       _("Target domain video card count %zu "
                         "does not match source %zu"),
15284
                       dst->nvideos, src->nvideos);
15285
        goto error;
15286 15287
    }

15288
    for (i = 0; i < src->nvideos; i++)
15289
        if (!virDomainVideoDefCheckABIStability(src->videos[i], dst->videos[i]))
15290
            goto error;
15291 15292

    if (src->nhostdevs != dst->nhostdevs) {
15293
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
15294 15295
                       _("Target domain host device count %zu "
                         "does not match source %zu"),
15296
                       dst->nhostdevs, src->nhostdevs);
15297
        goto error;
15298 15299
    }

15300
    for (i = 0; i < src->nhostdevs; i++)
15301 15302
        if (!virDomainHostdevDefCheckABIStability(src->hostdevs[i],
                                                  dst->hostdevs[i]))
15303
            goto error;
15304 15305

    if (src->nsmartcards != dst->nsmartcards) {
15306
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
15307 15308
                       _("Target domain smartcard count %zu "
                         "does not match source %zu"),
15309
                       dst->nsmartcards, src->nsmartcards);
15310
        goto error;
15311 15312
    }

15313
    for (i = 0; i < src->nsmartcards; i++)
15314 15315
        if (!virDomainSmartcardDefCheckABIStability(src->smartcards[i],
                                                    dst->smartcards[i]))
15316
            goto error;
15317 15318

    if (src->nserials != dst->nserials) {
15319
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
15320 15321
                       _("Target domain serial port count %zu "
                         "does not match source %zu"),
15322
                       dst->nserials, src->nserials);
15323
        goto error;
15324 15325
    }

15326
    for (i = 0; i < src->nserials; i++)
15327 15328
        if (!virDomainSerialDefCheckABIStability(src->serials[i],
                                                 dst->serials[i]))
15329
            goto error;
15330 15331

    if (src->nparallels != dst->nparallels) {
15332
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
15333 15334
                       _("Target domain parallel port count %zu "
                         "does not match source %zu"),
15335
                       dst->nparallels, src->nparallels);
15336
        goto error;
15337 15338
    }

15339
    for (i = 0; i < src->nparallels; i++)
15340 15341
        if (!virDomainParallelDefCheckABIStability(src->parallels[i],
                                                   dst->parallels[i]))
15342
            goto error;
15343 15344

    if (src->nchannels != dst->nchannels) {
15345
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
15346 15347
                       _("Target domain channel count %zu "
                         "does not match source %zu"),
15348
                       dst->nchannels, src->nchannels);
15349
        goto error;
15350 15351
    }

15352
    for (i = 0; i < src->nchannels; i++)
15353 15354
        if (!virDomainChannelDefCheckABIStability(src->channels[i],
                                                  dst->channels[i]))
15355
            goto error;
15356

15357
    if (src->nconsoles != dst->nconsoles) {
15358
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
15359 15360
                       _("Target domain console count %zu "
                         "does not match source %zu"),
15361
                       dst->nconsoles, src->nconsoles);
15362
        goto error;
15363 15364
    }

15365
    for (i = 0; i < src->nconsoles; i++)
15366 15367
        if (!virDomainConsoleDefCheckABIStability(src->consoles[i],
                                                  dst->consoles[i]))
15368
            goto error;
15369

M
Marc-André Lureau 已提交
15370
    if (src->nhubs != dst->nhubs) {
15371
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
15372 15373
                       _("Target domain hub device count %zu "
                         "does not match source %zu"),
15374
                       dst->nhubs, src->nhubs);
15375
        goto error;
M
Marc-André Lureau 已提交
15376 15377
    }

15378
    for (i = 0; i < src->nhubs; i++)
M
Marc-André Lureau 已提交
15379
        if (!virDomainHubDefCheckABIStability(src->hubs[i], dst->hubs[i]))
15380
            goto error;
M
Marc-André Lureau 已提交
15381

15382 15383 15384 15385
    if (src->nredirdevs != dst->nredirdevs) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target domain redirected devices count %zu "
                         "does not match source %zu"),
15386
                       dst->nredirdevs, src->nredirdevs);
15387 15388 15389 15390 15391 15392 15393 15394 15395
        goto error;
    }

    for (i = 0; i < src->nredirdevs; i++) {
        if (!virDomainRedirdevDefCheckABIStability(src->redirdevs[i],
                                                   dst->redirdevs[i]))
            goto error;
    }

15396 15397 15398
    if ((!src->redirfilter && dst->redirfilter) ||
        (src->redirfilter && !dst->redirfilter)) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
15399 15400
                       _("Target domain USB redirection filter count %d "
                         "does not match source %d"),
15401
                       dst->redirfilter ? 1 : 0, src->redirfilter ? 1 : 0);
15402
        goto error;
15403 15404 15405
    }

    if (src->redirfilter &&
15406 15407
        !virDomainRedirFilterDefCheckABIStability(src->redirfilter,
                                                  dst->redirfilter))
15408
        goto error;
15409 15410 15411

    if ((!src->watchdog && dst->watchdog) ||
        (src->watchdog && !dst->watchdog)) {
15412
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
15413 15414
                       _("Target domain watchdog count %d "
                         "does not match source %d"),
15415
                       dst->watchdog ? 1 : 0, src->watchdog ? 1 : 0);
15416
        goto error;
15417 15418 15419 15420
    }

    if (src->watchdog &&
        !virDomainWatchdogDefCheckABIStability(src->watchdog, dst->watchdog))
15421
        goto error;
15422 15423 15424

    if ((!src->memballoon && dst->memballoon) ||
        (src->memballoon && !dst->memballoon)) {
15425
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
15426 15427
                       _("Target domain memory balloon count %d "
                         "does not match source %d"),
15428
                       dst->memballoon ? 1 : 0, src->memballoon ? 1 : 0);
15429
        goto error;
15430 15431 15432
    }

    if (src->memballoon &&
15433 15434
        !virDomainMemballoonDefCheckABIStability(src->memballoon,
                                                 dst->memballoon))
15435
        goto error;
15436

15437 15438 15439 15440
    if (src->nrngs != dst->nrngs) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target domain RNG device count %zu "
                         "does not match source %zu"), dst->nrngs, src->nrngs);
15441
        goto error;
15442 15443 15444 15445 15446
    }

    for (i = 0; i < src->nrngs; i++)
        if (!virDomainRNGDefCheckABIStability(src->rngs[i], dst->rngs[i]))
            goto error;
15447

H
Hu Tao 已提交
15448
    if (!virDomainPanicCheckABIStability(src->panic, dst->panic))
15449
        goto error;
H
Hu Tao 已提交
15450

15451 15452 15453 15454 15455 15456 15457 15458 15459 15460 15461 15462
    if (src->nshmems != dst->nshmems) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target domain shared memory device count %zu "
                         "does not match source %zu"), dst->nshmems, src->nshmems);
        goto error;
    }

    for (i = 0; i < src->nshmems; i++) {
        if (!virDomainShmemDefCheckABIStability(src->shmems[i], dst->shmems[i]))
            goto error;
    }

15463 15464 15465 15466 15467 15468 15469 15470 15471 15472 15473 15474 15475 15476 15477 15478 15479 15480 15481 15482 15483 15484 15485 15486 15487 15488 15489 15490 15491 15492 15493 15494 15495
    /* Coverity is not very happy with this - all dead_error_condition */
#if !STATIC_ANALYSIS
    /* This switch statement is here to trigger compiler warning when adding
     * a new device type. When you are adding a new field to the switch you
     * also have to add an check above. Otherwise the switch statement has no
     * real function here and should be optimized out by the compiler. */
    i = VIR_DOMAIN_DEVICE_LAST;
    switch ((virDomainDeviceType) i) {
    case VIR_DOMAIN_DEVICE_DISK:
    case VIR_DOMAIN_DEVICE_LEASE:
    case VIR_DOMAIN_DEVICE_FS:
    case VIR_DOMAIN_DEVICE_NET:
    case VIR_DOMAIN_DEVICE_INPUT:
    case VIR_DOMAIN_DEVICE_SOUND:
    case VIR_DOMAIN_DEVICE_VIDEO:
    case VIR_DOMAIN_DEVICE_HOSTDEV:
    case VIR_DOMAIN_DEVICE_WATCHDOG:
    case VIR_DOMAIN_DEVICE_CONTROLLER:
    case VIR_DOMAIN_DEVICE_GRAPHICS:
    case VIR_DOMAIN_DEVICE_HUB:
    case VIR_DOMAIN_DEVICE_REDIRDEV:
    case VIR_DOMAIN_DEVICE_NONE:
    case VIR_DOMAIN_DEVICE_SMARTCARD:
    case VIR_DOMAIN_DEVICE_CHR:
    case VIR_DOMAIN_DEVICE_MEMBALLOON:
    case VIR_DOMAIN_DEVICE_NVRAM:
    case VIR_DOMAIN_DEVICE_LAST:
    case VIR_DOMAIN_DEVICE_RNG:
    case VIR_DOMAIN_DEVICE_SHMEM:
        break;
    }
#endif

15496
    return true;
15497

15498
 error:
15499 15500 15501 15502 15503 15504 15505 15506 15507 15508 15509 15510 15511 15512
    err = virSaveLastError();

    strSrc = virDomainDefFormat(src, 0);
    strDst = virDomainDefFormat(dst, 0);
    VIR_DEBUG("XMLs that failed stability check were: src=\"%s\", dst=\"%s\"",
              NULLSTR(strSrc), NULLSTR(strDst));
    VIR_FREE(strSrc);
    VIR_FREE(strDst);

    if (err) {
        virSetError(err);
        virFreeError(err);
    }
    return false;
15513 15514 15515
}


15516 15517 15518 15519
static int
virDomainDefAddDiskControllersForType(virDomainDefPtr def,
                                      int controllerType,
                                      int diskBus)
15520
{
15521
    size_t i;
15522 15523
    int maxController = -1;

15524
    for (i = 0; i < def->ndisks; i++) {
15525 15526 15527 15528 15529 15530 15531 15532 15533 15534
        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;
    }

15535 15536 15537
    if (maxController == -1)
        return 0;

15538
    for (i = 0; i <= maxController; i++) {
15539
        if (virDomainDefMaybeAddController(def, controllerType, i, -1) < 0)
15540 15541 15542 15543 15544 15545 15546
            return -1;
    }

    return 0;
}


15547 15548
static int
virDomainDefMaybeAddVirtioSerialController(virDomainDefPtr def)
15549
{
C
Cole Robinson 已提交
15550
    /* Look for any virtio serial or virtio console devs */
15551
    size_t i;
15552

15553
    for (i = 0; i < def->nchannels; i++) {
15554 15555
        virDomainChrDefPtr channel = def->channels[i];

15556
        if (channel->targetType == VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO) {
15557 15558 15559 15560
            int idx = 0;
            if (channel->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL)
                idx = channel->info.addr.vioserial.controller;

15561
            if (virDomainDefMaybeAddController(def,
15562
                VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL, idx, -1) < 0)
15563 15564 15565 15566
                return -1;
        }
    }

15567
    for (i = 0; i < def->nconsoles; i++) {
15568
        virDomainChrDefPtr console = def->consoles[i];
C
Cole Robinson 已提交
15569 15570 15571 15572 15573 15574 15575 15576

        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,
15577
                VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL, idx, -1) < 0)
C
Cole Robinson 已提交
15578 15579 15580 15581
                return -1;
        }
    }

15582 15583 15584 15585
    return 0;
}


E
Eric Blake 已提交
15586 15587 15588 15589
static int
virDomainDefMaybeAddSmartcardController(virDomainDefPtr def)
{
    /* Look for any smartcard devs */
15590
    size_t i;
E
Eric Blake 已提交
15591

15592
    for (i = 0; i < def->nsmartcards; i++) {
E
Eric Blake 已提交
15593 15594 15595 15596 15597 15598 15599
        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) {
15600
            size_t j;
E
Eric Blake 已提交
15601 15602 15603 15604 15605 15606 15607 15608 15609 15610 15611 15612 15613 15614 15615 15616
            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,
15617
                                           idx, -1) < 0)
E
Eric Blake 已提交
15618 15619 15620 15621 15622 15623
            return -1;
    }

    return 0;
}

15624
/*
15625
 * Based on the declared <address/> info for any devices,
15626
 * add necessary drive controllers which are not already present
15627 15628 15629
 * in the XML. This is for compat with existing apps which will
 * not know/care about <controller> info in the XML
 */
15630 15631
int
virDomainDefAddImplicitControllers(virDomainDefPtr def)
15632 15633 15634 15635 15636 15637 15638 15639 15640 15641 15642 15643 15644 15645 15646 15647
{
    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;

J
Jim Fehlig 已提交
15648 15649 15650 15651 15652
    if (virDomainDefAddDiskControllersForType(def,
                                              VIR_DOMAIN_CONTROLLER_TYPE_SATA,
                                              VIR_DOMAIN_DISK_BUS_SATA) < 0)
        return -1;

15653 15654 15655
    if (virDomainDefMaybeAddVirtioSerialController(def) < 0)
        return -1;

E
Eric Blake 已提交
15656 15657 15658
    if (virDomainDefMaybeAddSmartcardController(def) < 0)
        return -1;

H
Han Cheng 已提交
15659 15660 15661
    if (virDomainDefMaybeAddHostdevSCSIcontroller(def) < 0)
        return -1;

15662 15663 15664
    return 0;
}

15665 15666 15667
/* Check if vcpupin with same vcpuid already exists.
 * Return 1 if exists, 0 if not. */
int
E
Eric Blake 已提交
15668
virDomainVcpuPinIsDuplicate(virDomainVcpuPinDefPtr *def,
15669 15670 15671
                            int nvcpupin,
                            int vcpu)
{
15672
    size_t i;
15673 15674 15675 15676 15677 15678 15679 15680 15681 15682 15683 15684

    if (!def || !nvcpupin)
        return 0;

    for (i = 0; i < nvcpupin; i++) {
        if (def[i]->vcpuid == vcpu)
            return 1;
    }

    return 0;
}

E
Eric Blake 已提交
15685 15686
virDomainVcpuPinDefPtr
virDomainVcpuPinFindByVcpu(virDomainVcpuPinDefPtr *def,
15687 15688 15689
                           int nvcpupin,
                           int vcpu)
{
15690
    size_t i;
15691 15692 15693 15694 15695 15696 15697 15698 15699 15700 15701 15702

    if (!def || !nvcpupin)
        return NULL;

    for (i = 0; i < nvcpupin; i++) {
        if (def[i]->vcpuid == vcpu)
            return def[i];
    }

    return NULL;
}

15703 15704
int
virDomainVcpuPinAdd(virDomainVcpuPinDefPtr **vcpupin_list,
15705
                    size_t *nvcpupin,
15706 15707 15708
                    unsigned char *cpumap,
                    int maplen,
                    int vcpu)
15709 15710 15711
{
    virDomainVcpuPinDefPtr vcpupin = NULL;

H
Hu Tao 已提交
15712 15713
    if (!vcpupin_list)
        return -1;
15714

15715
    vcpupin = virDomainVcpuPinFindByVcpu(*vcpupin_list,
H
Hu Tao 已提交
15716 15717 15718
                                         *nvcpupin,
                                         vcpu);
    if (vcpupin) {
15719
        vcpupin->vcpuid = vcpu;
H
Hu Tao 已提交
15720 15721
        virBitmapFree(vcpupin->cpumask);
        vcpupin->cpumask = virBitmapNewData(cpumap, maplen);
15722
        if (!vcpupin->cpumask)
H
Hu Tao 已提交
15723
            return -1;
15724

H
Hu Tao 已提交
15725 15726
        return 0;
    }
15727

H
Hu Tao 已提交
15728
    /* No existing vcpupin matches vcpu, adding a new one */
15729

15730
    if (VIR_ALLOC(vcpupin) < 0)
15731
        goto error;
15732

H
Hu Tao 已提交
15733
    vcpupin->vcpuid = vcpu;
H
Hu Tao 已提交
15734
    vcpupin->cpumask = virBitmapNewData(cpumap, maplen);
15735
    if (!vcpupin->cpumask)
15736
        goto error;
15737

15738
    if (VIR_APPEND_ELEMENT(*vcpupin_list, *nvcpupin, vcpupin) < 0)
15739
        goto error;
H
Hu Tao 已提交
15740 15741

    return 0;
15742

15743
 error:
G
Guido Günther 已提交
15744
    virDomainVcpuPinDefFree(vcpupin);
15745
    return -1;
15746 15747
}

15748
void
E
Eric Blake 已提交
15749
virDomainVcpuPinDel(virDomainDefPtr def, int vcpu)
15750 15751
{
    int n;
E
Eric Blake 已提交
15752
    virDomainVcpuPinDefPtr *vcpupin_list = def->cputune.vcpupin;
15753 15754 15755

    for (n = 0; n < def->cputune.nvcpupin; n++) {
        if (vcpupin_list[n]->vcpuid == vcpu) {
15756
            virBitmapFree(vcpupin_list[n]->cpumask);
15757
            VIR_FREE(vcpupin_list[n]);
15758
            VIR_DELETE_ELEMENT(vcpupin_list, n, def->cputune.nvcpupin);
15759
            return;
15760 15761 15762 15763
        }
    }
}

15764 15765 15766 15767 15768 15769 15770 15771 15772
int
virDomainEmulatorPinAdd(virDomainDefPtr def,
                        unsigned char *cpumap,
                        int maplen)
{
    virDomainVcpuPinDefPtr emulatorpin = NULL;

    if (!def->cputune.emulatorpin) {
        /* No emulatorpin exists yet. */
15773
        if (VIR_ALLOC(emulatorpin) < 0)
H
Hu Tao 已提交
15774
            return -1;
15775 15776

        emulatorpin->vcpuid = -1;
H
Hu Tao 已提交
15777
        emulatorpin->cpumask = virBitmapNewData(cpumap, maplen);
15778 15779
        if (!emulatorpin->cpumask) {
            virDomainVcpuPinDefFree(emulatorpin);
H
Hu Tao 已提交
15780
            return -1;
15781
        }
H
Hu Tao 已提交
15782

15783 15784 15785 15786 15787
        def->cputune.emulatorpin = emulatorpin;
    } else {
        /* Since there is only 1 emulatorpin for each vm,
         * juest replace the old one.
         */
H
Hu Tao 已提交
15788 15789 15790 15791
        virBitmapFree(def->cputune.emulatorpin->cpumask);
        def->cputune.emulatorpin->cpumask = virBitmapNewData(cpumap, maplen);
        if (!def->cputune.emulatorpin->cpumask)
            return -1;
15792 15793 15794 15795 15796 15797 15798 15799 15800 15801 15802 15803
    }

    return 0;
}

int
virDomainEmulatorPinDel(virDomainDefPtr def)
{
    if (!def->cputune.emulatorpin) {
        return 0;
    }

H
Hu Tao 已提交
15804
    virDomainVcpuPinDefFree(def->cputune.emulatorpin);
15805 15806 15807 15808 15809
    def->cputune.emulatorpin = NULL;

    return 0;
}

15810
static int
15811 15812 15813 15814
virDomainEventActionDefFormat(virBufferPtr buf,
                              int type,
                              const char *name,
                              virEventActionToStringFunc convFunc)
15815
{
15816
    const char *typeStr = convFunc(type);
15817
    if (!typeStr) {
15818
        virReportError(VIR_ERR_INTERNAL_ERROR,
15819
                       _("unexpected %s action: %d"), name, type);
15820 15821 15822
        return -1;
    }

15823
    virBufferAsprintf(buf, "<%s>%s</%s>\n", name, typeStr, name);
15824 15825 15826 15827 15828

    return 0;
}


15829
static void
15830
virSecurityLabelDefFormat(virBufferPtr buf,
15831
                          virSecurityLabelDefPtr def)
15832 15833 15834 15835
{
    const char *sectype = virDomainSeclabelTypeToString(def->type);

    if (!sectype)
15836 15837 15838 15839 15840
        return;

    if (def->type == VIR_DOMAIN_SECLABEL_DEFAULT)
        return;

15841 15842
    /* To avoid backward compatibility issues, suppress DAC and 'none' labels
     * that are automatically generated.
15843
     */
15844 15845
    if ((STREQ_NULLABLE(def->model, "dac") ||
         STREQ_NULLABLE(def->model, "none")) && def->implicit)
15846 15847
        return;

15848 15849 15850
    virBufferAsprintf(buf, "<seclabel type='%s'",
                      sectype);

15851
    virBufferEscapeString(buf, " model='%s'", def->model);
15852

15853 15854 15855 15856 15857
    if (def->type == VIR_DOMAIN_SECLABEL_NONE) {
        virBufferAddLit(buf, "/>\n");
        return;
    }

15858
    virBufferAsprintf(buf, " relabel='%s'",
15859
                      def->relabel ? "yes" : "no");
15860

15861 15862
    if (def->label || def->imagelabel || def->baselabel) {
        virBufferAddLit(buf, ">\n");
15863 15864
        virBufferAdjustIndent(buf, 2);
        virBufferEscapeString(buf, "<label>%s</label>\n",
15865
                              def->label);
15866
        if (def->relabel)
15867
            virBufferEscapeString(buf, "<imagelabel>%s</imagelabel>\n",
15868 15869
                                  def->imagelabel);
        if (def->type == VIR_DOMAIN_SECLABEL_DYNAMIC)
15870
            virBufferEscapeString(buf, "<baselabel>%s</baselabel>\n",
15871
                                  def->baselabel);
15872
        virBufferAdjustIndent(buf, -2);
15873
        virBufferAddLit(buf, "</seclabel>\n");
15874 15875
    } else {
        virBufferAddLit(buf, "/>\n");
15876 15877 15878 15879
    }
}


15880 15881
static void
virSecurityDeviceLabelDefFormat(virBufferPtr buf,
15882 15883
                                virSecurityDeviceLabelDefPtr def,
                                unsigned int flags)
15884
{
15885 15886
    /* For offline output, skip elements that allow labels but have no
     * label specified (possible if labelskip was ignored on input).  */
15887
    if ((flags & VIR_DOMAIN_XML_INACTIVE) && !def->label && def->relabel)
15888 15889
        return;

15890
    virBufferAddLit(buf, "<seclabel");
15891 15892 15893 15894

    if (def->model)
        virBufferAsprintf(buf, " model='%s'", def->model);

15895 15896 15897
    if (def->labelskip)
        virBufferAddLit(buf, " labelskip='yes'");
    else
15898
        virBufferAsprintf(buf, " relabel='%s'", def->relabel ? "yes" : "no");
15899

15900 15901
    if (def->label) {
        virBufferAddLit(buf, ">\n");
15902 15903
        virBufferAdjustIndent(buf, 2);
        virBufferEscapeString(buf, "<label>%s</label>\n",
15904
                              def->label);
15905
        virBufferAdjustIndent(buf, -2);
15906 15907 15908 15909 15910 15911 15912
        virBufferAddLit(buf, "</seclabel>\n");
    } else {
        virBufferAddLit(buf, "/>\n");
    }
}


15913 15914 15915 15916
static int
virDomainLeaseDefFormat(virBufferPtr buf,
                        virDomainLeaseDefPtr def)
{
15917 15918 15919 15920 15921
    virBufferAddLit(buf, "<lease>\n");
    virBufferAdjustIndent(buf, 2);
    virBufferEscapeString(buf, "<lockspace>%s</lockspace>\n", def->lockspace);
    virBufferEscapeString(buf, "<key>%s</key>\n", def->key);
    virBufferEscapeString(buf, "<target path='%s'", def->path);
15922 15923 15924
    if (def->offset)
        virBufferAsprintf(buf, " offset='%llu'", def->offset);
    virBufferAddLit(buf, "/>\n");
15925 15926
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</lease>\n");
15927 15928 15929 15930

    return 0;
}

15931 15932 15933
static void
virDomainDiskGeometryDefFormat(virBufferPtr buf,
                               virDomainDiskDefPtr def)
J
J.B. Joret 已提交
15934 15935 15936 15937 15938 15939 15940 15941
{
    const char *trans =
        virDomainDiskGeometryTransTypeToString(def->geometry.trans);

    if (def->geometry.cylinders > 0 &&
        def->geometry.heads > 0 &&
        def->geometry.sectors > 0) {
        virBufferAsprintf(buf,
15942
                          "<geometry cyls='%u' heads='%u' secs='%u'",
J
J.B. Joret 已提交
15943 15944 15945 15946 15947 15948 15949 15950 15951 15952
                          def->geometry.cylinders,
                          def->geometry.heads,
                          def->geometry.sectors);

        if (def->geometry.trans != VIR_DOMAIN_DISK_TRANS_DEFAULT)
            virBufferEscapeString(buf, " trans='%s'", trans);

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

15954 15955 15956
static void
virDomainDiskBlockIoDefFormat(virBufferPtr buf,
                              virDomainDiskDefPtr def)
15957
{
V
Viktor Mihajlovski 已提交
15958 15959
    if (def->blockio.logical_block_size > 0 ||
        def->blockio.physical_block_size > 0) {
15960
        virBufferAddLit(buf, "<blockio");
V
Viktor Mihajlovski 已提交
15961
        if (def->blockio.logical_block_size > 0) {
15962 15963
            virBufferAsprintf(buf,
                              " logical_block_size='%u'",
V
Viktor Mihajlovski 已提交
15964
                              def->blockio.logical_block_size);
15965
        }
V
Viktor Mihajlovski 已提交
15966
        if (def->blockio.physical_block_size > 0) {
15967 15968
            virBufferAsprintf(buf,
                              " physical_block_size='%u'",
V
Viktor Mihajlovski 已提交
15969
                              def->blockio.physical_block_size);
15970 15971 15972 15973 15974
        }
        virBufferAddLit(buf, "/>\n");
    }
}

15975

15976
/* virDomainSourceDefFormatSeclabel:
15977 15978 15979 15980 15981
 *
 * This function automaticaly closes the <source> element and formats any
 * possible seclabels.
 */
static void
15982 15983 15984 15985 15986
virDomainDiskSourceDefFormatSeclabel(virBufferPtr buf,
                                     size_t nseclabels,
                                     virSecurityDeviceLabelDefPtr *seclabels,
                                     unsigned int flags,
                                     bool skipSeclables)
15987 15988 15989
{
    size_t n;

15990
    if (nseclabels && !skipSeclables) {
15991
        virBufferAddLit(buf, ">\n");
15992
        virBufferAdjustIndent(buf, 2);
15993 15994
        for (n = 0; n < nseclabels; n++)
            virSecurityDeviceLabelDefFormat(buf, seclabels[n], flags);
15995 15996
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</source>\n");
15997 15998 15999 16000 16001
    } else {
        virBufferAddLit(buf, "/>\n");
    }
}

16002 16003 16004 16005 16006 16007 16008 16009 16010 16011 16012 16013 16014 16015 16016
static void
virDomainSourceDefFormatSeclabel(virBufferPtr buf,
                                 size_t nseclabels,
                                 virSecurityDeviceLabelDefPtr *seclabels,
                                 unsigned int flags)
{
    virDomainDiskSourceDefFormatSeclabel(buf, nseclabels, seclabels, flags, false);
}

static int
virDomainDiskSourceFormatInternal(virBufferPtr buf,
                                  virStorageSourcePtr src,
                                  int policy,
                                  unsigned int flags,
                                  bool skipSeclabels)
16017
{
16018
    size_t n;
16019
    char *path = NULL;
16020
    const char *startupPolicy = NULL;
16021

16022 16023 16024
    if (policy)
        startupPolicy = virDomainStartupPolicyTypeToString(policy);

16025
    if (src->path || src->nhosts > 0 || src->srcpool || startupPolicy) {
16026
        switch ((virStorageType)src->type) {
E
Eric Blake 已提交
16027
        case VIR_STORAGE_TYPE_FILE:
16028
            virBufferAddLit(buf, "<source");
16029
            virBufferEscapeString(buf, " file='%s'", src->path);
16030 16031
            virBufferEscapeString(buf, " startupPolicy='%s'", startupPolicy);

16032 16033 16034
            virDomainDiskSourceDefFormatSeclabel(buf, src->nseclabels,
                                                 src->seclabels, flags,
                                                 skipSeclabels);
16035
            break;
16036

E
Eric Blake 已提交
16037
        case VIR_STORAGE_TYPE_BLOCK:
16038
            virBufferAddLit(buf, "<source");
16039
            virBufferEscapeString(buf, " dev='%s'", src->path);
16040 16041
            virBufferEscapeString(buf, " startupPolicy='%s'", startupPolicy);

16042 16043 16044
            virDomainDiskSourceDefFormatSeclabel(buf, src->nseclabels,
                                                 src->seclabels, flags,
                                                 skipSeclabels);
16045
            break;
16046

E
Eric Blake 已提交
16047
        case VIR_STORAGE_TYPE_DIR:
16048
            virBufferAddLit(buf, "<source");
16049
            virBufferEscapeString(buf, " dir='%s'", src->path);
16050
            virBufferEscapeString(buf, " startupPolicy='%s'", startupPolicy);
16051
            virBufferAddLit(buf, "/>\n");
16052
            break;
16053

E
Eric Blake 已提交
16054
        case VIR_STORAGE_TYPE_NETWORK:
16055
            virBufferAsprintf(buf, "<source protocol='%s'",
16056
                              virStorageNetProtocolTypeToString(src->protocol));
16057 16058 16059 16060 16061 16062 16063 16064 16065 16066


            if (src->volume) {
                if (virAsprintf(&path, "%s%s", src->volume, src->path) < 0)
                    return -1;
            }

            virBufferEscapeString(buf, " name='%s'", path ? path : src->path);

            VIR_FREE(path);
16067

16068
            if (src->nhosts == 0) {
16069 16070 16071
                virBufferAddLit(buf, "/>\n");
            } else {
                virBufferAddLit(buf, ">\n");
16072
                virBufferAdjustIndent(buf, 2);
16073
                for (n = 0; n < src->nhosts; n++) {
16074
                    virBufferAddLit(buf, "<host");
16075 16076 16077 16078
                    virBufferEscapeString(buf, " name='%s'",
                                          src->hosts[n].name);
                    virBufferEscapeString(buf, " port='%s'",
                                          src->hosts[n].port);
16079

16080
                    if (src->hosts[n].transport)
16081
                        virBufferAsprintf(buf, " transport='%s'",
16082
                                          virStorageNetHostTransportTypeToString(src->hosts[n].transport));
16083

16084 16085
                    virBufferEscapeString(buf, " socket='%s'",
                                          src->hosts[n].socket);
16086

16087 16088
                    virBufferAddLit(buf, "/>\n");
                }
16089 16090
                virBufferAdjustIndent(buf, -2);
                virBufferAddLit(buf, "</source>\n");
16091 16092
            }
            break;
16093

E
Eric Blake 已提交
16094
        case VIR_STORAGE_TYPE_VOLUME:
16095
            virBufferAddLit(buf, "<source");
16096

16097 16098 16099 16100 16101
            if (src->srcpool) {
                virBufferEscapeString(buf, " pool='%s'", src->srcpool->pool);
                virBufferEscapeString(buf, " volume='%s'",
                                      src->srcpool->volume);
                if (src->srcpool->mode)
16102
                    virBufferAsprintf(buf, " mode='%s'",
16103
                                      virStorageSourcePoolModeTypeToString(src->srcpool->mode));
16104
            }
16105
            virBufferEscapeString(buf, " startupPolicy='%s'", startupPolicy);
16106

16107 16108 16109
            virDomainDiskSourceDefFormatSeclabel(buf, src->nseclabels,
                                                 src->seclabels, flags,
                                                 skipSeclabels);
16110
            break;
16111

16112
        case VIR_STORAGE_TYPE_NONE:
16113
        case VIR_STORAGE_TYPE_LAST:
16114
            virReportError(VIR_ERR_INTERNAL_ERROR,
16115
                           _("unexpected disk type %d"), src->type);
16116 16117 16118 16119 16120 16121
            return -1;
        }
    }

    return 0;
}
J
J.B. Joret 已提交
16122

16123

16124 16125 16126 16127 16128 16129 16130 16131 16132 16133
int
virDomainDiskSourceFormat(virBufferPtr buf,
                          virStorageSourcePtr src,
                          int policy,
                          unsigned int flags)
{
    return virDomainDiskSourceFormatInternal(buf, src, policy, flags, false);
}


16134 16135 16136 16137
static int
virDomainDiskBackingStoreFormat(virBufferPtr buf,
                                virStorageSourcePtr backingStore,
                                const char *backingStoreRaw,
16138
                                unsigned int idx)
16139 16140 16141 16142 16143 16144 16145 16146 16147 16148 16149 16150 16151 16152 16153 16154 16155 16156 16157 16158 16159 16160 16161 16162 16163 16164 16165
{
    const char *type;
    const char *format;

    if (!backingStore) {
        if (!backingStoreRaw)
            virBufferAddLit(buf, "<backingStore/>\n");
        return 0;
    }

    if (!backingStore->type ||
        !(type = virStorageTypeToString(backingStore->type))) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected disk backing store type %d"),
                       backingStore->type);
        return -1;
    }

    if (backingStore->format <= 0 ||
        !(format = virStorageFileFormatTypeToString(backingStore->format))) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected disk backing store format %d"),
                       backingStore->format);
        return -1;
    }

    virBufferAsprintf(buf, "<backingStore type='%s' index='%u'>\n",
16166
                      type, idx);
16167 16168 16169
    virBufferAdjustIndent(buf, 2);

    virBufferAsprintf(buf, "<format type='%s'/>\n", format);
16170 16171
    /* We currently don't output seclabels for backing chain element */
    if (virDomainDiskSourceFormatInternal(buf, backingStore, 0, 0, true) < 0 ||
16172 16173 16174
        virDomainDiskBackingStoreFormat(buf,
                                        backingStore->backingStore,
                                        backingStore->backingStoreRaw,
16175
                                        idx + 1) < 0)
16176 16177 16178 16179 16180 16181 16182 16183
        return -1;

    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</backingStore>\n");
    return 0;
}


16184
static int
16185
virDomainDiskDefFormat(virBufferPtr buf,
D
Daniel P. Berrange 已提交
16186
                       virDomainDiskDefPtr def,
E
Eric Blake 已提交
16187
                       unsigned int flags)
16188
{
16189
    const char *type = virStorageTypeToString(def->src->type);
16190 16191
    const char *device = virDomainDiskDeviceTypeToString(def->device);
    const char *bus = virDomainDiskBusTypeToString(def->bus);
16192
    const char *cachemode = virDomainDiskCacheTypeToString(def->cachemode);
16193
    const char *error_policy = virDomainDiskErrorPolicyTypeToString(def->error_policy);
16194
    const char *rerror_policy = virDomainDiskErrorPolicyTypeToString(def->rerror_policy);
M
Matthias Dahl 已提交
16195
    const char *iomode = virDomainDiskIoTypeToString(def->iomode);
J
Ján Tomko 已提交
16196 16197 16198
    const char *ioeventfd = virTristateSwitchTypeToString(def->ioeventfd);
    const char *event_idx = virTristateSwitchTypeToString(def->event_idx);
    const char *copy_on_read = virTristateSwitchTypeToString(def->copy_on_read);
16199
    const char *sgio = virDomainDeviceSGIOTypeToString(def->sgio);
O
Osier Yang 已提交
16200
    const char *discard = virDomainDiskDiscardTypeToString(def->discard);
16201

16202
    if (!type || !def->src->type) {
16203
        virReportError(VIR_ERR_INTERNAL_ERROR,
16204
                       _("unexpected disk type %d"), def->src->type);
16205 16206 16207
        return -1;
    }
    if (!device) {
16208 16209
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected disk device %d"), def->device);
16210 16211 16212
        return -1;
    }
    if (!bus) {
16213 16214
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected disk bus %d"), def->bus);
16215 16216
        return -1;
    }
16217
    if (!cachemode) {
16218 16219
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected disk cache mode %d"), def->cachemode);
16220 16221
        return -1;
    }
M
Matthias Dahl 已提交
16222
    if (!iomode) {
16223 16224
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected disk io mode %d"), def->iomode);
M
Matthias Dahl 已提交
16225 16226
        return -1;
    }
O
Osier Yang 已提交
16227 16228 16229 16230 16231
    if (!sgio) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unexpected disk sgio mode '%d'"), def->sgio);
        return -1;
    }
16232

16233
    virBufferAsprintf(buf,
16234
                      "<disk type='%s' device='%s'",
16235
                      type, device);
16236 16237 16238
    if (def->rawio) {
        virBufferAsprintf(buf, " rawio='%s'",
                          virTristateBoolTypeToString(def->rawio));
16239
    }
O
Osier Yang 已提交
16240 16241 16242 16243

    if (def->sgio)
        virBufferAsprintf(buf, " sgio='%s'", sgio);

16244
    if (def->snapshot &&
16245 16246
        !(def->snapshot == VIR_DOMAIN_SNAPSHOT_LOCATION_NONE &&
          def->src->readonly))
16247
        virBufferAsprintf(buf, " snapshot='%s'",
E
Eric Blake 已提交
16248
                          virDomainSnapshotLocationTypeToString(def->snapshot));
16249
    virBufferAddLit(buf, ">\n");
16250
    virBufferAdjustIndent(buf, 2);
16251

16252
    if (def->src->driverName || def->src->format > 0 || def->cachemode ||
16253 16254
        def->error_policy || def->rerror_policy || def->iomode ||
        def->ioeventfd || def->event_idx || def->copy_on_read ||
16255
        def->discard || def->iothread) {
16256
        virBufferAddLit(buf, "<driver");
16257 16258 16259
        if (def->src->driverName)
            virBufferAsprintf(buf, " name='%s'", def->src->driverName);
        if (def->src->format > 0)
16260
            virBufferAsprintf(buf, " type='%s'",
16261
                              virStorageFileFormatTypeToString(def->src->format));
16262
        if (def->cachemode)
16263
            virBufferAsprintf(buf, " cache='%s'", cachemode);
16264
        if (def->error_policy)
16265
            virBufferAsprintf(buf, " error_policy='%s'", error_policy);
16266 16267
        if (def->rerror_policy)
            virBufferAsprintf(buf, " rerror_policy='%s'", rerror_policy);
M
Matthias Dahl 已提交
16268
        if (def->iomode)
16269
            virBufferAsprintf(buf, " io='%s'", iomode);
16270 16271
        if (def->ioeventfd)
            virBufferAsprintf(buf, " ioeventfd='%s'", ioeventfd);
16272 16273
        if (def->event_idx)
            virBufferAsprintf(buf, " event_idx='%s'", event_idx);
O
Osier Yang 已提交
16274 16275
        if (def->copy_on_read)
            virBufferAsprintf(buf, " copy_on_read='%s'", copy_on_read);
O
Osier Yang 已提交
16276 16277
        if (def->discard)
            virBufferAsprintf(buf, " discard='%s'", discard);
16278 16279
        if (def->iothread)
            virBufferAsprintf(buf, " iothread='%u'", def->iothread);
16280
        virBufferAddLit(buf, "/>\n");
16281 16282
    }

16283 16284 16285
    if (def->src->auth) {
        if (virStorageAuthDefFormat(buf, def->src->auth) < 0)
            return -1;
16286 16287
    }

16288
    if (virDomainDiskSourceFormat(buf, def->src, def->startupPolicy,
16289
                                  flags) < 0)
16290
        return -1;
16291 16292 16293 16294

    /* Don't format backingStore to inactive XMLs until the code for
     * persistent storage of backing chains is ready. */
    if (!(flags & VIR_DOMAIN_XML_INACTIVE) &&
16295 16296
        virDomainDiskBackingStoreFormat(buf, def->src->backingStore,
                                        def->src->backingStoreRaw, 1) < 0)
16297 16298
        return -1;

J
J.B. Joret 已提交
16299
    virDomainDiskGeometryDefFormat(buf, def);
V
Viktor Mihajlovski 已提交
16300
    virDomainDiskBlockIoDefFormat(buf, def);
J
J.B. Joret 已提交
16301

16302 16303
    /* For now, mirroring is currently output-only: we only output it
     * for live domains, therefore we ignore it on input except for
16304 16305 16306 16307
     * the internal parse on libvirtd restart.  We prefer to output
     * the new style similar to backingStore, but for back-compat on
     * blockcopy files we also have to output old style attributes.
     * The parser accepts either style across libvirtd upgrades. */
16308
    if (def->mirror && !(flags & VIR_DOMAIN_XML_INACTIVE)) {
16309 16310 16311 16312
        const char *formatStr = NULL;

        if (def->mirror->format)
            formatStr = virStorageFileFormatTypeToString(def->mirror->format);
E
Eric Blake 已提交
16313 16314
        virBufferAsprintf(buf, "<mirror type='%s'",
                          virStorageTypeToString(def->mirror->type));
E
Eric Blake 已提交
16315 16316
        if (def->mirror->type == VIR_STORAGE_TYPE_FILE &&
            def->mirrorJob == VIR_DOMAIN_BLOCK_JOB_TYPE_COPY) {
16317 16318 16319
            virBufferEscapeString(buf, " file='%s'", def->mirror->path);
            virBufferEscapeString(buf, " format='%s'", formatStr);
        }
E
Eric Blake 已提交
16320 16321
        virBufferEscapeString(buf, " job='%s'",
                              virDomainBlockJobTypeToString(def->mirrorJob));
16322 16323 16324 16325 16326 16327
        if (def->mirrorState) {
            const char *mirror;

            mirror = virDomainDiskMirrorStateTypeToString(def->mirrorState);
            virBufferEscapeString(buf, " ready='%s'", mirror);
        }
E
Eric Blake 已提交
16328 16329
        virBufferAddLit(buf, ">\n");
        virBufferAdjustIndent(buf, 2);
16330
        virBufferEscapeString(buf, "<format type='%s'/>\n", formatStr);
E
Eric Blake 已提交
16331 16332 16333 16334
        if (virDomainDiskSourceFormat(buf, def->mirror, 0, 0) < 0)
            return -1;
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</mirror>\n");
16335 16336
    }

16337
    virBufferAsprintf(buf, "<target dev='%s' bus='%s'",
16338
                      def->dst, bus);
16339 16340
    if ((def->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY ||
         def->device == VIR_DOMAIN_DISK_DEVICE_CDROM) &&
E
Eric Blake 已提交
16341
        def->tray_status != VIR_DOMAIN_DISK_TRAY_CLOSED)
16342
        virBufferAsprintf(buf, " tray='%s'",
16343
                          virDomainDiskTrayTypeToString(def->tray_status));
16344
    if (def->bus == VIR_DOMAIN_DISK_BUS_USB &&
J
Ján Tomko 已提交
16345
        def->removable != VIR_TRISTATE_SWITCH_ABSENT) {
16346
        virBufferAsprintf(buf, " removable='%s'",
J
Ján Tomko 已提交
16347
                          virTristateSwitchTypeToString(def->removable));
16348 16349
    }
    virBufferAddLit(buf, "/>\n");
16350

L
Lei Li 已提交
16351 16352 16353 16354 16355 16356 16357
    /*disk I/O throttling*/
    if (def->blkdeviotune.total_bytes_sec ||
        def->blkdeviotune.read_bytes_sec ||
        def->blkdeviotune.write_bytes_sec ||
        def->blkdeviotune.total_iops_sec ||
        def->blkdeviotune.read_iops_sec ||
        def->blkdeviotune.write_iops_sec) {
16358 16359
        virBufferAddLit(buf, "<iotune>\n");
        virBufferAdjustIndent(buf, 2);
L
Lei Li 已提交
16360
        if (def->blkdeviotune.total_bytes_sec) {
16361
            virBufferAsprintf(buf, "<total_bytes_sec>%llu</total_bytes_sec>\n",
L
Lei Li 已提交
16362 16363 16364 16365
                              def->blkdeviotune.total_bytes_sec);
        }

        if (def->blkdeviotune.read_bytes_sec) {
16366
            virBufferAsprintf(buf, "<read_bytes_sec>%llu</read_bytes_sec>\n",
L
Lei Li 已提交
16367 16368 16369 16370 16371
                              def->blkdeviotune.read_bytes_sec);

        }

        if (def->blkdeviotune.write_bytes_sec) {
16372
            virBufferAsprintf(buf, "<write_bytes_sec>%llu</write_bytes_sec>\n",
L
Lei Li 已提交
16373 16374 16375 16376
                              def->blkdeviotune.write_bytes_sec);
        }

        if (def->blkdeviotune.total_iops_sec) {
16377
            virBufferAsprintf(buf, "<total_iops_sec>%llu</total_iops_sec>\n",
L
Lei Li 已提交
16378 16379 16380 16381
                              def->blkdeviotune.total_iops_sec);
        }

        if (def->blkdeviotune.read_iops_sec) {
16382
            virBufferAsprintf(buf, "<read_iops_sec>%llu</read_iops_sec>\n",
L
Lei Li 已提交
16383 16384 16385 16386
                              def->blkdeviotune.read_iops_sec);
        }

        if (def->blkdeviotune.write_iops_sec) {
16387
            virBufferAsprintf(buf, "<write_iops_sec>%llu</write_iops_sec>\n",
L
Lei Li 已提交
16388 16389
                              def->blkdeviotune.write_iops_sec);
        }
16390 16391
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</iotune>\n");
L
Lei Li 已提交
16392 16393
    }

16394
    if (def->src->readonly)
16395
        virBufferAddLit(buf, "<readonly/>\n");
16396
    if (def->src->shared)
16397
        virBufferAddLit(buf, "<shareable/>\n");
16398
    if (def->transient)
16399 16400 16401 16402 16403
        virBufferAddLit(buf, "<transient/>\n");
    virBufferEscapeString(buf, "<serial>%s</serial>\n", def->serial);
    virBufferEscapeString(buf, "<wwn>%s</wwn>\n", def->wwn);
    virBufferEscapeString(buf, "<vendor>%s</vendor>\n", def->vendor);
    virBufferEscapeString(buf, "<product>%s</product>\n", def->product);
16404 16405
    if (def->src->encryption &&
        virStorageEncryptionFormat(buf, def->src->encryption) < 0)
16406
        return -1;
16407 16408
    if (virDomainDeviceInfoFormat(buf, &def->info,
                                  flags | VIR_DOMAIN_XML_INTERNAL_ALLOW_BOOT) < 0)
16409
        return -1;
16410

16411 16412
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</disk>\n");
16413 16414 16415
    return 0;
}

16416 16417 16418 16419 16420 16421
static const char *
virDomainControllerModelTypeToString(virDomainControllerDefPtr def,
                                     int model)
{
    if (def->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI)
        return virDomainControllerModelSCSITypeToString(model);
16422 16423
    else if (def->type == VIR_DOMAIN_CONTROLLER_TYPE_USB)
        return virDomainControllerModelUSBTypeToString(model);
J
Ján Tomko 已提交
16424 16425
    else if (def->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI)
        return virDomainControllerModelPCITypeToString(model);
16426 16427 16428 16429

    return NULL;
}

16430
static int
16431
virDomainControllerDefFormat(virBufferPtr buf,
D
Daniel P. Berrange 已提交
16432
                             virDomainControllerDefPtr def,
E
Eric Blake 已提交
16433
                             unsigned int flags)
16434 16435
{
    const char *type = virDomainControllerTypeToString(def->type);
16436
    const char *model = NULL;
16437
    bool pcihole64 = false;
16438 16439

    if (!type) {
16440 16441
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected controller type %d"), def->type);
16442 16443 16444
        return -1;
    }

16445
    if (def->model != -1) {
16446
        model = virDomainControllerModelTypeToString(def, def->model);
16447 16448

        if (!model) {
16449 16450
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected model type %d"), def->model);
16451 16452 16453 16454
            return -1;
        }
    }

16455
    virBufferAsprintf(buf,
16456
                      "<controller type='%s' index='%u'",
16457 16458
                      type, def->idx);

16459 16460 16461 16462
    if (model) {
        virBufferEscapeString(buf, " model='%s'", model);
    }

16463 16464 16465
    switch (def->type) {
    case VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL:
        if (def->opts.vioserial.ports != -1) {
16466
            virBufferAsprintf(buf, " ports='%d'",
16467 16468 16469
                              def->opts.vioserial.ports);
        }
        if (def->opts.vioserial.vectors != -1) {
16470
            virBufferAsprintf(buf, " vectors='%d'",
16471 16472 16473 16474
                              def->opts.vioserial.vectors);
        }
        break;

16475 16476 16477 16478 16479
    case VIR_DOMAIN_CONTROLLER_TYPE_PCI:
        if (def->opts.pciopts.pcihole64)
            pcihole64 = true;
        break;

16480 16481 16482 16483
    default:
        break;
    }

16484 16485
    if (def->queues || def->cmd_per_lun || def->max_sectors ||
        virDomainDeviceInfoIsSet(&def->info, flags) || pcihole64) {
16486
        virBufferAddLit(buf, ">\n");
16487
        virBufferAdjustIndent(buf, 2);
16488
        if (def->queues)
16489
            virBufferAsprintf(buf, "<driver queues='%u'/>\n", def->queues);
16490

16491 16492 16493 16494 16495 16496
        if (def->cmd_per_lun)
            virBufferAsprintf(buf, "<driver cmd_per_lun='%u'/>\n", def->cmd_per_lun);

        if (def->max_sectors)
            virBufferAsprintf(buf, "<driver max_sectors='%u'/>\n", def->max_sectors);

16497 16498
        if (virDomainDeviceInfoIsSet(&def->info, flags) &&
            virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
16499
            return -1;
16500

16501
        if (pcihole64) {
16502
            virBufferAsprintf(buf, "<pcihole64 unit='KiB'>%lu</"
16503 16504 16505
                              "pcihole64>\n", def->opts.pciopts.pcihole64size);
        }

16506 16507
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</controller>\n");
16508 16509 16510 16511 16512 16513 16514
    } else {
        virBufferAddLit(buf, "/>\n");
    }

    return 0;
}

16515 16516 16517 16518 16519

int
virDomainFSIndexByName(virDomainDefPtr def, const char *name)
{
    virDomainFSDefPtr fs;
16520
    size_t i;
16521 16522 16523 16524 16525 16526 16527 16528 16529 16530

    for (i = 0; i < def->nfss; i++) {
        fs = def->fss[i];
        if (STREQ(fs->dst, name))
            return i;
    }
    return -1;
}


16531
static int
16532
virDomainFSDefFormat(virBufferPtr buf,
16533
                     virDomainFSDefPtr def,
E
Eric Blake 已提交
16534
                     unsigned int flags)
16535 16536
{
    const char *type = virDomainFSTypeToString(def->type);
16537
    const char *accessmode = virDomainFSAccessModeTypeToString(def->accessmode);
16538
    const char *fsdriver = virDomainFSDriverTypeToString(def->fsdriver);
16539
    const char *wrpolicy = virDomainFSWrpolicyTypeToString(def->wrpolicy);
16540 16541

    if (!type) {
16542 16543
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected filesystem type %d"), def->type);
16544 16545 16546
        return -1;
    }

16547
   if (!accessmode) {
16548 16549
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected accessmode %d"), def->accessmode);
16550 16551 16552 16553
        return -1;
    }


16554
    virBufferAsprintf(buf,
16555
                      "<filesystem type='%s' accessmode='%s'>\n",
16556
                      type, accessmode);
16557
    virBufferAdjustIndent(buf, 2);
16558
    if (def->fsdriver) {
16559
        virBufferAsprintf(buf, "<driver type='%s'", fsdriver);
16560

16561 16562 16563 16564
        if (def->format)
            virBufferAsprintf(buf, " format='%s'",
                              virStorageFileFormatTypeToString(def->format));

16565
        /* Don't generate anything if wrpolicy is set to default */
16566
        if (def->wrpolicy)
16567 16568 16569
            virBufferAsprintf(buf, " wrpolicy='%s'", wrpolicy);

        virBufferAddLit(buf, "/>\n");
16570 16571
    }

16572 16573
    switch (def->type) {
    case VIR_DOMAIN_FS_TYPE_MOUNT:
16574
    case VIR_DOMAIN_FS_TYPE_BIND:
16575
        virBufferEscapeString(buf, "<source dir='%s'/>\n",
16576 16577
                              def->src);
        break;
16578

16579
    case VIR_DOMAIN_FS_TYPE_BLOCK:
16580
        virBufferEscapeString(buf, "<source dev='%s'/>\n",
16581 16582
                              def->src);
        break;
16583

16584
    case VIR_DOMAIN_FS_TYPE_FILE:
16585
        virBufferEscapeString(buf, "<source file='%s'/>\n",
16586 16587
                              def->src);
        break;
16588

16589
    case VIR_DOMAIN_FS_TYPE_TEMPLATE:
16590
        virBufferEscapeString(buf, "<source name='%s'/>\n",
16591 16592 16593 16594
                              def->src);
        break;

    case VIR_DOMAIN_FS_TYPE_RAM:
16595
        virBufferAsprintf(buf, "<source usage='%lld' units='KiB'/>\n",
16596 16597
                          def->usage / 1024);
        break;
16598 16599
    }

16600
    virBufferEscapeString(buf, "<target dir='%s'/>\n",
16601
                          def->dst);
16602 16603

    if (def->readonly)
16604
        virBufferAddLit(buf, "<readonly/>\n");
16605

16606 16607 16608
    if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
        return -1;

16609 16610

    if (def->space_hard_limit)
16611
        virBufferAsprintf(buf, "<space_hard_limit unit='bytes'>"
16612 16613
                          "%llu</space_hard_limit>\n", def->space_hard_limit);
    if (def->space_soft_limit) {
16614
        virBufferAsprintf(buf, "<space_soft_limit unit='bytes'>"
16615 16616
                          "%llu</space_soft_limit>\n", def->space_soft_limit);
    }
16617 16618
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</filesystem>\n");
16619 16620 16621
    return 0;
}

16622
static int
16623 16624 16625 16626
virDomainHostdevDefFormatSubsys(virBufferPtr buf,
                                virDomainHostdevDefPtr def,
                                unsigned int flags,
                                bool includeTypeInAddr)
16627
{
16628
    virDomainHostdevSubsysUSBPtr usbsrc = &def->source.subsys.u.usb;
16629
    virDomainHostdevSubsysPCIPtr pcisrc = &def->source.subsys.u.pci;
16630
    virDomainHostdevSubsysSCSIPtr scsisrc = &def->source.subsys.u.scsi;
16631
    virDomainHostdevSubsysSCSIHostPtr scsihostsrc = &scsisrc->u.host;
J
John Ferlan 已提交
16632
    virDomainHostdevSubsysSCSIiSCSIPtr iscsisrc = &scsisrc->u.iscsi;
16633

16634
    if (def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI &&
16635 16636 16637
        pcisrc->backend != VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT) {
        const char *backend =
            virDomainHostdevSubsysPCIBackendTypeToString(pcisrc->backend);
16638 16639 16640 16641

        if (!backend) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected pci hostdev driver name type %d"),
16642
                           pcisrc->backend);
16643 16644 16645 16646 16647
            return -1;
        }
        virBufferAsprintf(buf, "<driver name='%s'/>\n", backend);
    }

16648
    virBufferAddLit(buf, "<source");
J
John Ferlan 已提交
16649 16650 16651 16652 16653 16654 16655 16656 16657 16658 16659
    if (def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {
        if (def->startupPolicy) {
            const char *policy;
            policy = virDomainStartupPolicyTypeToString(def->startupPolicy);
            virBufferAsprintf(buf, " startupPolicy='%s'", policy);
        }
        if (usbsrc->autoAddress && (flags & VIR_DOMAIN_XML_MIGRATABLE))
            virBufferAddLit(buf, " autoAddress='yes'");

        if (def->missing && !(flags & VIR_DOMAIN_XML_INACTIVE))
            virBufferAddLit(buf, " missing='yes'");
16660
    }
16661

J
John Ferlan 已提交
16662 16663 16664 16665 16666 16667 16668 16669
    if (def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI &&
        scsisrc->protocol == VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_ISCSI) {
        const char *protocol =
            virDomainHostdevSubsysSCSIProtocolTypeToString(scsisrc->protocol);

        virBufferAsprintf(buf, " protocol='%s' name='%s'",
                          protocol, iscsisrc->path);
    }
16670

16671 16672
    virBufferAddLit(buf, ">\n");

16673
    virBufferAdjustIndent(buf, 2);
E
Eric Blake 已提交
16674
    switch (def->source.subsys.type) {
16675
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
16676 16677 16678 16679 16680
        if (usbsrc->vendor) {
            virBufferAsprintf(buf, "<vendor id='0x%.4x'/>\n", usbsrc->vendor);
            virBufferAsprintf(buf, "<product id='0x%.4x'/>\n", usbsrc->product);
        }
        if (usbsrc->bus || usbsrc->device) {
16681
            virBufferAsprintf(buf, "<address %sbus='%d' device='%d'/>\n",
16682
                              includeTypeInAddr ? "type='usb' " : "",
16683
                              usbsrc->bus, usbsrc->device);
16684 16685 16686
        }
        break;
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
16687
        if (virDevicePCIAddressFormat(buf, pcisrc->addr,
16688 16689 16690
                                      includeTypeInAddr) != 0)
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("PCI address Formatting failed"));
16691 16692 16693 16694 16695

        if ((flags & VIR_DOMAIN_XML_INTERNAL_PCI_ORIG_STATES) &&
            (def->origstates.states.pci.unbind_from_stub ||
             def->origstates.states.pci.remove_slot ||
             def->origstates.states.pci.reprobe)) {
16696
            virBufferAddLit(buf, "<origstates>\n");
16697
            virBufferAdjustIndent(buf, 2);
16698
            if (def->origstates.states.pci.unbind_from_stub)
16699
                virBufferAddLit(buf, "<unbind/>\n");
16700
            if (def->origstates.states.pci.remove_slot)
16701
                virBufferAddLit(buf, "<removeslot/>\n");
16702
            if (def->origstates.states.pci.reprobe)
16703 16704
                virBufferAddLit(buf, "<reprobe/>\n");
            virBufferAdjustIndent(buf, -2);
16705
            virBufferAddLit(buf, "</origstates>\n");
16706 16707
        }
        break;
H
Han Cheng 已提交
16708
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
J
John Ferlan 已提交
16709 16710 16711 16712 16713 16714 16715 16716 16717 16718 16719 16720 16721 16722
        if (scsisrc->protocol == VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_ISCSI) {
            virBufferAddLit(buf, "<host");
            virBufferEscapeString(buf, " name='%s'", iscsisrc->hosts[0].name);
            virBufferEscapeString(buf, " port='%s'", iscsisrc->hosts[0].port);
            virBufferAddLit(buf, "/>\n");
        } else {
            virBufferAsprintf(buf, "<adapter name='%s'/>\n",
                              scsihostsrc->adapter);
            virBufferAsprintf(buf,
                              "<address %sbus='%d' target='%d' unit='%d'/>\n",
                              includeTypeInAddr ? "type='scsi' " : "",
                              scsihostsrc->bus, scsihostsrc->target,
                              scsihostsrc->unit);
        }
H
Han Cheng 已提交
16723
        break;
16724
    default:
16725 16726 16727
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected hostdev type %d"),
                       def->source.subsys.type);
16728 16729 16730
        return -1;
    }

J
John Ferlan 已提交
16731 16732 16733 16734 16735 16736 16737
    if (def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI &&
        scsisrc->protocol == VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_ISCSI &&
        iscsisrc->auth) {
        if (virStorageAuthDefFormat(buf, iscsisrc->auth) < 0)
            return -1;
    }

16738
    virBufferAdjustIndent(buf, -2);
16739
    virBufferAddLit(buf, "</source>\n");
J
John Ferlan 已提交
16740

16741 16742 16743
    return 0;
}

16744 16745 16746 16747 16748 16749 16750
static int
virDomainHostdevDefFormatCaps(virBufferPtr buf,
                              virDomainHostdevDefPtr def)
{
    virBufferAddLit(buf, "<source>\n");

    virBufferAdjustIndent(buf, 2);
E
Eric Blake 已提交
16751
    switch (def->source.caps.type) {
16752 16753 16754 16755 16756 16757 16758 16759
    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_STORAGE:
        virBufferEscapeString(buf, "<block>%s</block>\n",
                              def->source.caps.u.storage.block);
        break;
    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_MISC:
        virBufferEscapeString(buf, "<char>%s</char>\n",
                              def->source.caps.u.misc.chardev);
        break;
16760 16761 16762 16763
    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_NET:
        virBufferEscapeString(buf, "<interface>%s</interface>\n",
                              def->source.caps.u.net.iface);
        break;
16764 16765 16766 16767 16768 16769 16770 16771 16772 16773 16774 16775
    default:
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected hostdev type %d"),
                       def->source.caps.type);
        return -1;
    }

    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</source>\n");
    return 0;
}

16776 16777 16778 16779 16780
/* virDomainActualNetDefContentsFormat() - format just the subelements
 * of <interface> that may be overridden by what is in the
 * virDomainActualNetDef, but inside the current element, rather
 * than enclosed in an <actual> subelement.
 */
16781
static int
16782 16783 16784 16785 16786
virDomainActualNetDefContentsFormat(virBufferPtr buf,
                                    virDomainNetDefPtr def,
                                    const char *typeStr,
                                    bool inSubelement,
                                    unsigned int flags)
16787 16788 16789
{
    const char *mode;

16790
    switch (virDomainNetGetActualType(def)) {
16791
    case VIR_DOMAIN_NET_TYPE_BRIDGE:
16792
        virBufferEscapeString(buf, "<source bridge='%s'/>\n",
16793
                              virDomainNetGetActualBridgeName(def));
16794 16795 16796
        break;

    case VIR_DOMAIN_NET_TYPE_DIRECT:
16797
        virBufferAddLit(buf, "<source");
16798 16799
        virBufferEscapeString(buf, " dev='%s'",
                              virDomainNetGetActualDirectDev(def));
16800

16801
        mode = virNetDevMacVLanModeTypeToString(virDomainNetGetActualDirectMode(def));
16802
        if (!mode) {
16803 16804
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected source mode %d"),
16805
                           virDomainNetGetActualDirectMode(def));
16806
            return -1;
16807 16808 16809
        }
        virBufferAsprintf(buf, " mode='%s'/>\n", mode);
        break;
16810 16811

    case VIR_DOMAIN_NET_TYPE_HOSTDEV:
16812
        if (virDomainHostdevDefFormatSubsys(buf, virDomainNetGetActualHostdev(def),
16813
                                            flags, true) < 0) {
16814 16815
            return -1;
        }
16816
        break;
16817 16818

    case VIR_DOMAIN_NET_TYPE_NETWORK:
16819 16820 16821 16822 16823 16824 16825 16826 16827 16828 16829 16830 16831 16832
        if (!inSubelement) {
            /* the <source> element isn't included in <actual>
             * (i.e. when we're putting our output into a subelement
             * rather than inline) because the main element has the
             * same info already. If we're outputting inline, though,
             * we *do* need to output <source>, because the caller
             * won't have done it.
             */
            virBufferEscapeString(buf, "<source network='%s'/>\n",
                                  def->data.network.name);
        }
        if (def->data.network.actual && def->data.network.actual->class_id)
            virBufferAsprintf(buf, "<class id='%u'/>\n",
                              def->data.network.actual->class_id);
16833 16834
        break;
    default:
16835
        virReportError(VIR_ERR_INTERNAL_ERROR,
16836
                       _("unexpected actual net type %s"), typeStr);
16837
        return -1;
16838
    }
16839

16840
    if (virNetDevVlanFormat(virDomainNetGetActualVlan(def), buf) < 0)
16841
        return -1;
16842
    if (virNetDevVPortProfileFormat(virDomainNetGetActualVirtPortProfile(def), buf) < 0)
16843
        return -1;
16844
    if (virNetDevBandwidthFormat(virDomainNetGetActualBandwidth(def), buf) < 0)
16845
        return -1;
16846 16847 16848 16849 16850 16851 16852 16853 16854 16855 16856 16857 16858
    return 0;
}


/* virDomainActualNetDefFormat() - format the ActualNetDef
 * info inside an <actual> element, as required for internal storage
 * of domain status
 */
static int
virDomainActualNetDefFormat(virBufferPtr buf,
                            virDomainNetDefPtr def,
                            unsigned int flags)
{
16859 16860
    unsigned int type;
    const char *typeStr;
16861 16862 16863

    if (!def)
        return 0;
16864 16865
    type = virDomainNetGetActualType(def);
    typeStr = virDomainNetTypeToString(type);
16866

16867 16868 16869 16870 16871 16872 16873 16874 16875 16876 16877 16878
    if (!typeStr) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected net type %d"), def->type);
        return -1;
    }

    virBufferAsprintf(buf, "<actual type='%s'", typeStr);
    if (type == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
        virDomainHostdevDefPtr hostdef = virDomainNetGetActualHostdev(def);
        if  (hostdef && hostdef->managed)
            virBufferAddLit(buf, " managed='yes'");
    }
16879 16880 16881
    if (def->trustGuestRxFilters)
        virBufferAsprintf(buf, " trustGuestRxFilters='%s'",
                          virTristateBoolTypeToString(def->trustGuestRxFilters));
16882 16883 16884 16885 16886
    virBufferAddLit(buf, ">\n");

    virBufferAdjustIndent(buf, 2);
    if (virDomainActualNetDefContentsFormat(buf, def, typeStr, true, flags) < 0)
       return -1;
16887 16888
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</actual>\n");
16889
    return 0;
16890 16891
}

16892

16893 16894 16895 16896 16897 16898 16899 16900 16901 16902 16903 16904 16905 16906 16907 16908 16909 16910 16911 16912 16913 16914 16915 16916 16917 16918 16919 16920 16921 16922 16923 16924 16925 16926 16927 16928 16929 16930 16931 16932 16933 16934 16935 16936 16937 16938 16939 16940 16941 16942 16943 16944 16945 16946 16947 16948 16949 16950 16951 16952 16953 16954 16955 16956 16957 16958 16959 16960 16961 16962 16963 16964 16965 16966
static int
virDomainVirtioNetGuestOptsFormat(char **outstr,
                                  virDomainNetDefPtr def)
{
    virBuffer buf = VIR_BUFFER_INITIALIZER;
    if (def->driver.virtio.guest.csum) {
        virBufferAsprintf(&buf, "csum='%s' ",
                          virTristateSwitchTypeToString(def->driver.virtio.guest.csum));
    }
    if (def->driver.virtio.guest.tso4) {
        virBufferAsprintf(&buf, "tso4='%s' ",
                          virTristateSwitchTypeToString(def->driver.virtio.guest.tso4));
    }
    if (def->driver.virtio.guest.tso6) {
        virBufferAsprintf(&buf, "tso6='%s' ",
                          virTristateSwitchTypeToString(def->driver.virtio.guest.tso6));
    }
    if (def->driver.virtio.guest.ecn) {
        virBufferAsprintf(&buf, "ecn='%s' ",
                          virTristateSwitchTypeToString(def->driver.virtio.guest.ecn));
    }
    if (def->driver.virtio.guest.ufo) {
        virBufferAsprintf(&buf, "ufo='%s' ",
                          virTristateSwitchTypeToString(def->driver.virtio.guest.ufo));
    }
    virBufferTrim(&buf, " ", -1);

    if (virBufferCheckError(&buf) < 0)
        return -1;

    *outstr = virBufferContentAndReset(&buf);
    return 0;
}


static int
virDomainVirtioNetHostOptsFormat(char **outstr,
                                 virDomainNetDefPtr def)
{
    virBuffer buf = VIR_BUFFER_INITIALIZER;
    if (def->driver.virtio.host.csum) {
        virBufferAsprintf(&buf, "csum='%s' ",
                          virTristateSwitchTypeToString(def->driver.virtio.host.csum));
    }
    if (def->driver.virtio.host.gso) {
        virBufferAsprintf(&buf, "gso='%s' ",
                          virTristateSwitchTypeToString(def->driver.virtio.host.gso));
    }
    if (def->driver.virtio.host.tso4) {
        virBufferAsprintf(&buf, "tso4='%s' ",
                          virTristateSwitchTypeToString(def->driver.virtio.host.tso4));
    }
    if (def->driver.virtio.host.tso6) {
        virBufferAsprintf(&buf, "tso6='%s' ",
                          virTristateSwitchTypeToString(def->driver.virtio.host.tso6));
    }
    if (def->driver.virtio.host.ecn) {
        virBufferAsprintf(&buf, "ecn='%s' ",
                          virTristateSwitchTypeToString(def->driver.virtio.host.ecn));
    }
    if (def->driver.virtio.host.ufo) {
        virBufferAsprintf(&buf, "ufo='%s' ",
                          virTristateSwitchTypeToString(def->driver.virtio.host.ufo));
    }
    virBufferTrim(&buf, " ", -1);

    if (virBufferCheckError(&buf) < 0)
        return -1;

    *outstr = virBufferContentAndReset(&buf);
    return 0;
}


16967 16968 16969 16970 16971 16972 16973 16974 16975 16976 16977 16978 16979 16980 16981 16982 16983 16984 16985 16986 16987 16988 16989 16990 16991 16992 16993 16994 16995 16996 16997 16998 16999 17000
static int
virDomainVirtioNetDriverFormat(char **outstr,
                               virDomainNetDefPtr def)
{
    virBuffer buf = VIR_BUFFER_INITIALIZER;
    if (def->driver.virtio.name) {
        virBufferAsprintf(&buf, "name='%s' ",
                          virDomainNetBackendTypeToString(def->driver.virtio.name));
    }
    if (def->driver.virtio.txmode) {
        virBufferAsprintf(&buf, "txmode='%s' ",
                          virDomainNetVirtioTxModeTypeToString(def->driver.virtio.txmode));
    }
    if (def->driver.virtio.ioeventfd) {
        virBufferAsprintf(&buf, "ioeventfd='%s' ",
                          virTristateSwitchTypeToString(def->driver.virtio.ioeventfd));
    }
    if (def->driver.virtio.event_idx) {
        virBufferAsprintf(&buf, "event_idx='%s' ",
                          virTristateSwitchTypeToString(def->driver.virtio.event_idx));
    }
    if (def->driver.virtio.queues)
        virBufferAsprintf(&buf, "queues='%u' ", def->driver.virtio.queues);

    virBufferTrim(&buf, " ", -1);

    if (virBufferCheckError(&buf) < 0)
        return -1;

    *outstr = virBufferContentAndReset(&buf);
    return 0;
}


17001
int
17002
virDomainNetDefFormat(virBufferPtr buf,
17003
                      virDomainNetDefPtr def,
E
Eric Blake 已提交
17004
                      unsigned int flags)
17005
{
17006 17007 17008 17009 17010 17011 17012 17013 17014 17015
    /* publicActual is true if we should report the current state in
     * def->data.network.actual *instead of* the config (*not* in
     * addition to)
     */
    unsigned int actualType = virDomainNetGetActualType(def);
    bool publicActual
       = (def->type == VIR_DOMAIN_NET_TYPE_NETWORK && def->data.network.actual &&
          !(flags & (VIR_DOMAIN_XML_INACTIVE | VIR_DOMAIN_XML_INTERNAL_ACTUAL_NET)));
    const char *typeStr;
    virDomainHostdevDefPtr hostdef = NULL;
17016
    char macstr[VIR_MAC_STRING_BUFLEN];
17017

17018 17019 17020 17021 17022 17023 17024 17025 17026 17027 17028 17029 17030 17031 17032 17033
    if (publicActual) {
        if (!(typeStr = virDomainNetTypeToString(actualType))) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected actual net type %d"), actualType);
            return -1;
        }
        if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV)
            hostdef = virDomainNetGetActualHostdev(def);
    } else {
        if (!(typeStr = virDomainNetTypeToString(def->type))) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected net type %d"), def->type);
            return -1;
        }
        if (def->type == VIR_DOMAIN_NET_TYPE_HOSTDEV)
            hostdef = &def->data.hostdev.def;
17034 17035
    }

17036
    virBufferAsprintf(buf, "<interface type='%s'", typeStr);
17037
    if (hostdef && hostdef->managed)
17038
        virBufferAddLit(buf, " managed='yes'");
17039 17040 17041
    if (def->trustGuestRxFilters)
        virBufferAsprintf(buf, " trustGuestRxFilters='%s'",
                          virTristateBoolTypeToString(def->trustGuestRxFilters));
17042
    virBufferAddLit(buf, ">\n");
17043

17044
    virBufferAdjustIndent(buf, 2);
17045 17046
    virBufferAsprintf(buf, "<mac address='%s'/>\n",
                      virMacAddrFormat(&def->mac, macstr));
17047

17048 17049 17050 17051 17052 17053 17054
    if (publicActual) {
        /* when there is a virDomainActualNetDef, and we haven't been
         * asked to 1) report the domain's inactive XML, or 2) give
         * the internal version of the ActualNetDef separately in an
         * <actual> subelement, we can just put the ActualDef data in
         * the standard place...  (this is for public reporting of
         * interface status)
17055
         */
17056
        if (virDomainActualNetDefContentsFormat(buf, def, typeStr, false, flags) < 0)
17057
            return -1;
17058 17059 17060 17061 17062 17063 17064 17065 17066 17067 17068 17069 17070 17071 17072
    } else {
        /* ...but if we've asked for the inactive XML (rather than
         * status), or to report the ActualDef as a separate <actual>
         * subelement (this is how we privately store interface
         * status), or there simply *isn't* any ActualNetDef, then
         * format the NetDef's data here, and optionally format the
         * ActualNetDef as an <actual> subelement of this element.
         */
        switch (def->type) {
        case VIR_DOMAIN_NET_TYPE_NETWORK:
            virBufferEscapeString(buf, "<source network='%s'",
                                  def->data.network.name);
            virBufferEscapeString(buf, " portgroup='%s'",
                                  def->data.network.portgroup);
            virBufferAddLit(buf, "/>\n");
17073

17074 17075 17076 17077 17078 17079 17080 17081
            /* ONLY for internal status storage - format the ActualNetDef
             * as a subelement of <interface> so that no persistent config
             * data is overwritten.
             */
            if ((flags & VIR_DOMAIN_XML_INTERNAL_ACTUAL_NET) &&
                (virDomainActualNetDefFormat(buf, def, flags) < 0))
                return -1;
            break;
17082

17083 17084 17085 17086 17087 17088 17089
        case VIR_DOMAIN_NET_TYPE_ETHERNET:
            virBufferEscapeString(buf, "<source dev='%s'/>\n",
                                  def->data.ethernet.dev);
            if (def->data.ethernet.ipaddr)
                virBufferAsprintf(buf, "<ip address='%s'/>\n",
                                  def->data.ethernet.ipaddr);
            break;
17090

M
Michele Paolino 已提交
17091 17092 17093 17094 17095
        case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
            if (def->data.vhostuser->type == VIR_DOMAIN_CHR_TYPE_UNIX) {
                virBufferAddLit(buf, "<source type='unix'");
                virBufferEscapeString(buf, " path='%s'",
                                      def->data.vhostuser->data.nix.path);
17096 17097 17098
                virBufferAsprintf(buf, " mode='%s'",
                                  def->data.vhostuser->data.nix.listen ?
                                  "server"  : "client");
M
Michele Paolino 已提交
17099 17100 17101 17102
                virBufferAddLit(buf, "/>\n");
            }
            break;

17103 17104 17105 17106 17107 17108 17109 17110
        case VIR_DOMAIN_NET_TYPE_BRIDGE:
            virBufferEscapeString(buf, "<source bridge='%s'/>\n",
                                  def->data.bridge.brname);
            if (def->data.bridge.ipaddr) {
                virBufferAsprintf(buf, "<ip address='%s'/>\n",
                                  def->data.bridge.ipaddr);
            }
            break;
D
Daniel Veillard 已提交
17111

17112 17113 17114 17115 17116 17117 17118 17119 17120 17121 17122
        case VIR_DOMAIN_NET_TYPE_SERVER:
        case VIR_DOMAIN_NET_TYPE_CLIENT:
        case VIR_DOMAIN_NET_TYPE_MCAST:
            if (def->data.socket.address) {
                virBufferAsprintf(buf, "<source address='%s' port='%d'/>\n",
                                  def->data.socket.address, def->data.socket.port);
            } else {
                virBufferAsprintf(buf, "<source port='%d'/>\n",
                                  def->data.socket.port);
            }
            break;
D
Daniel Veillard 已提交
17123

17124 17125 17126 17127
        case VIR_DOMAIN_NET_TYPE_INTERNAL:
            virBufferEscapeString(buf, "<source name='%s'/>\n",
                                  def->data.internal.name);
            break;
S
Stefan Berger 已提交
17128

17129 17130 17131 17132 17133 17134 17135 17136 17137 17138 17139 17140 17141 17142 17143 17144 17145 17146
        case VIR_DOMAIN_NET_TYPE_DIRECT:
            virBufferEscapeString(buf, "<source dev='%s'",
                                  def->data.direct.linkdev);
            virBufferAsprintf(buf, " mode='%s'",
                              virNetDevMacVLanModeTypeToString(def->data.direct.mode));
            virBufferAddLit(buf, "/>\n");
            break;

        case VIR_DOMAIN_NET_TYPE_HOSTDEV:
            if (virDomainHostdevDefFormatSubsys(buf, &def->data.hostdev.def,
                                                flags, true) < 0) {
                return -1;
            }
            break;

        case VIR_DOMAIN_NET_TYPE_USER:
        case VIR_DOMAIN_NET_TYPE_LAST:
            break;
17147 17148
        }

17149 17150 17151 17152 17153 17154
        if (virNetDevVlanFormat(&def->vlan, buf) < 0)
            return -1;
        if (virNetDevVPortProfileFormat(def->virtPortProfile, buf) < 0)
            return -1;
        if (virNetDevBandwidthFormat(def->bandwidth, buf) < 0)
            return -1;
17155 17156
    }

17157
    virBufferEscapeString(buf, "<script path='%s'/>\n",
17158
                          def->script);
17159 17160 17161 17162
    if (def->ifname &&
        !((flags & VIR_DOMAIN_XML_INACTIVE) &&
          (STRPREFIX(def->ifname, VIR_NET_GENERATED_PREFIX)))) {
        /* Skip auto-generated target names for inactive config. */
17163
        virBufferEscapeString(buf, "<target dev='%s'/>\n", def->ifname);
17164
    }
17165 17166 17167 17168 17169 17170 17171 17172 17173 17174 17175
    if (def->ifname_guest || def->ifname_guest_actual) {
        virBufferAddLit(buf, "<guest");
        /* Skip auto-generated target names for inactive config. */
        if (def->ifname_guest)
            virBufferEscapeString(buf, " dev='%s'", def->ifname_guest);

        /* Only set if the host is running, so shouldn't pollute output */
        if (def->ifname_guest_actual)
            virBufferEscapeString(buf, " actual='%s'", def->ifname_guest_actual);
        virBufferAddLit(buf, "/>\n");
    }
17176
    if (def->model) {
17177
        virBufferEscapeString(buf, "<model type='%s'/>\n",
17178
                              def->model);
17179
        if (STREQ(def->model, "virtio")) {
17180 17181
            char *str = NULL, *gueststr = NULL, *hoststr = NULL;
            int rc = 0;
17182

17183 17184 17185 17186
            if (virDomainVirtioNetDriverFormat(&str, def) < 0 ||
                virDomainVirtioNetGuestOptsFormat(&gueststr, def) < 0 ||
                virDomainVirtioNetHostOptsFormat(&hoststr, def) < 0)
                rc = -1;
17187

17188 17189 17190 17191 17192 17193 17194 17195 17196 17197 17198 17199 17200 17201 17202 17203
            if (!gueststr && !hoststr) {
                if (str)
                    virBufferAsprintf(buf, "<driver %s/>\n", str);
            } else {
                if (str)
                    virBufferAsprintf(buf, "<driver %s>\n", str);
                else
                    virBufferAddLit(buf, "<driver>\n");
                virBufferAdjustIndent(buf, 2);
                if (hoststr)
                    virBufferAsprintf(buf, "<host %s/>\n", hoststr);
                if (gueststr)
                    virBufferAsprintf(buf, "<guest %s/>\n", gueststr);
                virBufferAdjustIndent(buf, -2);
                virBufferAddLit(buf, "</driver>\n");
            }
17204
            VIR_FREE(str);
17205 17206 17207 17208 17209
            VIR_FREE(hoststr);
            VIR_FREE(gueststr);

            if (rc < 0)
                return -1;
17210 17211
        }
    }
17212 17213 17214 17215 17216 17217
    if (def->backend.tap || def->backend.vhost) {
        virBufferAddLit(buf, "<backend");
        virBufferEscapeString(buf, " tap='%s'", def->backend.tap);
        virBufferEscapeString(buf, " vhost='%s'", def->backend.vhost);
        virBufferAddLit(buf, "/>\n");
    }
17218
    if (def->filter) {
17219 17220 17221
        if (virNWFilterFormatParamAttributes(buf, def->filterparams,
                                             def->filter) < 0)
            return -1;
17222
    }
17223

17224
    if (def->tune.sndbuf_specified) {
17225
        virBufferAddLit(buf,   "<tune>\n");
17226 17227 17228
        virBufferAdjustIndent(buf, 2);
        virBufferAsprintf(buf, "<sndbuf>%lu</sndbuf>\n", def->tune.sndbuf);
        virBufferAdjustIndent(buf, -2);
17229
        virBufferAddLit(buf,   "</tune>\n");
17230 17231
    }

17232 17233
    if (def->linkstate) {
        virBufferAsprintf(buf, "<link state='%s'/>\n",
17234
                          virDomainNetInterfaceLinkStateTypeToString(def->linkstate));
17235
    }
17236
    if (virDomainDeviceInfoFormat(buf, &def->info,
17237 17238
                                  flags | VIR_DOMAIN_XML_INTERNAL_ALLOW_BOOT
                                  | VIR_DOMAIN_XML_INTERNAL_ALLOW_ROM) < 0)
17239 17240
        return -1;

17241 17242
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</interface>\n");
17243 17244 17245 17246
    return 0;
}


17247 17248
/* Assumes that "<device" has already been generated, and starts
 * output at " type='type'>". */
17249
static int
17250
virDomainChrSourceDefFormat(virBufferPtr buf,
J
Ján Tomko 已提交
17251
                            virDomainChrDefPtr chr_def,
17252 17253
                            virDomainChrSourceDefPtr def,
                            bool tty_compat,
E
Eric Blake 已提交
17254
                            unsigned int flags)
17255 17256
{
    const char *type = virDomainChrTypeToString(def->type);
J
Ján Tomko 已提交
17257 17258 17259 17260 17261 17262 17263
    size_t nseclabels = 0;
    virSecurityDeviceLabelDefPtr *seclabels = NULL;

    if (chr_def) {
        nseclabels = chr_def->nseclabels;
        seclabels = chr_def->seclabels;
    }
17264

17265
    if (!type) {
17266 17267
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected char type %d"), def->type);
17268
        return -1;
17269 17270
    }

17271
    /* Compat with legacy <console tty='/dev/pts/5'/> syntax */
17272
    virBufferAsprintf(buf, " type='%s'", type);
17273
    if (tty_compat) {
C
Cole Robinson 已提交
17274
        virBufferEscapeString(buf, " tty='%s'",
17275 17276
                              def->data.file.path);
    }
C
Cole Robinson 已提交
17277
    virBufferAddLit(buf, ">\n");
17278

17279
    switch ((virDomainChrType)def->type) {
17280 17281 17282
    case VIR_DOMAIN_CHR_TYPE_NULL:
    case VIR_DOMAIN_CHR_TYPE_VC:
    case VIR_DOMAIN_CHR_TYPE_STDIO:
17283
    case VIR_DOMAIN_CHR_TYPE_SPICEVMC:
17284
    case VIR_DOMAIN_CHR_TYPE_LAST:
17285 17286 17287 17288 17289 17290 17291 17292
        /* 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 ||
17293 17294
            (def->data.file.path &&
             !(flags & VIR_DOMAIN_XML_INACTIVE))) {
J
Ján Tomko 已提交
17295
            virBufferEscapeString(buf, "<source path='%s'",
17296
                                  def->data.file.path);
J
Ján Tomko 已提交
17297
            virDomainSourceDefFormatSeclabel(buf, nseclabels, seclabels, flags);
17298 17299 17300
        }
        break;

17301 17302 17303 17304 17305 17306
    case VIR_DOMAIN_CHR_TYPE_NMDM:
        virBufferAsprintf(buf, "<source master='%s' slave='%s'/>\n",
                          def->data.nmdm.master,
                          def->data.nmdm.slave);
        break;

17307 17308 17309
    case VIR_DOMAIN_CHR_TYPE_UDP:
        if (def->data.udp.bindService &&
            def->data.udp.bindHost) {
17310
            virBufferAsprintf(buf,
17311
                              "<source mode='bind' host='%s' "
17312
                              "service='%s'/>\n",
17313 17314 17315
                              def->data.udp.bindHost,
                              def->data.udp.bindService);
        } else if (def->data.udp.bindHost) {
17316
            virBufferAsprintf(buf, "<source mode='bind' host='%s'/>\n",
17317 17318
                              def->data.udp.bindHost);
        } else if (def->data.udp.bindService) {
17319
            virBufferAsprintf(buf, "<source mode='bind' service='%s'/>\n",
17320 17321 17322 17323 17324
                              def->data.udp.bindService);
        }

        if (def->data.udp.connectService &&
            def->data.udp.connectHost) {
17325
            virBufferAsprintf(buf,
17326
                              "<source mode='connect' host='%s' "
17327
                              "service='%s'/>\n",
17328 17329 17330
                              def->data.udp.connectHost,
                              def->data.udp.connectService);
        } else if (def->data.udp.connectHost) {
17331
            virBufferAsprintf(buf, "<source mode='connect' host='%s'/>\n",
17332 17333
                              def->data.udp.connectHost);
        } else if (def->data.udp.connectService) {
17334
            virBufferAsprintf(buf,
17335
                              "<source mode='connect' service='%s'/>\n",
17336 17337 17338 17339 17340
                              def->data.udp.connectService);
        }
        break;

    case VIR_DOMAIN_CHR_TYPE_TCP:
17341
        virBufferAsprintf(buf,
17342
                          "<source mode='%s' host='%s' service='%s'/>\n",
17343 17344 17345
                          def->data.tcp.listen ? "bind" : "connect",
                          def->data.tcp.host,
                          def->data.tcp.service);
17346
        virBufferAsprintf(buf, "<protocol type='%s'/>\n",
17347 17348
                          virDomainChrTcpProtocolTypeToString(
                              def->data.tcp.protocol));
17349 17350 17351
        break;

    case VIR_DOMAIN_CHR_TYPE_UNIX:
17352
        virBufferAsprintf(buf, "<source mode='%s'",
17353
                          def->data.nix.listen ? "bind" : "connect");
17354
        virBufferEscapeString(buf, " path='%s'", def->data.nix.path);
J
Ján Tomko 已提交
17355
        virDomainSourceDefFormatSeclabel(buf, nseclabels, seclabels, flags);
17356
        break;
17357 17358

    case VIR_DOMAIN_CHR_TYPE_SPICEPORT:
17359
        virBufferAsprintf(buf, "<source channel='%s'/>\n",
17360 17361 17362
                          def->data.spiceport.channel);
        break;

17363 17364
    }

17365 17366 17367 17368 17369 17370
    return 0;
}

static int
virDomainChrDefFormat(virBufferPtr buf,
                      virDomainChrDefPtr def,
E
Eric Blake 已提交
17371
                      unsigned int flags)
17372 17373 17374 17375 17376 17377 17378 17379 17380
{
    const char *elementName = virDomainChrDeviceTypeToString(def->deviceType);
    const char *targetType = virDomainChrTargetTypeToString(def->deviceType,
                                                            def->targetType);
    bool tty_compat;

    int ret = 0;

    if (!elementName) {
17381 17382 17383
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected char device type %d"),
                       def->deviceType);
17384 17385 17386
        return -1;
    }

17387 17388
    virBufferAsprintf(buf, "<%s", elementName);
    virBufferAdjustIndent(buf, 2);
17389 17390 17391 17392 17393
    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);
J
Ján Tomko 已提交
17394
    if (virDomainChrSourceDefFormat(buf, def, &def->source, tty_compat, flags) < 0)
17395 17396
        return -1;

17397
    /* Format <target> block */
17398
    switch (def->deviceType) {
17399 17400
    case VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL: {
        if (!targetType) {
17401 17402
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Could not format channel target type"));
17403 17404
            return -1;
        }
17405
        virBufferAsprintf(buf, "<target type='%s'", targetType);
17406 17407 17408

        switch (def->targetType) {
        case VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_GUESTFWD: {
17409
            int port = virSocketAddrGetPort(def->target.addr);
17410
            if (port < 0) {
17411 17412
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Unable to format guestfwd port"));
17413 17414
                return -1;
            }
17415

17416
            char *addr = virSocketAddrFormat(def->target.addr);
17417
            if (addr == NULL)
17418
                return -1;
17419

17420
            virBufferAsprintf(buf, " address='%s' port='%d'",
17421 17422 17423
                              addr, port);
            VIR_FREE(addr);
            break;
17424 17425
        }

17426 17427 17428 17429 17430 17431 17432
        case VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO: {
            if (def->target.name) {
                virBufferEscapeString(buf, " name='%s'", def->target.name);
            }
            break;
        }

17433 17434 17435
        }
        virBufferAddLit(buf, "/>\n");
        break;
17436
    }
17437

17438
    case VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE:
17439
        virBufferAsprintf(buf,
17440
                          "<target type='%s' port='%d'/>\n",
17441 17442 17443 17444 17445
                          virDomainChrTargetTypeToString(def->deviceType,
                                                         def->targetType),
                          def->target.port);
        break;

G
Guannan Ren 已提交
17446 17447 17448
    case VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL:
        if (def->targetTypeAttr) {
            virBufferAsprintf(buf,
17449
                              "<target type='%s' port='%d'/>\n",
G
Guannan Ren 已提交
17450 17451 17452 17453 17454
                              virDomainChrTargetTypeToString(def->deviceType,
                                                             def->targetType),
                              def->target.port);
            break;
        }
17455
    default:
17456
        virBufferAsprintf(buf, "<target port='%d'/>\n",
17457
                          def->target.port);
17458
        break;
17459
    }
17460

17461
    if (virDomainDeviceInfoIsSet(&def->info, flags)) {
17462 17463 17464
        if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
            return -1;
    }
17465

17466 17467
    virBufferAdjustIndent(buf, -2);
    virBufferAsprintf(buf, "</%s>\n", elementName);
17468

17469
    return ret;
17470 17471
}

E
Eric Blake 已提交
17472 17473 17474
static int
virDomainSmartcardDefFormat(virBufferPtr buf,
                            virDomainSmartcardDefPtr def,
E
Eric Blake 已提交
17475
                            unsigned int flags)
E
Eric Blake 已提交
17476 17477 17478 17479 17480
{
    const char *mode = virDomainSmartcardTypeToString(def->type);
    size_t i;

    if (!mode) {
17481 17482
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected smartcard type %d"), def->type);
E
Eric Blake 已提交
17483 17484 17485
        return -1;
    }

17486 17487
    virBufferAsprintf(buf, "<smartcard mode='%s'", mode);
    virBufferAdjustIndent(buf, 2);
E
Eric Blake 已提交
17488 17489
    switch (def->type) {
    case VIR_DOMAIN_SMARTCARD_TYPE_HOST:
17490
        if (!virDomainDeviceInfoIsSet(&def->info, flags)) {
17491
            virBufferAdjustIndent(buf, -2);
E
Eric Blake 已提交
17492 17493 17494
            virBufferAddLit(buf, "/>\n");
            return 0;
        }
17495
        virBufferAddLit(buf, ">\n");
E
Eric Blake 已提交
17496 17497 17498 17499 17500
        break;

    case VIR_DOMAIN_SMARTCARD_TYPE_HOST_CERTIFICATES:
        virBufferAddLit(buf, ">\n");
        for (i = 0; i < VIR_DOMAIN_SMARTCARD_NUM_CERTIFICATES; i++)
17501
            virBufferEscapeString(buf, "<certificate>%s</certificate>\n",
E
Eric Blake 已提交
17502
                                  def->data.cert.file[i]);
17503
        virBufferEscapeString(buf, "<database>%s</database>\n",
17504
                              def->data.cert.database);
E
Eric Blake 已提交
17505 17506 17507
        break;

    case VIR_DOMAIN_SMARTCARD_TYPE_PASSTHROUGH:
J
Ján Tomko 已提交
17508
        if (virDomainChrSourceDefFormat(buf, NULL, &def->data.passthru, false,
E
Eric Blake 已提交
17509 17510 17511 17512 17513
                                        flags) < 0)
            return -1;
        break;

    default:
17514 17515
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected smartcard type %d"), def->type);
E
Eric Blake 已提交
17516 17517 17518 17519
        return -1;
    }
    if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
        return -1;
17520 17521
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</smartcard>\n");
E
Eric Blake 已提交
17522 17523 17524
    return 0;
}

17525 17526 17527 17528 17529 17530 17531
static int
virDomainSoundCodecDefFormat(virBufferPtr buf,
                             virDomainSoundCodecDefPtr def)
{
    const char *type = virDomainSoundCodecTypeToString(def->type);

    if (!type) {
17532 17533
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected codec type %d"), def->type);
17534 17535 17536
        return -1;
    }

17537
    virBufferAsprintf(buf, "<codec type='%s'/>\n",  type);
17538 17539 17540 17541

    return 0;
}

17542 17543 17544 17545 17546
static int
virDomainTPMDefFormat(virBufferPtr buf,
                      virDomainTPMDefPtr def,
                      unsigned int flags)
{
17547
    virBufferAsprintf(buf, "<tpm model='%s'>\n",
17548
                      virDomainTPMModelTypeToString(def->model));
17549 17550
    virBufferAdjustIndent(buf, 2);
    virBufferAsprintf(buf, "<backend type='%s'>\n",
17551
                      virDomainTPMBackendTypeToString(def->type));
17552
    virBufferAdjustIndent(buf, 2);
17553 17554 17555

    switch (def->type) {
    case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH:
17556
        virBufferEscapeString(buf, "<device path='%s'/>\n",
17557 17558 17559 17560 17561 17562
                              def->data.passthrough.source.data.file.path);
        break;
    case VIR_DOMAIN_TPM_TYPE_LAST:
        break;
    }

17563 17564
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</backend>\n");
17565 17566 17567 17568 17569 17570

    if (virDomainDeviceInfoIsSet(&def->info, flags)) {
        if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
            return -1;
    }

17571 17572
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</tpm>\n");
17573 17574 17575 17576 17577

    return 0;
}


17578
static int
17579
virDomainSoundDefFormat(virBufferPtr buf,
D
Daniel P. Berrange 已提交
17580
                        virDomainSoundDefPtr def,
E
Eric Blake 已提交
17581
                        unsigned int flags)
17582 17583
{
    const char *model = virDomainSoundModelTypeToString(def->model);
17584
    bool children = false;
17585
    size_t i;
17586 17587

    if (!model) {
17588 17589
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected sound model %d"), def->model);
17590 17591 17592
        return -1;
    }

17593
    virBufferAsprintf(buf, "<sound model='%s'",  model);
17594

17595 17596 17597
    for (i = 0; i < def->ncodecs; i++) {
        if (!children) {
            virBufferAddLit(buf, ">\n");
17598
            virBufferAdjustIndent(buf, 2);
17599 17600 17601 17602 17603
            children = true;
        }
        virDomainSoundCodecDefFormat(buf, def->codecs[i]);
    }

17604
    if (virDomainDeviceInfoIsSet(&def->info, flags)) {
17605 17606
        if (!children) {
            virBufferAddLit(buf, ">\n");
17607
            virBufferAdjustIndent(buf, 2);
17608 17609
            children = true;
        }
D
Daniel P. Berrange 已提交
17610
        if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
17611
            return -1;
17612 17613 17614
    }

    if (children) {
17615 17616
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</sound>\n");
17617 17618 17619 17620
    } else {
        virBufferAddLit(buf, "/>\n");
    }

17621 17622 17623
    return 0;
}

17624

17625 17626 17627
static int
virDomainMemballoonDefFormat(virBufferPtr buf,
                             virDomainMemballoonDefPtr def,
E
Eric Blake 已提交
17628
                             unsigned int flags)
17629 17630
{
    const char *model = virDomainMemballoonModelTypeToString(def->model);
17631
    bool noopts = true;
17632 17633

    if (!model) {
17634 17635
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected memballoon model %d"), def->model);
17636 17637 17638
        return -1;
    }

17639 17640
    virBufferAsprintf(buf, "<memballoon model='%s'", model);
    virBufferAdjustIndent(buf, 2);
17641

17642
    if (virDomainDeviceInfoIsSet(&def->info, flags)) {
17643 17644 17645
        virBufferAddLit(buf, ">\n");
        if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
            return -1;
17646
        noopts = false;
17647 17648
    }

17649 17650 17651
    if (def->period) {
        if (noopts)
            virBufferAddLit(buf, ">\n");
17652
        virBufferAsprintf(buf, "<stats period='%u'/>\n", def->period);
17653 17654 17655
        noopts = false;
    }

17656
    virBufferAdjustIndent(buf, -2);
17657 17658 17659
    if (noopts)
        virBufferAddLit(buf, "/>\n");
    else
17660
        virBufferAddLit(buf, "</memballoon>\n");
17661

17662 17663 17664
    return 0;
}

L
Li Zhang 已提交
17665 17666 17667 17668 17669
static int
virDomainNVRAMDefFormat(virBufferPtr buf,
                        virDomainNVRAMDefPtr def,
                        unsigned int flags)
{
17670 17671
    virBufferAddLit(buf, "<nvram>\n");
    virBufferAdjustIndent(buf, 2);
L
Li Zhang 已提交
17672 17673 17674 17675
    if (virDomainDeviceInfoIsSet(&def->info, flags) &&
        virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
        return -1;

17676 17677
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</nvram>\n");
L
Li Zhang 已提交
17678 17679 17680 17681

    return 0;
}

17682

R
Richard Jones 已提交
17683
static int
17684
virDomainWatchdogDefFormat(virBufferPtr buf,
D
Daniel P. Berrange 已提交
17685
                           virDomainWatchdogDefPtr def,
E
Eric Blake 已提交
17686
                           unsigned int flags)
R
Richard Jones 已提交
17687
{
17688 17689
    const char *model = virDomainWatchdogModelTypeToString(def->model);
    const char *action = virDomainWatchdogActionTypeToString(def->action);
R
Richard Jones 已提交
17690 17691

    if (!model) {
17692 17693
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected watchdog model %d"), def->model);
R
Richard Jones 已提交
17694 17695 17696 17697
        return -1;
    }

    if (!action) {
17698 17699
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected watchdog action %d"), def->action);
R
Richard Jones 已提交
17700 17701 17702
        return -1;
    }

17703
    virBufferAsprintf(buf, "<watchdog model='%s' action='%s'",
R
Richard Jones 已提交
17704 17705
                      model, action);

17706
    if (virDomainDeviceInfoIsSet(&def->info, flags)) {
17707
        virBufferAddLit(buf, ">\n");
17708
        virBufferAdjustIndent(buf, 2);
D
Daniel P. Berrange 已提交
17709
        if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
17710
            return -1;
17711 17712
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</watchdog>\n");
17713 17714 17715 17716
    } else {
        virBufferAddLit(buf, "/>\n");
    }

R
Richard Jones 已提交
17717 17718 17719
    return 0;
}

H
Hu Tao 已提交
17720 17721 17722
static int virDomainPanicDefFormat(virBufferPtr buf,
                                     virDomainPanicDefPtr def)
{
17723 17724
    virBufferAddLit(buf, "<panic>\n");
    virBufferAdjustIndent(buf, 2);
H
Hu Tao 已提交
17725 17726
    if (virDomainDeviceInfoFormat(buf, &def->info, 0) < 0)
        return -1;
17727 17728
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</panic>\n");
H
Hu Tao 已提交
17729 17730 17731

    return 0;
}
R
Richard Jones 已提交
17732

17733 17734 17735 17736 17737
static int
virDomainShmemDefFormat(virBufferPtr buf,
                        virDomainShmemDefPtr def,
                        unsigned int flags)
{
M
Martin Kletzander 已提交
17738
    virBufferEscapeString(buf, "<shmem name='%s'", def->name);
17739 17740 17741 17742 17743 17744 17745 17746 17747 17748 17749 17750 17751 17752

    if (!def->size &&
        !def->server.enabled &&
        !def->msi.enabled &&
        !virDomainDeviceInfoIsSet(&def->info, flags)) {
        virBufferAddLit(buf, "/>\n");
        return 0;
    } else {
        virBufferAddLit(buf, ">\n");
    }

    virBufferAdjustIndent(buf, 2);

    if (def->size)
M
Martin Kletzander 已提交
17753
        virBufferAsprintf(buf, "<size unit='M'>%llu</size>\n", def->size >> 20);
17754 17755 17756 17757 17758 17759 17760 17761 17762 17763 17764 17765 17766 17767 17768 17769 17770 17771 17772 17773 17774 17775 17776 17777 17778 17779

    if (def->server.enabled) {
        virBufferAddLit(buf, "<server");
        virBufferEscapeString(buf, " path='%s'", def->server.path);
        virBufferAddLit(buf, "/>\n");
    }

    if (def->msi.enabled) {
        virBufferAddLit(buf, "<msi");
        if (def->msi.vectors)
            virBufferAsprintf(buf, " vectors='%u'", def->msi.vectors);
        if (def->msi.ioeventfd)
            virBufferAsprintf(buf, " ioeventfd='%s'",
                              virTristateSwitchTypeToString(def->msi.ioeventfd));
        virBufferAddLit(buf, "/>\n");
    }

    if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
        return -1;

    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</shmem>\n");

    return 0;
}

17780 17781 17782 17783 17784 17785 17786 17787
static int
virDomainRNGDefFormat(virBufferPtr buf,
                      virDomainRNGDefPtr def,
                      unsigned int flags)
{
    const char *model = virDomainRNGModelTypeToString(def->model);
    const char *backend = virDomainRNGBackendTypeToString(def->backend);

17788 17789
    virBufferAsprintf(buf, "<rng model='%s'>\n", model);
    virBufferAdjustIndent(buf, 2);
17790
    if (def->rate) {
17791
        virBufferAsprintf(buf, "<rate bytes='%u'", def->rate);
17792 17793 17794 17795
        if (def->period)
            virBufferAsprintf(buf, " period='%u'", def->period);
        virBufferAddLit(buf, "/>\n");
    }
17796
    virBufferAsprintf(buf, "<backend model='%s'", backend);
17797

17798
    switch ((virDomainRNGBackend) def->backend) {
17799
    case VIR_DOMAIN_RNG_BACKEND_RANDOM:
17800
        virBufferEscapeString(buf, ">%s</backend>\n", def->source.file);
17801 17802 17803 17804
        break;

    case VIR_DOMAIN_RNG_BACKEND_EGD:
        virBufferAdjustIndent(buf, 2);
J
Ján Tomko 已提交
17805
        if (virDomainChrSourceDefFormat(buf, NULL, def->source.chardev,
17806 17807 17808
                                        false, flags) < 0)
            return -1;
        virBufferAdjustIndent(buf, -2);
17809
        virBufferAddLit(buf, "</backend>\n");
17810 17811 17812 17813 17814

    case VIR_DOMAIN_RNG_BACKEND_LAST:
        break;
    }

17815 17816 17817 17818 17819
    if (virDomainDeviceInfoIsSet(&def->info, flags)) {
        if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
            return -1;
    }

17820 17821
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</rng>\n");
17822 17823 17824 17825 17826 17827 17828 17829 17830
    return 0;
}

void
virDomainRNGDefFree(virDomainRNGDefPtr def)
{
    if (!def)
        return;

17831
    switch ((virDomainRNGBackend) def->backend) {
17832 17833 17834 17835 17836 17837 17838 17839 17840 17841
    case VIR_DOMAIN_RNG_BACKEND_RANDOM:
        VIR_FREE(def->source.file);
        break;
    case VIR_DOMAIN_RNG_BACKEND_EGD:
        virDomainChrSourceDefFree(def->source.chardev);
        break;
    case VIR_DOMAIN_RNG_BACKEND_LAST:
        break;
    }

J
John Ferlan 已提交
17842
    virDomainDeviceInfoClear(&def->info);
17843 17844 17845
    VIR_FREE(def);
}

17846 17847 17848 17849
static void
virDomainVideoAccelDefFormat(virBufferPtr buf,
                             virDomainVideoAccelDefPtr def)
{
17850
    virBufferAsprintf(buf, "<acceleration accel3d='%s'",
17851
                      def->support3d ? "yes" : "no");
17852
    virBufferAsprintf(buf, " accel2d='%s'",
17853 17854 17855 17856 17857
                      def->support2d ? "yes" : "no");
    virBufferAddLit(buf, "/>\n");
}


17858
static int
17859
virDomainVideoDefFormat(virBufferPtr buf,
D
Daniel P. Berrange 已提交
17860
                        virDomainVideoDefPtr def,
E
Eric Blake 已提交
17861
                        unsigned int flags)
17862 17863 17864 17865
{
    const char *model = virDomainVideoTypeToString(def->type);

    if (!model) {
17866 17867
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected video model %d"), def->type);
17868 17869 17870
        return -1;
    }

17871 17872 17873
    virBufferAddLit(buf, "<video>\n");
    virBufferAdjustIndent(buf, 2);
    virBufferAsprintf(buf, "<model type='%s'",
17874
                      model);
17875 17876
    if (def->ram)
        virBufferAsprintf(buf, " ram='%u'", def->ram);
17877
    if (def->vram)
17878
        virBufferAsprintf(buf, " vram='%u'", def->vram);
17879
    if (def->heads)
17880
        virBufferAsprintf(buf, " heads='%u'", def->heads);
17881 17882
    if (def->primary)
        virBufferAddLit(buf, " primary='yes'");
17883 17884
    if (def->accel) {
        virBufferAddLit(buf, ">\n");
17885
        virBufferAdjustIndent(buf, 2);
17886
        virDomainVideoAccelDefFormat(buf, def->accel);
17887 17888
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</model>\n");
17889 17890 17891 17892
    } else {
        virBufferAddLit(buf, "/>\n");
    }

D
Daniel P. Berrange 已提交
17893
    if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
17894 17895
        return -1;

17896 17897
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</video>\n");
17898 17899 17900
    return 0;
}

17901
static int
17902
virDomainInputDefFormat(virBufferPtr buf,
17903
                        virDomainInputDefPtr def,
E
Eric Blake 已提交
17904
                        unsigned int flags)
17905 17906 17907 17908 17909
{
    const char *type = virDomainInputTypeToString(def->type);
    const char *bus = virDomainInputBusTypeToString(def->bus);

    if (!type) {
17910 17911
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected input type %d"), def->type);
17912 17913 17914
        return -1;
    }
    if (!bus) {
17915 17916
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected input bus type %d"), def->bus);
17917 17918 17919
        return -1;
    }

17920
    virBufferAsprintf(buf, "<input type='%s' bus='%s'",
17921 17922
                      type, bus);

17923
    if (virDomainDeviceInfoIsSet(&def->info, flags)) {
17924
        virBufferAddLit(buf, ">\n");
17925
        virBufferAdjustIndent(buf, 2);
17926 17927
        if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
            return -1;
17928 17929
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</input>\n");
17930 17931 17932 17933
    } else {
        virBufferAddLit(buf, "/>\n");
    }

17934 17935 17936 17937
    return 0;
}


17938 17939 17940 17941 17942 17943 17944
static int
virDomainTimerDefFormat(virBufferPtr buf,
                        virDomainTimerDefPtr def)
{
    const char *name = virDomainTimerNameTypeToString(def->name);

    if (!name) {
17945 17946
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected timer name %d"), def->name);
17947 17948
        return -1;
    }
17949
    virBufferAsprintf(buf, "<timer name='%s'", name);
17950 17951 17952 17953 17954 17955 17956 17957 17958 17959 17960

    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) {
17961 17962 17963
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected timer tickpolicy %d"),
                           def->tickpolicy);
17964 17965
            return -1;
        }
17966
        virBufferAsprintf(buf, " tickpolicy='%s'", tickpolicy);
17967 17968 17969 17970
    }

    if ((def->name == VIR_DOMAIN_TIMER_NAME_PLATFORM)
        || (def->name == VIR_DOMAIN_TIMER_NAME_RTC)) {
17971 17972 17973 17974
        if (def->track != -1) {
            const char *track
                = virDomainTimerTrackTypeToString(def->track);
            if (!track) {
17975 17976 17977
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unexpected timer track %d"),
                               def->track);
17978 17979
                return -1;
            }
17980
            virBufferAsprintf(buf, " track='%s'", track);
17981 17982 17983 17984 17985
        }
    }

    if (def->name == VIR_DOMAIN_TIMER_NAME_TSC) {
        if (def->frequency > 0) {
17986
            virBufferAsprintf(buf, " frequency='%lu'", def->frequency);
17987 17988 17989 17990 17991 17992
        }

        if (def->mode != -1) {
            const char *mode
                = virDomainTimerModeTypeToString(def->mode);
            if (!mode) {
17993 17994 17995
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unexpected timer mode %d"),
                               def->mode);
17996 17997
                return -1;
            }
17998
            virBufferAsprintf(buf, " mode='%s'", mode);
17999 18000 18001
        }
    }

E
Eric Blake 已提交
18002 18003
    if (def->catchup.threshold == 0 && def->catchup.slew == 0 &&
        def->catchup.limit == 0) {
18004 18005
        virBufferAddLit(buf, "/>\n");
    } else {
18006
        virBufferAddLit(buf, ">\n");
18007 18008
        virBufferAdjustIndent(buf, 2);
        virBufferAddLit(buf, "<catchup");
18009
        if (def->catchup.threshold > 0) {
18010
            virBufferAsprintf(buf, " threshold='%lu'", def->catchup.threshold);
18011 18012
        }
        if (def->catchup.slew > 0) {
18013
            virBufferAsprintf(buf, " slew='%lu'", def->catchup.slew);
18014 18015
        }
        if (def->catchup.limit > 0) {
18016
            virBufferAsprintf(buf, " limit='%lu'", def->catchup.limit);
18017
        }
18018
        virBufferAddLit(buf, "/>\n");
18019 18020
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</timer>\n");
18021
    }
18022 18023 18024 18025

    return 0;
}

18026 18027 18028 18029 18030 18031 18032 18033 18034 18035 18036 18037 18038 18039 18040 18041 18042
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);
18043
        virBufferAsprintf(buf, " passwdValidTo='%s'", strbuf);
18044
    }
18045 18046 18047 18048

    if (def->connected)
        virBufferEscapeString(buf, " connected='%s'",
                              virDomainGraphicsAuthConnectedTypeToString(def->connected));
18049 18050
}

18051 18052 18053 18054 18055 18056

static void
virDomainGraphicsListenDefFormat(virBufferPtr buf,
                                 virDomainGraphicsListenDefPtr def,
                                 unsigned int flags)
{
18057 18058 18059 18060 18061
    /* If generating migratable XML, skip listen address
     * dragged in from config file */
    if ((flags & VIR_DOMAIN_XML_MIGRATABLE) && def->fromConfig)
        return;

18062
    virBufferAddLit(buf, "<listen");
18063 18064 18065 18066 18067 18068
    if (def->type) {
        virBufferAsprintf(buf, " type='%s'",
                          virDomainGraphicsListenTypeToString(def->type));
    }

    if (def->address &&
E
Eric Blake 已提交
18069 18070
        (def->type == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS ||
         (def->type == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NETWORK &&
18071 18072 18073 18074 18075 18076 18077 18078
          !(flags & VIR_DOMAIN_XML_INACTIVE)))) {
        /* address may also be set to show current status when type='network',
         * but we don't want to print that if INACTIVE data is requested. */
        virBufferAsprintf(buf, " address='%s'", def->address);
    }

    if (def->network &&
        (def->type == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NETWORK)) {
18079
        virBufferEscapeString(buf, " network='%s'", def->network);
18080 18081
    }

18082 18083 18084
    if (flags & VIR_DOMAIN_XML_INTERNAL_STATUS)
        virBufferAsprintf(buf, " fromConfig='%d'", def->fromConfig);

18085 18086 18087 18088
    virBufferAddLit(buf, "/>\n");
}


18089
static int
18090
virDomainGraphicsDefFormat(virBufferPtr buf,
18091
                           virDomainGraphicsDefPtr def,
E
Eric Blake 已提交
18092
                           unsigned int flags)
18093 18094
{
    const char *type = virDomainGraphicsTypeToString(def->type);
18095
    const char *listenAddr = NULL;
18096
    bool children = false;
18097
    size_t i;
18098 18099

    if (!type) {
18100 18101
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected net type %d"), def->type);
18102 18103 18104
        return -1;
    }

18105 18106 18107 18108 18109 18110
    /* find the first listen element of type='address' and duplicate
    * its address attribute as the listen attribute of
    * <graphics>. This is done to improve backward compatibility. */
    for (i = 0; i < def->nListens; i++) {
        if (virDomainGraphicsListenGetType(def, i)
            == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS) {
18111 18112 18113
            if (flags & VIR_DOMAIN_XML_MIGRATABLE &&
                def->listens[i].fromConfig)
                continue;
18114 18115 18116 18117 18118
            listenAddr = virDomainGraphicsListenGetAddress(def, i);
            break;
        }
    }

18119
    virBufferAsprintf(buf, "<graphics type='%s'", type);
18120 18121 18122

    switch (def->type) {
    case VIR_DOMAIN_GRAPHICS_TYPE_VNC:
18123 18124
        if (def->data.vnc.socket) {
            if (def->data.vnc.socket)
18125
                virBufferAsprintf(buf, " socket='%s'",
18126 18127 18128 18129
                                  def->data.vnc.socket);
        } else {
            if (def->data.vnc.port &&
                (!def->data.vnc.autoport || !(flags & VIR_DOMAIN_XML_INACTIVE)))
18130
                virBufferAsprintf(buf, " port='%d'",
18131 18132 18133
                                  def->data.vnc.port);
            else if (def->data.vnc.autoport)
                virBufferAddLit(buf, " port='-1'");
18134

18135
            virBufferAsprintf(buf, " autoport='%s'",
18136
                              def->data.vnc.autoport ? "yes" : "no");
18137

M
Martin Kletzander 已提交
18138 18139 18140
            if (def->data.vnc.websocket)
                virBufferAsprintf(buf, " websocket='%d'", def->data.vnc.websocket);

18141 18142
            if (listenAddr)
                virBufferAsprintf(buf, " listen='%s'", listenAddr);
18143
        }
18144 18145 18146 18147 18148

        if (def->data.vnc.keymap)
            virBufferEscapeString(buf, " keymap='%s'",
                                  def->data.vnc.keymap);

18149 18150 18151 18152 18153
        if (def->data.vnc.sharePolicy)
            virBufferAsprintf(buf, " sharePolicy='%s'",
                              virDomainGraphicsVNCSharePolicyTypeToString(
                              def->data.vnc.sharePolicy));

18154
        virDomainGraphicsAuthDefFormatAttr(buf, &def->data.vnc.auth, flags);
18155 18156 18157 18158 18159 18160 18161 18162 18163 18164
        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);
18165 18166 18167
        if (def->data.sdl.fullscreen)
            virBufferAddLit(buf, " fullscreen='yes'");

18168
        break;
18169 18170 18171

    case VIR_DOMAIN_GRAPHICS_TYPE_RDP:
        if (def->data.rdp.port)
18172
            virBufferAsprintf(buf, " port='%d'",
18173 18174 18175 18176 18177
                              def->data.rdp.port);
        else if (def->data.rdp.autoport)
            virBufferAddLit(buf, " port='0'");

        if (def->data.rdp.autoport)
18178
            virBufferAddLit(buf, " autoport='yes'");
18179 18180

        if (def->data.rdp.replaceUser)
18181
            virBufferAddLit(buf, " replaceUser='yes'");
18182 18183

        if (def->data.rdp.multiUser)
18184
            virBufferAddLit(buf, " multiUser='yes'");
18185

18186 18187
        if (listenAddr)
            virBufferAsprintf(buf, " listen='%s'", listenAddr);
18188 18189 18190 18191 18192 18193 18194 18195 18196 18197 18198 18199 18200

        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;

18201 18202
    case VIR_DOMAIN_GRAPHICS_TYPE_SPICE:
        if (def->data.spice.port)
18203
            virBufferAsprintf(buf, " port='%d'",
18204 18205 18206
                              def->data.spice.port);

        if (def->data.spice.tlsPort)
18207
            virBufferAsprintf(buf, " tlsPort='%d'",
18208 18209
                              def->data.spice.tlsPort);

18210
        virBufferAsprintf(buf, " autoport='%s'",
18211 18212
                          def->data.spice.autoport ? "yes" : "no");

18213 18214
        if (listenAddr)
            virBufferAsprintf(buf, " listen='%s'", listenAddr);
18215 18216 18217 18218 18219

        if (def->data.spice.keymap)
            virBufferEscapeString(buf, " keymap='%s'",
                                  def->data.spice.keymap);

18220 18221 18222 18223
        if (def->data.spice.defaultMode != VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_ANY)
            virBufferAsprintf(buf, " defaultMode='%s'",
              virDomainGraphicsSpiceChannelModeTypeToString(def->data.spice.defaultMode));

18224
        virDomainGraphicsAuthDefFormatAttr(buf, &def->data.spice.auth, flags);
18225 18226
        break;

18227 18228
    }

18229 18230 18231 18232
    for (i = 0; i < def->nListens; i++) {
        if (virDomainGraphicsListenGetType(def, i)
            == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NONE)
            continue;
18233 18234 18235
        if (flags & VIR_DOMAIN_XML_MIGRATABLE &&
            def->listens[i].fromConfig)
            continue;
18236 18237
        if (!children) {
            virBufferAddLit(buf, ">\n");
18238
            virBufferAdjustIndent(buf, 2);
18239
            children = true;
18240 18241 18242 18243
        }
        virDomainGraphicsListenDefFormat(buf, &def->listens[i], flags);
    }

18244
    if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) {
18245
        for (i = 0; i < VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_LAST; i++) {
18246 18247 18248 18249 18250 18251
            int mode = def->data.spice.channels[i];
            if (mode == VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_ANY)
                continue;

            if (!children) {
                virBufferAddLit(buf, ">\n");
18252
                virBufferAdjustIndent(buf, 2);
18253
                children = true;
18254 18255
            }

18256
            virBufferAsprintf(buf, "<channel name='%s' mode='%s'/>\n",
18257 18258 18259
                              virDomainGraphicsSpiceChannelNameTypeToString(i),
                              virDomainGraphicsSpiceChannelModeTypeToString(mode));
        }
18260 18261
        if (!children && (def->data.spice.image || def->data.spice.jpeg ||
                          def->data.spice.zlib || def->data.spice.playback ||
P
Peng Zhou 已提交
18262
                          def->data.spice.streaming || def->data.spice.copypaste ||
18263
                          def->data.spice.mousemode || def->data.spice.filetransfer)) {
18264
            virBufferAddLit(buf, ">\n");
18265
            virBufferAdjustIndent(buf, 2);
18266
            children = true;
18267
        }
18268
        if (def->data.spice.image)
18269
            virBufferAsprintf(buf, "<image compression='%s'/>\n",
18270 18271
                              virDomainGraphicsSpiceImageCompressionTypeToString(def->data.spice.image));
        if (def->data.spice.jpeg)
18272
            virBufferAsprintf(buf, "<jpeg compression='%s'/>\n",
18273 18274
                              virDomainGraphicsSpiceJpegCompressionTypeToString(def->data.spice.jpeg));
        if (def->data.spice.zlib)
18275
            virBufferAsprintf(buf, "<zlib compression='%s'/>\n",
18276 18277
                              virDomainGraphicsSpiceZlibCompressionTypeToString(def->data.spice.zlib));
        if (def->data.spice.playback)
18278
            virBufferAsprintf(buf, "<playback compression='%s'/>\n",
J
Ján Tomko 已提交
18279
                              virTristateSwitchTypeToString(def->data.spice.playback));
18280
        if (def->data.spice.streaming)
18281
            virBufferAsprintf(buf, "<streaming mode='%s'/>\n",
18282
                              virDomainGraphicsSpiceStreamingModeTypeToString(def->data.spice.streaming));
P
Peng Zhou 已提交
18283
        if (def->data.spice.mousemode)
18284
            virBufferAsprintf(buf, "<mouse mode='%s'/>\n",
P
Peng Zhou 已提交
18285
                              virDomainGraphicsSpiceMouseModeTypeToString(def->data.spice.mousemode));
18286
        if (def->data.spice.copypaste)
18287
            virBufferAsprintf(buf, "<clipboard copypaste='%s'/>\n",
J
Ján Tomko 已提交
18288
                              virTristateBoolTypeToString(def->data.spice.copypaste));
18289
        if (def->data.spice.filetransfer)
18290
            virBufferAsprintf(buf, "<filetransfer enable='%s'/>\n",
J
Ján Tomko 已提交
18291
                              virTristateBoolTypeToString(def->data.spice.filetransfer));
18292 18293 18294
    }

    if (children) {
18295 18296
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</graphics>\n");
18297 18298 18299
    } else {
        virBufferAddLit(buf, "/>\n");
    }
18300 18301 18302 18303

    return 0;
}

18304 18305

static int
18306
virDomainHostdevDefFormat(virBufferPtr buf,
D
Daniel P. Berrange 已提交
18307
                          virDomainHostdevDefPtr def,
E
Eric Blake 已提交
18308
                          unsigned int flags)
18309 18310
{
    const char *mode = virDomainHostdevModeTypeToString(def->mode);
18311
    virDomainHostdevSubsysSCSIPtr scsisrc = &def->source.subsys.u.scsi;
18312 18313
    const char *type;

18314
    if (!mode) {
18315 18316
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected hostdev mode %d"), def->mode);
18317 18318 18319
        return -1;
    }

18320 18321 18322 18323 18324 18325 18326 18327 18328 18329
    switch (def->mode) {
    case VIR_DOMAIN_HOSTDEV_MODE_SUBSYS:
        type = virDomainHostdevSubsysTypeToString(def->source.subsys.type);
        if (!type) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected hostdev type %d"),
                           def->source.subsys.type);
            return -1;
        }
        break;
18330 18331 18332 18333 18334 18335 18336 18337 18338
    case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
        type = virDomainHostdevCapsTypeToString(def->source.caps.type);
        if (!type) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected hostdev type %d"),
                           def->source.caps.type);
            return -1;
        }
        break;
18339
    default:
18340
        virReportError(VIR_ERR_INTERNAL_ERROR,
18341
                       _("unexpected hostdev mode %d"), def->mode);
18342 18343 18344
        return -1;
    }

18345
    virBufferAsprintf(buf, "<hostdev mode='%s' type='%s'",
18346
                      mode, type);
O
Osier Yang 已提交
18347 18348
    if (def->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
        virBufferAsprintf(buf, " managed='%s'",
18349
                          def->managed ? "yes" : "no");
O
Osier Yang 已提交
18350

18351 18352
        if (def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI &&
            scsisrc->sgio)
O
Osier Yang 已提交
18353
            virBufferAsprintf(buf, " sgio='%s'",
18354
                              virDomainDeviceSGIOTypeToString(scsisrc->sgio));
18355 18356 18357 18358 18359 18360

        if (def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI &&
            scsisrc->rawio) {
            virBufferAsprintf(buf, " rawio='%s'",
                              virTristateBoolTypeToString(scsisrc->rawio));
        }
O
Osier Yang 已提交
18361 18362
    }
    virBufferAddLit(buf, ">\n");
18363
    virBufferAdjustIndent(buf, 2);
18364

18365 18366 18367 18368 18369
    switch (def->mode) {
    case VIR_DOMAIN_HOSTDEV_MODE_SUBSYS:
        if (virDomainHostdevDefFormatSubsys(buf, def, flags, false) < 0)
            return -1;
        break;
18370 18371 18372 18373
    case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
        if (virDomainHostdevDefFormatCaps(buf, def) < 0)
            return -1;
        break;
18374
    }
O
Osier Yang 已提交
18375 18376 18377

    if (def->readonly)
        virBufferAddLit(buf, "<readonly/>\n");
18378 18379
    if (def->shareable)
        virBufferAddLit(buf, "<shareable/>\n");
18380

18381
    if (virDomainDeviceInfoFormat(buf, def->info,
18382 18383
                                  flags | VIR_DOMAIN_XML_INTERNAL_ALLOW_BOOT
                                  | VIR_DOMAIN_XML_INTERNAL_ALLOW_ROM) < 0)
18384 18385
        return -1;

18386 18387
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</hostdev>\n");
18388 18389 18390 18391

    return 0;
}

18392 18393 18394 18395 18396 18397 18398 18399 18400
static int
virDomainRedirdevDefFormat(virBufferPtr buf,
                           virDomainRedirdevDefPtr def,
                           unsigned int flags)
{
    const char *bus;

    bus = virDomainRedirdevBusTypeToString(def->bus);

18401 18402
    virBufferAsprintf(buf, "<redirdev bus='%s'", bus);
    virBufferAdjustIndent(buf, 2);
J
Ján Tomko 已提交
18403
    if (virDomainChrSourceDefFormat(buf, NULL, &def->source.chr, false, flags) < 0)
18404
        return -1;
18405 18406
    if (virDomainDeviceInfoFormat(buf, &def->info,
                                  flags | VIR_DOMAIN_XML_INTERNAL_ALLOW_BOOT) < 0)
18407
        return -1;
18408 18409
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</redirdev>\n");
18410 18411
    return 0;
}
18412

18413 18414 18415 18416 18417 18418
static int
virDomainRedirFilterDefFormat(virBufferPtr buf,
                              virDomainRedirFilterDefPtr filter)
{
    size_t i;

18419 18420
    virBufferAddLit(buf, "<redirfilter>\n");
    virBufferAdjustIndent(buf, 2);
18421
    for (i = 0; i < filter->nusbdevs; i++) {
18422
        virDomainRedirFilterUSBDevDefPtr usbdev = filter->usbdevs[i];
18423
        virBufferAddLit(buf, "<usbdev");
18424 18425 18426 18427 18428 18429 18430 18431 18432 18433 18434 18435 18436 18437 18438 18439 18440 18441 18442
        if (usbdev->usbClass >= 0)
            virBufferAsprintf(buf, " class='0x%02X'", usbdev->usbClass);

        if (usbdev->vendor >= 0)
            virBufferAsprintf(buf, " vendor='0x%04X'", usbdev->vendor);

        if (usbdev->product >= 0)
            virBufferAsprintf(buf, " product='0x%04X'", usbdev->product);

        if (usbdev->version >= 0)
            virBufferAsprintf(buf, " version='%d.%d'",
                                 ((usbdev->version & 0xf000) >> 12) * 10 +
                                 ((usbdev->version & 0x0f00) >>  8),
                                 ((usbdev->version & 0x00f0) >>  4) * 10 +
                                 ((usbdev->version & 0x000f) >>  0));

        virBufferAsprintf(buf, " allow='%s'/>\n", usbdev->allow ? "yes" : "no");

    }
18443 18444
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</redirfilter>\n");
18445 18446 18447
    return 0;
}

M
Marc-André Lureau 已提交
18448 18449
static int
virDomainHubDefFormat(virBufferPtr buf,
18450 18451
                      virDomainHubDefPtr def,
                      unsigned int flags)
M
Marc-André Lureau 已提交
18452 18453 18454 18455
{
    const char *type = virDomainHubTypeToString(def->type);

    if (!type) {
18456 18457
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected hub type %d"), def->type);
M
Marc-André Lureau 已提交
18458 18459 18460
        return -1;
    }

18461
    virBufferAsprintf(buf, "<hub type='%s'", type);
M
Marc-André Lureau 已提交
18462 18463 18464

    if (virDomainDeviceInfoIsSet(&def->info, flags)) {
        virBufferAddLit(buf, ">\n");
18465
        virBufferAdjustIndent(buf, 2);
M
Marc-André Lureau 已提交
18466 18467
        if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
            return -1;
18468 18469
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</hub>\n");
M
Marc-André Lureau 已提交
18470 18471 18472 18473 18474 18475 18476
    } else {
        virBufferAddLit(buf, "/>\n");
    }

    return 0;
}

18477 18478 18479 18480 18481 18482 18483 18484
/*
 * Return true if no <vcpupin> specified in domain XML
 * (I.e. all vcpus inherit the cpuset from "cpuset" of
 * <vcpu>). Or false otherwise.
 */
static bool
virDomainIsAllVcpupinInherited(virDomainDefPtr def)
{
18485
    size_t i;
18486 18487

    if (!def->cpumask) {
18488
        if (def->cputune.nvcpupin)
18489
            return false;
18490 18491
        else
            return true;
18492 18493 18494 18495 18496 18497 18498 18499 18500 18501
    } else {
        for (i = 0; i < def->cputune.nvcpupin; i++) {
            if (!virBitmapEqual(def->cputune.vcpupin[i]->cpumask,
                                def->cpumask))
                return false;
        }

        return true;
   }
}
M
Marc-André Lureau 已提交
18502

18503 18504 18505 18506 18507

static void
virDomainResourceDefFormat(virBufferPtr buf,
                           virDomainResourceDefPtr def)
{
18508 18509 18510 18511 18512
    virBufferAddLit(buf, "<resource>\n");
    virBufferAdjustIndent(buf, 2);
    virBufferEscapeString(buf, "<partition>%s</partition>\n", def->partition);
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</resource>\n");
18513 18514 18515
}


18516 18517 18518 18519 18520 18521 18522 18523 18524 18525 18526 18527 18528 18529 18530 18531 18532 18533 18534 18535 18536 18537 18538 18539 18540 18541 18542 18543 18544 18545 18546 18547 18548 18549 18550 18551 18552 18553 18554 18555 18556 18557 18558 18559 18560 18561 18562
static int
virDomainHugepagesFormatBuf(virBufferPtr buf,
                            virDomainHugePagePtr hugepage)
{
    int ret = -1;

    virBufferAsprintf(buf, "<page size='%llu' unit='KiB'",
                      hugepage->size);

    if (hugepage->nodemask) {
        char *nodeset = NULL;
        if (!(nodeset = virBitmapFormat(hugepage->nodemask)))
            goto cleanup;
        virBufferAsprintf(buf, " nodeset='%s'", nodeset);
        VIR_FREE(nodeset);
    }

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

    ret = 0;
 cleanup:
    return ret;
}

static void
virDomainHugepagesFormat(virBufferPtr buf,
                         virDomainHugePagePtr hugepages,
                         size_t nhugepages)
{
    size_t i;

    if (nhugepages == 1 &&
        hugepages[0].size == 0) {
        virBufferAddLit(buf, "<hugepages/>\n");
        return;
    }

    virBufferAddLit(buf, "<hugepages>\n");
    virBufferAdjustIndent(buf, 2);

    for (i = 0; i < nhugepages; i++)
        virDomainHugepagesFormatBuf(buf, &hugepages[i]);

    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</hugepages>\n");
}

18563 18564 18565 18566 18567 18568 18569 18570 18571 18572 18573 18574 18575 18576 18577
static void
virDomainLoaderDefFormat(virBufferPtr buf,
                         virDomainLoaderDefPtr loader)
{
    const char *readonly = virTristateBoolTypeToString(loader->readonly);
    const char *type = virDomainLoaderTypeToString(loader->type);

    virBufferAddLit(buf, "<loader");

    if (loader->readonly)
        virBufferAsprintf(buf, " readonly='%s'", readonly);

    virBufferAsprintf(buf, " type='%s'>", type);

    virBufferEscapeString(buf, "%s</loader>\n", loader->path);
18578 18579 18580 18581 18582 18583 18584 18585
    if (loader->nvram || loader->templt) {
        virBufferAddLit(buf, "<nvram");
        virBufferEscapeString(buf, " template='%s'", loader->templt);
        if (loader->nvram)
            virBufferEscapeString(buf, ">%s</nvram>\n", loader->nvram);
        else
            virBufferAddLit(buf, "/>\n");
    }
18586
}
18587

18588 18589 18590 18591 18592 18593
static bool
virDomainDefHasCapabilitiesFeatures(virDomainDefPtr def)
{
    size_t i;

    for (i = 0; i < VIR_DOMAIN_CAPS_FEATURE_LAST; i++) {
J
Ján Tomko 已提交
18594
        if (def->caps_features[i] != VIR_TRISTATE_SWITCH_ABSENT)
18595 18596 18597 18598 18599 18600
            return true;
    }

    return false;
}

18601
/* This internal version can accept VIR_DOMAIN_XML_INTERNAL_*,
18602
 * whereas the public version cannot.  Also, it appends to an existing
18603 18604 18605
 * buffer (possibly with auto-indent), rather than flattening to string.
 * Return -1 on failure.  */
int
18606
virDomainDefFormatInternal(virDomainDefPtr def,
18607 18608
                           unsigned int flags,
                           virBufferPtr buf)
18609 18610 18611
{
    unsigned char *uuid;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
18612
    const char *type = NULL;
H
Hu Tao 已提交
18613
    int n;
18614
    size_t i;
18615
    bool blkio = false;
18616
    bool cputune = false;
18617

18618 18619
    virCheckFlags(DUMPXML_FLAGS |
                  VIR_DOMAIN_XML_INTERNAL_STATUS |
18620
                  VIR_DOMAIN_XML_INTERNAL_ACTUAL_NET |
18621 18622
                  VIR_DOMAIN_XML_INTERNAL_PCI_ORIG_STATES |
                  VIR_DOMAIN_XML_INTERNAL_CLOCK_ADJUST,
18623
                  -1);
18624

18625
    if (!(type = virDomainVirtTypeToString(def->virtType))) {
18626 18627
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected domain type %d"), def->virtType);
18628
        goto error;
18629 18630
    }

18631 18632 18633
    if (def->id == -1)
        flags |= VIR_DOMAIN_XML_INACTIVE;

18634
    virBufferAsprintf(buf, "<domain type='%s'", type);
18635
    if (!(flags & VIR_DOMAIN_XML_INACTIVE))
18636
        virBufferAsprintf(buf, " id='%d'", def->id);
18637
    if (def->namespaceData && def->ns.href)
18638 18639
        virBufferAsprintf(buf, " %s", (def->ns.href)());
    virBufferAddLit(buf, ">\n");
18640
    virBufferAdjustIndent(buf, 2);
18641

18642
    virBufferEscapeString(buf, "<name>%s</name>\n", def->name);
18643 18644 18645

    uuid = def->uuid;
    virUUIDFormat(uuid, uuidstr);
18646
    virBufferAsprintf(buf, "<uuid>%s</uuid>\n", uuidstr);
18647

18648
    virBufferEscapeString(buf, "<title>%s</title>\n", def->title);
18649

18650
    virBufferEscapeString(buf, "<description>%s</description>\n",
18651
                          def->description);
18652

18653 18654 18655 18656 18657 18658 18659 18660 18661 18662 18663 18664 18665
    if (def->metadata) {
        xmlBufferPtr xmlbuf;
        int oldIndentTreeOutput = xmlIndentTreeOutput;

        /* Indentation on output requires that we previously set
         * xmlKeepBlanksDefault to 0 when parsing; also, libxml does 2
         * spaces per level of indentation of intermediate elements,
         * but no leading indentation before the starting element.
         * Thankfully, libxml maps what looks like globals into
         * thread-local uses, so we are thread-safe.  */
        xmlIndentTreeOutput = 1;
        xmlbuf = xmlBufferCreate();
        if (xmlNodeDump(xmlbuf, def->metadata->doc, def->metadata,
18666
                        virBufferGetIndent(buf, false) / 2, 1) < 0) {
18667 18668
            xmlBufferFree(xmlbuf);
            xmlIndentTreeOutput = oldIndentTreeOutput;
18669
            goto error;
18670
        }
18671
        virBufferAsprintf(buf, "%s\n", (char *) xmlBufferContent(xmlbuf));
18672 18673 18674 18675
        xmlBufferFree(xmlbuf);
        xmlIndentTreeOutput = oldIndentTreeOutput;
    }

18676
    virBufferAddLit(buf, "<memory");
18677 18678
    if (def->mem.dump_core)
        virBufferAsprintf(buf, " dumpCore='%s'",
J
Ján Tomko 已提交
18679
                          virTristateSwitchTypeToString(def->mem.dump_core));
18680
    virBufferAsprintf(buf, " unit='KiB'>%llu</memory>\n",
E
Eric Blake 已提交
18681
                      def->mem.max_balloon);
18682

18683
    virBufferAsprintf(buf, "<currentMemory unit='KiB'>%llu</currentMemory>\n",
18684 18685
                      def->mem.cur_balloon);

18686 18687
    /* add blkiotune only if there are any */
    if (def->blkio.weight) {
18688 18689 18690
        blkio = true;
    } else {
        for (n = 0; n < def->blkio.ndevices; n++) {
18691 18692 18693 18694 18695
            if (def->blkio.devices[n].weight ||
                def->blkio.devices[n].riops ||
                def->blkio.devices[n].wiops ||
                def->blkio.devices[n].rbps ||
                def->blkio.devices[n].wbps) {
18696 18697 18698 18699 18700 18701 18702
                blkio = true;
                break;
            }
        }
    }

    if (blkio) {
18703 18704
        virBufferAddLit(buf, "<blkiotune>\n");
        virBufferAdjustIndent(buf, 2);
18705 18706

        if (def->blkio.weight)
18707
            virBufferAsprintf(buf, "<weight>%u</weight>\n",
18708 18709 18710
                              def->blkio.weight);

        for (n = 0; n < def->blkio.ndevices; n++) {
18711 18712 18713 18714
            virBlkioDevicePtr dev = &def->blkio.devices[n];

            if (!dev->weight && !dev->riops && !dev->wiops &&
                !dev->rbps && !dev->wbps)
18715
                continue;
18716 18717 18718
            virBufferAddLit(buf, "<device>\n");
            virBufferAdjustIndent(buf, 2);
            virBufferEscapeString(buf, "<path>%s</path>\n",
18719 18720
                                  dev->path);
            if (dev->weight)
18721
                virBufferAsprintf(buf, "<weight>%u</weight>\n",
18722 18723
                                  dev->weight);
            if (dev->riops)
18724
                virBufferAsprintf(buf, "<read_iops_sec>%u</read_iops_sec>\n",
18725 18726
                                  dev->riops);
            if (dev->wiops)
18727
                virBufferAsprintf(buf, "<write_iops_sec>%u</write_iops_sec>\n",
18728 18729
                                  dev->wiops);
            if (dev->rbps)
18730
                virBufferAsprintf(buf, "<read_bytes_sec>%llu</read_bytes_sec>\n",
18731 18732
                                  dev->rbps);
            if (dev->wbps)
18733
                virBufferAsprintf(buf, "<write_bytes_sec>%llu</write_bytes_sec>\n",
18734
                                  dev->wbps);
18735 18736
            virBufferAdjustIndent(buf, -2);
            virBufferAddLit(buf, "</device>\n");
18737 18738
        }

18739 18740
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</blkiotune>\n");
18741 18742
    }

18743
    /* add memtune only if there are any */
18744 18745 18746
    if ((def->mem.hard_limit &&
         def->mem.hard_limit != VIR_DOMAIN_MEMORY_PARAM_UNLIMITED) ||
        (def->mem.soft_limit &&
18747
         def->mem.soft_limit != VIR_DOMAIN_MEMORY_PARAM_UNLIMITED) ||
18748
        (def->mem.swap_hard_limit &&
18749
         def->mem.swap_hard_limit != VIR_DOMAIN_MEMORY_PARAM_UNLIMITED) ||
18750
        def->mem.min_guarantee) {
18751 18752
        virBufferAddLit(buf, "<memtune>\n");
        virBufferAdjustIndent(buf, 2);
18753
        if (def->mem.hard_limit) {
18754
            virBufferAsprintf(buf, "<hard_limit unit='KiB'>"
18755 18756 18757
                              "%llu</hard_limit>\n", def->mem.hard_limit);
        }
        if (def->mem.soft_limit) {
18758
            virBufferAsprintf(buf, "<soft_limit unit='KiB'>"
18759 18760 18761
                              "%llu</soft_limit>\n", def->mem.soft_limit);
        }
        if (def->mem.min_guarantee) {
18762
            virBufferAsprintf(buf, "<min_guarantee unit='KiB'>"
18763 18764 18765
                              "%llu</min_guarantee>\n", def->mem.min_guarantee);
        }
        if (def->mem.swap_hard_limit) {
18766
            virBufferAsprintf(buf, "<swap_hard_limit unit='KiB'>"
18767 18768
                              "%llu</swap_hard_limit>\n", def->mem.swap_hard_limit);
        }
18769 18770
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</memtune>\n");
18771
    }
18772

18773
    if (def->mem.nhugepages || def->mem.nosharepages || def->mem.locked) {
18774 18775
        virBufferAddLit(buf, "<memoryBacking>\n");
        virBufferAdjustIndent(buf, 2);
18776 18777
        if (def->mem.nhugepages)
            virDomainHugepagesFormat(buf, def->mem.hugepages, def->mem.nhugepages);
18778
        if (def->mem.nosharepages)
18779
            virBufferAddLit(buf, "<nosharepages/>\n");
18780
        if (def->mem.locked)
18781 18782 18783
            virBufferAddLit(buf, "<locked/>\n");
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</memoryBacking>\n");
18784
    }
18785

18786
    virBufferAddLit(buf, "<vcpu");
18787 18788
    virBufferAsprintf(buf, " placement='%s'",
                      virDomainCpuPlacementModeTypeToString(def->placement_mode));
H
Hu Tao 已提交
18789 18790

    if (def->cpumask && !virBitmapIsAllSet(def->cpumask)) {
18791
        char *cpumask = NULL;
H
Hu Tao 已提交
18792
        if ((cpumask = virBitmapFormat(def->cpumask)) == NULL)
18793
            goto error;
18794
        virBufferAsprintf(buf, " cpuset='%s'", cpumask);
18795 18796
        VIR_FREE(cpumask);
    }
E
Eric Blake 已提交
18797
    if (def->vcpus != def->maxvcpus)
18798 18799
        virBufferAsprintf(buf, " current='%u'", def->vcpus);
    virBufferAsprintf(buf, ">%u</vcpu>\n", def->maxvcpus);
18800

18801 18802 18803
    if (def->iothreads > 0)
        virBufferAsprintf(buf, "<iothreads>%u</iothreads>\n", def->iothreads);

18804
    if (def->cputune.sharesSpecified ||
18805
        (def->cputune.nvcpupin && !virDomainIsAllVcpupinInherited(def)) ||
T
Tang Chen 已提交
18806
        def->cputune.period || def->cputune.quota ||
18807
        def->cputune.emulatorpin ||
18808 18809
        def->cputune.emulator_period || def->cputune.emulator_quota ||
        def->cputune.niothreadspin) {
18810
        virBufferAddLit(buf, "<cputune>\n");
18811 18812
        cputune = true;
    }
18813

18814
    virBufferAdjustIndent(buf, 2);
18815
    if (def->cputune.sharesSpecified)
18816
        virBufferAsprintf(buf, "<shares>%lu</shares>\n",
18817
                          def->cputune.shares);
18818
    if (def->cputune.period)
18819
        virBufferAsprintf(buf, "<period>%llu</period>\n",
18820 18821
                          def->cputune.period);
    if (def->cputune.quota)
18822
        virBufferAsprintf(buf, "<quota>%lld</quota>\n",
18823
                          def->cputune.quota);
18824 18825

    if (def->cputune.emulator_period)
18826
        virBufferAsprintf(buf, "<emulator_period>%llu"
18827 18828 18829 18830
                          "</emulator_period>\n",
                          def->cputune.emulator_period);

    if (def->cputune.emulator_quota)
18831
        virBufferAsprintf(buf, "<emulator_quota>%lld"
18832 18833 18834
                          "</emulator_quota>\n",
                          def->cputune.emulator_quota);

18835
    for (i = 0; i < def->cputune.nvcpupin; i++) {
P
Peter Krempa 已提交
18836 18837
        char *cpumask;
        /* Ignore the vcpupin which inherit from "cpuset of "<vcpu>." */
18838 18839 18840 18841
        if (def->cpumask &&
            virBitmapEqual(def->cpumask,
                           def->cputune.vcpupin[i]->cpumask))
            continue;
18842

18843
        virBufferAsprintf(buf, "<vcpupin vcpu='%u' ",
18844
                          def->cputune.vcpupin[i]->vcpuid);
18845

18846
        if (!(cpumask = virBitmapFormat(def->cputune.vcpupin[i]->cpumask)))
18847
            goto error;
18848 18849 18850

        virBufferAsprintf(buf, "cpuset='%s'/>\n", cpumask);
        VIR_FREE(cpumask);
18851 18852
    }

T
Tang Chen 已提交
18853
    if (def->cputune.emulatorpin) {
P
Peter Krempa 已提交
18854
        char *cpumask;
18855
        virBufferAddLit(buf, "<emulatorpin ");
T
Tang Chen 已提交
18856

18857 18858
        if (!(cpumask = virBitmapFormat(def->cputune.emulatorpin->cpumask)))
            goto error;
T
Tang Chen 已提交
18859 18860 18861 18862

        virBufferAsprintf(buf, "cpuset='%s'/>\n", cpumask);
        VIR_FREE(cpumask);
    }
18863 18864 18865 18866 18867 18868 18869 18870 18871 18872 18873 18874 18875 18876 18877 18878 18879 18880 18881

    for (i = 0; i < def->cputune.niothreadspin; i++) {
        char *cpumask;
        /* Ignore the iothreadpin which inherit from "cpuset of "<vcpu>." */
        if (def->cpumask &&
            virBitmapEqual(def->cpumask,
                           def->cputune.iothreadspin[i]->cpumask))
            continue;

        virBufferAsprintf(buf, "<iothreadpin iothread='%u' ",
                          def->cputune.iothreadspin[i]->vcpuid);

        if (!(cpumask = virBitmapFormat(def->cputune.iothreadspin[i]->cpumask)))
            goto error;

        virBufferAsprintf(buf, "cpuset='%s'/>\n", cpumask);
        VIR_FREE(cpumask);
    }

18882
    virBufferAdjustIndent(buf, -2);
18883
    if (cputune)
18884
        virBufferAddLit(buf, "</cputune>\n");
18885

18886 18887
    if (virDomainNumatuneFormatXML(buf, def->numatune) < 0)
        goto error;
18888

18889 18890 18891
    if (def->resource)
        virDomainResourceDefFormat(buf, def->resource);

18892
    if (def->sysinfo)
18893
        virSysinfoFormat(buf, def->sysinfo);
18894

18895
    if (def->os.bootloader) {
18896
        virBufferEscapeString(buf, "<bootloader>%s</bootloader>\n",
18897
                              def->os.bootloader);
18898
        virBufferEscapeString(buf,
18899
                              "<bootloader_args>%s</bootloader_args>\n",
18900
                              def->os.bootloaderArgs);
18901 18902
    }

18903 18904 18905
    virBufferAddLit(buf, "<os>\n");
    virBufferAdjustIndent(buf, 2);
    virBufferAddLit(buf, "<type");
18906
    if (def->os.arch)
18907
        virBufferAsprintf(buf, " arch='%s'", virArchToString(def->os.arch));
18908
    if (def->os.machine)
18909
        virBufferAsprintf(buf, " machine='%s'", def->os.machine);
18910 18911 18912 18913 18914 18915 18916
    /*
     * 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"))
18917
        virBufferAsprintf(buf, ">%s</type>\n", "linux");
18918
    else
18919
        virBufferAsprintf(buf, ">%s</type>\n", def->os.type);
18920

18921
    virBufferEscapeString(buf, "<init>%s</init>\n",
18922
                          def->os.init);
18923
    for (i = 0; def->os.initargv && def->os.initargv[i]; i++)
18924
        virBufferEscapeString(buf, "<initarg>%s</initarg>\n",
18925
                              def->os.initargv[i]);
18926 18927
    if (def->os.loader)
        virDomainLoaderDefFormat(buf, def->os.loader);
18928
    virBufferEscapeString(buf, "<kernel>%s</kernel>\n",
18929
                          def->os.kernel);
18930
    virBufferEscapeString(buf, "<initrd>%s</initrd>\n",
18931
                          def->os.initrd);
18932
    virBufferEscapeString(buf, "<cmdline>%s</cmdline>\n",
18933
                          def->os.cmdline);
18934
    virBufferEscapeString(buf, "<dtb>%s</dtb>\n",
18935
                          def->os.dtb);
18936
    virBufferEscapeString(buf, "<root>%s</root>\n",
18937
                          def->os.root);
18938 18939

    if (!def->os.bootloader) {
18940
        for (n = 0; n < def->os.nBootDevs; n++) {
18941 18942 18943
            const char *boottype =
                virDomainBootTypeToString(def->os.bootDevs[n]);
            if (!boottype) {
18944 18945 18946
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unexpected boot device type %d"),
                               def->os.bootDevs[n]);
18947
                goto error;
18948
            }
18949
            virBufferAsprintf(buf, "<boot dev='%s'/>\n", boottype);
18950
        }
18951

18952 18953
        if (def->os.bootmenu) {
            virBufferAsprintf(buf, "<bootmenu enable='%s'",
J
Ján Tomko 已提交
18954
                              virTristateBoolTypeToString(def->os.bootmenu));
18955 18956 18957 18958
            if (def->os.bm_timeout_set)
                virBufferAsprintf(buf, " timeout='%u'", def->os.bm_timeout);
            virBufferAddLit(buf, "/>\n");
        }
M
Michal Privoznik 已提交
18959

18960
        if (def->os.bios.useserial || def->os.bios.rt_set) {
18961
            virBufferAddLit(buf, "<bios");
18962 18963
            if (def->os.bios.useserial)
                virBufferAsprintf(buf, " useserial='%s'",
J
Ján Tomko 已提交
18964
                                  virTristateBoolTypeToString(def->os.bios.useserial));
18965 18966 18967 18968
            if (def->os.bios.rt_set)
                virBufferAsprintf(buf, " rebootTimeout='%d'", def->os.bios.rt_delay);

            virBufferAddLit(buf, "/>\n");
M
Michal Privoznik 已提交
18969
        }
18970 18971
    }

18972 18973 18974 18975 18976
    if (def->os.smbios_mode) {
        const char *mode;

        mode = virDomainSmbiosModeTypeToString(def->os.smbios_mode);
        if (mode == NULL) {
18977 18978
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected smbios mode %d"), def->os.smbios_mode);
18979
            goto error;
18980
        }
18981
        virBufferAsprintf(buf, "<smbios mode='%s'/>\n", mode);
18982 18983
    }

18984 18985
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</os>\n");
18986

18987 18988

    if (def->idmap.uidmap) {
18989 18990
        virBufferAddLit(buf, "<idmap>\n");
        virBufferAdjustIndent(buf, 2);
18991 18992
        for (i = 0; i < def->idmap.nuidmap; i++) {
            virBufferAsprintf(buf,
18993
                              "<uid start='%u' target='%u' count='%u'/>\n",
18994 18995 18996 18997 18998 18999
                              def->idmap.uidmap[i].start,
                              def->idmap.uidmap[i].target,
                              def->idmap.uidmap[i].count);
        }
        for (i = 0; i < def->idmap.ngidmap; i++) {
            virBufferAsprintf(buf,
19000
                              "<gid start='%u' target='%u' count='%u'/>\n",
19001 19002 19003 19004
                              def->idmap.gidmap[i].start,
                              def->idmap.gidmap[i].target,
                              def->idmap.gidmap[i].count);
        }
19005 19006
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</idmap>\n");
19007 19008
    }

19009
    for (i = 0; i < VIR_DOMAIN_FEATURE_LAST; i++) {
J
Ján Tomko 已提交
19010
        if (def->features[i] != VIR_TRISTATE_SWITCH_ABSENT)
19011 19012
            break;
    }
19013

19014 19015
    if (i != VIR_DOMAIN_FEATURE_LAST ||
        virDomainDefHasCapabilitiesFeatures(def)) {
19016 19017
        virBufferAddLit(buf, "<features>\n");
        virBufferAdjustIndent(buf, 2);
19018

19019
        for (i = 0; i < VIR_DOMAIN_FEATURE_LAST; i++) {
19020 19021 19022 19023 19024 19025 19026
            const char *name = virDomainFeatureTypeToString(i);
            size_t j;

            if (!name) {
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unexpected feature %zu"), i);
                goto error;
19027
            }
19028

19029
            switch ((virDomainFeature) i) {
19030 19031 19032 19033 19034
            case VIR_DOMAIN_FEATURE_ACPI:
            case VIR_DOMAIN_FEATURE_PAE:
            case VIR_DOMAIN_FEATURE_HAP:
            case VIR_DOMAIN_FEATURE_VIRIDIAN:
            case VIR_DOMAIN_FEATURE_PRIVNET:
J
Ján Tomko 已提交
19035 19036
                switch ((virTristateSwitch) def->features[i]) {
                case VIR_TRISTATE_SWITCH_ABSENT:
19037 19038
                    break;

J
Ján Tomko 已提交
19039
                case VIR_TRISTATE_SWITCH_ON:
19040
                   virBufferAsprintf(buf, "<%s/>\n", name);
19041 19042
                   break;

J
Ján Tomko 已提交
19043 19044
                case VIR_TRISTATE_SWITCH_LAST:
                case VIR_TRISTATE_SWITCH_OFF:
19045 19046 19047 19048 19049 19050 19051 19052
                   virReportError(VIR_ERR_INTERNAL_ERROR,
                                 _("Unexpected state of feature '%s'"), name);

                   goto error;
                   break;
                }

                break;
19053

19054
            case VIR_DOMAIN_FEATURE_PVSPINLOCK:
J
Ján Tomko 已提交
19055 19056 19057
                switch ((virTristateSwitch) def->features[i]) {
                case VIR_TRISTATE_SWITCH_LAST:
                case VIR_TRISTATE_SWITCH_ABSENT:
19058 19059
                    break;

J
Ján Tomko 已提交
19060
                case VIR_TRISTATE_SWITCH_ON:
19061
                   virBufferAsprintf(buf, "<%s state='on'/>\n", name);
19062 19063
                   break;

J
Ján Tomko 已提交
19064
                case VIR_TRISTATE_SWITCH_OFF:
19065
                   virBufferAsprintf(buf, "<%s state='off'/>\n", name);
19066 19067 19068 19069 19070
                   break;
                }

                break;

19071
            case VIR_DOMAIN_FEATURE_APIC:
J
Ján Tomko 已提交
19072
                if (def->features[i] == VIR_TRISTATE_SWITCH_ON) {
19073
                    virBufferAddLit(buf, "<apic");
19074 19075
                    if (def->apic_eoi) {
                        virBufferAsprintf(buf, " eoi='%s'",
J
Ján Tomko 已提交
19076
                                          virTristateSwitchTypeToString(def->apic_eoi));
19077
                    }
19078
                    virBufferAddLit(buf, "/>\n");
19079 19080
                }
                break;
19081

19082
            case VIR_DOMAIN_FEATURE_HYPERV:
J
Ján Tomko 已提交
19083
                if (def->features[i] != VIR_TRISTATE_SWITCH_ON)
19084
                    break;
19085

19086 19087
                virBufferAddLit(buf, "<hyperv>\n");
                virBufferAdjustIndent(buf, 2);
19088
                for (j = 0; j < VIR_DOMAIN_HYPERV_LAST; j++) {
19089
                    switch ((virDomainHyperv) j) {
19090 19091 19092
                    case VIR_DOMAIN_HYPERV_RELAXED:
                    case VIR_DOMAIN_HYPERV_VAPIC:
                        if (def->hyperv_features[j])
19093
                            virBufferAsprintf(buf, "<%s state='%s'/>\n",
19094
                                              virDomainHypervTypeToString(j),
J
Ján Tomko 已提交
19095
                                              virTristateSwitchTypeToString(
19096 19097 19098 19099 19100 19101 19102
                                                  def->hyperv_features[j]));
                        break;

                    case VIR_DOMAIN_HYPERV_SPINLOCKS:
                        if (def->hyperv_features[j] == 0)
                            break;

19103
                        virBufferAsprintf(buf, "<spinlocks state='%s'",
J
Ján Tomko 已提交
19104
                                          virTristateSwitchTypeToString(
19105
                                              def->hyperv_features[j]));
J
Ján Tomko 已提交
19106
                        if (def->hyperv_features[j] == VIR_TRISTATE_SWITCH_ON)
19107 19108 19109 19110 19111
                            virBufferAsprintf(buf, " retries='%d'",
                                              def->hyperv_spinlocks);
                        virBufferAddLit(buf, "/>\n");
                        break;

19112
                    /* coverity[dead_error_begin] */
19113 19114 19115
                    case VIR_DOMAIN_HYPERV_LAST:
                        break;
                    }
19116
                }
19117 19118
                virBufferAdjustIndent(buf, -2);
                virBufferAddLit(buf, "</hyperv>\n");
19119 19120
                break;

19121 19122 19123 19124 19125 19126 19127 19128 19129 19130 19131 19132 19133 19134 19135 19136
            case VIR_DOMAIN_FEATURE_KVM:
                if (def->features[i] != VIR_TRISTATE_SWITCH_ON)
                    break;

                virBufferAddLit(buf, "<kvm>\n");
                virBufferAdjustIndent(buf, 2);
                for (j = 0; j < VIR_DOMAIN_KVM_LAST; j++) {
                    switch ((virDomainKVM) j) {
                    case VIR_DOMAIN_KVM_HIDDEN:
                        if (def->kvm_features[j])
                            virBufferAsprintf(buf, "<%s state='%s'/>\n",
                                              virDomainKVMTypeToString(j),
                                              virTristateSwitchTypeToString(
                                                  def->kvm_features[j]));
                        break;

19137
                    /* coverity[dead_error_begin] */
19138 19139 19140 19141 19142 19143 19144 19145
                    case VIR_DOMAIN_KVM_LAST:
                        break;
                    }
                }
                virBufferAdjustIndent(buf, -2);
                virBufferAddLit(buf, "</kvm>\n");
                break;

19146 19147 19148 19149 19150 19151 19152 19153 19154
            case VIR_DOMAIN_FEATURE_CAPABILITIES:
                if (def->features[i] == VIR_DOMAIN_CAPABILITIES_POLICY_DEFAULT &&
                        !virDomainDefHasCapabilitiesFeatures(def))
                    break;

                virBufferAsprintf(buf, "<capabilities policy='%s'>\n",
                                  virDomainCapabilitiesPolicyTypeToString(def->features[i]));
                virBufferAdjustIndent(buf, 2);
                for (j = 0; j < VIR_DOMAIN_CAPS_FEATURE_LAST; j++) {
J
Ján Tomko 已提交
19155
                    if (def->caps_features[j] != VIR_TRISTATE_SWITCH_ABSENT)
19156 19157
                        virBufferAsprintf(buf, "<%s state='%s'/>\n",
                                          virDomainCapsFeatureTypeToString(j),
J
Ján Tomko 已提交
19158
                                          virTristateSwitchTypeToString(
19159 19160 19161 19162 19163 19164
                                              def->caps_features[j]));
                }
                virBufferAdjustIndent(buf, -2);
                virBufferAddLit(buf, "</capabilities>\n");
                break;

19165
            /* coverity[dead_error_begin] */
19166 19167
            case VIR_DOMAIN_FEATURE_LAST:
                break;
19168 19169 19170
            }
        }

19171 19172
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</features>\n");
19173 19174
    }

19175
    if (virCPUDefFormatBufFull(buf, def->cpu, flags) < 0)
19176
        goto error;
19177

19178
    virBufferAsprintf(buf, "<clock offset='%s'",
19179
                      virDomainClockOffsetTypeToString(def->clock.offset));
19180
    switch (def->clock.offset) {
19181 19182 19183 19184 19185
    case VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME:
    case VIR_DOMAIN_CLOCK_OFFSET_UTC:
        if (def->clock.data.utc_reset)
            virBufferAddLit(buf, " adjustment='reset'");
        break;
19186
    case VIR_DOMAIN_CLOCK_OFFSET_VARIABLE:
19187 19188 19189
        virBufferAsprintf(buf, " adjustment='%lld' basis='%s'",
                          def->clock.data.variable.adjustment,
                          virDomainClockBasisTypeToString(def->clock.data.variable.basis));
19190 19191 19192 19193 19194
        if (flags & VIR_DOMAIN_XML_INTERNAL_CLOCK_ADJUST) {
            if (def->clock.data.variable.adjustment0)
                virBufferAsprintf(buf, " adjustment0='%lld'",
                                  def->clock.data.variable.adjustment0);
        }
19195 19196
        break;
    case VIR_DOMAIN_CLOCK_OFFSET_TIMEZONE:
19197
        virBufferEscapeString(buf, " timezone='%s'", def->clock.data.timezone);
19198 19199
        break;
    }
19200
    if (def->clock.ntimers == 0) {
19201
        virBufferAddLit(buf, "/>\n");
19202
    } else {
19203
        virBufferAddLit(buf, ">\n");
19204
        virBufferAdjustIndent(buf, 2);
19205
        for (n = 0; n < def->clock.ntimers; n++) {
19206
            if (virDomainTimerDefFormat(buf, def->clock.timers[n]) < 0)
19207
                goto error;
19208
        }
19209 19210
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</clock>\n");
19211
    }
19212

19213 19214 19215
    if (virDomainEventActionDefFormat(buf, def->onPoweroff,
                                      "on_poweroff",
                                      virDomainLifecycleTypeToString) < 0)
19216
        goto error;
19217 19218 19219
    if (virDomainEventActionDefFormat(buf, def->onReboot,
                                      "on_reboot",
                                      virDomainLifecycleTypeToString) < 0)
19220
        goto error;
19221 19222 19223
    if (virDomainEventActionDefFormat(buf, def->onCrash,
                                      "on_crash",
                                      virDomainLifecycleCrashTypeToString) < 0)
19224
        goto error;
19225 19226 19227 19228
    if (def->onLockFailure != VIR_DOMAIN_LOCK_FAILURE_DEFAULT &&
        virDomainEventActionDefFormat(buf, def->onLockFailure,
                                      "on_lockfailure",
                                      virDomainLockFailureTypeToString) < 0)
19229
        goto error;
19230

19231
    if (def->pm.s3 || def->pm.s4) {
19232 19233
        virBufferAddLit(buf, "<pm>\n");
        virBufferAdjustIndent(buf, 2);
19234
        if (def->pm.s3) {
19235
            virBufferAsprintf(buf, "<suspend-to-mem enabled='%s'/>\n",
J
Ján Tomko 已提交
19236
                              virTristateBoolTypeToString(def->pm.s3));
19237 19238
        }
        if (def->pm.s4) {
19239
            virBufferAsprintf(buf, "<suspend-to-disk enabled='%s'/>\n",
J
Ján Tomko 已提交
19240
                              virTristateBoolTypeToString(def->pm.s4));
19241
        }
19242 19243
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</pm>\n");
19244 19245
    }

19246 19247
    virBufferAddLit(buf, "<devices>\n");
    virBufferAdjustIndent(buf, 2);
19248

19249
    virBufferEscapeString(buf, "<emulator>%s</emulator>\n",
19250
                          def->emulator);
19251

19252
    for (n = 0; n < def->ndisks; n++)
19253
        if (virDomainDiskDefFormat(buf, def->disks[n], flags) < 0)
19254
            goto error;
19255

19256
    for (n = 0; n < def->ncontrollers; n++)
19257
        if (virDomainControllerDefFormat(buf, def->controllers[n], flags) < 0)
19258
            goto error;
19259

19260
    for (n = 0; n < def->nleases; n++)
19261
        if (virDomainLeaseDefFormat(buf, def->leases[n]) < 0)
19262
            goto error;
19263

19264
    for (n = 0; n < def->nfss; n++)
19265
        if (virDomainFSDefFormat(buf, def->fss[n], flags) < 0)
19266
            goto error;
19267

19268
    for (n = 0; n < def->nnets; n++)
19269
        if (virDomainNetDefFormat(buf, def->nets[n], flags) < 0)
19270
            goto error;
19271

19272
    for (n = 0; n < def->nsmartcards; n++)
19273
        if (virDomainSmartcardDefFormat(buf, def->smartcards[n], flags) < 0)
19274
            goto error;
E
Eric Blake 已提交
19275

19276
    for (n = 0; n < def->nserials; n++)
19277
        if (virDomainChrDefFormat(buf, def->serials[n], flags) < 0)
19278
            goto error;
19279

19280
    for (n = 0; n < def->nparallels; n++)
19281
        if (virDomainChrDefFormat(buf, def->parallels[n], flags) < 0)
19282
            goto error;
19283

19284
    for (n = 0; n < def->nconsoles; n++) {
19285 19286 19287 19288 19289
        virDomainChrDef console;
        /* Back compat, ignore the console element for hvm guests
         * if it is type == serial
         */
        if (STREQ(def->os.type, "hvm") &&
19290 19291
            (def->consoles[n]->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL ||
             def->consoles[n]->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_NONE) &&
19292 19293 19294
            (n < def->nserials)) {
            memcpy(&console, def->serials[n], sizeof(console));
            console.deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE;
G
Guannan Ren 已提交
19295
            console.targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL;
19296 19297 19298 19299
        } else {
            memcpy(&console, def->consoles[n], sizeof(console));
        }
        if (virDomainChrDefFormat(buf, &console, flags) < 0)
19300
            goto error;
19301 19302 19303 19304
    }
    if (STREQ(def->os.type, "hvm") &&
        def->nconsoles == 0 &&
        def->nserials > 0) {
19305
        virDomainChrDef console;
19306
        memcpy(&console, def->serials[n], sizeof(console));
19307
        console.deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE;
19308
        console.targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL;
19309
        if (virDomainChrDefFormat(buf, &console, flags) < 0)
19310
            goto error;
19311 19312
    }

19313
    for (n = 0; n < def->nchannels; n++)
19314
        if (virDomainChrDefFormat(buf, def->channels[n], flags) < 0)
19315
            goto error;
19316

19317
    for (n = 0; n < def->ninputs; n++)
19318
        if (def->inputs[n]->bus == VIR_DOMAIN_INPUT_BUS_USB &&
19319
            virDomainInputDefFormat(buf, def->inputs[n], flags) < 0)
19320
            goto error;
19321

19322 19323 19324 19325 19326
    if (def->tpm) {
        if (virDomainTPMDefFormat(buf, def->tpm, flags) < 0)
            goto error;
    }

19327
    if (def->ngraphics > 0) {
L
Li Zhang 已提交
19328
        /* If graphics is enabled, add the implicit mouse/keyboard */
19329 19330 19331 19332 19333 19334 19335
        if ((ARCH_IS_X86(def->os.arch)) || def->os.arch == VIR_ARCH_NONE) {
            virDomainInputDef autoInput = {
                VIR_DOMAIN_INPUT_TYPE_MOUSE,
                STREQ(def->os.type, "hvm") ?
                VIR_DOMAIN_INPUT_BUS_PS2 : VIR_DOMAIN_INPUT_BUS_XEN,
                { .alias = NULL },
            };
19336

L
Li Zhang 已提交
19337 19338
            if (virDomainInputDefFormat(buf, &autoInput, flags) < 0)
                goto error;
19339 19340 19341 19342 19343 19344

            if (!(flags & VIR_DOMAIN_XML_MIGRATABLE)) {
                autoInput.type = VIR_DOMAIN_INPUT_TYPE_KBD;
                if (virDomainInputDefFormat(buf, &autoInput, flags) < 0)
                    goto error;
            }
L
Li Zhang 已提交
19345 19346
        }

19347
        for (n = 0; n < def->ngraphics; n++)
19348
            if (virDomainGraphicsDefFormat(buf, def->graphics[n], flags) < 0)
19349
                goto error;
19350 19351
    }

19352
    for (n = 0; n < def->nsounds; n++)
19353
        if (virDomainSoundDefFormat(buf, def->sounds[n], flags) < 0)
19354
            goto error;
19355

19356
    for (n = 0; n < def->nvideos; n++)
19357
        if (virDomainVideoDefFormat(buf, def->videos[n], flags) < 0)
19358
            goto error;
19359

19360
    for (n = 0; n < def->nhostdevs; n++) {
19361 19362 19363 19364
        /* If parent.type != NONE, this is just a pointer to the
         * hostdev in a higher-level device (e.g. virDomainNetDef),
         * and will have already been formatted there.
         */
E
Eric Blake 已提交
19365 19366
        if (def->hostdevs[n]->parent.type == VIR_DOMAIN_DEVICE_NONE &&
            virDomainHostdevDefFormat(buf, def->hostdevs[n], flags) < 0) {
19367
            goto error;
19368 19369
        }
    }
19370

19371
    for (n = 0; n < def->nredirdevs; n++)
19372
        if (virDomainRedirdevDefFormat(buf, def->redirdevs[n], flags) < 0)
19373
            goto error;
19374

19375 19376 19377
    if (def->redirfilter)
        virDomainRedirFilterDefFormat(buf, def->redirfilter);

19378
    for (n = 0; n < def->nhubs; n++)
19379
        if (virDomainHubDefFormat(buf, def->hubs[n], flags) < 0)
19380
            goto error;
M
Marc-André Lureau 已提交
19381

R
Richard Jones 已提交
19382
    if (def->watchdog)
19383
        virDomainWatchdogDefFormat(buf, def->watchdog, flags);
R
Richard Jones 已提交
19384

19385
    if (def->memballoon)
19386
        virDomainMemballoonDefFormat(buf, def->memballoon, flags);
19387

19388 19389 19390 19391
    for (n = 0; n < def->nrngs; n++) {
        if (virDomainRNGDefFormat(buf, def->rngs[n], flags))
            goto error;
    }
19392

L
Li Zhang 已提交
19393 19394 19395
    if (def->nvram)
        virDomainNVRAMDefFormat(buf, def->nvram, flags);

H
Hu Tao 已提交
19396 19397 19398 19399
    if (def->panic &&
        virDomainPanicDefFormat(buf, def->panic) < 0)
        goto error;

19400 19401 19402 19403
    for (n = 0; n < def->nshmems; n++)
        if (virDomainShmemDefFormat(buf, def->shmems[n], flags) < 0)
            goto error;

19404 19405
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</devices>\n");
19406

19407
    for (n = 0; n < def->nseclabels; n++)
19408
        virSecurityLabelDefFormat(buf, def->seclabels[n]);
19409

19410
    if (def->namespaceData && def->ns.format) {
19411
        if ((def->ns.format)(buf, def->namespaceData) < 0)
19412
            goto error;
19413 19414
    }

19415
    virBufferAdjustIndent(buf, -2);
19416
    virBufferAddLit(buf, "</domain>\n");
19417

19418 19419
    if (virBufferCheckError(buf) < 0)
        goto error;
19420

19421
    return 0;
19422

19423
 error:
19424 19425
    virBufferFreeAndReset(buf);
    return -1;
19426 19427
}

19428 19429 19430
char *
virDomainDefFormat(virDomainDefPtr def, unsigned int flags)
{
19431 19432
    virBuffer buf = VIR_BUFFER_INITIALIZER;

19433
    virCheckFlags(DUMPXML_FLAGS, NULL);
19434 19435 19436 19437
    if (virDomainDefFormatInternal(def, flags, &buf) < 0)
        return NULL;

    return virBufferContentAndReset(&buf);
19438 19439
}

19440

19441
static char *
19442
virDomainObjFormat(virDomainXMLOptionPtr xmlopt,
19443 19444
                   virDomainObjPtr obj,
                   unsigned int flags)
19445 19446
{
    virBuffer buf = VIR_BUFFER_INITIALIZER;
J
Jiri Denemark 已提交
19447 19448
    int state;
    int reason;
19449
    size_t i;
19450

J
Jiri Denemark 已提交
19451
    state = virDomainObjGetState(obj, &reason);
19452
    virBufferAsprintf(&buf, "<domstatus state='%s' reason='%s' pid='%lld'>\n",
J
Jiri Denemark 已提交
19453 19454
                      virDomainStateTypeToString(state),
                      virDomainStateReasonToString(state, reason),
19455
                      (long long)obj->pid);
19456
    virBufferAdjustIndent(&buf, 2);
19457

19458
    for (i = 0; i < VIR_DOMAIN_TAINT_LAST; i++) {
19459
        if (obj->taint & (1 << i))
19460
            virBufferAsprintf(&buf, "<taint flag='%s'/>\n",
19461 19462 19463
                              virDomainTaintTypeToString(i));
    }

19464 19465
    if (xmlopt->privateData.format &&
        ((xmlopt->privateData.format)(&buf, obj->privateData)) < 0)
19466
        goto error;
19467

19468
    if (virDomainDefFormatInternal(obj->def, flags, &buf) < 0)
19469 19470
        goto error;

19471
    virBufferAdjustIndent(&buf, -2);
19472 19473
    virBufferAddLit(&buf, "</domstatus>\n");

19474 19475
    if (virBufferCheckError(&buf) < 0)
        goto error;
19476 19477 19478

    return virBufferContentAndReset(&buf);

19479
 error:
19480
    virBufferFreeAndReset(&buf);
19481 19482 19483
    return NULL;
}

19484 19485 19486
static bool
virDomainDefHasUSB(virDomainDefPtr def)
{
19487
    size_t i;
19488 19489 19490 19491 19492 19493 19494 19495 19496 19497 19498 19499 19500 19501 19502 19503 19504 19505 19506 19507 19508 19509 19510 19511 19512 19513 19514 19515 19516 19517 19518

    for (i = 0; i < def->ncontrollers; i++) {
        if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_USB &&
            def->controllers[i]->model != VIR_DOMAIN_CONTROLLER_MODEL_USB_NONE)
            return true;
    }

    return false;
}

static bool
virDomainDeviceIsUSB(virDomainDeviceDefPtr dev)
{
    int t = dev->type;
    if ((t == VIR_DOMAIN_DEVICE_DISK &&
         dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_USB) ||
        (t == VIR_DOMAIN_DEVICE_INPUT &&
         dev->data.input->type == VIR_DOMAIN_INPUT_BUS_USB) ||
        (t == VIR_DOMAIN_DEVICE_HOSTDEV &&
         dev->data.hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
         dev->data.hostdev->source.subsys.type ==
         VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) ||
        (t == VIR_DOMAIN_DEVICE_HUB &&
         dev->data.hub->type == VIR_DOMAIN_HUB_TYPE_USB) ||
        (t == VIR_DOMAIN_DEVICE_REDIRDEV &&
         dev->data.redirdev->bus == VIR_DOMAIN_REDIRDEV_BUS_USB))
        return true;

    return false;
}

19519 19520 19521 19522 19523 19524 19525 19526 19527 19528 19529 19530 19531 19532 19533 19534 19535
static int
virDomainDeviceInfoCheckBootIndex(virDomainDefPtr def ATTRIBUTE_UNUSED,
                                  virDomainDeviceDefPtr device ATTRIBUTE_UNUSED,
                                  virDomainDeviceInfoPtr info,
                                  void *opaque)
{
    virDomainDeviceInfoPtr newinfo = opaque;

    if (info->bootIndex == newinfo->bootIndex) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("boot order %d is already used by another device"),
                       newinfo->bootIndex);
        return -1;
    }
    return 0;
}

19536 19537
int
virDomainDefCompatibleDevice(virDomainDefPtr def,
19538 19539
                             virDomainDeviceDefPtr dev,
                             virDomainDeviceAction action)
19540
{
19541 19542
    virDomainDeviceInfoPtr info = virDomainDeviceGetInfo(dev);

19543 19544 19545
    if (action != VIR_DOMAIN_DEVICE_ACTION_ATTACH)
        return 0;

19546
    if (!virDomainDefHasUSB(def) &&
19547
        STRNEQ(def->os.type, "exe") &&
19548 19549 19550 19551 19552 19553 19554
        virDomainDeviceIsUSB(dev)) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Device configuration is not compatible: "
                         "Domain has no USB bus support"));
        return -1;
    }

19555 19556 19557 19558 19559 19560 19561 19562 19563 19564 19565 19566 19567
    if (info && info->bootIndex > 0) {
        if (def->os.nBootDevs > 0) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("per-device boot elements cannot be used"
                             " together with os/boot elements"));
            return -1;
        }
        if (virDomainDeviceInfoIterate(def,
                                       virDomainDeviceInfoCheckBootIndex,
                                       info) < 0)
            return -1;
    }

19568 19569 19570
    return 0;
}

19571 19572 19573 19574
int
virDomainSaveXML(const char *configDir,
                 virDomainDefPtr def,
                 const char *xml)
19575
{
J
Ján Tomko 已提交
19576
    char uuidstr[VIR_UUID_STRING_BUFLEN];
19577
    char *configFile = NULL;
19578
    int ret = -1;
19579

19580 19581 19582
    if (!configDir)
        return 0;

19583
    if ((configFile = virDomainConfigFile(configDir, def->name)) == NULL)
19584 19585
        goto cleanup;

19586
    if (virFileMakePath(configDir) < 0) {
19587
        virReportSystemError(errno,
19588 19589
                             _("cannot create config directory '%s'"),
                             configDir);
19590 19591 19592
        goto cleanup;
    }

J
Ján Tomko 已提交
19593 19594 19595 19596
    virUUIDFormat(def->uuid, uuidstr);
    ret = virXMLSaveFile(configFile,
                         virXMLPickShellSafeComment(def->name, uuidstr), "edit",
                         xml);
19597

19598
 cleanup:
R
Ryota Ozaki 已提交
19599
    VIR_FREE(configFile);
19600 19601 19602
    return ret;
}

19603 19604 19605
int
virDomainSaveConfig(const char *configDir,
                    virDomainDefPtr def)
19606 19607 19608
{
    int ret = -1;
    char *xml;
19609

19610
    if (!(xml = virDomainDefFormat(def, VIR_DOMAIN_XML_WRITE_FLAGS)))
19611 19612
        goto cleanup;

19613
    if (virDomainSaveXML(configDir, def, xml))
19614 19615 19616
        goto cleanup;

    ret = 0;
19617
 cleanup:
19618
    VIR_FREE(xml);
19619 19620 19621
    return ret;
}

19622
int
19623
virDomainSaveStatus(virDomainXMLOptionPtr xmlopt,
19624 19625
                    const char *statusDir,
                    virDomainObjPtr obj)
19626
{
19627 19628
    unsigned int flags = (VIR_DOMAIN_XML_SECURE |
                          VIR_DOMAIN_XML_INTERNAL_STATUS |
19629
                          VIR_DOMAIN_XML_INTERNAL_ACTUAL_NET |
19630 19631
                          VIR_DOMAIN_XML_INTERNAL_PCI_ORIG_STATES |
                          VIR_DOMAIN_XML_INTERNAL_CLOCK_ADJUST);
19632

19633 19634 19635
    int ret = -1;
    char *xml;

19636
    if (!(xml = virDomainObjFormat(xmlopt, obj, flags)))
19637 19638
        goto cleanup;

19639
    if (virDomainSaveXML(statusDir, obj->def, xml))
19640 19641 19642
        goto cleanup;

    ret = 0;
19643
 cleanup:
19644 19645 19646 19647
    VIR_FREE(xml);
    return ret;
}

19648

19649 19650 19651
static virDomainObjPtr
virDomainObjListLoadConfig(virDomainObjListPtr doms,
                           virCapsPtr caps,
19652
                           virDomainXMLOptionPtr xmlopt,
19653 19654 19655 19656 19657 19658
                           const char *configDir,
                           const char *autostartDir,
                           const char *name,
                           unsigned int expectedVirtTypes,
                           virDomainLoadConfigNotify notify,
                           void *opaque)
19659 19660 19661 19662 19663
{
    char *configFile = NULL, *autostartLink = NULL;
    virDomainDefPtr def = NULL;
    virDomainObjPtr dom;
    int autostart;
19664
    virDomainDefPtr oldDef = NULL;
19665

19666
    if ((configFile = virDomainConfigFile(configDir, name)) == NULL)
19667
        goto error;
19668
    if (!(def = virDomainDefParseFile(configFile, caps, xmlopt,
19669
                                      expectedVirtTypes,
19670
                                      VIR_DOMAIN_XML_INACTIVE)))
19671 19672
        goto error;

19673 19674 19675 19676 19677 19678
    if ((autostartLink = virDomainConfigFile(autostartDir, name)) == NULL)
        goto error;

    if ((autostart = virFileLinkPointsTo(autostartLink, configFile)) < 0)
        goto error;

19679
    if (!(dom = virDomainObjListAddLocked(doms, def, xmlopt, 0, &oldDef)))
19680 19681 19682 19683
        goto error;

    dom->autostart = autostart;

19684
    if (notify)
19685
        (*notify)(dom, oldDef == NULL, opaque);
19686

19687
    virDomainDefFree(oldDef);
19688 19689
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
19690 19691
    return dom;

19692
 error:
19693 19694 19695 19696 19697 19698
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
    virDomainDefFree(def);
    return NULL;
}

19699 19700 19701 19702
static virDomainObjPtr
virDomainObjListLoadStatus(virDomainObjListPtr doms,
                           const char *statusDir,
                           const char *name,
19703 19704
                           virCapsPtr caps,
                           virDomainXMLOptionPtr xmlopt,
19705 19706 19707
                           unsigned int expectedVirtTypes,
                           virDomainLoadConfigNotify notify,
                           void *opaque)
19708 19709 19710
{
    char *statusFile = NULL;
    virDomainObjPtr obj = NULL;
19711
    char uuidstr[VIR_UUID_STRING_BUFLEN];
19712

19713
    if ((statusFile = virDomainConfigFile(statusDir, name)) == NULL)
19714 19715
        goto error;

19716
    if (!(obj = virDomainObjParseFile(statusFile, caps, xmlopt, expectedVirtTypes,
19717
                                      VIR_DOMAIN_XML_INTERNAL_STATUS |
19718
                                      VIR_DOMAIN_XML_INTERNAL_ACTUAL_NET |
19719 19720
                                      VIR_DOMAIN_XML_INTERNAL_PCI_ORIG_STATES |
                                      VIR_DOMAIN_XML_INTERNAL_CLOCK_ADJUST)))
19721 19722
        goto error;

19723 19724 19725
    virUUIDFormat(obj->def->uuid, uuidstr);

    if (virHashLookup(doms->objs, uuidstr) != NULL) {
19726 19727 19728
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected domain %s already exists"),
                       obj->def->name);
19729 19730 19731
        goto error;
    }

19732
    if (virHashAddEntry(doms->objs, uuidstr, obj) < 0)
19733 19734 19735 19736 19737 19738 19739 19740
        goto error;

    if (notify)
        (*notify)(obj, 1, opaque);

    VIR_FREE(statusFile);
    return obj;

19741
 error:
19742
    virObjectUnref(obj);
19743 19744 19745 19746
    VIR_FREE(statusFile);
    return NULL;
}

19747 19748 19749 19750 19751
int
virDomainObjListLoadAllConfigs(virDomainObjListPtr doms,
                               const char *configDir,
                               const char *autostartDir,
                               int liveStatus,
19752 19753
                               virCapsPtr caps,
                               virDomainXMLOptionPtr xmlopt,
19754 19755 19756
                               unsigned int expectedVirtTypes,
                               virDomainLoadConfigNotify notify,
                               void *opaque)
19757 19758 19759
{
    DIR *dir;
    struct dirent *entry;
E
Eric Blake 已提交
19760
    int ret = -1;
19761

19762 19763
    VIR_INFO("Scanning for configs in %s", configDir);

19764 19765 19766
    if (!(dir = opendir(configDir))) {
        if (errno == ENOENT)
            return 0;
19767
        virReportSystemError(errno,
19768 19769
                             _("Failed to open dir '%s'"),
                             configDir);
19770 19771 19772
        return -1;
    }

19773 19774
    virObjectLock(doms);

E
Eric Blake 已提交
19775
    while ((ret = virDirRead(dir, &entry, configDir)) > 0) {
19776 19777
        virDomainObjPtr dom;

19778 19779 19780
        if (entry->d_name[0] == '.')
            continue;

19781
        if (!virFileStripSuffix(entry->d_name, ".xml"))
19782 19783 19784 19785
            continue;

        /* NB: ignoring errors, so one malformed config doesn't
           kill the whole process */
19786 19787
        VIR_INFO("Loading config file '%s.xml'", entry->d_name);
        if (liveStatus)
19788 19789 19790
            dom = virDomainObjListLoadStatus(doms,
                                             configDir,
                                             entry->d_name,
19791 19792
                                             caps,
                                             xmlopt,
19793 19794 19795
                                             expectedVirtTypes,
                                             notify,
                                             opaque);
19796
        else
19797 19798
            dom = virDomainObjListLoadConfig(doms,
                                             caps,
19799
                                             xmlopt,
19800 19801 19802 19803 19804 19805
                                             configDir,
                                             autostartDir,
                                             entry->d_name,
                                             expectedVirtTypes,
                                             notify,
                                             opaque);
19806
        if (dom) {
D
Daniel Veillard 已提交
19807 19808
            if (!liveStatus)
                dom->persistent = 1;
19809
            virObjectUnlock(dom);
19810
        }
19811 19812 19813
    }

    closedir(dir);
19814
    virObjectUnlock(doms);
E
Eric Blake 已提交
19815
    return ret;
19816 19817
}

19818 19819 19820 19821
int
virDomainDeleteConfig(const char *configDir,
                      const char *autostartDir,
                      virDomainObjPtr dom)
19822
{
19823 19824 19825
    char *configFile = NULL, *autostartLink = NULL;
    int ret = -1;

19826
    if ((configFile = virDomainConfigFile(configDir, dom->def->name)) == NULL)
19827
        goto cleanup;
19828 19829
    if ((autostartLink = virDomainConfigFile(autostartDir,
                                             dom->def->name)) == NULL)
19830
        goto cleanup;
19831 19832

    /* Not fatal if this doesn't work */
19833
    unlink(autostartLink);
19834

19835 19836
    if (unlink(configFile) < 0 &&
        errno != ENOENT) {
19837
        virReportSystemError(errno,
19838 19839
                             _("cannot remove config %s"),
                             configFile);
19840
        goto cleanup;
19841 19842
    }

19843 19844
    ret = 0;

19845
 cleanup:
19846 19847 19848
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
    return ret;
19849
}
19850

19851 19852 19853
char
*virDomainConfigFile(const char *dir,
                     const char *name)
19854
{
19855
    char *ret;
19856

19857
    ignore_value(virAsprintf(&ret, "%s/%s.xml", dir, name));
19858 19859 19860
    return ret;
}

19861 19862
/* 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 已提交
19863
 *                                               hdd => (1,1), vdaa => (0,26))
19864 19865 19866 19867 19868
 * @param disk The disk device
 * @param busIdx parsed bus number
 * @param devIdx parsed device number
 * @return 0 on success, -1 on failure
 */
19869
int
19870
virDiskNameToBusDeviceIndex(virDomainDiskDefPtr disk,
19871
                            int *busIdx,
19872 19873
                            int *devIdx)
{
19874 19875

    int idx = virDiskNameToIndex(disk->dst);
19876
    if (idx < 0)
19877 19878 19879 19880 19881 19882 19883 19884 19885 19886 19887 19888 19889 19890 19891
        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:
19892
        case VIR_DOMAIN_DISK_BUS_SD:
19893 19894 19895 19896 19897 19898 19899 19900
        default:
            *busIdx = 0;
            *devIdx = idx;
            break;
    }

    return 0;
}
19901

19902 19903 19904 19905 19906 19907 19908 19909 19910 19911 19912 19913 19914 19915 19916 19917
int
virDomainFSInsert(virDomainDefPtr def, virDomainFSDefPtr fs)
{

    return VIR_APPEND_ELEMENT(def->fss, def->nfss, fs);
}

virDomainFSDefPtr
virDomainFSRemove(virDomainDefPtr def, size_t i)
{
    virDomainFSDefPtr fs = def->fss[i];

    VIR_DELETE_ELEMENT(def->fss, i, def->nfss);
    return fs;
}

19918
virDomainFSDefPtr
19919
virDomainGetFilesystemForTarget(virDomainDefPtr def,
19920
                                const char *target)
19921
{
19922
    size_t i;
19923

19924
    for (i = 0; i < def->nfss; i++) {
19925
        if (STREQ(def->fss[i]->dst, target))
19926 19927 19928 19929 19930 19931
            return def->fss[i];
    }

    return NULL;
}

19932

19933 19934 19935 19936 19937 19938
struct virDomainObjListData {
    virDomainObjListFilter filter;
    virConnectPtr conn;
    bool active;
    int count;
};
19939

19940
static void
19941 19942 19943
virDomainObjListCount(void *payload,
                      const void *name ATTRIBUTE_UNUSED,
                      void *opaque)
19944 19945
{
    virDomainObjPtr obj = payload;
19946
    struct virDomainObjListData *data = opaque;
19947
    virObjectLock(obj);
19948 19949 19950 19951 19952 19953 19954 19955 19956 19957
    if (data->filter &&
        !data->filter(data->conn, obj->def))
        goto cleanup;
    if (virDomainObjIsActive(obj)) {
        if (data->active)
            data->count++;
    } else {
        if (!data->active)
            data->count++;
    }
19958
 cleanup:
19959
    virObjectUnlock(obj);
19960 19961
}

19962 19963
int
virDomainObjListNumOfDomains(virDomainObjListPtr doms,
19964 19965 19966
                             bool active,
                             virDomainObjListFilter filter,
                             virConnectPtr conn)
19967
{
19968
    struct virDomainObjListData data = { filter, conn, active, 0 };
19969
    virObjectLock(doms);
19970
    virHashForEach(doms->objs, virDomainObjListCount, &data);
19971
    virObjectUnlock(doms);
19972
    return data.count;
19973 19974 19975
}

struct virDomainIDData {
19976 19977
    virDomainObjListFilter filter;
    virConnectPtr conn;
19978 19979 19980 19981 19982
    int numids;
    int maxids;
    int *ids;
};

19983 19984 19985 19986
static void
virDomainObjListCopyActiveIDs(void *payload,
                              const void *name ATTRIBUTE_UNUSED,
                              void *opaque)
19987 19988 19989
{
    virDomainObjPtr obj = payload;
    struct virDomainIDData *data = opaque;
19990
    virObjectLock(obj);
19991 19992 19993
    if (data->filter &&
        !data->filter(data->conn, obj->def))
        goto cleanup;
D
Daniel P. Berrange 已提交
19994
    if (virDomainObjIsActive(obj) && data->numids < data->maxids)
19995
        data->ids[data->numids++] = obj->def->id;
19996
 cleanup:
19997
    virObjectUnlock(obj);
19998 19999
}

20000 20001 20002
int
virDomainObjListGetActiveIDs(virDomainObjListPtr doms,
                             int *ids,
20003 20004 20005
                             int maxids,
                             virDomainObjListFilter filter,
                             virConnectPtr conn)
20006
{
20007 20008
    struct virDomainIDData data = { filter, conn,
                                    0, maxids, ids };
20009
    virObjectLock(doms);
20010
    virHashForEach(doms->objs, virDomainObjListCopyActiveIDs, &data);
20011
    virObjectUnlock(doms);
20012 20013 20014 20015
    return data.numids;
}

struct virDomainNameData {
20016 20017
    virDomainObjListFilter filter;
    virConnectPtr conn;
20018 20019 20020 20021 20022 20023
    int oom;
    int numnames;
    int maxnames;
    char **const names;
};

20024 20025 20026 20027
static void
virDomainObjListCopyInactiveNames(void *payload,
                                  const void *name ATTRIBUTE_UNUSED,
                                  void *opaque)
20028 20029 20030 20031 20032 20033 20034
{
    virDomainObjPtr obj = payload;
    struct virDomainNameData *data = opaque;

    if (data->oom)
        return;

20035
    virObjectLock(obj);
20036 20037 20038
    if (data->filter &&
        !data->filter(data->conn, obj->def))
        goto cleanup;
D
Daniel P. Berrange 已提交
20039
    if (!virDomainObjIsActive(obj) && data->numnames < data->maxnames) {
20040
        if (VIR_STRDUP(data->names[data->numnames], obj->def->name) < 0)
20041 20042 20043 20044
            data->oom = 1;
        else
            data->numnames++;
    }
20045
 cleanup:
20046
    virObjectUnlock(obj);
20047 20048 20049
}


20050 20051 20052
int
virDomainObjListGetInactiveNames(virDomainObjListPtr doms,
                                 char **const names,
20053 20054 20055
                                 int maxnames,
                                 virDomainObjListFilter filter,
                                 virConnectPtr conn)
20056
{
20057 20058
    struct virDomainNameData data = { filter, conn,
                                      0, 0, maxnames, names };
20059
    size_t i;
20060
    virObjectLock(doms);
20061
    virHashForEach(doms->objs, virDomainObjListCopyInactiveNames, &data);
20062
    virObjectUnlock(doms);
20063
    if (data.oom) {
20064
        for (i = 0; i < data.numnames; i++)
20065 20066
            VIR_FREE(data.names[i]);
        return -1;
20067 20068 20069 20070 20071
    }

    return data.numnames;
}

20072 20073 20074 20075 20076 20077 20078 20079 20080 20081 20082 20083 20084 20085 20086 20087 20088 20089

struct virDomainListIterData {
    virDomainObjListIterator callback;
    void *opaque;
    int ret;
};

static void
virDomainObjListHelper(void *payload,
                       const void *name ATTRIBUTE_UNUSED,
                       void *opaque)
{
    struct virDomainListIterData *data = opaque;

    if (data->callback(payload, data->opaque) < 0)
        data->ret = -1;
}

20090 20091 20092 20093
int
virDomainObjListForEach(virDomainObjListPtr doms,
                        virDomainObjListIterator callback,
                        void *opaque)
20094 20095 20096 20097
{
    struct virDomainListIterData data = {
        callback, opaque, 0,
    };
20098
    virObjectLock(doms);
20099
    virHashForEach(doms->objs, virDomainObjListHelper, &data);
20100
    virObjectUnlock(doms);
20101 20102 20103 20104
    return data.ret;
}


20105 20106 20107 20108 20109
int
virDomainChrDefForeach(virDomainDefPtr def,
                       bool abortOnError,
                       virDomainChrDefIterator iter,
                       void *opaque)
20110
{
20111
    size_t i;
20112 20113
    int rc = 0;

20114
    for (i = 0; i < def->nserials; i++) {
20115 20116 20117 20118 20119 20120 20121 20122 20123
        if ((iter)(def,
                   def->serials[i],
                   opaque) < 0)
            rc = -1;

        if (abortOnError && rc != 0)
            goto done;
    }

20124
    for (i = 0; i < def->nparallels; i++) {
20125 20126 20127 20128 20129 20130 20131 20132 20133
        if ((iter)(def,
                   def->parallels[i],
                   opaque) < 0)
            rc = -1;

        if (abortOnError && rc != 0)
            goto done;
    }

20134
    for (i = 0; i < def->nchannels; i++) {
20135 20136 20137 20138 20139 20140 20141 20142
        if ((iter)(def,
                   def->channels[i],
                   opaque) < 0)
            rc = -1;

        if (abortOnError && rc != 0)
            goto done;
    }
20143
    for (i = 0; i < def->nconsoles; i++) {
20144
        if ((iter)(def,
20145
                   def->consoles[i],
20146 20147 20148 20149 20150 20151 20152
                   opaque) < 0)
            rc = -1;

        if (abortOnError && rc != 0)
            goto done;
    }

20153
 done:
20154 20155 20156 20157
    return rc;
}


20158 20159 20160 20161 20162
int
virDomainSmartcardDefForeach(virDomainDefPtr def,
                             bool abortOnError,
                             virDomainSmartcardDefIterator iter,
                             void *opaque)
E
Eric Blake 已提交
20163
{
20164
    size_t i;
E
Eric Blake 已提交
20165 20166
    int rc = 0;

20167
    for (i = 0; i < def->nsmartcards; i++) {
E
Eric Blake 已提交
20168 20169 20170 20171 20172 20173 20174 20175 20176
        if ((iter)(def,
                   def->smartcards[i],
                   opaque) < 0)
            rc = -1;

        if (abortOnError && rc != 0)
            goto done;
    }

20177
 done:
E
Eric Blake 已提交
20178 20179 20180 20181
    return rc;
}


20182
/* Call iter(disk, name, depth, opaque) for each element of disk and
20183
 * its backing chain in the pre-populated disk->src.backingStore.
20184 20185 20186
 * ignoreOpenFailure determines whether to warn about a chain that
 * mentions a backing file without also having metadata on that
 * file.  */
20187 20188 20189 20190 20191
int
virDomainDiskDefForeachPath(virDomainDiskDefPtr disk,
                            bool ignoreOpenFailure,
                            virDomainDiskDefPathIterator iter,
                            void *opaque)
20192 20193 20194
{
    int ret = -1;
    size_t depth = 0;
20195
    virStorageSourcePtr tmp;
20196
    char *brokenRaw = NULL;
20197

20198
    if (!ignoreOpenFailure) {
20199
        if (virStorageFileChainGetBroken(disk->src, &brokenRaw) < 0)
20200
            goto cleanup;
20201

20202
        if (brokenRaw) {
20203
            virReportError(VIR_ERR_INTERNAL_ERROR,
20204
                           _("unable to visit backing chain file %s"),
20205
                           brokenRaw);
20206 20207
            goto cleanup;
        }
20208 20209
    }

20210
    for (tmp = disk->src; tmp; tmp = tmp->backingStore) {
20211 20212 20213 20214 20215 20216 20217 20218 20219 20220
        int actualType = virStorageSourceGetActualType(tmp);
        /* execute the callback only for local storage */
        if (actualType != VIR_STORAGE_TYPE_NETWORK &&
            actualType != VIR_STORAGE_TYPE_VOLUME &&
            tmp->path) {
            if (iter(disk, tmp->path, depth, opaque) < 0)
                goto cleanup;
        }

        depth++;
20221
    }
20222 20223 20224

    ret = 0;

20225
 cleanup:
20226
    VIR_FREE(brokenRaw);
20227 20228
    return ret;
}
20229 20230


20231 20232 20233 20234
/* Copy src into a new definition; with the quality of the copy
 * depending on the migratable flag (false for transitions between
 * persistent and active, true for transitions across save files or
 * snapshots).  */
20235
virDomainDefPtr
20236 20237
virDomainDefCopy(virDomainDefPtr src,
                 virCapsPtr caps,
20238
                 virDomainXMLOptionPtr xmlopt,
20239
                 bool migratable)
20240 20241
{
    char *xml;
20242 20243 20244
    virDomainDefPtr ret;
    unsigned int write_flags = VIR_DOMAIN_XML_WRITE_FLAGS;
    unsigned int read_flags = VIR_DOMAIN_XML_READ_FLAGS;
20245

20246 20247
    if (migratable)
        write_flags |= VIR_DOMAIN_XML_INACTIVE | VIR_DOMAIN_XML_MIGRATABLE;
20248

20249
    /* Easiest to clone via a round-trip through XML.  */
20250
    if (!(xml = virDomainDefFormat(src, write_flags)))
20251 20252
        return NULL;

20253
    ret = virDomainDefParseString(xml, caps, xmlopt, -1, read_flags);
20254 20255 20256 20257

    VIR_FREE(xml);
    return ret;
}
J
Jiri Denemark 已提交
20258

20259
virDomainDefPtr
20260 20261 20262
virDomainObjCopyPersistentDef(virDomainObjPtr dom,
                              virCapsPtr caps,
                              virDomainXMLOptionPtr xmlopt)
20263 20264 20265
{
    virDomainDefPtr cur;

20266
    cur = virDomainObjGetPersistentDef(caps, xmlopt, dom);
20267
    return virDomainDefCopy(cur, caps, xmlopt, false);
20268 20269
}

J
Jiri Denemark 已提交
20270 20271 20272 20273 20274 20275 20276 20277 20278 20279 20280 20281 20282 20283 20284 20285 20286

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) {
O
Osier Yang 已提交
20287 20288 20289 20290 20291 20292 20293 20294 20295 20296 20297 20298 20299 20300 20301 20302 20303 20304 20305 20306 20307 20308 20309 20310 20311 20312
    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;
    case VIR_DOMAIN_PMSUSPENDED:
        last = VIR_DOMAIN_PMSUSPENDED_LAST;
        break;
    default:
        last = -1;
J
Jiri Denemark 已提交
20313 20314 20315 20316 20317 20318 20319 20320 20321 20322 20323 20324 20325 20326 20327 20328 20329 20330 20331 20332 20333 20334 20335 20336 20337 20338 20339 20340 20341 20342 20343 20344 20345
    }

    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);
20346 20347 20348 20349
    case VIR_DOMAIN_PMSUSPENDED:
        return virDomainPMSuspendedReasonTypeToString(reason);
    case VIR_DOMAIN_LAST:
        break;
J
Jiri Denemark 已提交
20350
    }
20351 20352
    VIR_WARN("Unexpected domain state: %d", state);
    return NULL;
J
Jiri Denemark 已提交
20353 20354 20355 20356 20357 20358 20359 20360 20361 20362 20363 20364 20365 20366 20367 20368 20369 20370 20371 20372 20373
}


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);
20374 20375 20376 20377
    case VIR_DOMAIN_PMSUSPENDED:
        return virDomainPMSuspendedReasonTypeFromString(reason);
    case VIR_DOMAIN_LAST:
        break;
J
Jiri Denemark 已提交
20378
    }
20379 20380
    VIR_WARN("Unexpected domain state: %d", state);
    return -1;
J
Jiri Denemark 已提交
20381
}
20382 20383 20384 20385 20386 20387 20388 20389 20390 20391 20392 20393 20394 20395 20396 20397 20398 20399


/* Some access functions to gloss over the difference between NetDef
 * (<interface>) and ActualNetDef (<actual>). If the NetDef has an
 * ActualNetDef, return the requested value from the ActualNetDef,
 * otherwise return the value from the NetDef.
 */

int
virDomainNetGetActualType(virDomainNetDefPtr iface)
{
    if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK)
        return iface->type;
    if (!iface->data.network.actual)
        return iface->type;
    return iface->data.network.actual->type;
}

20400
const char *
20401 20402 20403 20404
virDomainNetGetActualBridgeName(virDomainNetDefPtr iface)
{
    if (iface->type == VIR_DOMAIN_NET_TYPE_BRIDGE)
        return iface->data.bridge.brname;
20405 20406 20407 20408 20409 20410
    if (iface->type == VIR_DOMAIN_NET_TYPE_NETWORK &&
        iface->data.network.actual &&
        iface->data.network.actual->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
        return iface->data.network.actual->data.bridge.brname;
    }
    return NULL;
20411 20412
}

20413
const char *
20414 20415 20416 20417
virDomainNetGetActualDirectDev(virDomainNetDefPtr iface)
{
    if (iface->type == VIR_DOMAIN_NET_TYPE_DIRECT)
        return iface->data.direct.linkdev;
20418 20419 20420 20421 20422 20423
    if (iface->type == VIR_DOMAIN_NET_TYPE_NETWORK &&
        iface->data.network.actual &&
        iface->data.network.actual->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
        return iface->data.network.actual->data.direct.linkdev;
    }
    return NULL;
20424 20425 20426 20427 20428 20429 20430
}

int
virDomainNetGetActualDirectMode(virDomainNetDefPtr iface)
{
    if (iface->type == VIR_DOMAIN_NET_TYPE_DIRECT)
        return iface->data.direct.mode;
20431 20432 20433 20434 20435 20436
    if (iface->type == VIR_DOMAIN_NET_TYPE_NETWORK &&
        iface->data.network.actual &&
        iface->data.network.actual->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
        return iface->data.network.actual->data.direct.mode;
    }
    return 0;
20437 20438
}

20439 20440 20441 20442 20443
virDomainHostdevDefPtr
virDomainNetGetActualHostdev(virDomainNetDefPtr iface)
{
    if (iface->type == VIR_DOMAIN_NET_TYPE_HOSTDEV)
        return &iface->data.hostdev.def;
E
Eric Blake 已提交
20444
    if (iface->type == VIR_DOMAIN_NET_TYPE_NETWORK &&
20445
        iface->data.network.actual &&
E
Eric Blake 已提交
20446
        iface->data.network.actual->type == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
20447 20448 20449 20450 20451
        return &iface->data.network.actual->data.hostdev.def;
    }
    return NULL;
}

20452
virNetDevVPortProfilePtr
20453
virDomainNetGetActualVirtPortProfile(virDomainNetDefPtr iface)
20454
{
A
Ansis Atteka 已提交
20455 20456 20457
    switch (iface->type) {
    case VIR_DOMAIN_NET_TYPE_DIRECT:
    case VIR_DOMAIN_NET_TYPE_BRIDGE:
20458
    case VIR_DOMAIN_NET_TYPE_HOSTDEV:
20459
        return iface->virtPortProfile;
A
Ansis Atteka 已提交
20460 20461 20462 20463 20464 20465
    case VIR_DOMAIN_NET_TYPE_NETWORK:
        if (!iface->data.network.actual)
            return NULL;
        switch (iface->data.network.actual->type) {
        case VIR_DOMAIN_NET_TYPE_DIRECT:
        case VIR_DOMAIN_NET_TYPE_BRIDGE:
20466
        case VIR_DOMAIN_NET_TYPE_HOSTDEV:
20467
            return iface->data.network.actual->virtPortProfile;
A
Ansis Atteka 已提交
20468 20469 20470 20471
        default:
            return NULL;
        }
    default:
20472
        return NULL;
A
Ansis Atteka 已提交
20473
    }
20474
}
20475

20476
virNetDevBandwidthPtr
20477 20478
virDomainNetGetActualBandwidth(virDomainNetDefPtr iface)
{
20479 20480 20481
    /* if there is an ActualNetDef, *always* return
     * its bandwidth rather than the NetDef's bandwidth.
     */
E
Eric Blake 已提交
20482
    if (iface->type == VIR_DOMAIN_NET_TYPE_NETWORK &&
20483
        iface->data.network.actual) {
20484 20485 20486 20487
        return iface->data.network.actual->bandwidth;
    }
    return iface->bandwidth;
}
20488

20489 20490 20491
virNetDevVlanPtr
virDomainNetGetActualVlan(virDomainNetDefPtr iface)
{
20492 20493 20494 20495 20496
    virNetDevVlanPtr vlan = &iface->vlan;

    /* if there is an ActualNetDef, *always* return
     * its vlan rather than the NetDef's vlan.
     */
20497
    if (iface->type == VIR_DOMAIN_NET_TYPE_NETWORK &&
20498 20499 20500 20501 20502 20503
        iface->data.network.actual)
        vlan = &iface->data.network.actual->vlan;

    if (vlan->nTags > 0)
        return vlan;
    return NULL;
20504
}
20505

20506 20507 20508 20509 20510 20511 20512 20513 20514 20515 20516 20517

bool
virDomainNetGetActualTrustGuestRxFilters(virDomainNetDefPtr iface)
{
    if (iface->type == VIR_DOMAIN_NET_TYPE_NETWORK &&
        iface->data.network.actual)
        return (iface->data.network.actual->trustGuestRxFilters
                == VIR_TRISTATE_BOOL_YES);
    return iface->trustGuestRxFilters == VIR_TRISTATE_BOOL_YES;
}


20518
/* Return listens[i] from the appropriate union for the graphics
20519
 * type, or NULL if this is an unsuitable type, or the index is out of
20520
 * bounds. If force0 is TRUE, i == 0, and there is no listen array,
20521 20522
 * allocate one with a single item. */
static virDomainGraphicsListenDefPtr
20523
virDomainGraphicsGetListen(virDomainGraphicsDefPtr def, size_t i, bool force0)
20524
{
E
Eric Blake 已提交
20525 20526 20527
    if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC ||
        def->type == VIR_DOMAIN_GRAPHICS_TYPE_RDP ||
        def->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) {
20528

20529
        if (!def->listens && (i == 0) && force0) {
20530
            if (VIR_ALLOC(def->listens) >= 0)
20531 20532 20533
                def->nListens = 1;
        }

20534
        if (!def->listens || (def->nListens <= i))
20535 20536
            return NULL;

20537
        return &def->listens[i];
20538 20539 20540 20541 20542 20543 20544 20545 20546 20547 20548 20549 20550 20551 20552 20553 20554 20555 20556 20557 20558
    }

    /* it's a type that has no listens array */
    return NULL;
}


/* Access functions for the fields in a virDomainGraphicsDef's
 * "listens" array.
 *
 * NB: For simple backward compatibility with existing code, any of
 * the "Set" functions will auto-create listens[0] to store the new
 * setting, when necessary. Auto-creation beyond the first item is not
 * supported.
 *
 * Return values: All "Get" functions return the requested item, or
 * 0/NULL. (in the case of returned const char *, the caller should
 * make a copy if they want to keep it around). All "Set" functions
 * return 0 on success, -1 on failure. */

int
20559
virDomainGraphicsListenGetType(virDomainGraphicsDefPtr def, size_t i)
20560 20561
{
    virDomainGraphicsListenDefPtr listenInfo
20562
        = virDomainGraphicsGetListen(def, i, false);
20563 20564 20565 20566 20567 20568 20569 20570 20571 20572 20573

    if (!listenInfo)
        return VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NONE;
    return listenInfo->type;
}


/* NB: This function assumes type has not previously been set. It
 * *will not* free any existing address or network based on a change
 * in value of type. */
int
20574
virDomainGraphicsListenSetType(virDomainGraphicsDefPtr def, size_t i, int val)
20575 20576
{
    virDomainGraphicsListenDefPtr listenInfo
20577
        = virDomainGraphicsGetListen(def, i, true);
20578 20579 20580 20581 20582 20583 20584 20585 20586

    if (!listenInfo)
        return -1;
    listenInfo->type = val;
    return 0;
}


const char *
20587
virDomainGraphicsListenGetAddress(virDomainGraphicsDefPtr def, size_t i)
20588 20589
{
    virDomainGraphicsListenDefPtr listenInfo
20590
        = virDomainGraphicsGetListen(def, i, false);
20591

20592
    /* even a network can have a listen address */
20593
    if (!listenInfo ||
20594 20595
        !(listenInfo->type == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS ||
          listenInfo->type == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NETWORK))
20596 20597 20598 20599 20600 20601
        return NULL;
    return listenInfo->address;
}


/* Make a copy of up to len characters of address, and store it in
20602
 * listens[i].address. If setType is true, set the listen's type
20603 20604 20605
 * to 'address', otherwise leave type alone. */
int
virDomainGraphicsListenSetAddress(virDomainGraphicsDefPtr def,
20606
                                  size_t i, const char *address,
20607 20608 20609
                                  int len, bool setType)
{
    virDomainGraphicsListenDefPtr listenInfo
20610
        = virDomainGraphicsGetListen(def, i, true);
20611 20612 20613 20614 20615 20616 20617 20618 20619 20620 20621 20622

    if (!listenInfo)
        return -1;

    if (setType)
        listenInfo->type = VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS;

    if (!address) {
        listenInfo->address = NULL;
        return 0;
    }

20623
    if (VIR_STRNDUP(listenInfo->address, address, len) < 0)
20624 20625 20626 20627 20628 20629
        return -1;
    return 0;
}


const char *
20630
virDomainGraphicsListenGetNetwork(virDomainGraphicsDefPtr def, size_t i)
20631 20632
{
    virDomainGraphicsListenDefPtr listenInfo
20633
        = virDomainGraphicsGetListen(def, i, false);
20634 20635 20636 20637 20638 20639 20640 20641 20642

    if (!listenInfo ||
        (listenInfo->type != VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NETWORK))
        return NULL;
    return listenInfo->network;
}


/* Make a copy of up to len characters of address, and store it in
20643
 * listens[i].network */
20644 20645
int
virDomainGraphicsListenSetNetwork(virDomainGraphicsDefPtr def,
20646
                                  size_t i, const char *network, int len)
20647 20648
{
    virDomainGraphicsListenDefPtr listenInfo
20649
        = virDomainGraphicsGetListen(def, i, true);
20650 20651 20652 20653 20654 20655 20656 20657 20658 20659 20660

    if (!listenInfo)
        return -1;

    listenInfo->type = VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NETWORK;

    if (!network) {
        listenInfo->network = NULL;
        return 0;
    }

20661
    if (VIR_STRNDUP(listenInfo->network, network, len) < 0)
20662 20663 20664
        return -1;
    return 0;
}
20665 20666 20667 20668 20669 20670 20671 20672 20673 20674 20675 20676 20677 20678 20679

/**
 * virDomainNetFind:
 * @def: domain's def
 * @device: could be the interface name or MAC address
 *
 * Finds a domain's net def, given the interface name or MAC address
 *
 * Returns a pointer to the net def or NULL if not found.
 */
virDomainNetDefPtr
virDomainNetFind(virDomainDefPtr def, const char *device)
{
    bool isMac = false;
    virDomainNetDefPtr net = NULL;
20680
    virMacAddr mac;
20681
    size_t i;
20682

20683
    if (virMacAddrParse(device, &mac) == 0)
20684 20685 20686 20687
        isMac = true;

    if (isMac) {
        for (i = 0; i < def->nnets; i++) {
20688
            if (virMacAddrCmp(&mac, &def->nets[i]->mac) == 0) {
20689 20690 20691 20692 20693 20694 20695 20696 20697 20698 20699 20700 20701 20702 20703
                net = def->nets[i];
                break;
            }
        }
    } else { /* ifname */
        for (i = 0; i < def->nnets; i++) {
            if (STREQ_NULLABLE(device, def->nets[i]->ifname)) {
                net = def->nets[i];
                break;
            }
        }
    }

    return net;
}
20704 20705 20706 20707 20708 20709 20710 20711 20712 20713 20714 20715 20716 20717 20718 20719

/**
 * virDomainDeviceDefCopy:
 * @caps: Capabilities
 * @def: Domain definition to which @src belongs
 * @src: source to be copied
 *
 * virDomainDeviceDefCopy does a deep copy of only the parts of a
 * DeviceDef that are valid when just the flag VIR_DOMAIN_XML_INACTIVE is
 * set. This means that any part of the device xml that is conditionally
 * parsed/formatted based on some other flag being set (or on the INACTIVE
 * flag being reset) *will not* be copied to the destination. Caveat emptor.
 *
 * Returns a pointer to copied @src or NULL in case of error.
 */
virDomainDeviceDefPtr
20720
virDomainDeviceDefCopy(virDomainDeviceDefPtr src,
20721
                       const virDomainDef *def,
20722 20723
                       virCapsPtr caps,
                       virDomainXMLOptionPtr xmlopt)
20724 20725 20726 20727 20728 20729 20730
{
    virDomainDeviceDefPtr ret = NULL;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
    int flags = VIR_DOMAIN_XML_INACTIVE;
    char *xmlStr = NULL;
    int rc = -1;

20731
    switch ((virDomainDeviceType) src->type) {
20732 20733 20734 20735 20736 20737 20738 20739 20740 20741 20742 20743 20744 20745 20746 20747 20748 20749 20750 20751 20752 20753 20754 20755 20756 20757 20758 20759 20760 20761 20762 20763 20764 20765 20766 20767 20768 20769 20770
    case VIR_DOMAIN_DEVICE_DISK:
        rc = virDomainDiskDefFormat(&buf, src->data.disk, flags);
        break;
    case VIR_DOMAIN_DEVICE_LEASE:
        rc = virDomainLeaseDefFormat(&buf, src->data.lease);
        break;
    case VIR_DOMAIN_DEVICE_FS:
        rc = virDomainFSDefFormat(&buf, src->data.fs, flags);
        break;
    case VIR_DOMAIN_DEVICE_NET:
        rc = virDomainNetDefFormat(&buf, src->data.net, flags);
        break;
    case VIR_DOMAIN_DEVICE_INPUT:
        rc = virDomainInputDefFormat(&buf, src->data.input, flags);
        break;
    case VIR_DOMAIN_DEVICE_SOUND:
        rc = virDomainSoundDefFormat(&buf, src->data.sound, flags);
        break;
    case VIR_DOMAIN_DEVICE_VIDEO:
        rc = virDomainVideoDefFormat(&buf, src->data.video, flags);
        break;
    case VIR_DOMAIN_DEVICE_HOSTDEV:
        rc = virDomainHostdevDefFormat(&buf, src->data.hostdev, flags);
        break;
    case VIR_DOMAIN_DEVICE_WATCHDOG:
        rc = virDomainWatchdogDefFormat(&buf, src->data.watchdog, flags);
        break;
    case VIR_DOMAIN_DEVICE_CONTROLLER:
        rc = virDomainControllerDefFormat(&buf, src->data.controller, flags);
        break;
    case VIR_DOMAIN_DEVICE_GRAPHICS:
        rc = virDomainGraphicsDefFormat(&buf, src->data.graphics, flags);
        break;
    case VIR_DOMAIN_DEVICE_HUB:
        rc = virDomainHubDefFormat(&buf, src->data.hub, flags);
        break;
    case VIR_DOMAIN_DEVICE_REDIRDEV:
        rc = virDomainRedirdevDefFormat(&buf, src->data.redirdev, flags);
        break;
20771 20772 20773
    case VIR_DOMAIN_DEVICE_RNG:
        rc = virDomainRNGDefFormat(&buf, src->data.rng, flags);
        break;
20774 20775 20776
    case VIR_DOMAIN_DEVICE_CHR:
        rc = virDomainChrDefFormat(&buf, src->data.chr, flags);
        break;
20777 20778 20779
    case VIR_DOMAIN_DEVICE_NONE:
    case VIR_DOMAIN_DEVICE_SMARTCARD:
    case VIR_DOMAIN_DEVICE_MEMBALLOON:
L
Li Zhang 已提交
20780
    case VIR_DOMAIN_DEVICE_NVRAM:
20781
    case VIR_DOMAIN_DEVICE_SHMEM:
20782
    case VIR_DOMAIN_DEVICE_LAST:
20783 20784 20785 20786
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Copying definition of '%d' type "
                         "is not implemented yet."),
                       src->type);
20787 20788 20789 20790 20791 20792 20793
        goto cleanup;
    }

    if (rc < 0)
        goto cleanup;

    xmlStr = virBufferContentAndReset(&buf);
20794
    ret = virDomainDeviceDefParse(xmlStr, def, caps, xmlopt, flags);
20795

20796
 cleanup:
20797 20798 20799
    VIR_FREE(xmlStr);
    return ret;
}
O
Osier Yang 已提交
20800 20801 20802 20803

struct virDomainListData {
    virConnectPtr conn;
    virDomainPtr *domains;
20804
    virDomainObjListFilter filter;
O
Osier Yang 已提交
20805 20806 20807 20808 20809 20810 20811 20812 20813 20814 20815 20816 20817 20818 20819 20820 20821 20822
    unsigned int flags;
    int ndomains;
    bool error;
};

#define MATCH(FLAG) (data->flags & (FLAG))
static void
virDomainListPopulate(void *payload,
                      const void *name ATTRIBUTE_UNUSED,
                      void *opaque)
{
    struct virDomainListData *data = opaque;
    virDomainObjPtr vm = payload;
    virDomainPtr dom;

    if (data->error)
        return;

20823
    virObjectLock(vm);
O
Osier Yang 已提交
20824 20825
    /* check if the domain matches the filter */

20826 20827 20828 20829 20830
    /* filter by the callback function (access control checks) */
    if (data->filter != NULL &&
        !data->filter(data->conn, vm->def))
        goto cleanup;

O
Osier Yang 已提交
20831 20832 20833 20834 20835 20836 20837 20838 20839 20840 20841 20842 20843 20844 20845 20846 20847 20848 20849 20850 20851 20852 20853 20854 20855 20856 20857 20858 20859 20860 20861 20862 20863 20864 20865 20866 20867 20868 20869 20870 20871 20872 20873 20874 20875 20876 20877 20878
    /* filter by active state */
    if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_ACTIVE) &&
        !((MATCH(VIR_CONNECT_LIST_DOMAINS_ACTIVE) &&
           virDomainObjIsActive(vm)) ||
          (MATCH(VIR_CONNECT_LIST_DOMAINS_INACTIVE) &&
           !virDomainObjIsActive(vm))))
        goto cleanup;

    /* filter by persistence */
    if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_PERSISTENT) &&
        !((MATCH(VIR_CONNECT_LIST_DOMAINS_PERSISTENT) &&
           vm->persistent) ||
          (MATCH(VIR_CONNECT_LIST_DOMAINS_TRANSIENT) &&
           !vm->persistent)))
        goto cleanup;

    /* filter by domain state */
    if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_STATE)) {
        int st = virDomainObjGetState(vm, NULL);
        if (!((MATCH(VIR_CONNECT_LIST_DOMAINS_RUNNING) &&
               st == VIR_DOMAIN_RUNNING) ||
              (MATCH(VIR_CONNECT_LIST_DOMAINS_PAUSED) &&
               st == VIR_DOMAIN_PAUSED) ||
              (MATCH(VIR_CONNECT_LIST_DOMAINS_SHUTOFF) &&
               st == VIR_DOMAIN_SHUTOFF) ||
              (MATCH(VIR_CONNECT_LIST_DOMAINS_OTHER) &&
               (st != VIR_DOMAIN_RUNNING &&
                st != VIR_DOMAIN_PAUSED &&
                st != VIR_DOMAIN_SHUTOFF))))
            goto cleanup;
    }

    /* filter by existence of managed save state */
    if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_MANAGEDSAVE) &&
        !((MATCH(VIR_CONNECT_LIST_DOMAINS_MANAGEDSAVE) &&
           vm->hasManagedSave) ||
          (MATCH(VIR_CONNECT_LIST_DOMAINS_NO_MANAGEDSAVE) &&
           !vm->hasManagedSave)))
            goto cleanup;

    /* filter by autostart option */
    if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_AUTOSTART) &&
        !((MATCH(VIR_CONNECT_LIST_DOMAINS_AUTOSTART) && vm->autostart) ||
          (MATCH(VIR_CONNECT_LIST_DOMAINS_NO_AUTOSTART) && !vm->autostart)))
        goto cleanup;

    /* filter by snapshot existence */
    if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_SNAPSHOT)) {
20879
        int nsnap = virDomainSnapshotObjListNum(vm->snapshots, NULL, 0);
O
Osier Yang 已提交
20880 20881 20882 20883 20884 20885 20886 20887
        if (!((MATCH(VIR_CONNECT_LIST_DOMAINS_HAS_SNAPSHOT) && nsnap > 0) ||
              (MATCH(VIR_CONNECT_LIST_DOMAINS_NO_SNAPSHOT) && nsnap <= 0)))
            goto cleanup;
    }

    /* just count the machines */
    if (!data->domains) {
        data->ndomains++;
P
Pavel Hrdina 已提交
20888
        goto cleanup;
O
Osier Yang 已提交
20889 20890 20891 20892 20893 20894 20895 20896 20897 20898 20899
    }

    if (!(dom = virGetDomain(data->conn, vm->def->name, vm->def->uuid))) {
        data->error = true;
        goto cleanup;
    }

    dom->id = vm->def->id;

    data->domains[data->ndomains++] = dom;

20900
 cleanup:
20901
    virObjectUnlock(vm);
O
Osier Yang 已提交
20902 20903 20904 20905
    return;
}
#undef MATCH

20906 20907 20908 20909 20910 20911 20912 20913 20914 20915 20916 20917 20918 20919 20920 20921 20922 20923 20924 20925 20926 20927 20928

/**
 * virDomainListFree:
 * @list: list of domains to free
 *
 * Frees a NULL-terminated list of domains without messing with currently
 * set libvirt errors.
 */
void
virDomainListFree(virDomainPtr *list)
{
    virDomainPtr *next;

    if (!list)
        return;

    for (next = list; *next; next++)
        virObjectUnref(*next);

    VIR_FREE(list);
}


O
Osier Yang 已提交
20929
int
20930 20931 20932
virDomainObjListExport(virDomainObjListPtr doms,
                       virConnectPtr conn,
                       virDomainPtr **domains,
20933
                       virDomainObjListFilter filter,
20934
                       unsigned int flags)
O
Osier Yang 已提交
20935 20936 20937
{
    int ret = -1;

20938 20939 20940 20941 20942
    struct virDomainListData data = {
        conn, NULL,
        filter,
        flags, 0, false
    };
O
Osier Yang 已提交
20943

20944
    virObjectLock(doms);
20945 20946 20947
    if (domains &&
        VIR_ALLOC_N(data.domains, virHashSize(doms->objs) + 1) < 0)
        goto cleanup;
O
Osier Yang 已提交
20948

20949
    virHashForEach(doms->objs, virDomainListPopulate, &data);
O
Osier Yang 已提交
20950 20951 20952 20953 20954 20955 20956 20957 20958 20959 20960 20961 20962

    if (data.error)
        goto cleanup;

    if (data.domains) {
        /* trim the array to the final size */
        ignore_value(VIR_REALLOC_N(data.domains, data.ndomains + 1));
        *domains = data.domains;
        data.domains = NULL;
    }

    ret = data.ndomains;

20963
 cleanup:
20964
    virDomainListFree(data.domains);
20965
    virObjectUnlock(doms);
O
Osier Yang 已提交
20966 20967 20968
    return ret;
}

20969 20970 20971
virSecurityLabelDefPtr
virDomainDefGetSecurityLabelDef(virDomainDefPtr def, const char *model)
{
20972
    size_t i;
20973
    virSecurityLabelDefPtr seclabel = NULL;
20974 20975 20976 20977 20978 20979 20980 20981 20982 20983 20984

    if (def == NULL || model == NULL)
        return NULL;

    for (i = 0; i < def->nseclabels; i++) {
        if (def->seclabels[i]->model == NULL)
            continue;
        if (STREQ(def->seclabels[i]->model, model))
            return def->seclabels[i];
    }

20985
    return seclabel;
20986 20987 20988
}


20989 20990 20991
virSecurityDeviceLabelDefPtr
virDomainChrDefGetSecurityLabelDef(virDomainChrDefPtr def, const char *model)
{
20992
    size_t i;
20993 20994 20995 20996 20997 20998 20999 21000 21001 21002 21003

    if (def == NULL)
        return NULL;

    for (i = 0; i < def->nseclabels; i++) {
        if (STREQ_NULLABLE(def->seclabels[i]->model, model))
            return def->seclabels[i];
    }
    return NULL;
}

21004 21005 21006 21007 21008 21009 21010 21011 21012 21013 21014 21015 21016 21017 21018 21019 21020 21021 21022 21023 21024 21025 21026 21027

typedef struct {
    const char *devAlias;
    virDomainDeviceDefPtr dev;
} virDomainDefFindDeviceCallbackData;

static int
virDomainDefFindDeviceCallback(virDomainDefPtr def ATTRIBUTE_UNUSED,
                               virDomainDeviceDefPtr dev,
                               virDomainDeviceInfoPtr info,
                               void *opaque)
{
    virDomainDefFindDeviceCallbackData *data = opaque;

    if (STREQ_NULLABLE(info->alias, data->devAlias)) {
        *data->dev = *dev;
        return -1;
    }
    return 0;
}

int
virDomainDefFindDevice(virDomainDefPtr def,
                       const char *devAlias,
21028 21029
                       virDomainDeviceDefPtr dev,
                       bool reportError)
21030 21031 21032 21033 21034 21035 21036 21037
{
    virDomainDefFindDeviceCallbackData data = { devAlias, dev };

    dev->type = VIR_DOMAIN_DEVICE_NONE;
    virDomainDeviceInfoIterateInternal(def, virDomainDefFindDeviceCallback,
                                       true, &data);

    if (dev->type == VIR_DOMAIN_DEVICE_NONE) {
21038 21039 21040 21041 21042 21043
        if (reportError) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("no device found with alias %s"), devAlias);
        } else {
            VIR_DEBUG("no device found with alias %s", devAlias);
        }
21044 21045 21046 21047 21048
        return -1;
    }

    return 0;
}
21049 21050 21051 21052 21053 21054 21055 21056 21057 21058 21059

/**
 * virDomainDiskSourceIsBlockType:
 *
 * Check if the disk *source* is of block type. This just tries
 * to check from the type of disk def, not to probe the underlying
 * storage.
 *
 * Return true if its source is block type, or false otherwise.
 */
bool
21060
virDomainDiskSourceIsBlockType(virStorageSourcePtr src)
21061
{
21062
    if (!src->path)
21063 21064
        return false;

21065
    if (src->type == VIR_STORAGE_TYPE_BLOCK)
21066 21067 21068 21069 21070
        return true;

    /* For volume types, check the srcpool.
     * If it's a block type source pool, then it's possible
     */
21071 21072 21073
    if (src->type == VIR_STORAGE_TYPE_VOLUME &&
        src->srcpool &&
        src->srcpool->voltype == VIR_STORAGE_VOL_BLOCK) {
21074 21075 21076 21077
        /* We don't think the volume accessed by remote URI is
         * block type source, since we can't/shouldn't manage it
         * (e.g. set sgio=filtered|unfiltered for it) in libvirt.
         */
21078 21079
         if (src->srcpool->pooltype == VIR_STORAGE_POOL_ISCSI &&
             src->srcpool->mode == VIR_STORAGE_SOURCE_POOL_MODE_DIRECT)
21080 21081
             return false;

21082 21083 21084 21085
        return true;
    }
    return false;
}
21086 21087 21088 21089 21090 21091 21092 21093 21094 21095 21096 21097 21098 21099 21100 21101


char *
virDomainObjGetMetadata(virDomainObjPtr vm,
                        int type,
                        const char *uri ATTRIBUTE_UNUSED,
                        virCapsPtr caps,
                        virDomainXMLOptionPtr xmlopt,
                        unsigned int flags)
{
    virDomainDefPtr def;
    char *ret = NULL;

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, NULL);

21102 21103 21104 21105 21106 21107
    if (type >= VIR_DOMAIN_METADATA_LAST) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("unknown metadata type '%d'"), type);
        goto cleanup;
    }

21108 21109 21110 21111 21112 21113 21114 21115 21116
    if (virDomainLiveConfigHelperMethod(caps, xmlopt, vm, &flags, &def) < 0)
        goto cleanup;

    /* use correct domain definition according to flags */
    if (flags & VIR_DOMAIN_AFFECT_LIVE)
        def = vm->def;

    switch ((virDomainMetadataType) type) {
    case VIR_DOMAIN_METADATA_DESCRIPTION:
21117 21118
        if (VIR_STRDUP(ret, def->description) < 0)
            goto cleanup;
21119 21120 21121
        break;

    case VIR_DOMAIN_METADATA_TITLE:
21122 21123
        if (VIR_STRDUP(ret, def->title) < 0)
            goto cleanup;
21124 21125 21126
        break;

    case VIR_DOMAIN_METADATA_ELEMENT:
21127 21128 21129 21130 21131
        if (!def->metadata)
            break;

        if (virXMLExtractNamespaceXML(def->metadata, uri, &ret) < 0)
            goto cleanup;
21132 21133
        break;

21134
    /* coverity[dead_error_begin] */
21135
    case VIR_DOMAIN_METADATA_LAST:
21136 21137 21138
        break;
    }

21139
    if (!ret)
21140 21141 21142
        virReportError(VIR_ERR_NO_DOMAIN_METADATA, "%s",
                       _("Requested metadata element is not present"));

21143
 cleanup:
21144 21145
    return ret;
}
21146

21147 21148 21149 21150 21151

static int
virDomainDefSetMetadata(virDomainDefPtr def,
                        int type,
                        const char *metadata,
21152 21153
                        const char *key,
                        const char *uri)
21154
{
21155 21156
    xmlDocPtr doc = NULL;
    xmlNodePtr old;
21157
    xmlNodePtr new = NULL;
21158
    char *tmp;
21159 21160
    int ret = -1;

21161 21162 21163 21164 21165 21166
    if (type >= VIR_DOMAIN_METADATA_LAST) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("unknown metadata type '%d'"), type);
        goto cleanup;
    }

21167 21168
    switch ((virDomainMetadataType) type) {
    case VIR_DOMAIN_METADATA_DESCRIPTION:
21169
        if (VIR_STRDUP(tmp, metadata) < 0)
21170
            goto cleanup;
21171 21172 21173

        VIR_FREE(def->description);
        def->description = tmp;
21174 21175 21176
        break;

    case VIR_DOMAIN_METADATA_TITLE:
21177
        if (VIR_STRDUP(tmp, metadata) < 0)
21178
            goto cleanup;
21179 21180 21181

        VIR_FREE(def->title);
        def->title = tmp;
21182 21183 21184
        break;

    case VIR_DOMAIN_METADATA_ELEMENT:
21185 21186 21187 21188 21189 21190 21191 21192 21193 21194 21195 21196 21197 21198 21199 21200 21201 21202 21203 21204 21205 21206 21207 21208 21209 21210 21211
        if (metadata) {
            /* parse and modify the xml from the user */
            if (!(doc = virXMLParseString(metadata, _("(metadata_xml)"))))
                goto cleanup;

            if (virXMLInjectNamespace(doc->children, uri, key) < 0)
                goto cleanup;

            /* create the root node if needed */
            if (!def->metadata &&
                !(def->metadata = xmlNewNode(NULL, (unsigned char *)"metadata"))) {
                virReportOOMError();
                goto cleanup;
            }

            if (!(new = xmlCopyNode(doc->children, 1))) {
                virReportOOMError();
                goto cleanup;
            }
        }

        /* remove possible other nodes sharing the namespace */
        while ((old = virXMLFindChildNodeByNs(def->metadata, uri))) {
            xmlUnlinkNode(old);
            xmlFreeNode(old);
        }

21212 21213
        if (new &&
            !(xmlAddChild(def->metadata, new))) {
21214 21215 21216 21217
            xmlFreeNode(new);
            virReportOOMError();
            goto cleanup;
        }
21218 21219
        break;

21220
    /* coverity[dead_error_begin] */
21221
    case VIR_DOMAIN_METADATA_LAST:
21222 21223 21224 21225 21226
        break;
    }

    ret = 0;

21227
 cleanup:
21228
    xmlFreeDoc(doc);
21229 21230 21231 21232
    return ret;
}


21233 21234 21235 21236
int
virDomainObjSetMetadata(virDomainObjPtr vm,
                        int type,
                        const char *metadata,
21237 21238
                        const char *key,
                        const char *uri,
21239 21240
                        virCapsPtr caps,
                        virDomainXMLOptionPtr xmlopt,
21241
                        const char *stateDir,
21242 21243 21244 21245 21246 21247 21248 21249 21250 21251
                        const char *configDir,
                        unsigned int flags)
{
    virDomainDefPtr persistentDef;

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

    if (virDomainLiveConfigHelperMethod(caps, xmlopt, vm, &flags,
                                        &persistentDef) < 0)
21252
        return -1;
21253

21254
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
21255 21256
        if (virDomainDefSetMetadata(vm->def, type, metadata, key, uri) < 0)
            return -1;
21257

21258 21259 21260 21261
        if (virDomainSaveStatus(xmlopt, stateDir, vm) < 0)
            return -1;
    }

21262
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
21263 21264
        if (virDomainDefSetMetadata(persistentDef, type, metadata, key,
                                    uri) < 0)
21265
            return -1;
21266 21267

        if (virDomainSaveConfig(configDir, persistentDef) < 0)
21268
            return -1;
21269 21270
    }

21271
    return 0;
21272
}
21273 21274 21275 21276 21277 21278 21279 21280 21281 21282 21283 21284 21285


bool
virDomainDefNeedsPlacementAdvice(virDomainDefPtr def)
{
    if (def->placement_mode == VIR_DOMAIN_CPU_PLACEMENT_MODE_AUTO)
        return true;

    if (virDomainNumatuneHasPlacementAuto(def->numatune))
        return true;

    return false;
}