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

#include <config.h>

27 28 29
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
30

31
#include "configmake.h"
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 "virxml.h"
39
#include "viruuid.h"
40
#include "virbuffer.h"
41
#include "virlog.h"
42
#include "nwfilter_conf.h"
43
#include "storage_conf.h"
44
#include "virstoragefile.h"
E
Eric Blake 已提交
45
#include "virfile.h"
46
#include "virbitmap.h"
M
Matthias Bolte 已提交
47
#include "count-one-bits.h"
48
#include "secret_conf.h"
49 50
#include "netdev_vport_profile_conf.h"
#include "netdev_bandwidth_conf.h"
51
#include "netdev_vlan_conf.h"
52
#include "device_conf.h"
53
#include "network_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");

61 62
/* This structure holds various callbacks and data needed
 * while parsing and creating domain XMLs */
63
struct _virDomainXMLOption {
64 65
    virObject parent;

66 67 68
    /* XML parser callbacks and defaults */
    virDomainDefParserConfig config;

69 70 71 72 73
    /* domain private data management callbacks */
    virDomainXMLPrivateDataCallbacks privateData;

    /* XML namespace callbacks */
    virDomainXMLNamespace ns;
74 75 76 77 78 79 80
};

#define VIR_DOMAIN_DEF_FORMAT_COMMON_FLAGS             \
    (VIR_DOMAIN_DEF_FORMAT_SECURE |                    \
     VIR_DOMAIN_DEF_FORMAT_INACTIVE |                  \
     VIR_DOMAIN_DEF_FORMAT_UPDATE_CPU |                \
     VIR_DOMAIN_DEF_FORMAT_MIGRATABLE)
81

82 83 84 85 86
VIR_ENUM_IMPL(virDomainTaint, VIR_DOMAIN_TAINT_LAST,
              "custom-argv",
              "custom-monitor",
              "high-privileges",
              "shell-scripts",
87
              "disk-probing",
88
              "external-launch",
89
              "host-cpu",
90
              "hook-script",
91 92
              "cdrom-passthrough",
              "custom-dtb");
93

94
VIR_ENUM_IMPL(virDomainVirt, VIR_DOMAIN_VIRT_LAST,
95
              "none",
96 97 98 99 100 101 102 103 104
              "qemu",
              "kqemu",
              "kvm",
              "xen",
              "lxc",
              "uml",
              "openvz",
              "test",
              "vmware",
105
              "hyperv",
D
Daniel Veillard 已提交
106
              "vbox",
D
Dmitry Guryanov 已提交
107
              "phyp",
R
Roman Bogorodskiy 已提交
108
              "parallels",
109 110
              "bhyve",
              "vz")
111

112 113 114 115 116
VIR_ENUM_IMPL(virDomainOS, VIR_DOMAIN_OSTYPE_LAST,
              "hvm",
              "xen",
              "linux",
              "exe",
117
              "uml")
118

119 120 121 122 123 124 125 126 127
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 已提交
128
              "pae",
129
              "hap",
130
              "viridian",
131
              "privnet",
132
              "hyperv",
133
              "kvm",
134
              "pvspinlock",
135
              "capabilities",
136
              "pmu",
M
Michal Privoznik 已提交
137 138
              "vmport",
              "gic")
139

140 141 142 143 144
VIR_ENUM_IMPL(virDomainCapabilitiesPolicy, VIR_DOMAIN_CAPABILITIES_POLICY_LAST,
              "default",
              "allow",
              "deny")

145
VIR_ENUM_IMPL(virDomainHyperv, VIR_DOMAIN_HYPERV_LAST,
146 147 148
              "relaxed",
              "vapic",
              "spinlocks")
149

150 151 152
VIR_ENUM_IMPL(virDomainKVM, VIR_DOMAIN_KVM_LAST,
              "hidden")

153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
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")

192 193 194 195 196 197
VIR_ENUM_IMPL(virDomainLifecycle, VIR_DOMAIN_LIFECYCLE_LAST,
              "destroy",
              "restart",
              "rename-restart",
              "preserve")

198 199 200 201 202 203 204 205
VIR_ENUM_IMPL(virDomainLifecycleCrash, VIR_DOMAIN_LIFECYCLE_CRASH_LAST,
              "destroy",
              "restart",
              "rename-restart",
              "preserve",
              "coredump-destroy",
              "coredump-restart")

206 207 208 209 210 211 212
VIR_ENUM_IMPL(virDomainLockFailure, VIR_DOMAIN_LOCK_FAILURE_LAST,
              "default",
              "poweroff",
              "restart",
              "pause",
              "ignore")

213
VIR_ENUM_IMPL(virDomainDevice, VIR_DOMAIN_DEVICE_LAST,
214
              "none",
215
              "disk",
216
              "lease",
217 218 219 220
              "filesystem",
              "interface",
              "input",
              "sound",
221
              "video",
R
Richard Jones 已提交
222
              "hostdev",
223
              "watchdog",
224
              "controller",
M
Marc-André Lureau 已提交
225
              "graphics",
226
              "hub",
227 228 229
              "redirdev",
              "smartcard",
              "chr",
230
              "memballoon",
L
Li Zhang 已提交
231
              "nvram",
232
              "rng",
233
              "shmem",
234
              "tpm",
235 236
              "panic",
              "memory")
237

238 239
VIR_ENUM_IMPL(virDomainDeviceAddress, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST,
              "none",
240
              "pci",
241
              "drive",
E
Eric Blake 已提交
242
              "virtio-serial",
243
              "ccid",
244
              "usb",
245
              "spapr-vio",
246
              "virtio-s390",
247
              "ccw",
H
Hu Tao 已提交
248
              "virtio-mmio",
249 250
              "isa",
              "dimm")
251

252 253 254
VIR_ENUM_IMPL(virDomainDiskDevice, VIR_DOMAIN_DISK_DEVICE_LAST,
              "disk",
              "cdrom",
255 256
              "floppy",
              "lun")
257

J
J.B. Joret 已提交
258 259 260 261 262 263
VIR_ENUM_IMPL(virDomainDiskGeometryTrans, VIR_DOMAIN_DISK_TRANS_LAST,
              "default",
              "none",
              "auto",
              "lba")

264 265 266 267 268
VIR_ENUM_IMPL(virDomainDiskBus, VIR_DOMAIN_DISK_BUS_LAST,
              "ide",
              "fdc",
              "scsi",
              "virtio",
269
              "xen",
270
              "usb",
271
              "uml",
272 273
              "sata",
              "sd")
274

275 276 277 278
VIR_ENUM_IMPL(virDomainDiskCache, VIR_DOMAIN_DISK_CACHE_LAST,
              "default",
              "none",
              "writethrough",
279
              "writeback",
280 281
              "directsync",
              "unsafe")
282

283 284 285
VIR_ENUM_IMPL(virDomainDiskErrorPolicy, VIR_DOMAIN_DISK_ERROR_POLICY_LAST,
              "default",
              "stop",
286
              "report",
287 288
              "ignore",
              "enospace")
289

M
Matthias Dahl 已提交
290 291 292 293
VIR_ENUM_IMPL(virDomainDiskIo, VIR_DOMAIN_DISK_IO_LAST,
              "default",
              "native",
              "threads")
O
Osier Yang 已提交
294

295
VIR_ENUM_IMPL(virDomainDeviceSGIO, VIR_DOMAIN_DEVICE_SGIO_LAST,
O
Osier Yang 已提交
296 297 298 299
              "default",
              "filtered",
              "unfiltered")

300 301 302 303
VIR_ENUM_IMPL(virDomainController, VIR_DOMAIN_CONTROLLER_TYPE_LAST,
              "ide",
              "fdc",
              "scsi",
304
              "sata",
E
Eric Blake 已提交
305
              "virtio-serial",
306
              "ccid",
J
Ján Tomko 已提交
307 308 309 310 311
              "usb",
              "pci")

VIR_ENUM_IMPL(virDomainControllerModelPCI, VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST,
              "pci-root",
L
Laine Stump 已提交
312
              "pcie-root",
313
              "pci-bridge",
314
              "dmi-to-pci-bridge",
315
              "pcie-root-port",
316 317
              "pcie-switch-upstream-port",
              "pcie-switch-downstream-port")
318

319 320 321 322
VIR_ENUM_IMPL(virDomainControllerPCIModelName,
              VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_LAST,
              "none",
              "pci-bridge",
323
              "i82801b11-bridge",
324
              "ioh3420",
325 326
              "x3130-upstream",
              "xio3130-downstream")
327

328
VIR_ENUM_IMPL(virDomainControllerModelSCSI, VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LAST,
329
              "auto",
330 331
              "buslogic",
              "lsilogic",
332
              "lsisas1068",
333
              "vmpvscsi",
334
              "ibmvscsi",
335 336
              "virtio-scsi",
              "lsisas1078");
337

M
Marc-André Lureau 已提交
338 339 340 341 342 343 344 345 346
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 已提交
347
              "pci-ohci",
348 349
              "nec-xhci",
              "none")
M
Marc-André Lureau 已提交
350

351 352 353 354
VIR_ENUM_IMPL(virDomainFS, VIR_DOMAIN_FS_TYPE_LAST,
              "mount",
              "block",
              "file",
355
              "template",
356 357
              "ram",
              "bind")
358

359
VIR_ENUM_IMPL(virDomainFSDriver, VIR_DOMAIN_FS_DRIVER_TYPE_LAST,
360 361
              "default",
              "path",
362
              "handle",
363
              "loop",
D
Dmitry Guryanov 已提交
364 365
              "nbd",
              "ploop")
366

367 368 369 370 371
VIR_ENUM_IMPL(virDomainFSAccessMode, VIR_DOMAIN_FS_ACCESSMODE_LAST,
              "passthrough",
              "mapped",
              "squash")

372 373 374
VIR_ENUM_IMPL(virDomainFSWrpolicy, VIR_DOMAIN_FS_WRPOLICY_LAST,
              "default",
              "immediate")
375

376 377 378
VIR_ENUM_IMPL(virDomainNet, VIR_DOMAIN_NET_TYPE_LAST,
              "user",
              "ethernet",
M
Michele Paolino 已提交
379
              "vhostuser",
380 381 382 383
              "server",
              "client",
              "mcast",
              "network",
D
Daniel Veillard 已提交
384
              "bridge",
385
              "internal",
386
              "direct",
387 388
              "hostdev",
              "udp")
389

390 391 392 393 394
VIR_ENUM_IMPL(virDomainNetBackend, VIR_DOMAIN_NET_BACKEND_TYPE_LAST,
              "default",
              "qemu",
              "vhost")

395 396 397 398 399
VIR_ENUM_IMPL(virDomainNetVirtioTxMode, VIR_DOMAIN_NET_VIRTIO_TX_MODE_LAST,
              "default",
              "iothread",
              "timer")

400 401 402 403 404
VIR_ENUM_IMPL(virDomainNetInterfaceLinkState, VIR_DOMAIN_NET_INTERFACE_LINK_STATE_LAST,
              "default",
              "up",
              "down")

405 406 407 408 409
VIR_ENUM_IMPL(virDomainChrDeviceState, VIR_DOMAIN_CHR_DEVICE_STATE_LAST,
              "default",
              "connected",
              "disconnected");

G
Guannan Ren 已提交
410 411 412
VIR_ENUM_IMPL(virDomainChrSerialTarget,
              VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_LAST,
              "isa-serial",
M
Michal Privoznik 已提交
413 414
              "usb-serial",
              "pci-serial")
G
Guannan Ren 已提交
415

416 417
VIR_ENUM_IMPL(virDomainChrChannelTarget,
              VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_LAST,
418
              "none",
419 420 421
              "guestfwd",
              "virtio")

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

434
VIR_ENUM_IMPL(virDomainChrDevice, VIR_DOMAIN_CHR_DEVICE_TYPE_LAST,
435 436
              "parallel",
              "serial",
437
              "console",
438
              "channel")
439

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

455 456 457 458 459 460
VIR_ENUM_IMPL(virDomainChrTcpProtocol, VIR_DOMAIN_CHR_TCP_PROTOCOL_LAST,
              "raw",
              "telnet",
              "telnets",
              "tls")

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

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

471 472 473 474
VIR_ENUM_IMPL(virDomainSoundCodec, VIR_DOMAIN_SOUND_CODEC_TYPE_LAST,
              "duplex",
              "micro")

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

484 485 486 487 488
VIR_ENUM_IMPL(virDomainKeyWrapCipherName,
              VIR_DOMAIN_KEY_WRAP_CIPHER_NAME_LAST,
              "aes",
              "dea")

489 490
VIR_ENUM_IMPL(virDomainMemballoonModel, VIR_DOMAIN_MEMBALLOON_MODEL_LAST,
              "virtio",
491
              "xen",
492 493
              "none")

494 495 496 497 498 499
VIR_ENUM_IMPL(virDomainSmbiosMode, VIR_DOMAIN_SMBIOS_LAST,
              "none",
              "emulate",
              "host",
              "sysinfo")

R
Richard Jones 已提交
500 501
VIR_ENUM_IMPL(virDomainWatchdogModel, VIR_DOMAIN_WATCHDOG_MODEL_LAST,
              "i6300esb",
502 503
              "ib700",
              "diag288")
R
Richard Jones 已提交
504 505 506 507 508 509

VIR_ENUM_IMPL(virDomainWatchdogAction, VIR_DOMAIN_WATCHDOG_ACTION_LAST,
              "reset",
              "shutdown",
              "poweroff",
              "pause",
H
Hu Tao 已提交
510
              "dump",
511 512
              "none",
              "inject-nmi")
R
Richard Jones 已提交
513

514 515 516 517 518 519
VIR_ENUM_IMPL(virDomainPanicModel, VIR_DOMAIN_PANIC_MODEL_LAST,
              "default",
              "isa",
              "pseries",
              "hyperv")

520 521 522 523 524
VIR_ENUM_IMPL(virDomainVideo, VIR_DOMAIN_VIDEO_TYPE_LAST,
              "vga",
              "cirrus",
              "vmvga",
              "xen",
525
              "vbox",
526
              "qxl",
M
Marc-André Lureau 已提交
527 528
              "parallels",
              "virtio")
529

530 531
VIR_ENUM_IMPL(virDomainInput, VIR_DOMAIN_INPUT_TYPE_LAST,
              "mouse",
L
Li Zhang 已提交
532
              "tablet",
533 534
              "keyboard",
              "passthrough")
535 536 537 538

VIR_ENUM_IMPL(virDomainInputBus, VIR_DOMAIN_INPUT_BUS_LAST,
              "ps2",
              "usb",
539
              "xen",
540 541
              "parallels",
              "virtio")
542 543 544

VIR_ENUM_IMPL(virDomainGraphics, VIR_DOMAIN_GRAPHICS_TYPE_LAST,
              "sdl",
545 546
              "vnc",
              "rdp",
547 548
              "desktop",
              "spice")
549

550 551 552 553 554
VIR_ENUM_IMPL(virDomainGraphicsListen, VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_LAST,
              "none",
              "address",
              "network")

555 556 557 558 559 560 561
VIR_ENUM_IMPL(virDomainGraphicsAuthConnected,
              VIR_DOMAIN_GRAPHICS_AUTH_CONNECTED_LAST,
              "default",
              "fail",
              "disconnect",
              "keep")

562 563 564 565 566 567 568
VIR_ENUM_IMPL(virDomainGraphicsVNCSharePolicy,
              VIR_DOMAIN_GRAPHICS_VNC_SHARE_LAST,
              "default",
              "allow-exclusive",
              "force-shared",
              "ignore")

569 570 571 572 573 574 575
VIR_ENUM_IMPL(virDomainGraphicsSpiceChannelName,
              VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_LAST,
              "main",
              "display",
              "inputs",
              "cursor",
              "playback",
E
Eric Blake 已提交
576
              "record",
577 578
              "smartcard",
              "usbredir");
579 580 581 582 583 584 585

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

586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609
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 已提交
610 611 612 613 614 615
VIR_ENUM_IMPL(virDomainGraphicsSpiceMouseMode,
              VIR_DOMAIN_GRAPHICS_SPICE_MOUSE_MODE_LAST,
              "default",
              "server",
              "client");

616 617 618 619 620 621 622
VIR_ENUM_IMPL(virDomainGraphicsSpiceStreamingMode,
              VIR_DOMAIN_GRAPHICS_SPICE_STREAMING_MODE_LAST,
              "default",
              "filter",
              "all",
              "off");

623 624 625 626 627 628
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 已提交
629 630
              "pci",
              "scsi")
631

632
VIR_ENUM_IMPL(virDomainHostdevSubsysPCIBackend,
633 634 635
              VIR_DOMAIN_HOSTDEV_PCI_BACKEND_TYPE_LAST,
              "default",
              "kvm",
636 637
              "vfio",
              "xen")
638

J
John Ferlan 已提交
639 640 641 642 643
VIR_ENUM_IMPL(virDomainHostdevSubsysSCSIProtocol,
              VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_LAST,
              "adapter",
              "iscsi")

644 645
VIR_ENUM_IMPL(virDomainHostdevCaps, VIR_DOMAIN_HOSTDEV_CAPS_TYPE_LAST,
              "storage",
646 647
              "misc",
              "net")
648

649 650 651 652 653 654 655
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,
656 657 658 659 660 661
              "nostate",
              "running",
              "blocked",
              "paused",
              "shutdown",
              "shutoff",
O
Osier Yang 已提交
662 663
              "crashed",
              "pmsuspended")
664

J
Jiri Denemark 已提交
665 666 667 668 669 670 671 672 673 674 675
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",
676
              "save canceled",
677 678
              "wakeup",
              "crashed")
J
Jiri Denemark 已提交
679 680 681 682 683 684 685 686 687 688 689 690

VIR_ENUM_IMPL(virDomainBlockedReason, VIR_DOMAIN_BLOCKED_LAST,
              "unknown")

VIR_ENUM_IMPL(virDomainPausedReason, VIR_DOMAIN_PAUSED_LAST,
              "unknown",
              "user",
              "migration",
              "save",
              "dump",
              "ioerror",
              "watchdog",
691
              "from snapshot",
692
              "shutdown",
693
              "snapshot",
694 695
              "panicked",
              "starting up")
J
Jiri Denemark 已提交
696 697 698

VIR_ENUM_IMPL(virDomainShutdownReason, VIR_DOMAIN_SHUTDOWN_LAST,
              "unknown",
699
              "user")
J
Jiri Denemark 已提交
700 701 702 703 704 705 706 707 708 709 710 711

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,
712 713
              "unknown",
              "panicked")
J
Jiri Denemark 已提交
714

715 716 717
VIR_ENUM_IMPL(virDomainPMSuspendedReason, VIR_DOMAIN_PMSUSPENDED_LAST,
              "unknown")

718
VIR_ENUM_IMPL(virDomainSeclabel, VIR_DOMAIN_SECLABEL_LAST,
719 720
              "default",
              "none",
721 722 723
              "dynamic",
              "static")

724 725
VIR_ENUM_IMPL(virDomainClockOffset, VIR_DOMAIN_CLOCK_OFFSET_LAST,
              "utc",
726
              "localtime",
727 728
              "variable",
              "timezone");
729

730 731 732 733
VIR_ENUM_IMPL(virDomainClockBasis, VIR_DOMAIN_CLOCK_BASIS_LAST,
              "utc",
              "localtime");

734 735 736 737 738
VIR_ENUM_IMPL(virDomainTimerName, VIR_DOMAIN_TIMER_NAME_LAST,
              "platform",
              "pit",
              "rtc",
              "hpet",
P
Paolo Bonzini 已提交
739
              "tsc",
740 741
              "kvmclock",
              "hypervclock");
742

743 744 745 746
VIR_ENUM_IMPL(virDomainTimerTrack, VIR_DOMAIN_TIMER_TRACK_LAST,
              "boot",
              "guest",
              "wall");
747 748 749 750 751 752 753 754 755 756 757

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",
758 759
              "paravirt",
              "smpsafe");
760

761 762 763 764 765 766
VIR_ENUM_IMPL(virDomainStartupPolicy, VIR_DOMAIN_STARTUP_POLICY_LAST,
              "default",
              "mandatory",
              "requisite",
              "optional");

O
Osier Yang 已提交
767 768 769 770
VIR_ENUM_IMPL(virDomainCpuPlacementMode, VIR_DOMAIN_CPU_PLACEMENT_MODE_LAST,
              "static",
              "auto");

771 772 773 774
VIR_ENUM_IMPL(virDomainDiskTray, VIR_DOMAIN_DISK_TRAY_LAST,
              "closed",
              "open");

775 776 777 778 779 780 781 782 783
VIR_ENUM_IMPL(virDomainRNGModel,
              VIR_DOMAIN_RNG_MODEL_LAST,
              "virtio");

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

784 785 786 787 788 789
VIR_ENUM_IMPL(virDomainTPMModel, VIR_DOMAIN_TPM_MODEL_LAST,
              "tpm-tis")

VIR_ENUM_IMPL(virDomainTPMBackend, VIR_DOMAIN_TPM_TYPE_LAST,
              "passthrough")

O
Osier Yang 已提交
790 791
VIR_ENUM_IMPL(virDomainDiskDiscard, VIR_DOMAIN_DISK_DISCARD_LAST,
              "default",
O
Osier Yang 已提交
792 793
              "unmap",
              "ignore")
794

795 796 797 798 799 800
VIR_ENUM_IMPL(virDomainDiskMirrorState, VIR_DOMAIN_DISK_MIRROR_STATE_LAST,
              "none",
              "yes",
              "abort",
              "pivot")

801 802 803 804 805
VIR_ENUM_IMPL(virDomainLoader,
              VIR_DOMAIN_LOADER_TYPE_LAST,
              "rom",
              "pflash")

E
Eric Blake 已提交
806 807 808 809 810 811
/* 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")

812 813 814
VIR_ENUM_IMPL(virDomainMemoryModel, VIR_DOMAIN_MEMORY_MODEL_LAST,
              "", "dimm")

815
static virClassPtr virDomainObjClass;
816
static virClassPtr virDomainXMLOptionClass;
817
static void virDomainObjDispose(void *obj);
818
static void virDomainXMLOptionClassDispose(void *obj);
819 820 821

static int virDomainObjOnceInit(void)
{
822
    if (!(virDomainObjClass = virClassNew(virClassForObjectLockable(),
823
                                          "virDomainObj",
824 825 826 827
                                          sizeof(virDomainObj),
                                          virDomainObjDispose)))
        return -1;

828 829 830
    if (!(virDomainXMLOptionClass = virClassNew(virClassForObject(),
                                                "virDomainXMLOption",
                                                sizeof(virDomainXMLOption),
831
                                                virDomainXMLOptionClassDispose)))
832 833
        return -1;

834 835 836 837 838
    return 0;
}

VIR_ONCE_GLOBAL_INIT(virDomainObj)

839

840 841 842 843 844 845 846 847 848
static void
virDomainXMLOptionClassDispose(void *obj)
{
    virDomainXMLOptionPtr xmlopt = obj;

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

849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949
/**
 * virDomainKeyWrapCipherDefParseXML:
 *
 * @def  Domain definition
 * @node An XML cipher node
 * @ctxt The XML context
 *
 * Parse the attributes from the cipher node and store the state
 * attribute in @def.
 *
 * A cipher node has the form of
 *
 *   <cipher name='aes|dea' state='on|off'/>
 *
 * Returns: 0 if the parse succeeded
 *         -1 otherwise
 */
static int
virDomainKeyWrapCipherDefParseXML(virDomainKeyWrapDefPtr keywrap,
                                  xmlNodePtr node,
                                  xmlXPathContextPtr ctxt)
{

    char *name = NULL;
    char *state = NULL;
    int state_type;
    int name_type;
    int ret = -1;
    xmlNodePtr oldnode = ctxt->node;

    ctxt->node = node;
    if (!(name = virXPathString("string(./@name)", ctxt))) {
        virReportError(VIR_ERR_CONF_SYNTAX, "%s",
                       _("missing name for cipher"));
        goto cleanup;
    }

    if ((name_type = virDomainKeyWrapCipherNameTypeFromString(name)) < 0) {
        virReportError(VIR_ERR_CONF_SYNTAX,
                       _("%s is not a supported cipher name"), name);
        goto cleanup;
    }

    if (!(state = virXPathString("string(./@state)", ctxt))) {
        virReportError(VIR_ERR_CONF_SYNTAX,
                       _("missing state for cipher named %s"), name);
        goto cleanup;
    }

    if ((state_type = virTristateSwitchTypeFromString(state)) < 0) {
        virReportError(VIR_ERR_CONF_SYNTAX,
                       _("%s is not a supported cipher state"), state);
        goto cleanup;
    }

    switch ((virDomainKeyWrapCipherName) name_type) {
    case VIR_DOMAIN_KEY_WRAP_CIPHER_NAME_AES:
        if (keywrap->aes != VIR_TRISTATE_SWITCH_ABSENT) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("A domain definition can have no more than "
                             "one cipher node with name %s"),
                           virDomainKeyWrapCipherNameTypeToString(name_type));

            goto cleanup;
        }
        keywrap->aes = state_type;
        break;

    case VIR_DOMAIN_KEY_WRAP_CIPHER_NAME_DEA:
        if (keywrap->dea != VIR_TRISTATE_SWITCH_ABSENT) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("A domain definition can have no more than "
                             "one cipher node with name %s"),
                           virDomainKeyWrapCipherNameTypeToString(name_type));

            goto cleanup;
        }
        keywrap->dea = state_type;
        break;

    case VIR_DOMAIN_KEY_WRAP_CIPHER_NAME_LAST:
        break;
    }

    ret = 0;

 cleanup:
    VIR_FREE(name);
    VIR_FREE(state);
    ctxt->node = oldnode;
    return ret;
}

static int
virDomainKeyWrapDefParseXML(virDomainDefPtr def, xmlXPathContextPtr ctxt)
{
    size_t i;
    int ret = -1;
    xmlNodePtr *nodes = NULL;
    int n;

950 951
    if ((n = virXPathNodeSet("./keywrap/cipher", ctxt, &nodes)) < 0)
        return n;
952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973

    if (VIR_ALLOC(def->keywrap) < 0)
        goto cleanup;

    for (i = 0; i < n; i++) {
        if (virDomainKeyWrapCipherDefParseXML(def->keywrap, nodes[i], ctxt) < 0)
            goto cleanup;
    }

    if (!def->keywrap->aes &&
        !def->keywrap->dea)
        VIR_FREE(def->keywrap);

    ret = 0;

 cleanup:
    if (ret < 0)
        VIR_FREE(def->keywrap);
    VIR_FREE(nodes);
    return ret;
}

974

975
/**
976
 * virDomainXMLOptionNew:
977 978 979
 *
 * Allocate a new domain XML configuration
 */
980
virDomainXMLOptionPtr
981 982
virDomainXMLOptionNew(virDomainDefParserConfigPtr config,
                      virDomainXMLPrivateDataCallbacksPtr priv,
983
                      virDomainXMLNamespacePtr xmlns)
984
{
985
    virDomainXMLOptionPtr xmlopt;
986 987 988 989

    if (virDomainObjInitialize() < 0)
        return NULL;

990
    if (!(xmlopt = virObjectNew(virDomainXMLOptionClass)))
991 992 993
        return NULL;

    if (priv)
994
        xmlopt->privateData = *priv;
995

996 997 998
    if (config)
        xmlopt->config = *config;

999
    if (xmlns)
1000
        xmlopt->ns = *xmlns;
1001

1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013
    /* 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;
    }

1014
    return xmlopt;
1015 1016 1017
}

/**
1018
 * virDomainXMLOptionGetNamespace:
1019
 *
1020
 * @xmlopt: XML parser configuration object
1021 1022
 *
 * Returns a pointer to the stored namespace structure.
1023
 * The lifetime of the pointer is equal to @xmlopt;
1024 1025
 */
virDomainXMLNamespacePtr
1026
virDomainXMLOptionGetNamespace(virDomainXMLOptionPtr xmlopt)
1027
{
1028
    return &xmlopt->ns;
1029 1030 1031
}


1032
void
1033
virBlkioDeviceArrayClear(virBlkioDevicePtr devices,
1034
                         int ndevices)
1035
{
1036
    size_t i;
1037 1038

    for (i = 0; i < ndevices; i++)
1039
        VIR_FREE(devices[i].path);
1040 1041 1042
}

/**
1043
 * virDomainBlkioDeviceParseXML
1044 1045 1046 1047 1048 1049
 *
 * this function parses a XML node:
 *
 *   <device>
 *     <path>/fully/qualified/device/path</path>
 *     <weight>weight</weight>
1050 1051 1052 1053
 *     <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>
1054 1055
 *   </device>
 *
1056
 * and fills a virBlkioDevicePtr struct.
1057 1058
 */
static int
1059
virDomainBlkioDeviceParseXML(xmlNodePtr root,
1060
                             virBlkioDevicePtr dev)
1061
{
1062
    char *c = NULL;
1063 1064 1065 1066 1067
    xmlNodePtr node;

    node = root->children;
    while (node) {
        if (node->type == XML_ELEMENT_NODE) {
1068 1069
            if (xmlStrEqual(node->name, BAD_CAST "path") && !dev->path) {
                dev->path = (char *)xmlNodeGetContent(node);
1070 1071
            } else if (xmlStrEqual(node->name, BAD_CAST "weight")) {
                c = (char *)xmlNodeGetContent(node);
1072
                if (virStrToLong_ui(c, NULL, 10, &dev->weight) < 0) {
1073 1074 1075
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("could not parse weight %s"),
                                   c);
1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112
                        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;
1113 1114 1115 1116 1117 1118
                }
                VIR_FREE(c);
            }
        }
        node = node->next;
    }
1119
    if (!dev->path) {
1120 1121
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("missing per-device path"));
1122 1123 1124 1125
        return -1;
    }

    return 0;
1126

1127
 error:
1128 1129 1130
    VIR_FREE(c);
    VIR_FREE(dev->path);
    return -1;
1131 1132 1133
}


1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144
/**
 * virDomainDefCheckUnsupportedMemoryHotplug:
 * @def: domain definition
 *
 * Returns -1 if the domain definition would enable memory hotplug via the
 * <maxMemory> tunable and reports an error. Otherwise returns 0.
 */
int
virDomainDefCheckUnsupportedMemoryHotplug(virDomainDefPtr def)
{
    /* memory hotplug tunables are not supported by this driver */
1145
    if (virDomainDefHasMemoryHotplug(def)) {
1146 1147 1148 1149 1150 1151 1152 1153 1154
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("memory hotplug tunables <maxMemory> are not "
                         "supported by this hypervisor driver"));
        return -1;
    }

    return 0;
}

1155

1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176
/**
 * virDomainDeviceDefCheckUnsupportedMemoryDevice:
 * @dev: device definition
 *
 * Returns -1 if the device definition describes a memory device and reports an
 * error. Otherwise returns 0.
 */
int
virDomainDeviceDefCheckUnsupportedMemoryDevice(virDomainDeviceDefPtr dev)
{
    /* This driver doesn't yet know how to handle memory devices */
    if (dev->type == VIR_DOMAIN_DEVICE_MEMORY) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("memory devices are not supported by this driver"));
        return -1;
    }

    return 0;
}


1177
bool virDomainObjTaint(virDomainObjPtr obj,
1178
                       virDomainTaintFlags taint)
1179
{
E
Eric Blake 已提交
1180
    unsigned int flag = (1 << taint);
1181 1182 1183 1184 1185 1186 1187 1188

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

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

1189 1190 1191 1192 1193 1194 1195 1196 1197
static void
virDomainDeviceInfoFree(virDomainDeviceInfoPtr info)
{
    if (info) {
        virDomainDeviceInfoClear(info);
        VIR_FREE(info);
    }
}

1198

1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209
static void
virDomainGraphicsAuthDefClear(virDomainGraphicsAuthDefPtr def)
{
    if (!def)
        return;

    VIR_FREE(def->passwd);

    /* Don't free def */
}

1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220
static void
virDomainGraphicsListenDefClear(virDomainGraphicsListenDefPtr def)
{
    if (!def)
        return;

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

1221

1222 1223
void virDomainGraphicsDefFree(virDomainGraphicsDefPtr def)
{
1224
    size_t i;
1225

1226 1227 1228
    if (!def)
        return;

1229
    switch ((virDomainGraphicsType)def->type) {
1230
    case VIR_DOMAIN_GRAPHICS_TYPE_VNC:
1231
        VIR_FREE(def->data.vnc.socket);
1232
        VIR_FREE(def->data.vnc.keymap);
1233
        virDomainGraphicsAuthDefClear(&def->data.vnc.auth);
1234 1235 1236 1237 1238 1239
        break;

    case VIR_DOMAIN_GRAPHICS_TYPE_SDL:
        VIR_FREE(def->data.sdl.display);
        VIR_FREE(def->data.sdl.xauth);
        break;
1240 1241 1242 1243 1244 1245 1246

    case VIR_DOMAIN_GRAPHICS_TYPE_RDP:
        break;

    case VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP:
        VIR_FREE(def->data.desktop.display);
        break;
1247 1248 1249

    case VIR_DOMAIN_GRAPHICS_TYPE_SPICE:
        VIR_FREE(def->data.spice.keymap);
1250
        virDomainGraphicsAuthDefClear(&def->data.spice.auth);
1251
        break;
1252 1253 1254

    case VIR_DOMAIN_GRAPHICS_TYPE_LAST:
        break;
1255 1256
    }

1257 1258
    for (i = 0; i < def->nListens; i++)
        virDomainGraphicsListenDefClear(&def->listens[i]);
1259 1260
    VIR_FREE(def->listens);

1261 1262 1263 1264 1265 1266 1267 1268
    VIR_FREE(def);
}

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

1269
    virDomainDeviceInfoClear(&def->info);
1270
    VIR_FREE(def->source.evdev);
1271 1272 1273
    VIR_FREE(def);
}

1274
void virDomainLeaseDefFree(virDomainLeaseDefPtr def)
1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285
{
    if (!def)
        return;

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

    VIR_FREE(def);
}

1286

1287 1288 1289 1290
int
virDomainDefSetVcpusMax(virDomainDefPtr def,
                        unsigned int maxvcpus)
{
1291 1292 1293
    if (maxvcpus < def->vcpus)
        def->vcpus = maxvcpus;

1294 1295 1296 1297 1298 1299
    def->maxvcpus = maxvcpus;

    return 0;
}


1300 1301 1302 1303 1304 1305 1306
bool
virDomainDefHasVcpusOffline(const virDomainDef *def)
{
    return def->vcpus < def->maxvcpus;
}


1307
virDomainDiskDefPtr
1308
virDomainDiskDefNew(virDomainXMLOptionPtr xmlopt)
1309 1310 1311
{
    virDomainDiskDefPtr ret;

1312 1313
    if (VIR_ALLOC(ret) < 0)
        return NULL;
1314

1315
    if (VIR_ALLOC(ret->src) < 0)
1316 1317
        goto error;

1318 1319 1320 1321 1322
    if (xmlopt &&
        xmlopt->privateData.diskNew &&
        !(ret->privateData = xmlopt->privateData.diskNew()))
        goto error;

1323
    return ret;
1324 1325

 error:
1326
    virDomainDiskDefFree(ret);
1327
    return NULL;
1328 1329 1330
}


1331 1332 1333 1334 1335 1336
void
virDomainDiskDefFree(virDomainDiskDefPtr def)
{
    if (!def)
        return;

1337
    virStorageSourceFree(def->src);
1338 1339
    VIR_FREE(def->serial);
    VIR_FREE(def->dst);
1340
    virStorageSourceFree(def->mirror);
1341 1342 1343
    VIR_FREE(def->wwn);
    VIR_FREE(def->vendor);
    VIR_FREE(def->product);
1344
    VIR_FREE(def->domain_name);
1345
    virDomainDeviceInfoClear(&def->info);
1346
    virObjectUnref(def->privateData);
1347

1348 1349 1350
    VIR_FREE(def);
}

1351

1352 1353 1354
int
virDomainDiskGetType(virDomainDiskDefPtr def)
{
1355
    return def->src->type;
1356 1357 1358 1359 1360 1361
}


void
virDomainDiskSetType(virDomainDiskDefPtr def, int type)
{
1362
    def->src->type = type;
1363 1364 1365 1366
}


const char *
1367
virDomainDiskGetSource(virDomainDiskDef const *def)
1368
{
1369
    return def->src->path;
1370 1371 1372 1373 1374 1375 1376
}


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

1379
    ret = VIR_STRDUP(def->src->path, src);
1380
    if (ret < 0)
1381
        def->src->path = tmp;
1382 1383 1384 1385 1386 1387 1388 1389 1390
    else
        VIR_FREE(tmp);
    return ret;
}


const char *
virDomainDiskGetDriver(virDomainDiskDefPtr def)
{
1391
    return def->src->driverName;
1392 1393 1394 1395 1396 1397 1398
}


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

1401
    ret = VIR_STRDUP(def->src->driverName, name);
1402
    if (ret < 0)
1403
        def->src->driverName = tmp;
1404 1405 1406 1407 1408 1409 1410 1411 1412
    else
        VIR_FREE(tmp);
    return ret;
}


int
virDomainDiskGetFormat(virDomainDiskDefPtr def)
{
1413
    return def->src->format;
1414 1415 1416 1417 1418 1419
}


void
virDomainDiskSetFormat(virDomainDiskDefPtr def, int format)
{
1420
    def->src->format = format;
1421 1422 1423
}


1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441
static virDomainControllerDefPtr
virDomainControllerDefNew(virDomainControllerType type)
{
    virDomainControllerDefPtr def;

    if (VIR_ALLOC(def) < 0)
        return NULL;

    def->type = type;
    def->model = -1;

    /* initialize anything that has a non-0 default */
    switch ((virDomainControllerType) def->type) {
    case VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL:
        def->opts.vioserial.ports = -1;
        def->opts.vioserial.vectors = -1;
        break;
    case VIR_DOMAIN_CONTROLLER_TYPE_PCI:
1442
        def->opts.pciopts.chassisNr = -1;
1443 1444
        def->opts.pciopts.chassis = -1;
        def->opts.pciopts.port = -1;
1445
        break;
1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459
    case VIR_DOMAIN_CONTROLLER_TYPE_IDE:
    case VIR_DOMAIN_CONTROLLER_TYPE_FDC:
    case VIR_DOMAIN_CONTROLLER_TYPE_SCSI:
    case VIR_DOMAIN_CONTROLLER_TYPE_SATA:
    case VIR_DOMAIN_CONTROLLER_TYPE_CCID:
    case VIR_DOMAIN_CONTROLLER_TYPE_USB:
    case VIR_DOMAIN_CONTROLLER_TYPE_LAST:
        break;
    }

    return def;
}


1460 1461 1462 1463 1464 1465 1466 1467 1468 1469
void virDomainControllerDefFree(virDomainControllerDefPtr def)
{
    if (!def)
        return;

    virDomainDeviceInfoClear(&def->info);

    VIR_FREE(def);
}

1470 1471 1472 1473 1474 1475 1476
void virDomainFSDefFree(virDomainFSDefPtr def)
{
    if (!def)
        return;

    VIR_FREE(def->src);
    VIR_FREE(def->dst);
1477
    virDomainDeviceInfoClear(&def->info);
1478 1479 1480 1481

    VIR_FREE(def);
}

1482 1483 1484 1485 1486 1487 1488 1489
void
virDomainActualNetDefFree(virDomainActualNetDefPtr def)
{
    if (!def)
        return;

    switch (def->type) {
    case VIR_DOMAIN_NET_TYPE_BRIDGE:
1490
    case VIR_DOMAIN_NET_TYPE_NETWORK:
1491 1492 1493 1494 1495
        VIR_FREE(def->data.bridge.brname);
        break;
    case VIR_DOMAIN_NET_TYPE_DIRECT:
        VIR_FREE(def->data.direct.linkdev);
        break;
1496 1497 1498
    case VIR_DOMAIN_NET_TYPE_HOSTDEV:
        virDomainHostdevDefClear(&def->data.hostdev.def);
        break;
1499 1500 1501 1502
    default:
        break;
    }

1503
    VIR_FREE(def->virtPortProfile);
1504
    virNetDevBandwidthFree(def->bandwidth);
1505
    virNetDevVlanClear(&def->vlan);
1506 1507 1508
    VIR_FREE(def);
}

1509 1510
void virDomainNetDefFree(virDomainNetDefPtr def)
{
1511 1512
    size_t i;

1513 1514 1515 1516 1517 1518 1519 1520 1521 1522
    if (!def)
        return;

    VIR_FREE(def->model);

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

M
Michele Paolino 已提交
1523 1524 1525 1526
    case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
        virDomainChrSourceDefFree(def->data.vhostuser);
        break;

1527 1528 1529
    case VIR_DOMAIN_NET_TYPE_SERVER:
    case VIR_DOMAIN_NET_TYPE_CLIENT:
    case VIR_DOMAIN_NET_TYPE_MCAST:
1530
    case VIR_DOMAIN_NET_TYPE_UDP:
1531
        VIR_FREE(def->data.socket.address);
1532
        VIR_FREE(def->data.socket.localaddr);
1533 1534 1535 1536
        break;

    case VIR_DOMAIN_NET_TYPE_NETWORK:
        VIR_FREE(def->data.network.name);
1537 1538
        VIR_FREE(def->data.network.portgroup);
        virDomainActualNetDefFree(def->data.network.actual);
1539 1540 1541 1542 1543
        break;

    case VIR_DOMAIN_NET_TYPE_BRIDGE:
        VIR_FREE(def->data.bridge.brname);
        break;
D
Daniel Veillard 已提交
1544 1545 1546 1547

    case VIR_DOMAIN_NET_TYPE_INTERNAL:
        VIR_FREE(def->data.internal.name);
        break;
1548 1549 1550 1551

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

1553 1554 1555 1556
    case VIR_DOMAIN_NET_TYPE_HOSTDEV:
        virDomainHostdevDefClear(&def->data.hostdev.def);
        break;

S
Stefan Berger 已提交
1557 1558 1559
    case VIR_DOMAIN_NET_TYPE_USER:
    case VIR_DOMAIN_NET_TYPE_LAST:
        break;
1560 1561
    }

1562 1563
    VIR_FREE(def->backend.tap);
    VIR_FREE(def->backend.vhost);
1564
    VIR_FREE(def->virtPortProfile);
1565
    VIR_FREE(def->script);
1566
    VIR_FREE(def->domain_name);
1567
    VIR_FREE(def->ifname);
1568 1569
    VIR_FREE(def->ifname_guest);
    VIR_FREE(def->ifname_guest_actual);
1570

1571 1572 1573 1574
    for (i = 0; i < def->nips; i++)
        VIR_FREE(def->ips[i]);
    VIR_FREE(def->ips);

1575
    for (i = 0; i < def->nroutes; i++)
1576
        virNetworkRouteDefFree(def->routes[i]);
1577 1578
    VIR_FREE(def->routes);

1579
    virDomainDeviceInfoClear(&def->info);
1580

1581 1582 1583
    VIR_FREE(def->filter);
    virNWFilterHashTableFree(def->filterparams);

1584
    virNetDevBandwidthFree(def->bandwidth);
1585
    virNetDevVlanClear(&def->vlan);
1586

1587 1588 1589
    VIR_FREE(def);
}

1590
void ATTRIBUTE_NONNULL(1)
1591
virDomainChrSourceDefClear(virDomainChrSourceDefPtr def)
1592 1593 1594 1595 1596 1597 1598 1599 1600
{
    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;

1601 1602 1603 1604 1605
    case VIR_DOMAIN_CHR_TYPE_NMDM:
        VIR_FREE(def->data.nmdm.master);
        VIR_FREE(def->data.nmdm.slave);
        break;

1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620
    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;
1621 1622 1623 1624

    case VIR_DOMAIN_CHR_TYPE_SPICEPORT:
        VIR_FREE(def->data.spiceport.channel);
        break;
1625
    }
1626 1627
}

1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643
/* 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:
1644
        if (VIR_STRDUP(dest->data.file.path, src->data.file.path) < 0)
1645 1646 1647 1648
            return -1;
        break;

    case VIR_DOMAIN_CHR_TYPE_UDP:
1649
        if (VIR_STRDUP(dest->data.udp.bindHost, src->data.udp.bindHost) < 0)
1650 1651
            return -1;

1652
        if (VIR_STRDUP(dest->data.udp.bindService, src->data.udp.bindService) < 0)
1653 1654
            return -1;

1655
        if (VIR_STRDUP(dest->data.udp.connectHost, src->data.udp.connectHost) < 0)
1656 1657
            return -1;

1658
        if (VIR_STRDUP(dest->data.udp.connectService, src->data.udp.connectService) < 0)
1659 1660 1661 1662
            return -1;
        break;

    case VIR_DOMAIN_CHR_TYPE_TCP:
1663
        if (VIR_STRDUP(dest->data.tcp.host, src->data.tcp.host) < 0)
1664 1665
            return -1;

1666
        if (VIR_STRDUP(dest->data.tcp.service, src->data.tcp.service) < 0)
1667 1668 1669 1670
            return -1;
        break;

    case VIR_DOMAIN_CHR_TYPE_UNIX:
1671
        if (VIR_STRDUP(dest->data.nix.path, src->data.nix.path) < 0)
1672 1673
            return -1;
        break;
1674 1675 1676 1677 1678 1679 1680 1681

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

S
Stefan Berger 已提交
1684 1685
    dest->type = src->type;

1686 1687 1688
    return 0;
}

1689 1690 1691 1692 1693 1694 1695 1696 1697
void virDomainChrSourceDefFree(virDomainChrSourceDefPtr def)
{
    if (!def)
        return;

    virDomainChrSourceDefClear(def);

    VIR_FREE(def);
}
1698

1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712
/* 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;

1713
    switch ((virDomainChrType)src->type) {
1714 1715 1716 1717 1718 1719
    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;
1720 1721 1722 1723
    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;
1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740
    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;

1741 1742 1743 1744 1745
    case VIR_DOMAIN_CHR_TYPE_SPICEPORT:
        return STREQ_NULLABLE(src->data.spiceport.channel,
                              tgt->data.spiceport.channel);
        break;

J
Ján Tomko 已提交
1746 1747 1748
    case VIR_DOMAIN_CHR_TYPE_SPICEVMC:
        return src->data.spicevmc == tgt->data.spicevmc;

1749
    case VIR_DOMAIN_CHR_TYPE_NULL:
1750 1751
    case VIR_DOMAIN_CHR_TYPE_VC:
    case VIR_DOMAIN_CHR_TYPE_STDIO:
1752 1753
    case VIR_DOMAIN_CHR_TYPE_LAST:
        break;
1754 1755
    }

J
Ján Tomko 已提交
1756
    return true;
1757 1758
}

1759 1760
void virDomainChrDefFree(virDomainChrDefPtr def)
{
1761 1762
    size_t i;

1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783
    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);
1784 1785
    virDomainDeviceInfoClear(&def->info);

1786 1787 1788 1789 1790 1791
    if (def->seclabels) {
        for (i = 0; i < def->nseclabels; i++)
            virSecurityDeviceLabelDefFree(def->seclabels[i]);
        VIR_FREE(def->seclabels);
    }

1792 1793 1794
    VIR_FREE(def);
}

E
Eric Blake 已提交
1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823
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);
}

1824 1825 1826 1827 1828 1829 1830 1831
void virDomainSoundCodecDefFree(virDomainSoundCodecDefPtr def)
{
    if (!def)
        return;

    VIR_FREE(def);
}

1832 1833 1834 1835 1836
void virDomainSoundDefFree(virDomainSoundDefPtr def)
{
    if (!def)
        return;

1837 1838
    virDomainDeviceInfoClear(&def->info);

1839
    size_t i;
1840
    for (i = 0; i < def->ncodecs; i++)
1841 1842 1843
        virDomainSoundCodecDefFree(def->codecs[i]);
    VIR_FREE(def->codecs);

1844 1845 1846
    VIR_FREE(def);
}

1847 1848 1849 1850 1851 1852 1853 1854 1855 1856
void virDomainMemballoonDefFree(virDomainMemballoonDefPtr def)
{
    if (!def)
        return;

    virDomainDeviceInfoClear(&def->info);

    VIR_FREE(def);
}

L
Li Zhang 已提交
1857 1858 1859 1860 1861 1862 1863 1864 1865 1866
void virDomainNVRAMDefFree(virDomainNVRAMDefPtr def)
{
    if (!def)
        return;

    virDomainDeviceInfoClear(&def->info);

    VIR_FREE(def);
}

R
Richard Jones 已提交
1867 1868 1869 1870 1871
void virDomainWatchdogDefFree(virDomainWatchdogDefPtr def)
{
    if (!def)
        return;

1872 1873
    virDomainDeviceInfoClear(&def->info);

R
Richard Jones 已提交
1874 1875 1876
    VIR_FREE(def);
}

1877 1878 1879 1880 1881 1882
void virDomainShmemDefFree(virDomainShmemDefPtr def)
{
    if (!def)
        return;

    virDomainDeviceInfoClear(&def->info);
1883
    virDomainChrSourceDefClear(&def->server.chr);
1884 1885 1886 1887
    VIR_FREE(def->name);
    VIR_FREE(def);
}

1888 1889 1890 1891 1892
void virDomainVideoDefFree(virDomainVideoDefPtr def)
{
    if (!def)
        return;

1893 1894
    virDomainDeviceInfoClear(&def->info);

1895
    VIR_FREE(def->accel);
1896 1897 1898
    VIR_FREE(def);
}

1899 1900 1901 1902
virDomainHostdevDefPtr virDomainHostdevDefAlloc(void)
{
    virDomainHostdevDefPtr def = NULL;

1903 1904
    if (VIR_ALLOC(def) < 0 ||
        VIR_ALLOC(def->info) < 0)
1905 1906 1907 1908
        VIR_FREE(def);
    return def;
}

1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919
static void
virDomainHostdevSubsysSCSIiSCSIClear(virDomainHostdevSubsysSCSIiSCSIPtr iscsisrc)
{
    if (!iscsisrc)
        return;
    VIR_FREE(iscsisrc->path);
    virStorageNetHostDefFree(iscsisrc->nhosts, iscsisrc->hosts);
    virStorageAuthDefFree(iscsisrc->auth);
    iscsisrc->auth = NULL;
}

1920 1921
void virDomainHostdevDefClear(virDomainHostdevDefPtr def)
{
1922 1923
    size_t i;

1924 1925 1926 1927 1928 1929 1930
    if (!def)
        return;

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

1931 1932 1933 1934 1935
    /* If there is a parent device object, it will handle freeing
     * def->info.
     */
    if (def->parent.type == VIR_DOMAIN_DEVICE_NONE)
        virDomainDeviceInfoFree(def->info);
1936

H
Han Cheng 已提交
1937 1938
    switch (def->mode) {
    case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
1939 1940 1941 1942 1943 1944 1945
        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;
1946 1947
        case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_NET:
            VIR_FREE(def->source.caps.u.net.iface);
1948 1949 1950
            for (i = 0; i < def->source.caps.u.net.nips; i++)
                VIR_FREE(def->source.caps.u.net.ips[i]);
            VIR_FREE(def->source.caps.u.net.ips);
1951
            for (i = 0; i < def->source.caps.u.net.nroutes; i++)
1952
                virNetworkRouteDefFree(def->source.caps.u.net.routes[i]);
1953
            VIR_FREE(def->source.caps.u.net.routes);
1954
            break;
1955
        }
H
Han Cheng 已提交
1956 1957
        break;
    case VIR_DOMAIN_HOSTDEV_MODE_SUBSYS:
1958 1959 1960 1961 1962 1963 1964 1965 1966
        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 已提交
1967
        break;
1968
    }
1969 1970
}

1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987
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);
}

1988 1989 1990 1991 1992
void virDomainHostdevDefFree(virDomainHostdevDefPtr def)
{
    if (!def)
        return;

1993 1994 1995
    /* free all subordinate objects */
    virDomainHostdevDefClear(def);

1996 1997 1998 1999 2000
    /* If there is a parent device object, it will handle freeing
     * the memory.
     */
    if (def->parent.type == VIR_DOMAIN_DEVICE_NONE)
        VIR_FREE(def);
2001 2002
}

M
Marc-André Lureau 已提交
2003 2004 2005 2006 2007 2008 2009 2010 2011
void virDomainHubDefFree(virDomainHubDefPtr def)
{
    if (!def)
        return;

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

2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022
void virDomainRedirdevDefFree(virDomainRedirdevDefPtr def)
{
    if (!def)
        return;

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

    VIR_FREE(def);
}

2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036
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);
}

2037 2038 2039 2040 2041 2042 2043 2044 2045 2046
void virDomainMemoryDefFree(virDomainMemoryDefPtr def)
{
    if (!def)
        return;

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

2047 2048 2049 2050 2051
void virDomainDeviceDefFree(virDomainDeviceDefPtr def)
{
    if (!def)
        return;

2052
    switch ((virDomainDeviceType) def->type) {
2053 2054 2055
    case VIR_DOMAIN_DEVICE_DISK:
        virDomainDiskDefFree(def->data.disk);
        break;
2056 2057 2058
    case VIR_DOMAIN_DEVICE_LEASE:
        virDomainLeaseDefFree(def->data.lease);
        break;
2059 2060 2061 2062 2063 2064 2065 2066 2067
    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;
2068 2069 2070
    case VIR_DOMAIN_DEVICE_VIDEO:
        virDomainVideoDefFree(def->data.video);
        break;
2071 2072 2073
    case VIR_DOMAIN_DEVICE_HOSTDEV:
        virDomainHostdevDefFree(def->data.hostdev);
        break;
R
Richard Jones 已提交
2074 2075 2076
    case VIR_DOMAIN_DEVICE_WATCHDOG:
        virDomainWatchdogDefFree(def->data.watchdog);
        break;
2077 2078 2079
    case VIR_DOMAIN_DEVICE_CONTROLLER:
        virDomainControllerDefFree(def->data.controller);
        break;
2080 2081 2082
    case VIR_DOMAIN_DEVICE_GRAPHICS:
        virDomainGraphicsDefFree(def->data.graphics);
        break;
M
Marc-André Lureau 已提交
2083 2084 2085
    case VIR_DOMAIN_DEVICE_HUB:
        virDomainHubDefFree(def->data.hub);
        break;
2086 2087 2088
    case VIR_DOMAIN_DEVICE_REDIRDEV:
        virDomainRedirdevDefFree(def->data.redirdev);
        break;
2089 2090 2091
    case VIR_DOMAIN_DEVICE_RNG:
        virDomainRNGDefFree(def->data.rng);
        break;
2092 2093 2094
    case VIR_DOMAIN_DEVICE_CHR:
        virDomainChrDefFree(def->data.chr);
        break;
2095
    case VIR_DOMAIN_DEVICE_FS:
2096 2097
        virDomainFSDefFree(def->data.fs);
        break;
2098
    case VIR_DOMAIN_DEVICE_SMARTCARD:
2099 2100
        virDomainSmartcardDefFree(def->data.smartcard);
        break;
2101
    case VIR_DOMAIN_DEVICE_MEMBALLOON:
2102 2103
        virDomainMemballoonDefFree(def->data.memballoon);
        break;
L
Li Zhang 已提交
2104
    case VIR_DOMAIN_DEVICE_NVRAM:
2105 2106
        virDomainNVRAMDefFree(def->data.nvram);
        break;
2107 2108 2109
    case VIR_DOMAIN_DEVICE_SHMEM:
        virDomainShmemDefFree(def->data.shmem);
        break;
2110 2111 2112
    case VIR_DOMAIN_DEVICE_TPM:
        virDomainTPMDefFree(def->data.tpm);
        break;
2113 2114 2115
    case VIR_DOMAIN_DEVICE_PANIC:
        virDomainPanicDefFree(def->data.panic);
        break;
2116 2117 2118
    case VIR_DOMAIN_DEVICE_MEMORY:
        virDomainMemoryDefFree(def->data.memory);
        break;
2119
    case VIR_DOMAIN_DEVICE_LAST:
2120
    case VIR_DOMAIN_DEVICE_NONE:
2121
        break;
2122 2123 2124 2125 2126
    }

    VIR_FREE(def);
}

2127 2128 2129 2130 2131 2132
static void
virDomainClockDefClear(virDomainClockDefPtr def)
{
    if (def->offset == VIR_DOMAIN_CLOCK_OFFSET_TIMEZONE)
        VIR_FREE(def->data.timezone);

2133
    size_t i;
2134 2135 2136 2137 2138
    for (i = 0; i < def->ntimers; i++)
        VIR_FREE(def->timers[i]);
    VIR_FREE(def->timers);
}

2139
virDomainPinDefPtr *
2140
virDomainPinDefCopy(virDomainPinDefPtr *src, int npin)
2141
{
2142
    size_t i;
2143
    virDomainPinDefPtr *ret = NULL;
2144

2145
    if (VIR_ALLOC_N(ret, npin) < 0)
2146
        goto error;
2147

2148
    for (i = 0; i < npin; i++) {
2149
        if (VIR_ALLOC(ret[i]) < 0)
2150
            goto error;
2151
        ret[i]->id = src[i]->id;
H
Hu Tao 已提交
2152
        if ((ret[i]->cpumask = virBitmapNewCopy(src[i]->cpumask)) == NULL)
2153
            goto error;
2154 2155 2156 2157
    }

    return ret;

2158
 error:
2159
    if (ret) {
2160
        for (i = 0; i < npin; i++) {
2161
            if (ret[i]) {
H
Hu Tao 已提交
2162
                virBitmapFree(ret[i]->cpumask);
2163 2164 2165 2166
                VIR_FREE(ret[i]);
            }
        }
        VIR_FREE(ret);
2167 2168 2169 2170 2171
    }

    return NULL;
}

2172

2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185
static bool
virDomainIOThreadIDArrayHasPin(virDomainDefPtr def)
{
    size_t i;

    for (i = 0; i < def->niothreadids; i++) {
        if (def->iothreadids[i]->cpumask)
            return true;
    }
    return false;
}


2186 2187 2188 2189 2190
void
virDomainIOThreadIDDefFree(virDomainIOThreadIDDefPtr def)
{
    if (!def)
        return;
2191
    virBitmapFree(def->cpumask);
2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211
    VIR_FREE(def);
}


static void
virDomainIOThreadIDDefArrayFree(virDomainIOThreadIDDefPtr *def,
                                int nids)
{
    size_t i;

    if (!def)
        return;

    for (i = 0; i < nids; i++)
        virDomainIOThreadIDDefFree(def[i]);

    VIR_FREE(def);
}


2212 2213 2214 2215
static int
virDomainIOThreadIDDefArrayInit(virDomainDefPtr def)
{
    int retval = -1;
2216 2217 2218 2219
    size_t i;
    ssize_t nxt = -1;
    virDomainIOThreadIDDefPtr iothrid = NULL;
    virBitmapPtr thrmap = NULL;
2220 2221 2222 2223 2224 2225 2226

    /* Same value (either 0 or some number), then we have none to fill in or
     * the iothreadid array was filled from the XML
     */
    if (def->iothreads == def->niothreadids)
        return 0;

2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241
    /* iothread's are numbered starting at 1, account for that */
    if (!(thrmap = virBitmapNew(def->iothreads + 1)))
        goto error;
    virBitmapSetAll(thrmap);

    /* Clear 0 since we don't use it, then mark those which are
     * already provided by the user */
    ignore_value(virBitmapClearBit(thrmap, 0));
    for (i = 0; i < def->niothreadids; i++)
        ignore_value(virBitmapClearBit(thrmap,
                                       def->iothreadids[i]->iothread_id));

    /* resize array */
    if (VIR_REALLOC_N(def->iothreadids, def->iothreads) < 0)
        goto error;
2242

2243 2244 2245 2246 2247 2248
    /* Populate iothreadids[] using the set bit number from thrmap */
    while (def->niothreadids < def->iothreads) {
        if ((nxt = virBitmapNextSetBit(thrmap, nxt)) < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("failed to populate iothreadids"));
            goto error;
2249
        }
2250 2251 2252 2253 2254
        if (VIR_ALLOC(iothrid) < 0)
            goto error;
        iothrid->iothread_id = nxt;
        iothrid->autofill = true;
        def->iothreadids[def->niothreadids++] = iothrid;
2255
    }
2256

2257 2258 2259
    retval = 0;

 error:
2260
    virBitmapFree(thrmap);
2261 2262 2263 2264
    return retval;
}


2265
void
2266
virDomainPinDefFree(virDomainPinDefPtr def)
H
Hu Tao 已提交
2267 2268 2269 2270 2271 2272 2273 2274
{
    if (def) {
        virBitmapFree(def->cpumask);
        VIR_FREE(def);
    }
}

void
2275 2276
virDomainPinDefArrayFree(virDomainPinDefPtr *def,
                         int npin)
2277
{
2278
    size_t i;
2279

2280
    if (!def)
2281 2282
        return;

2283
    for (i = 0; i < npin; i++)
2284
        virDomainPinDefFree(def[i]);
2285 2286 2287 2288

    VIR_FREE(def);
}

2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299

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

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

H
Hu Tao 已提交
2300 2301 2302 2303 2304 2305 2306 2307 2308
void
virDomainPanicDefFree(virDomainPanicDefPtr panic)
{
    if (!panic)
        return;

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

2310 2311 2312 2313 2314 2315 2316 2317
void
virDomainLoaderDefFree(virDomainLoaderDefPtr loader)
{
    if (!loader)
        return;

    VIR_FREE(loader->path);
    VIR_FREE(loader->nvram);
2318
    VIR_FREE(loader->templt);
2319 2320 2321
    VIR_FREE(loader);
}

2322 2323
void virDomainDefFree(virDomainDefPtr def)
{
2324
    size_t i;
2325

2326 2327 2328
    if (!def)
        return;

2329 2330
    virDomainResourceDefFree(def->resource);

2331 2332 2333 2334 2335 2336
    /* 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().
     */
2337
    for (i = 0; i < def->nhostdevs; i++)
2338 2339 2340
        virDomainHostdevDefFree(def->hostdevs[i]);
    VIR_FREE(def->hostdevs);

2341
    for (i = 0; i < def->nleases; i++)
2342 2343 2344
        virDomainLeaseDefFree(def->leases[i]);
    VIR_FREE(def->leases);

2345
    for (i = 0; i < def->ngraphics; i++)
2346 2347
        virDomainGraphicsDefFree(def->graphics[i]);
    VIR_FREE(def->graphics);
2348

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

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

2357
    for (i = 0; i < def->ncontrollers; i++)
2358 2359 2360
        virDomainControllerDefFree(def->controllers[i]);
    VIR_FREE(def->controllers);

2361
    for (i = 0; i < def->nfss; i++)
2362 2363 2364
        virDomainFSDefFree(def->fss[i]);
    VIR_FREE(def->fss);

2365
    for (i = 0; i < def->nnets; i++)
2366 2367
        virDomainNetDefFree(def->nets[i]);
    VIR_FREE(def->nets);
2368

2369
    for (i = 0; i < def->nsmartcards; i++)
E
Eric Blake 已提交
2370 2371 2372
        virDomainSmartcardDefFree(def->smartcards[i]);
    VIR_FREE(def->smartcards);

2373
    for (i = 0; i < def->nserials; i++)
2374 2375 2376
        virDomainChrDefFree(def->serials[i]);
    VIR_FREE(def->serials);

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

2381
    for (i = 0; i < def->nchannels; i++)
2382 2383 2384
        virDomainChrDefFree(def->channels[i]);
    VIR_FREE(def->channels);

2385
    for (i = 0; i < def->nconsoles; i++)
2386 2387
        virDomainChrDefFree(def->consoles[i]);
    VIR_FREE(def->consoles);
2388

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

2393
    for (i = 0; i < def->nvideos; i++)
2394 2395 2396
        virDomainVideoDefFree(def->videos[i]);
    VIR_FREE(def->videos);

2397
    for (i = 0; i < def->nhubs; i++)
M
Marc-André Lureau 已提交
2398 2399 2400
        virDomainHubDefFree(def->hubs[i]);
    VIR_FREE(def->hubs);

2401
    for (i = 0; i < def->nredirdevs; i++)
2402 2403 2404
        virDomainRedirdevDefFree(def->redirdevs[i]);
    VIR_FREE(def->redirdevs);

2405 2406 2407
    for (i = 0; i < def->nrngs; i++)
        virDomainRNGDefFree(def->rngs[i]);
    VIR_FREE(def->rngs);
2408

2409 2410 2411 2412
    for (i = 0; i < def->nmems; i++)
        virDomainMemoryDefFree(def->mems[i]);
    VIR_FREE(def->mems);

2413 2414
    virDomainTPMDefFree(def->tpm);

D
Dmitry Andreev 已提交
2415 2416 2417
    for (i = 0; i < def->npanics; i++)
        virDomainPanicDefFree(def->panics[i]);
    VIR_FREE(def->panics);
H
Hu Tao 已提交
2418

2419 2420 2421
    VIR_FREE(def->idmap.uidmap);
    VIR_FREE(def->idmap.gidmap);

2422
    VIR_FREE(def->os.machine);
2423
    VIR_FREE(def->os.init);
2424
    for (i = 0; def->os.initargv && def->os.initargv[i]; i++)
2425 2426
        VIR_FREE(def->os.initargv[i]);
    VIR_FREE(def->os.initargv);
2427 2428 2429
    VIR_FREE(def->os.kernel);
    VIR_FREE(def->os.initrd);
    VIR_FREE(def->os.cmdline);
2430
    VIR_FREE(def->os.dtb);
2431
    VIR_FREE(def->os.root);
2432
    virDomainLoaderDefFree(def->os.loader);
2433 2434 2435
    VIR_FREE(def->os.bootloader);
    VIR_FREE(def->os.bootloaderArgs);

2436
    virDomainClockDefClear(&def->clock);
2437

2438
    VIR_FREE(def->name);
2439
    virBitmapFree(def->cpumask);
2440
    VIR_FREE(def->emulator);
2441
    VIR_FREE(def->description);
2442
    VIR_FREE(def->title);
2443

2444 2445
    virBlkioDeviceArrayClear(def->blkio.devices,
                             def->blkio.ndevices);
2446 2447
    VIR_FREE(def->blkio.devices);

R
Richard Jones 已提交
2448 2449
    virDomainWatchdogDefFree(def->watchdog);

C
Chris Lalancette 已提交
2450
    virDomainMemballoonDefFree(def->memballoon);
L
Li Zhang 已提交
2451
    virDomainNVRAMDefFree(def->nvram);
C
Chris Lalancette 已提交
2452

2453 2454 2455 2456
    for (i = 0; i < def->mem.nhugepages; i++)
        virBitmapFree(def->mem.hugepages[i].nodemask);
    VIR_FREE(def->mem.hugepages);

2457 2458 2459
    for (i = 0; i < def->nseclabels; i++)
        virSecurityLabelDefFree(def->seclabels[i]);
    VIR_FREE(def->seclabels);
2460

2461 2462
    virCPUDefFree(def->cpu);

2463 2464
    virDomainIOThreadIDDefArrayFree(def->iothreadids, def->niothreadids);

2465
    virDomainPinDefArrayFree(def->cputune.vcpupin, def->cputune.nvcpupin);
H
Hu Tao 已提交
2466

2467
    virBitmapFree(def->cputune.emulatorpin);
2468

2469 2470 2471 2472 2473 2474 2475 2476
    for (i = 0; i < def->cputune.nvcpusched; i++)
        virBitmapFree(def->cputune.vcpusched[i].ids);
    VIR_FREE(def->cputune.vcpusched);

    for (i = 0; i < def->cputune.niothreadsched; i++)
        virBitmapFree(def->cputune.iothreadsched[i].ids);
    VIR_FREE(def->cputune.iothreadsched);

2477
    virDomainNumaFree(def->numa);
O
Osier Yang 已提交
2478

2479 2480
    virSysinfoDefFree(def->sysinfo);

2481 2482
    virDomainRedirFilterDefFree(def->redirfilter);

2483 2484 2485 2486
    for (i = 0; i < def->nshmems; i++)
        virDomainShmemDefFree(def->shmems[i]);
    VIR_FREE(def->shmems);

2487 2488
    VIR_FREE(def->keywrap);

2489 2490 2491
    if (def->namespaceData && def->ns.free)
        (def->ns.free)(def->namespaceData);

2492 2493
    xmlFreeNode(def->metadata);

2494 2495 2496
    VIR_FREE(def);
}

2497
static void virDomainObjDispose(void *obj)
2498
{
2499
    virDomainObjPtr dom = obj;
2500

2501
    VIR_DEBUG("obj=%p", dom);
2502
    virCondDestroy(&dom->cond);
2503 2504 2505
    virDomainDefFree(dom->def);
    virDomainDefFree(dom->newDef);

2506 2507 2508
    if (dom->privateDataFreeFunc)
        (dom->privateDataFreeFunc)(dom->privateData);

2509
    virDomainSnapshotObjListFree(dom->snapshots);
2510 2511
}

2512
virDomainObjPtr
2513
virDomainObjNew(virDomainXMLOptionPtr xmlopt)
2514 2515 2516
{
    virDomainObjPtr domain;

2517 2518 2519
    if (virDomainObjInitialize() < 0)
        return NULL;

2520
    if (!(domain = virObjectLockableNew(virDomainObjClass)))
2521 2522
        return NULL;

2523 2524 2525 2526 2527 2528
    if (virCondInit(&domain->cond) < 0) {
        virReportSystemError(errno, "%s",
                             _("failed to initialize domain condition"));
        goto error;
    }

2529
    if (xmlopt->privateData.alloc) {
2530
        if (!(domain->privateData = (xmlopt->privateData.alloc)()))
2531
            goto error;
2532
        domain->privateDataFreeFunc = xmlopt->privateData.free;
2533 2534 2535 2536 2537
    }

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

2538
    virObjectLock(domain);
J
Jiri Denemark 已提交
2539 2540
    virDomainObjSetState(domain, VIR_DOMAIN_SHUTOFF,
                                 VIR_DOMAIN_SHUTOFF_UNKNOWN);
2541

2542
    VIR_DEBUG("obj=%p", domain);
2543
    return domain;
2544

2545
 error:
2546 2547
    virObjectUnref(domain);
    return NULL;
2548 2549
}

2550

2551 2552 2553 2554 2555
virDomainDefPtr
virDomainDefNew(void)
{
    virDomainDefPtr ret;

2556 2557 2558 2559 2560
    if (VIR_ALLOC(ret) < 0)
        return NULL;

    if (!(ret->numa = virDomainNumaNew()))
        goto error;
2561

2562 2563 2564 2565
    ret->mem.hard_limit = VIR_DOMAIN_MEMORY_PARAM_UNLIMITED;
    ret->mem.soft_limit = VIR_DOMAIN_MEMORY_PARAM_UNLIMITED;
    ret->mem.swap_hard_limit = VIR_DOMAIN_MEMORY_PARAM_UNLIMITED;

2566
    return ret;
2567 2568 2569 2570

 error:
    virDomainDefFree(ret);
    return NULL;
2571 2572 2573 2574 2575 2576 2577
}


virDomainDefPtr
virDomainDefNewFull(const char *name,
                    const unsigned char *uuid,
                    int id)
2578 2579 2580
{
    virDomainDefPtr def;

2581
    if (!(def = virDomainDefNew()))
2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595
        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;
}


2596
void virDomainObjAssignDef(virDomainObjPtr domain,
2597
                           virDomainDefPtr def,
2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609
                           bool live,
                           virDomainDefPtr *oldDef)
{
    if (oldDef)
        *oldDef = NULL;
    if (virDomainObjIsActive(domain)) {
        if (oldDef)
            *oldDef = domain->newDef;
        else
            virDomainDefFree(domain->newDef);
        domain->newDef = def;
    } else {
2610
        if (live) {
2611 2612 2613 2614 2615
            /* save current configuration to be restored on domain shutdown */
            if (!domain->newDef)
                domain->newDef = domain->def;
            else
                virDomainDefFree(domain->def);
2616 2617
            domain->def = def;
        } else {
2618 2619 2620 2621
            if (oldDef)
                *oldDef = domain->def;
            else
                virDomainDefFree(domain->def);
2622 2623 2624 2625 2626
            domain->def = def;
        }
    }
}

2627

M
Michal Privoznik 已提交
2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649
/**
 * virDomainObjEndAPI:
 * @vm: domain object
 *
 * Finish working with a domain object in an API.  This function
 * clears whatever was left of a domain that was gathered using
 * virDomainObjListFindByUUIDRef(). Currently that means only unlocking and
 * decrementing the reference counter of that domain.  And in order to
 * make sure the caller does not access the domain, the pointer is
 * cleared.
 */
void
virDomainObjEndAPI(virDomainObjPtr *vm)
{
    if (!*vm)
        return;

    virObjectUnlock(*vm);
    virObjectUnref(*vm);
    *vm = NULL;
}

2650

2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669
void
virDomainObjBroadcast(virDomainObjPtr vm)
{
    virCondBroadcast(&vm->cond);
}


int
virDomainObjWait(virDomainObjPtr vm)
{
    if (virCondWait(&vm->cond, &vm->parent.lock) < 0) {
        virReportSystemError(errno, "%s",
                             _("failed to wait for domain condition"));
        return -1;
    }
    return 0;
}


2670 2671 2672 2673 2674 2675 2676 2677
/**
 * Waits for domain condition to be triggered for a specific period of time.
 *
 * Returns:
 *  -1 in case of error
 *  0 on success
 *  1 on timeout
 */
2678 2679 2680 2681
int
virDomainObjWaitUntil(virDomainObjPtr vm,
                      unsigned long long whenms)
{
2682 2683 2684 2685 2686 2687 2688
    if (virCondWaitUntil(&vm->cond, &vm->parent.lock, whenms) < 0) {
        if (errno != ETIMEDOUT) {
            virReportSystemError(errno, "%s",
                                 _("failed to wait for domain condition"));
            return -1;
        }
        return 1;
2689 2690 2691 2692 2693
    }
    return 0;
}


2694 2695 2696 2697 2698
/*
 * 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 已提交
2699
 * @param xmlopt pointer to XML parser configuration object
2700
 * @param domain domain object pointer
2701 2702 2703 2704
 * @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.
2705 2706 2707 2708
 * @return 0 on success, -1 on failure
 */
int
virDomainObjSetDefTransient(virCapsPtr caps,
2709
                            virDomainXMLOptionPtr xmlopt,
2710 2711
                            virDomainObjPtr domain,
                            bool live)
2712 2713 2714
{
    int ret = -1;

2715
    if (!virDomainObjIsActive(domain) && !live)
2716 2717 2718 2719 2720 2721 2722 2723
        return 0;

    if (!domain->persistent)
        return 0;

    if (domain->newDef)
        return 0;

2724
    if (!(domain->newDef = virDomainDefCopy(domain->def, caps, xmlopt, false)))
2725 2726 2727
        goto out;

    ret = 0;
2728
 out:
2729 2730 2731
    return ret;
}

2732 2733 2734 2735 2736
/*
 * Return the persistent domain configuration. If domain is transient,
 * return the running config.
 *
 * @param caps pointer to capabilities info
W
Wang Rui 已提交
2737
 * @param xmlopt pointer to XML parser configuration object
2738 2739 2740 2741 2742
 * @param domain domain object pointer
 * @return NULL on error, virDOmainDefPtr on success
 */
virDomainDefPtr
virDomainObjGetPersistentDef(virCapsPtr caps,
2743
                             virDomainXMLOptionPtr xmlopt,
2744 2745
                             virDomainObjPtr domain)
{
2746
    if (virDomainObjSetDefTransient(caps, xmlopt, domain, false) < 0)
2747 2748 2749 2750 2751 2752 2753 2754
        return NULL;

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

2755 2756 2757

/**
 * virDomainObjUpdateModificationImpact:
2758
 *
2759 2760 2761 2762 2763 2764 2765 2766 2767
 * @vm: domain object
 * @flags: flags to update the modification impact on
 *
 * Resolves virDomainModificationImpact flags in @flags so that they correctly
 * apply to the actual state of @vm. @flags may be modified after call to this
 * function.
 *
 * Returns 0 on success if @flags point to a valid combination for @vm or -1 on
 * error.
2768 2769
 */
int
2770 2771
virDomainObjUpdateModificationImpact(virDomainObjPtr vm,
                                     unsigned int *flags)
2772
{
2773
    bool isActive = virDomainObjIsActive(vm);
2774 2775 2776 2777 2778 2779 2780 2781 2782 2783

    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)) {
2784 2785
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("domain is not running"));
2786
        return -1;
2787 2788 2789
    }

    if (*flags & VIR_DOMAIN_AFFECT_CONFIG) {
2790
        if (!vm->persistent) {
2791
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
2792 2793
                           _("transient domains do not have any "
                             "persistent config"));
2794
            return -1;
2795
        }
2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819
    }

    return 0;
}


/*
 * 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,
                                virDomainXMLOptionPtr xmlopt,
                                virDomainObjPtr dom,
                                unsigned int *flags,
                                virDomainDefPtr *persistentDef)
{
    if (virDomainObjUpdateModificationImpact(dom, flags) < 0)
        return -1;

    if (*flags & VIR_DOMAIN_AFFECT_CONFIG) {
2820
        if (!(*persistentDef = virDomainObjGetPersistentDef(caps, xmlopt, dom))) {
2821 2822
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Get persistent config failed"));
2823
            return -1;
2824 2825 2826
        }
    }

2827 2828
    return 0;
}
2829

2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857

/**
 * virDomainObjGetDefs:
 *
 * @vm: domain object
 * @flags: for virDomainModificationImpact
 * @liveDef: Set to the pointer to the live definition of @vm.
 * @persDef: Set to the pointer to the config definition of @vm.
 *
 * Helper function to resolve @flags and retrieve correct domain pointer
 * objects. This function should be used only when the hypervisor driver always
 * creates vm->newDef once the vm is started. (qemu driver does that)
 *
 * If @liveDef or @persDef are set it implies that @flags request modification
 * of thereof.
 *
 * Returns 0 on success and sets @liveDef and @persDef; -1 if @flags are
 * inappropriate.
 */
int
virDomainObjGetDefs(virDomainObjPtr vm,
                    unsigned int flags,
                    virDomainDefPtr *liveDef,
                    virDomainDefPtr *persDef)
{
    if (liveDef)
        *liveDef = NULL;

2858
    if (persDef)
2859 2860 2861 2862 2863
        *persDef = NULL;

    if (virDomainObjUpdateModificationImpact(vm, &flags) < 0)
        return -1;

2864 2865
    if (virDomainObjIsActive(vm)) {
        if (liveDef && (flags & VIR_DOMAIN_AFFECT_LIVE))
2866 2867
            *liveDef = vm->def;

2868
        if (persDef && (flags & VIR_DOMAIN_AFFECT_CONFIG))
2869
            *persDef = vm->newDef;
2870 2871 2872 2873 2874 2875
    } else {
        if (persDef)
            *persDef = vm->def;
    }

    return 0;
2876 2877
}

2878

2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914
/**
 * virDomainObjGetOneDef:
 *
 * @vm: Domain object
 * @flags: for virDomainModificationImpact
 *
 * Helper function to resolve @flags and return the correct domain pointer
 * object. This function returns one of @vm->def or @vm->persistentDef
 * according to @flags. This helper should be used only in APIs that guarantee
 * that @flags contains exactly one of VIR_DOMAIN_AFFECT_LIVE or
 * VIR_DOMAIN_AFFECT_CONFIG and not both.
 *
 * Returns the correct definition pointer or NULL on error.
 */
virDomainDefPtr
virDomainObjGetOneDef(virDomainObjPtr vm,
                      unsigned int flags)
{
    if (flags & VIR_DOMAIN_AFFECT_LIVE && flags & VIR_DOMAIN_AFFECT_CONFIG) {
            virReportInvalidArg(ctl, "%s",
                                _("Flags 'VIR_DOMAIN_AFFECT_LIVE' and "
                                  "'VIR_DOMAIN_AFFECT_CONFIG' are mutually "
                                  "exclusive"));
            return NULL;
    }

    if (virDomainObjUpdateModificationImpact(vm, &flags) < 0)
        return NULL;

    if (virDomainObjIsActive(vm) && flags & VIR_DOMAIN_AFFECT_CONFIG)
        return vm->newDef;
    else
        return vm->def;
}


2915 2916 2917 2918 2919 2920 2921
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;
}
2922

2923 2924 2925 2926 2927 2928 2929 2930
int virDomainDeviceAddressIsValid(virDomainDeviceInfoPtr info,
                                  int type)
{
    if (info->type != type)
        return 0;

    switch (info->type) {
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI:
2931
        return virDevicePCIAddressIsValid(&info->addr.pci, false);
2932 2933

    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE:
2934
        return 1;
2935

2936
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390:
2937
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO:
2938 2939 2940 2941 2942
        return 1;

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

2943
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB:
2944
        return 1;
2945 2946 2947 2948 2949
    }

    return 0;
}

2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983
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;
2984 2985
    case VIR_DOMAIN_DEVICE_SHMEM:
        return &device->data.shmem->info;
2986 2987
    case VIR_DOMAIN_DEVICE_RNG:
        return &device->data.rng->info;
2988 2989
    case VIR_DOMAIN_DEVICE_TPM:
        return &device->data.tpm->info;
2990 2991
    case VIR_DOMAIN_DEVICE_PANIC:
        return &device->data.panic->info;
2992 2993
    case VIR_DOMAIN_DEVICE_MEMORY:
        return &device->data.memory->info;
2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004

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

3005
static bool
3006
virDomainDeviceInfoNeedsFormat(virDomainDeviceInfoPtr info, unsigned int flags)
3007 3008
{
    if (info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
3009
        return true;
3010
    if (info->alias && !(flags & VIR_DOMAIN_DEF_FORMAT_INACTIVE))
3011 3012 3013
        return true;
    if (info->mastertype != VIR_DOMAIN_CONTROLLER_MASTER_NONE)
        return true;
J
Ján Tomko 已提交
3014
    if ((info->rombar != VIR_TRISTATE_SWITCH_ABSENT) ||
3015 3016 3017 3018 3019
        info->romfile)
        return true;
    if (info->bootIndex)
        return true;
    return false;
3020 3021
}

3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 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
static bool
virDomainDeviceInfoAddressIsEqual(const virDomainDeviceInfo *a,
                                  const virDomainDeviceInfo *b)
{

    if (a->type != b->type)
        return false;

    switch ((virDomainDeviceAddressType) a->type) {
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE:
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST:
    /* address types below don't have any specific data */
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO:
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390:
        break;

    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI:
        /* the 'multi' field shouldn't be checked */
        if (a->addr.pci.domain != b->addr.pci.domain ||
            a->addr.pci.bus != b->addr.pci.bus ||
            a->addr.pci.slot != b->addr.pci.slot ||
            a->addr.pci.function != b->addr.pci.function)
            return false;
        break;

    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE:
        if (memcmp(&a->addr.drive, &b->addr.drive, sizeof(a->addr.drive)))
            return false;
        break;

    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL:
        if (memcmp(&a->addr.vioserial, &b->addr.vioserial, sizeof(a->addr.vioserial)))
            return false;
        break;

    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCID:
        if (memcmp(&a->addr.ccid, &b->addr.ccid, sizeof(a->addr.ccid)))
            return false;
        break;

    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB:
        if (memcmp(&a->addr.usb, &b->addr.usb, sizeof(a->addr.usb)))
            return false;
        break;

    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO:
        if (memcmp(&a->addr.spaprvio, &b->addr.spaprvio, sizeof(a->addr.spaprvio)))
            return false;
        break;

    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW:
        /* the 'assigned' field denotes that the address was generated */
        if (a->addr.ccw.cssid != b->addr.ccw.cssid ||
            a->addr.ccw.ssid != b->addr.ccw.ssid ||
            a->addr.ccw.devno != b->addr.ccw.devno)
            return false;
        break;

    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_ISA:
        if (memcmp(&a->addr.isa, &b->addr.isa, sizeof(a->addr.isa)))
            return false;
        break;
3084 3085 3086 3087 3088

    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DIMM:
        if (memcmp(&a->addr.dimm, &b->addr.dimm, sizeof(a->addr.dimm)))
            return false;
        break;
3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110
    }

    return true;
}


static int
virDomainDefHasDeviceAddressIterator(virDomainDefPtr def ATTRIBUTE_UNUSED,
                                     virDomainDeviceDefPtr dev ATTRIBUTE_UNUSED,
                                     virDomainDeviceInfoPtr info,
                                     void *opaque)
{
    virDomainDeviceInfoPtr needle = opaque;

    /* break iteration if the info was found */
    if (virDomainDeviceInfoAddressIsEqual(info, needle))
        return -1;

    return 0;
}


3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123
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;

3124 3125
    if (VIR_STRDUP(dst->alias, src->alias) < 0 ||
        VIR_STRDUP(dst->romfile, src->romfile) < 0)
3126 3127 3128 3129
        return -1;
    return 0;
}

3130 3131
void virDomainDeviceInfoClear(virDomainDeviceInfoPtr info)
{
3132
    VIR_FREE(info->alias);
3133
    if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB)
3134
        VIR_FREE(info->addr.usb.port);
3135 3136
    memset(&info->addr, 0, sizeof(info->addr));
    info->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE;
3137
    VIR_FREE(info->romfile);
3138 3139 3140
}


3141
static int virDomainDeviceInfoClearAlias(virDomainDefPtr def ATTRIBUTE_UNUSED,
3142
                                         virDomainDeviceDefPtr device ATTRIBUTE_UNUSED,
3143 3144
                                         virDomainDeviceInfoPtr info,
                                         void *opaque ATTRIBUTE_UNUSED)
3145
{
3146 3147 3148 3149 3150
    VIR_FREE(info->alias);
    return 0;
}

static int virDomainDeviceInfoClearPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED,
3151
                                              virDomainDeviceDefPtr device ATTRIBUTE_UNUSED,
3152 3153 3154 3155
                                              virDomainDeviceInfoPtr info,
                                              void *opaque ATTRIBUTE_UNUSED)
{
    if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
3156 3157 3158
        memset(&info->addr, 0, sizeof(info->addr));
        info->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE;
    }
3159
    return 0;
3160 3161
}

3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174
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;
}

3175 3176 3177 3178 3179
static int
virDomainDeviceInfoIterateInternal(virDomainDefPtr def,
                                   virDomainDeviceInfoCallback cb,
                                   bool all,
                                   void *opaque)
3180
{
3181
    size_t i;
3182
    virDomainDeviceDef device;
3183

3184
    device.type = VIR_DOMAIN_DEVICE_DISK;
3185
    for (i = 0; i < def->ndisks; i++) {
3186 3187
        device.data.disk = def->disks[i];
        if (cb(def, &device, &def->disks[i]->info, opaque) < 0)
3188
            return -1;
3189 3190
    }
    device.type = VIR_DOMAIN_DEVICE_NET;
3191
    for (i = 0; i < def->nnets; i++) {
3192 3193
        device.data.net = def->nets[i];
        if (cb(def, &device, &def->nets[i]->info, opaque) < 0)
3194
            return -1;
3195 3196
    }
    device.type = VIR_DOMAIN_DEVICE_SOUND;
3197
    for (i = 0; i < def->nsounds; i++) {
3198 3199
        device.data.sound = def->sounds[i];
        if (cb(def, &device, &def->sounds[i]->info, opaque) < 0)
3200
            return -1;
3201 3202
    }
    device.type = VIR_DOMAIN_DEVICE_HOSTDEV;
3203
    for (i = 0; i < def->nhostdevs; i++) {
3204
        device.data.hostdev = def->hostdevs[i];
3205
        if (cb(def, &device, def->hostdevs[i]->info, opaque) < 0)
3206
            return -1;
3207 3208
    }
    device.type = VIR_DOMAIN_DEVICE_VIDEO;
3209
    for (i = 0; i < def->nvideos; i++) {
3210 3211
        device.data.video = def->videos[i];
        if (cb(def, &device, &def->videos[i]->info, opaque) < 0)
3212
            return -1;
3213 3214
    }
    device.type = VIR_DOMAIN_DEVICE_CONTROLLER;
3215
    for (i = 0; i < def->ncontrollers; i++) {
3216 3217
        device.data.controller = def->controllers[i];
        if (cb(def, &device, &def->controllers[i]->info, opaque) < 0)
3218
            return -1;
3219 3220
    }
    device.type = VIR_DOMAIN_DEVICE_SMARTCARD;
3221
    for (i = 0; i < def->nsmartcards; i++) {
3222 3223
        device.data.smartcard = def->smartcards[i];
        if (cb(def, &device, &def->smartcards[i]->info, opaque) < 0)
E
Eric Blake 已提交
3224
            return -1;
3225 3226
    }
    device.type = VIR_DOMAIN_DEVICE_CHR;
3227
    for (i = 0; i < def->nserials; i++) {
3228 3229
        device.data.chr = def->serials[i];
        if (cb(def, &device, &def->serials[i]->info, opaque) < 0)
3230
            return -1;
3231
    }
3232
    for (i = 0; i < def->nparallels; i++) {
3233 3234
        device.data.chr = def->parallels[i];
        if (cb(def, &device, &def->parallels[i]->info, opaque) < 0)
3235
            return -1;
3236
    }
3237
    for (i = 0; i < def->nchannels; i++) {
3238 3239
        device.data.chr = def->channels[i];
        if (cb(def, &device, &def->channels[i]->info, opaque) < 0)
3240
            return -1;
3241
    }
3242
    for (i = 0; i < def->nconsoles; i++) {
3243 3244 3245 3246
        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) &&
3247
             def->os.type == VIR_DOMAIN_OSTYPE_HVM)
3248
            continue;
3249 3250
        device.data.chr = def->consoles[i];
        if (cb(def, &device, &def->consoles[i]->info, opaque) < 0)
3251
            return -1;
3252 3253
    }
    device.type = VIR_DOMAIN_DEVICE_INPUT;
3254
    for (i = 0; i < def->ninputs; i++) {
3255 3256
        device.data.input = def->inputs[i];
        if (cb(def, &device, &def->inputs[i]->info, opaque) < 0)
3257
            return -1;
3258 3259
    }
    device.type = VIR_DOMAIN_DEVICE_FS;
3260
    for (i = 0; i < def->nfss; i++) {
3261 3262
        device.data.fs = def->fss[i];
        if (cb(def, &device, &def->fss[i]->info, opaque) < 0)
3263
            return -1;
3264 3265 3266 3267 3268
    }
    if (def->watchdog) {
        device.type = VIR_DOMAIN_DEVICE_WATCHDOG;
        device.data.watchdog = def->watchdog;
        if (cb(def, &device, &def->watchdog->info, opaque) < 0)
3269
            return -1;
3270 3271 3272 3273 3274
    }
    if (def->memballoon) {
        device.type = VIR_DOMAIN_DEVICE_MEMBALLOON;
        device.data.memballoon = def->memballoon;
        if (cb(def, &device, &def->memballoon->info, opaque) < 0)
3275
            return -1;
3276
    }
3277 3278 3279 3280
    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)
3281 3282
            return -1;
    }
L
Li Zhang 已提交
3283 3284 3285 3286 3287 3288
    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;
    }
3289
    device.type = VIR_DOMAIN_DEVICE_HUB;
3290
    for (i = 0; i < def->nhubs; i++) {
3291 3292
        device.data.hub = def->hubs[i];
        if (cb(def, &device, &def->hubs[i]->info, opaque) < 0)
M
Marc-André Lureau 已提交
3293
            return -1;
3294
    }
3295 3296 3297 3298 3299 3300
    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;
    }
3301 3302 3303 3304 3305 3306
    if (def->tpm) {
        device.type = VIR_DOMAIN_DEVICE_TPM;
        device.data.tpm = def->tpm;
        if (cb(def, &device, &def->tpm->info, opaque) < 0)
            return -1;
    }
D
Dmitry Andreev 已提交
3307 3308 3309 3310
    device.type = VIR_DOMAIN_DEVICE_PANIC;
    for (i = 0; i < def->npanics; i++) {
        device.data.panic = def->panics[i];
        if (cb(def, &device, &def->panics[i]->info, opaque) < 0)
3311 3312
            return -1;
    }
3313

3314 3315 3316 3317 3318 3319 3320
    device.type = VIR_DOMAIN_DEVICE_MEMORY;
    for (i = 0; i < def->nmems; i++) {
        device.data.memory = def->mems[i];
        if (cb(def, &device, &def->mems[i]->info, opaque) < 0)
            return -1;
    }

3321 3322
    /* Coverity is not very happy with this - all dead_error_condition */
#if !STATIC_ANALYSIS
3323
    /* This switch statement is here to trigger compiler warning when adding
E
Eric Blake 已提交
3324
     * a new device type. When you are adding a new field to the switch you
M
Martin Kletzander 已提交
3325
     * also have to add an iteration statement above. Otherwise the switch
3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346
     * 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 已提交
3347
    case VIR_DOMAIN_DEVICE_NVRAM:
3348
    case VIR_DOMAIN_DEVICE_SHMEM:
3349
    case VIR_DOMAIN_DEVICE_TPM:
3350
    case VIR_DOMAIN_DEVICE_PANIC:
3351
    case VIR_DOMAIN_DEVICE_LAST:
3352
    case VIR_DOMAIN_DEVICE_RNG:
3353
    case VIR_DOMAIN_DEVICE_MEMORY:
3354 3355
        break;
    }
3356
#endif
3357

3358
    return 0;
3359 3360 3361
}


3362 3363 3364 3365 3366 3367 3368 3369 3370
int
virDomainDeviceInfoIterate(virDomainDefPtr def,
                           virDomainDeviceInfoCallback cb,
                           void *opaque)
{
    return virDomainDeviceInfoIterateInternal(def, cb, false, opaque);
}


3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384
bool
virDomainDefHasDeviceAddress(virDomainDefPtr def,
                             virDomainDeviceInfoPtr info)
{
    if (virDomainDeviceInfoIterateInternal(def,
                                           virDomainDefHasDeviceAddressIterator,
                                           true,
                                           info) < 0)
        return true;

    return false;
}


3385 3386 3387 3388 3389 3390 3391 3392
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;
3393
    size_t i;
3394 3395 3396 3397 3398

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

    for (i = 0; i < def->ncontrollers; i++) {
        cont = def->controllers[i];
3399
        if ((int) cont->idx > max_idx[cont->type])
3400 3401 3402 3403 3404 3405 3406 3407
            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)))
3408
            goto cleanup;
3409 3410 3411 3412 3413 3414 3415 3416 3417
        nbitmaps++;
    }

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

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

J
Ján Tomko 已提交
3418
        if (virBitmapIsBitSet(bitmaps[cont->type], cont->idx)) {
3419 3420 3421 3422 3423 3424 3425 3426 3427 3428
            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;
3429
 cleanup:
3430 3431 3432 3433 3434
    for (i = 0; i < nbitmaps; i++)
        virBitmapFree(bitmaps[i]);
    return ret;
}

3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456
static int
virDomainDefRejectDuplicatePanics(virDomainDefPtr def)
{
    bool exists[VIR_DOMAIN_PANIC_MODEL_LAST];
    size_t i;

    for (i = 0; i < VIR_DOMAIN_PANIC_MODEL_LAST; i++)
         exists[i] = false;

    for (i = 0; i < def->npanics; i++) {
        virDomainPanicModel model = def->panics[i]->model;
        if (exists[model]) {
            virReportError(VIR_ERR_XML_ERROR,
                           _("Multiple panic devices with model '%s'"),
                           virDomainPanicModelTypeToString(model));
            return -1;
        }
        exists[model] = true;
    }

    return 0;
}
3457

3458
/**
3459 3460
 * virDomainDefMetadataSanitize:
 * @def: Sanitize metadata for this def
3461 3462
 *
 * This function removes metadata elements in @def that share the namespace.
3463 3464
 * The first metadata entry of every duplicate namespace is kept. Additionally
 * elements with no namespace are deleted.
3465 3466
 */
static void
3467
virDomainDefMetadataSanitize(virDomainDefPtr def)
3468 3469 3470
{
    xmlNodePtr child;
    xmlNodePtr next;
3471
    xmlNodePtr dupl;
3472 3473 3474 3475

    if (!def || !def->metadata)
        return;

3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487
    child = def->metadata->children;
    while (child) {
        /* remove metadata entries that don't have any namespace at all */
        if (!child->ns || !child->ns->href) {
            dupl = child;
            child = child->next;

            xmlUnlinkNode(dupl);
            xmlFreeNode(dupl);
            continue;
        }

3488 3489 3490 3491
        /* check that every other child of @root doesn't share the namespace of
         * the current one and delete them possibly */
        next = child->next;
        while (next) {
3492
            dupl = NULL;
3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505

            if (child->ns && next->ns &&
                STREQ_NULLABLE((const char *) child->ns->href,
                               (const char *) next->ns->href))
                dupl = next;

            next = next->next;

            if (dupl) {
                xmlUnlinkNode(dupl);
                xmlFreeNode(dupl);
            }
        }
3506 3507

        child = child->next;
3508 3509 3510 3511
    }
}


3512
static int
3513 3514
virDomainDefPostParseMemory(virDomainDefPtr def,
                            unsigned int parseFlags)
3515
{
3516
    size_t i;
3517 3518
    unsigned long long numaMemory = 0;
    unsigned long long hotplugMemory = 0;
3519

3520 3521 3522 3523 3524
    /* Attempt to infer the initial memory size from the sum NUMA memory sizes
     * in case ABI updates are allowed or the <memory> element wasn't specified */
    if (def->mem.total_memory == 0 ||
        parseFlags & VIR_DOMAIN_DEF_PARSE_ABI_UPDATE)
        numaMemory = virDomainNumaGetMemorySize(def->numa);
3525

3526 3527 3528 3529
    if (numaMemory) {
        virDomainDefSetMemoryInitial(def, numaMemory);
    } else {
        /* calculate the sizes of hotplug memory */
3530
        for (i = 0; i < def->nmems; i++)
3531 3532 3533 3534 3535 3536 3537 3538 3539 3540
            hotplugMemory += def->mems[i]->size;

        if (hotplugMemory > def->mem.total_memory) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("Total size of memory devices exceeds the total "
                             "memory size"));
            return -1;
        }

        virDomainDefSetMemoryInitial(def, def->mem.total_memory - hotplugMemory);
3541 3542
    }

3543 3544 3545 3546 3547 3548 3549
    if (virDomainDefGetMemoryInitial(def) == 0) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Memory size must be specified via <memory> or in the "
                         "<numa> configuration"));
        return -1;
    }

3550 3551
    if (def->mem.cur_balloon > virDomainDefGetMemoryActual(def) ||
        def->mem.cur_balloon == 0)
3552
        def->mem.cur_balloon = virDomainDefGetMemoryActual(def);
3553

3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569
    if ((def->mem.max_memory || def->mem.memory_slots) &&
        !(def->mem.max_memory && def->mem.memory_slots)) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("both maximum memory size and "
                         "memory slot count must be specified"));
        return -1;
    }

    if (def->mem.max_memory &&
        def->mem.max_memory < virDomainDefGetMemoryActual(def)) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("maximum memory size must be equal or greater than "
                         "the actual memory size"));
        return -1;
    }

3570 3571 3572 3573 3574 3575
    return 0;
}


static int
virDomainDefPostParseInternal(virDomainDefPtr def,
3576 3577
                              virCapsPtr caps ATTRIBUTE_UNUSED,
                              unsigned int parseFlags)
3578 3579 3580 3581 3582 3583 3584 3585 3586 3587
{
    size_t i;

    /* verify init path for container based domains */
    if (def->os.type == VIR_DOMAIN_OSTYPE_EXE && !def->os.init) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("init binary must be specified"));
        return -1;
    }

3588
    if (virDomainDefPostParseMemory(def, parseFlags) < 0)
3589 3590
        return -1;

3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604
    /*
     * 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
     */
3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617

    /* Only the first console (if there are any) can be of type serial,
     * verify that no other 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;
        }
    }
3618
    if (def->nconsoles > 0 && def->os.type == VIR_DOMAIN_OSTYPE_HVM &&
3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632
        (def->consoles[0]->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL ||
         def->consoles[0]->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_NONE)) {

        /* 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) {
3633 3634 3635 3636
            if (VIR_APPEND_ELEMENT(def->serials,
                                   def->nserials,
                                   def->consoles[0]) < 0)
                return -1;
3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653

            /* 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)
3654
                return -1;
3655 3656 3657 3658 3659

            /* 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;
        }
3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680
    } else if (def->os.type == VIR_DOMAIN_OSTYPE_HVM && def->nserials > 0 &&
               def->serials[0]->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL &&
               def->serials[0]->targetType == VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_ISA) {
        /* Create a stub console to match the serial port.
         * console[0] either does not exist
         *                or has a different type than SERIAL or NONE.
         */
        virDomainChrDefPtr chr;
        if (VIR_ALLOC(chr) < 0)
            return -1;

        if (VIR_INSERT_ELEMENT(def->consoles,
                               0,
                               def->nconsoles,
                               chr) < 0) {
            VIR_FREE(chr);
            return -1;
        }

        def->consoles[0]->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE;
        def->consoles[0]->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL;
3681 3682
    }

3683 3684
    if (virDomainDefRejectDuplicateControllers(def) < 0)
        return -1;
3685

3686 3687 3688
    if (virDomainDefRejectDuplicatePanics(def) < 0)
        return -1;

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

3693 3694
        if (timer->name == VIR_DOMAIN_TIMER_NAME_KVMCLOCK ||
            timer->name == VIR_DOMAIN_TIMER_NAME_HYPERVCLOCK) {
3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743
            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;
            }
        }
    }

3744
    /* clean up possibly duplicated metadata entries */
3745
    virDomainDefMetadataSanitize(def);
3746

3747 3748 3749 3750
    return 0;
}


3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799
/* Check if a drive type address $controller:$bus:$target:$unit is already
 * taken by a disk or not.
 */
static bool
virDomainDriveAddressIsUsedByDisk(const virDomainDef *def,
                                  virDomainDiskBus type,
                                  unsigned int controller,
                                  unsigned int bus,
                                  unsigned int target,
                                  unsigned int unit)
{
    virDomainDiskDefPtr disk;
    size_t i;

    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 == bus &&
            disk->info.addr.drive.target == target)
            return true;
    }

    return false;
}


/* Check if a drive type address $controller:$target:$bus:$unit is already
 * taken by a host device or not.
 */
static bool
virDomainDriveAddressIsUsedByHostdev(const virDomainDef *def,
                                     virDomainHostdevSubsysType type,
                                     unsigned int controller,
                                     unsigned int bus,
                                     unsigned int target,
                                     unsigned int unit)
{
    virDomainHostdevDefPtr hostdev;
    size_t i;

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

3800 3801
        if (hostdev->source.subsys.type != type ||
            hostdev->info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE)
3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867
            continue;

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

    return false;
}


static bool
virDomainSCSIDriveAddressIsUsed(const virDomainDef *def,
                                unsigned int controller,
                                unsigned int bus,
                                unsigned int target,
                                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, bus, target, unit) ||
        virDomainDriveAddressIsUsedByHostdev(def,
                                             VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI,
                                             controller, bus, target, unit))
        return true;

    return false;
}


/* Find out the next usable "unit" of a specific controller */
static int
virDomainControllerSCSINextUnit(const virDomainDef *def,
                                unsigned int max_unit,
                                unsigned int controller)
{
    size_t i;

    for (i = 0; i < max_unit; i++) {
        /* Default to assigning addresses using bus = target = 0 */
        if (!virDomainSCSIDriveAddressIsUsed(def, controller, 0, 0, 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,
                              const virDomainDef *def,
                              virDomainHostdevDefPtr hostdev)
{
    int next_unit = 0;
    unsigned controller = 0;
    size_t i;
3868
    int ret;
3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886

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

        controller++;
        ret = virDomainControllerSCSINextUnit(def,
                                              xmlopt->config.hasWideSCSIBus ?
                                              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;
        }
    }

3887 3888 3889 3890 3891 3892
    /* NB: Do not attempt calling virDomainDefMaybeAddController to
     * automagically add a "new" controller. Doing so will result in
     * qemuDomainFindOrCreateSCSIDiskController "finding" the controller
     * in the domain def list and thus not hotplugging the controller as
     * well as the hostdev in the event that there are either no SCSI
     * controllers defined or there was no space on an existing one.
3893 3894
     */

3895 3896 3897 3898 3899 3900 3901 3902 3903 3904
    hostdev->info->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE;
    hostdev->info->addr.drive.controller = controller;
    hostdev->info->addr.drive.bus = 0;
    hostdev->info->addr.drive.target = 0;
    hostdev->info->addr.drive.unit = next_unit;

    return 0;
}


3905 3906
static int
virDomainDeviceDefPostParseInternal(virDomainDeviceDefPtr dev,
3907
                                    const virDomainDef *def,
3908
                                    virCapsPtr caps ATTRIBUTE_UNUSED,
3909
                                    virDomainXMLOptionPtr xmlopt)
3910
{
3911 3912
    if (dev->type == VIR_DOMAIN_DEVICE_CHR) {
        virDomainChrDefPtr chr = dev->data.chr;
3913 3914
        const virDomainChrDef **arrPtr;
        size_t i, cnt;
3915

3916
        virDomainChrGetDomainPtrs(def, chr->deviceType, &arrPtr, &cnt);
3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927

        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;

3928 3929 3930
            for (i = 0; i < cnt; i++) {
                if (arrPtr[i]->target.port > maxport)
                    maxport = arrPtr[i]->target.port;
3931 3932 3933 3934 3935
            }

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

3937 3938 3939 3940 3941 3942 3943 3944
    /* 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;
    }

3945 3946 3947 3948
    /* verify disk source */
    if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
        virDomainDiskDefPtr disk = dev->data.disk;

3949 3950
        /* internal snapshots and config files are currently supported
         * only with rbd: */
3951 3952 3953 3954 3955 3956 3957 3958
        if (virStorageSourceGetActualType(disk->src) != VIR_STORAGE_TYPE_NETWORK &&
            disk->src->protocol != VIR_STORAGE_NET_PROTOCOL_RBD) {
            if (disk->src->snapshot) {
                virReportError(VIR_ERR_XML_ERROR, "%s",
                               _("<snapshot> element is currently supported "
                                 "only with 'rbd' disks"));
                return -1;
            }
3959 3960 3961 3962 3963 3964 3965

            if (disk->src->configFile) {
                virReportError(VIR_ERR_XML_ERROR, "%s",
                               _("<config> element is currently supported "
                                 "only with 'rbd' disks"));
                return -1;
            }
3966
        }
3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988

        /* Validate LUN configuration
         * NOTE: virStorageTranslateDiskSourcePool is not run yet, so for
         *       disk "volume"'s, the closest we can get at config time is
         *       to ensure mode isn't direct since host/default will allow
         *       lun/block usage. At run time if it's determined the wrong
         *       voltype and pooltype values are set, then failure occurs
         */
        if (disk->device == VIR_DOMAIN_DISK_DEVICE_LUN &&
            !(disk->src->type == VIR_STORAGE_TYPE_BLOCK ||
              (disk->src->type == VIR_STORAGE_TYPE_NETWORK &&
               disk->src->protocol == VIR_STORAGE_NET_PROTOCOL_ISCSI) ||
              (disk->src->type == VIR_STORAGE_TYPE_VOLUME &&
               disk->src->srcpool &&
               disk->src->srcpool->mode !=
               VIR_STORAGE_SOURCE_POOL_MODE_DIRECT))) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("disk '%s' improperly configured for a "
                             "device='lun'"),
                           disk->dst);
            return -1;
        }
3989 3990

        if (disk->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
3991
            virDomainDiskDefAssignAddress(xmlopt, disk, def) < 0)
3992
            return -1;
3993 3994
    }

3995 3996 3997 3998 3999 4000
    if (dev->type == VIR_DOMAIN_DEVICE_VIDEO) {
        virDomainVideoDefPtr video = dev->data.video;
        video->ram = VIR_ROUND_UP_POWER_OF_TWO(video->ram);
        video->vram = VIR_ROUND_UP_POWER_OF_TWO(video->vram);
    }

4001 4002 4003 4004
    if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV) {
        virDomainHostdevDefPtr hdev = dev->data.hostdev;

        if (hdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
4005 4006 4007 4008
            hdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI) {

            if (hdev->info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
                virDomainHostdevAssignAddress(xmlopt, def, hdev) < 0) {
4009 4010 4011
                virReportError(VIR_ERR_XML_ERROR, "%s",
                               _("Cannot assign SCSI host device address"));
                return -1;
4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031
            } else {
                /* Ensure provided address doesn't conflict with existing
                 * scsi disk drive address
                 */
                virDomainDeviceDriveAddressPtr addr = &hdev->info->addr.drive;
                if (virDomainDriveAddressIsUsedByDisk(def,
                                                      VIR_DOMAIN_DISK_BUS_SCSI,
                                                      addr->controller,
                                                      addr->bus,
                                                      addr->target,
                                                      addr->unit)) {
                    virReportError(VIR_ERR_XML_ERROR,
                                   _("SCSI host address controller='%u' "
                                     "bus='%u' target='%u' unit='%u' in "
                                     "use by a SCSI disk"),
                                   addr->controller, addr->bus,
                                   addr->target, addr->unit);
                    return -1;
                }
            }
4032 4033
        }
    }
4034 4035 4036 4037
    return 0;
}


4038 4039
static int
virDomainDeviceDefPostParse(virDomainDeviceDefPtr dev,
4040
                            const virDomainDef *def,
4041 4042 4043 4044 4045
                            virCapsPtr caps,
                            virDomainXMLOptionPtr xmlopt)
{
    int ret;

4046
    if (xmlopt->config.devicesPostParseCallback) {
4047 4048 4049 4050 4051 4052
        ret = xmlopt->config.devicesPostParseCallback(dev, def, caps,
                                                      xmlopt->config.priv);
        if (ret < 0)
            return ret;
    }

4053
    if ((ret = virDomainDeviceDefPostParseInternal(dev, def, caps, xmlopt)) < 0)
4054 4055
        return ret;

4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077
    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);
}


4078
int
4079 4080
virDomainDefPostParse(virDomainDefPtr def,
                      virCapsPtr caps,
4081
                      unsigned int parseFlags,
4082 4083 4084 4085 4086 4087 4088 4089 4090 4091
                      virDomainXMLOptionPtr xmlopt)
{
    int ret;
    struct virDomainDefPostParseDeviceIteratorData data = {
        .def = def,
        .caps = caps,
        .xmlopt = xmlopt,
    };

    /* call the domain config callback */
4092
    if (xmlopt->config.domainPostParseCallback) {
4093 4094 4095 4096 4097 4098 4099
        ret = xmlopt->config.domainPostParseCallback(def, caps,
                                                     xmlopt->config.priv);
        if (ret < 0)
            return ret;
    }

    /* iterate the devices */
4100 4101 4102 4103
    if ((ret = virDomainDeviceInfoIterateInternal(def,
                                                  virDomainDefPostParseDeviceIterator,
                                                  true,
                                                  &data)) < 0)
4104 4105
        return ret;

4106

4107
    if ((ret = virDomainDefPostParseInternal(def, caps, parseFlags)) < 0)
4108 4109
        return ret;

4110 4111 4112 4113
    return 0;
}


4114 4115
void virDomainDefClearPCIAddresses(virDomainDefPtr def)
{
4116
    virDomainDeviceInfoIterate(def, virDomainDeviceInfoClearPCIAddress, NULL);
D
Daniel P. Berrange 已提交
4117 4118
}

4119 4120 4121 4122 4123
void virDomainDefClearCCWAddresses(virDomainDefPtr def)
{
    virDomainDeviceInfoIterate(def, virDomainDeviceInfoClearCCWAddress, NULL);
}

D
Daniel P. Berrange 已提交
4124 4125
void virDomainDefClearDeviceAliases(virDomainDefPtr def)
{
4126
    virDomainDeviceInfoIterate(def, virDomainDeviceInfoClearAlias, NULL);
4127 4128 4129
}


4130
/* Generate a string representation of a device address
4131
 * @info address Device address to stringify
4132
 */
E
Eric Blake 已提交
4133 4134 4135
static int ATTRIBUTE_NONNULL(2)
virDomainDeviceInfoFormat(virBufferPtr buf,
                          virDomainDeviceInfoPtr info,
E
Eric Blake 已提交
4136
                          unsigned int flags)
4137
{
4138
    if ((flags & VIR_DOMAIN_DEF_FORMAT_ALLOW_BOOT) && info->bootIndex)
4139
        virBufferAsprintf(buf, "<boot order='%d'/>\n", info->bootIndex);
4140

D
Daniel P. Berrange 已提交
4141
    if (info->alias &&
4142
        !(flags & VIR_DOMAIN_DEF_FORMAT_INACTIVE)) {
4143
        virBufferAsprintf(buf, "<alias name='%s'/>\n", info->alias);
D
Daniel P. Berrange 已提交
4144 4145
    }

4146
    if (info->mastertype == VIR_DOMAIN_CONTROLLER_MASTER_USB) {
4147
        virBufferAsprintf(buf, "<master startport='%d'/>\n",
4148 4149 4150
                          info->master.usb.startport);
    }

4151
    if ((flags & VIR_DOMAIN_DEF_FORMAT_ALLOW_ROM) &&
4152 4153
        (info->rombar || info->romfile)) {

4154
        virBufferAddLit(buf, "<rom");
4155 4156
        if (info->rombar) {

J
Ján Tomko 已提交
4157
            const char *rombar = virTristateSwitchTypeToString(info->rombar);
4158 4159

            if (!rombar) {
4160 4161 4162
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unexpected rom bar value %d"),
                               info->rombar);
4163 4164 4165
                return -1;
            }
            virBufferAsprintf(buf, " bar='%s'", rombar);
4166
        }
4167
        if (info->romfile)
4168
            virBufferEscapeString(buf, " file='%s'", info->romfile);
4169
        virBufferAddLit(buf, "/>\n");
4170 4171
    }

4172 4173
    if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE ||
        info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390)
4174 4175 4176
        return 0;

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

4180
    switch ((virDomainDeviceAddressType) info->type) {
4181
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI:
4182
        virBufferAsprintf(buf, " domain='0x%.4x' bus='0x%.2x' slot='0x%.2x' function='0x%.1x'",
4183 4184 4185 4186
                          info->addr.pci.domain,
                          info->addr.pci.bus,
                          info->addr.pci.slot,
                          info->addr.pci.function);
4187 4188
        if (info->addr.pci.multi) {
           virBufferAsprintf(buf, " multifunction='%s'",
J
Ján Tomko 已提交
4189
                             virTristateSwitchTypeToString(info->addr.pci.multi));
4190
        }
4191 4192
        break;

4193
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE:
4194
        virBufferAsprintf(buf, " controller='%d' bus='%d' target='%d' unit='%d'",
4195 4196
                          info->addr.drive.controller,
                          info->addr.drive.bus,
4197
                          info->addr.drive.target,
4198 4199 4200
                          info->addr.drive.unit);
        break;

4201
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL:
4202
        virBufferAsprintf(buf, " controller='%d' bus='%d' port='%d'",
4203
                          info->addr.vioserial.controller,
4204 4205
                          info->addr.vioserial.bus,
                          info->addr.vioserial.port);
4206 4207
        break;

E
Eric Blake 已提交
4208
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCID:
4209
        virBufferAsprintf(buf, " controller='%d' slot='%d'",
E
Eric Blake 已提交
4210 4211 4212 4213
                          info->addr.ccid.controller,
                          info->addr.ccid.slot);
        break;

M
Marc-André Lureau 已提交
4214
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB:
4215
        virBufferAsprintf(buf, " bus='%d' port='%s'",
M
Marc-André Lureau 已提交
4216 4217 4218 4219
                          info->addr.usb.bus,
                          info->addr.usb.port);
        break;

4220 4221 4222 4223 4224
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO:
        if (info->addr.spaprvio.has_reg)
            virBufferAsprintf(buf, " reg='0x%llx'", info->addr.spaprvio.reg);
        break;

4225 4226 4227 4228 4229 4230 4231
    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;

4232 4233 4234
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO:
        break;

H
Hu Tao 已提交
4235 4236 4237 4238 4239 4240 4241
    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;

4242 4243 4244 4245 4246 4247
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DIMM:
        virBufferAsprintf(buf, " slot='%u'", info->addr.dimm.slot);
        virBufferAsprintf(buf, " base='0x%llx'", info->addr.dimm.base);

        break;

4248 4249 4250 4251
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390:
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE:
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST:
        break;
4252 4253 4254 4255 4256 4257
    }

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

4258
static int
4259
virDomainDeviceDriveAddressParseXML(xmlNodePtr node,
4260 4261
                                    virDomainDeviceDriveAddressPtr addr)
{
4262
    char *bus, *unit, *controller, *target;
4263 4264 4265 4266 4267 4268
    int ret = -1;

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

    controller = virXMLPropString(node, "controller");
    bus = virXMLPropString(node, "bus");
4269
    target = virXMLPropString(node, "target");
4270 4271 4272
    unit = virXMLPropString(node, "unit");

    if (controller &&
4273
        virStrToLong_uip(controller, NULL, 10, &addr->controller) < 0) {
4274 4275
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Cannot parse <address> 'controller' attribute"));
4276 4277 4278 4279
        goto cleanup;
    }

    if (bus &&
4280
        virStrToLong_uip(bus, NULL, 10, &addr->bus) < 0) {
4281 4282
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Cannot parse <address> 'bus' attribute"));
4283 4284 4285
        goto cleanup;
    }

4286
    if (target &&
4287
        virStrToLong_uip(target, NULL, 10, &addr->target) < 0) {
4288 4289
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Cannot parse <address> 'target' attribute"));
4290 4291 4292
        goto cleanup;
    }

4293
    if (unit &&
4294
        virStrToLong_uip(unit, NULL, 10, &addr->unit) < 0) {
4295 4296
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Cannot parse <address> 'unit' attribute"));
4297 4298 4299 4300 4301
        goto cleanup;
    }

    ret = 0;

4302
 cleanup:
4303 4304
    VIR_FREE(controller);
    VIR_FREE(bus);
4305
    VIR_FREE(target);
4306 4307 4308 4309
    VIR_FREE(unit);
    return ret;
}

4310 4311 4312 4313 4314 4315 4316

static int
virDomainDeviceVirtioSerialAddressParseXML(
    xmlNodePtr node,
    virDomainDeviceVirtioSerialAddressPtr addr
)
{
4317
    char *controller, *bus, *port;
4318 4319 4320 4321 4322 4323
    int ret = -1;

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

    controller = virXMLPropString(node, "controller");
    bus = virXMLPropString(node, "bus");
4324
    port = virXMLPropString(node, "port");
4325 4326

    if (controller &&
4327
        virStrToLong_uip(controller, NULL, 10, &addr->controller) < 0) {
4328 4329
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Cannot parse <address> 'controller' attribute"));
4330 4331 4332 4333
        goto cleanup;
    }

    if (bus &&
4334
        virStrToLong_uip(bus, NULL, 10, &addr->bus) < 0) {
4335 4336
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Cannot parse <address> 'bus' attribute"));
4337 4338 4339
        goto cleanup;
    }

4340
    if (port &&
4341
        virStrToLong_uip(port, NULL, 10, &addr->port) < 0) {
4342 4343
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Cannot parse <address> 'port' attribute"));
4344 4345 4346
        goto cleanup;
    }

4347 4348
    ret = 0;

4349
 cleanup:
4350 4351
    VIR_FREE(controller);
    VIR_FREE(bus);
E
Eric Blake 已提交
4352
    VIR_FREE(port);
4353 4354 4355
    return ret;
}

4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 4372
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 &&
4373
            virStrToLong_uip(cssid, NULL, 0, &addr->cssid) < 0) {
4374 4375 4376 4377 4378
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Cannot parse <address> 'cssid' attribute"));
            goto cleanup;
        }
        if (ssid &&
4379
            virStrToLong_uip(ssid, NULL, 0, &addr->ssid) < 0) {
4380 4381 4382 4383 4384
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Cannot parse <address> 'ssid' attribute"));
            goto cleanup;
        }
        if (devno &&
4385
            virStrToLong_uip(devno, NULL, 0, &addr->devno) < 0) {
4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406
            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;

4407
 cleanup:
4408 4409 4410 4411 4412 4413
    VIR_FREE(cssid);
    VIR_FREE(ssid);
    VIR_FREE(devno);
    return ret;
}

E
Eric Blake 已提交
4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426
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 &&
4427
        virStrToLong_uip(controller, NULL, 10, &addr->controller) < 0) {
4428 4429
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Cannot parse <address> 'controller' attribute"));
E
Eric Blake 已提交
4430 4431 4432 4433
        goto cleanup;
    }

    if (slot &&
4434
        virStrToLong_uip(slot, NULL, 10, &addr->slot) < 0) {
4435 4436
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Cannot parse <address> 'slot' attribute"));
E
Eric Blake 已提交
4437 4438 4439 4440 4441
        goto cleanup;
    }

    ret = 0;

4442
 cleanup:
E
Eric Blake 已提交
4443 4444 4445 4446 4447
    VIR_FREE(controller);
    VIR_FREE(slot);
    return ret;
}

4448 4449 4450 4451
static int
virDomainDeviceUSBAddressParseXML(xmlNodePtr node,
                                  virDomainDeviceUSBAddressPtr addr)
{
4452 4453
    char *port, *bus, *tmp;
    unsigned int p;
4454 4455 4456 4457 4458 4459 4460 4461
    int ret = -1;

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

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

    if (port &&
4462
        ((virStrToLong_uip(port, &tmp, 10, &p) < 0 || (*tmp != '\0' && *tmp != '.')) ||
4463 4464 4465
         (*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'))))) {
4466 4467
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Cannot parse <address> 'port' attribute"));
4468 4469 4470
        goto cleanup;
    }

4471 4472 4473
    addr->port = port;
    port = NULL;

4474
    if (bus &&
4475
        virStrToLong_uip(bus, NULL, 10, &addr->bus) < 0) {
4476 4477
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Cannot parse <address> 'bus' attribute"));
4478 4479 4480 4481 4482
        goto cleanup;
    }

    ret = 0;

4483
 cleanup:
4484 4485 4486 4487 4488
    VIR_FREE(bus);
    VIR_FREE(port);
    return ret;
}

4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500
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) {
4501 4502
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Cannot parse <address> 'reg' attribute"));
4503 4504 4505 4506 4507 4508 4509 4510
            ret = -1;
            goto cleanup;
        }

        addr->has_reg = true;
    }

    ret = 0;
4511
 cleanup:
4512 4513 4514 4515
    VIR_FREE(reg);
    return ret;
}

4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528
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) {
4529 4530
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Cannot parse <master> 'startport' attribute"));
4531 4532 4533 4534 4535
        goto cleanup;
    }

    ret = 0;

4536
 cleanup:
4537 4538 4539 4540
    VIR_FREE(startport);
    return ret;
}

4541 4542 4543
static int
virDomainDeviceBootParseXML(xmlNodePtr node,
                            int *bootIndex,
4544
                            virHashTablePtr bootHash)
4545 4546 4547 4548 4549 4550 4551
{
    char *order;
    int boot;
    int ret = -1;

    order = virXMLPropString(node, "order");
    if (!order) {
4552 4553
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing boot order attribute"));
4554 4555 4556
        goto cleanup;
    } else if (virStrToLong_i(order, NULL, 10, &boot) < 0 ||
               boot <= 0) {
4557 4558 4559
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("incorrect boot order '%s', expecting positive integer"),
                       order);
4560 4561 4562
        goto cleanup;
    }

4563 4564 4565 4566 4567
    if (bootHash) {
        if (virHashLookup(bootHash, order)) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("boot order '%s' used for more than one device"),
                           order);
4568 4569
            goto cleanup;
        }
4570 4571 4572

        if (virHashAddEntry(bootHash, order, (void *) 1) < 0)
            goto cleanup;
4573 4574 4575 4576 4577
    }

    *bootIndex = boot;
    ret = 0;

4578
 cleanup:
4579 4580 4581 4582
    VIR_FREE(order);
    return ret;
}

H
Hu Tao 已提交
4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596
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 &&
4597
        virStrToLong_uip(iobase, NULL, 16, &addr->iobase) < 0) {
H
Hu Tao 已提交
4598 4599 4600 4601 4602 4603
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Cannot parse <address> 'iobase' attribute"));
        goto cleanup;
    }

    if (irq &&
4604
        virStrToLong_uip(irq, NULL, 16, &addr->irq) < 0) {
H
Hu Tao 已提交
4605 4606 4607 4608 4609 4610
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Cannot parse <address> 'irq' attribute"));
        goto cleanup;
    }

    ret = 0;
4611
 cleanup:
H
Hu Tao 已提交
4612 4613 4614 4615 4616
    VIR_FREE(iobase);
    VIR_FREE(irq);
    return ret;
}

4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651

static int
virDomainDeviceDimmAddressParseXML(xmlNodePtr node,
                                   virDomainDeviceDimmAddressPtr addr)
{
    int ret = -1;
    char *tmp = NULL;

    if (!(tmp = virXMLPropString(node, "slot")) ||
        virStrToLong_uip(tmp, NULL, 10, &addr->slot) < 0) {
        virReportError(VIR_ERR_XML_ERROR,
                       _("invalid or missing dimm slot id '%s'"),
                       NULLSTR(tmp));
        goto cleanup;
    }
    VIR_FREE(tmp);

    if (!(tmp = virXMLPropString(node, "base")) ||
        virStrToLong_ullp(tmp, NULL, 16, &addr->base) < 0) {
        virReportError(VIR_ERR_XML_ERROR,
                       _("invalid or missing dimm base address '%s'"),
                       NULLSTR(tmp));
        goto cleanup;
    }
    VIR_FREE(tmp);

    ret = 0;

 cleanup:
    VIR_FREE(tmp);

    return ret;
}


4652 4653 4654 4655
/* Parse the XML definition for a device address
 * @param node XML nodeset to parse for device address definition
 */
static int
4656
virDomainDeviceInfoParseXML(xmlNodePtr node,
4657
                            virHashTablePtr bootHash,
4658
                            virDomainDeviceInfoPtr info,
E
Eric Blake 已提交
4659
                            unsigned int flags)
4660 4661 4662
{
    xmlNodePtr cur;
    xmlNodePtr address = NULL;
4663
    xmlNodePtr master = NULL;
D
Daniel P. Berrange 已提交
4664
    xmlNodePtr alias = NULL;
4665 4666
    xmlNodePtr boot = NULL;
    xmlNodePtr rom = NULL;
4667 4668 4669 4670 4671 4672 4673 4674
    char *type = NULL;
    int ret = -1;

    virDomainDeviceInfoClear(info);

    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
D
Daniel P. Berrange 已提交
4675
            if (alias == NULL &&
4676
                !(flags & VIR_DOMAIN_DEF_PARSE_INACTIVE) &&
D
Daniel P. Berrange 已提交
4677 4678 4679 4680
                xmlStrEqual(cur->name, BAD_CAST "alias")) {
                alias = cur;
            } else if (address == NULL &&
                       xmlStrEqual(cur->name, BAD_CAST "address")) {
4681
                address = cur;
4682 4683 4684
            } else if (master == NULL &&
                       xmlStrEqual(cur->name, BAD_CAST "master")) {
                master = cur;
4685
            } else if (boot == NULL &&
4686
                       (flags & VIR_DOMAIN_DEF_PARSE_ALLOW_BOOT) &&
4687 4688 4689
                       xmlStrEqual(cur->name, BAD_CAST "boot")) {
                boot = cur;
            } else if (rom == NULL &&
4690
                       (flags & VIR_DOMAIN_DEF_PARSE_ALLOW_ROM) &&
4691 4692
                       xmlStrEqual(cur->name, BAD_CAST "rom")) {
                rom = cur;
4693 4694 4695 4696 4697
            }
        }
        cur = cur->next;
    }

D
Daniel P. Berrange 已提交
4698 4699 4700
    if (alias)
        info->alias = virXMLPropString(alias, "name");

4701 4702 4703 4704 4705 4706
    if (master) {
        info->mastertype = VIR_DOMAIN_CONTROLLER_MASTER_USB;
        if (virDomainDeviceUSBMasterParseXML(master, &info->master.usb) < 0)
            goto cleanup;
    }

4707
    if (boot) {
4708
        if (virDomainDeviceBootParseXML(boot, &info->bootIndex, bootHash))
4709 4710 4711 4712 4713
            goto cleanup;
    }

    if (rom) {
        char *rombar = virXMLPropString(rom, "bar");
4714
        if (rombar &&
J
Ján Tomko 已提交
4715
            ((info->rombar = virTristateSwitchTypeFromString(rombar)) <= 0)) {
4716 4717
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown rom bar value '%s'"), rombar);
4718 4719 4720 4721
            VIR_FREE(rombar);
            goto cleanup;
        }
        VIR_FREE(rombar);
4722
        info->romfile = virXMLPropString(rom, "file");
4723 4724
    }

4725 4726 4727 4728 4729 4730
    if (!address)
        return 0;

    type = virXMLPropString(address, "type");

    if (type) {
4731
        if ((info->type = virDomainDeviceAddressTypeFromString(type)) <= 0) {
4732
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
4733
                           _("unknown address type '%s'"), type);
4734 4735 4736
            goto cleanup;
        }
    } else {
4737 4738
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("No type specified for device address"));
4739 4740 4741
        goto cleanup;
    }

4742
    switch ((virDomainDeviceAddressType) info->type) {
4743
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI:
4744
        if (virDevicePCIAddressParseXML(address, &info->addr.pci) < 0)
4745 4746 4747
            goto cleanup;
        break;

4748
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE:
4749
        if (virDomainDeviceDriveAddressParseXML(address, &info->addr.drive) < 0)
4750 4751 4752
            goto cleanup;
        break;

4753 4754 4755 4756 4757 4758
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL:
        if (virDomainDeviceVirtioSerialAddressParseXML
                (address, &info->addr.vioserial) < 0)
            goto cleanup;
        break;

E
Eric Blake 已提交
4759 4760 4761 4762 4763
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCID:
        if (virDomainDeviceCcidAddressParseXML(address, &info->addr.ccid) < 0)
            goto cleanup;
        break;

4764 4765 4766 4767 4768
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB:
        if (virDomainDeviceUSBAddressParseXML(address, &info->addr.usb) < 0)
            goto cleanup;
        break;

4769 4770 4771 4772 4773
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO:
        if (virDomainDeviceSpaprVioAddressParseXML(address, &info->addr.spaprvio) < 0)
            goto cleanup;
        break;

4774 4775 4776 4777 4778 4779
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW:
        if (virDomainDeviceCCWAddressParseXML
                (address, &info->addr.ccw) < 0)
            goto cleanup;
        break;

4780 4781 4782
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO:
        break;

H
Hu Tao 已提交
4783 4784 4785 4786 4787
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_ISA:
        if (virDomainDeviceISAAddressParseXML(address, &info->addr.isa) < 0)
            goto cleanup;
        break;

4788 4789 4790
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390:
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("virtio-s390 bus doesn't have an address"));
4791
        goto cleanup;
4792

4793 4794 4795 4796 4797
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DIMM:
        if (virDomainDeviceDimmAddressParseXML(address, &info->addr.dimm) < 0)
            goto cleanup;
        break;

4798 4799 4800
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE:
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST:
        break;
4801 4802 4803 4804
    }

    ret = 0;

4805
 cleanup:
D
Daniel P. Berrange 已提交
4806 4807
    if (ret == -1)
        VIR_FREE(info->alias);
4808 4809 4810 4811
    VIR_FREE(type);
    return ret;
}

4812 4813
static int
virDomainParseLegacyDeviceAddress(char *devaddr,
4814
                                  virDevicePCIAddressPtr pci)
4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828
{
    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;
}
4829

4830
static int
4831
virDomainHostdevSubsysUSBDefParseXML(xmlNodePtr node,
4832 4833 4834 4835
                                     virDomainHostdevDefPtr def)
{

    int ret = -1;
4836
    bool got_product, got_vendor;
4837
    xmlNodePtr cur;
4838
    char *startupPolicy = NULL;
4839
    char *autoAddress;
4840
    virDomainHostdevSubsysUSBPtr usbsrc = &def->source.subsys.u.usb;
4841 4842 4843 4844 4845

    if ((startupPolicy = virXMLPropString(node, "startupPolicy"))) {
        def->startupPolicy =
            virDomainStartupPolicyTypeFromString(startupPolicy);
        if (def->startupPolicy <= 0) {
4846
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
4847 4848 4849 4850 4851 4852 4853
                           _("Unknown startup policy '%s'"),
                           startupPolicy);
            VIR_FREE(startupPolicy);
            goto out;
        }
        VIR_FREE(startupPolicy);
    }
4854

4855 4856
    if ((autoAddress = virXMLPropString(node, "autoAddress"))) {
        if (STREQ(autoAddress, "yes"))
4857
            usbsrc->autoAddress = true;
4858 4859 4860
        VIR_FREE(autoAddress);
    }

4861 4862
    /* Product can validly be 0, so we need some extra help to determine
     * if it is uninitialized*/
4863 4864
    got_product = false;
    got_vendor = false;
4865 4866 4867 4868 4869 4870 4871 4872

    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) {
4873
                    got_vendor = true;
4874
                    if (virStrToLong_ui(vendor, NULL, 0, &usbsrc->vendor) < 0) {
4875 4876
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("cannot parse vendor id %s"), vendor);
4877 4878 4879 4880 4881
                        VIR_FREE(vendor);
                        goto out;
                    }
                    VIR_FREE(vendor);
                } else {
4882 4883
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   "%s", _("usb vendor needs id"));
4884 4885 4886 4887 4888 4889
                    goto out;
                }
            } else if (xmlStrEqual(cur->name, BAD_CAST "product")) {
                char* product = virXMLPropString(cur, "id");

                if (product) {
4890
                    got_product = true;
4891
                    if (virStrToLong_ui(product, NULL, 0,
4892
                                        &usbsrc->product) < 0) {
4893 4894 4895
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("cannot parse product %s"),
                                       product);
4896 4897 4898 4899 4900
                        VIR_FREE(product);
                        goto out;
                    }
                    VIR_FREE(product);
                } else {
4901 4902
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   "%s", _("usb product needs id"));
4903 4904 4905 4906 4907 4908 4909
                    goto out;
                }
            } else if (xmlStrEqual(cur->name, BAD_CAST "address")) {
                char *bus, *device;

                bus = virXMLPropString(cur, "bus");
                if (bus) {
4910
                    if (virStrToLong_ui(bus, NULL, 0, &usbsrc->bus) < 0) {
4911 4912
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("cannot parse bus %s"), bus);
4913 4914 4915 4916 4917
                        VIR_FREE(bus);
                        goto out;
                    }
                    VIR_FREE(bus);
                } else {
4918 4919
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   "%s", _("usb address needs bus id"));
4920 4921 4922 4923 4924
                    goto out;
                }

                device = virXMLPropString(cur, "device");
                if (device) {
4925
                    if (virStrToLong_ui(device, NULL, 0, &usbsrc->device) < 0) {
4926 4927 4928
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("cannot parse device %s"),
                                       device);
4929 4930 4931 4932 4933
                        VIR_FREE(device);
                        goto out;
                    }
                    VIR_FREE(device);
                } else {
4934 4935
                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                   _("usb address needs device id"));
4936 4937 4938
                    goto out;
                }
            } else {
4939 4940 4941
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unknown usb source type '%s'"),
                               cur->name);
4942 4943 4944 4945 4946 4947
                goto out;
            }
        }
        cur = cur->next;
    }

4948
    if (got_vendor && usbsrc->vendor == 0) {
4949 4950
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("vendor cannot be 0."));
4951 4952 4953 4954
        goto out;
    }

    if (!got_vendor && got_product) {
4955 4956
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing vendor"));
4957 4958 4959
        goto out;
    }
    if (got_vendor && !got_product) {
4960 4961
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing product"));
4962 4963 4964 4965
        goto out;
    }

    ret = 0;
4966
 out:
4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978
    return ret;
}

/* The internal XML for host PCI device's original states:
 *
 * <origstates>
 *   <unbind/>
 *   <removeslot/>
 *   <reprobe/>
 * </origstates>
 */
static int
4979
virDomainHostdevSubsysPCIOrigStatesDefParseXML(xmlNodePtr node,
4980 4981 4982 4983 4984 4985 4986 4987
                                               virDomainHostdevOrigStatesPtr def)
{
    xmlNodePtr cur;
    cur = node->children;

    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
            if (xmlStrEqual(cur->name, BAD_CAST "unbind")) {
4988
                def->states.pci.unbind_from_stub = true;
4989
            } else if (xmlStrEqual(cur->name, BAD_CAST "removeslot")) {
4990
                def->states.pci.remove_slot = true;
4991
            } else if (xmlStrEqual(cur->name, BAD_CAST "reprobe")) {
4992
                def->states.pci.reprobe = true;
4993
            } else {
4994 4995 4996
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unsupported element '%s' of 'origstates'"),
                               cur->name);
4997 4998 4999 5000 5001 5002 5003 5004 5005 5006
                return -1;
            }
        }
        cur = cur->next;
    }

    return 0;
}

static int
5007
virDomainHostdevSubsysPCIDefParseXML(xmlNodePtr node,
5008 5009 5010 5011 5012 5013 5014 5015 5016 5017
                                     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")) {
5018
                virDevicePCIAddressPtr addr =
5019
                    &def->source.subsys.u.pci.addr;
5020

5021
                if (virDevicePCIAddressParseXML(cur, addr) < 0)
5022
                    goto out;
5023
            } else if ((flags & VIR_DOMAIN_DEF_PARSE_STATUS) &&
5024 5025 5026 5027 5028
                       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,
5029
                                                      &def->info->addr.pci) < 0) {
5030 5031 5032
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Unable to parse devaddr parameter '%s'"),
                                   devaddr);
5033 5034 5035
                    VIR_FREE(devaddr);
                    goto out;
                }
5036
                def->info->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
5037
            } else if ((flags & VIR_DOMAIN_DEF_PARSE_PCI_ORIG_STATES) &&
5038 5039
                       xmlStrEqual(cur->name, BAD_CAST "origstates")) {
                virDomainHostdevOrigStatesPtr states = &def->origstates;
5040
                if (virDomainHostdevSubsysPCIOrigStatesDefParseXML(cur, states) < 0)
5041 5042
                    goto out;
            } else {
5043 5044 5045
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unknown pci source type '%s'"),
                               cur->name);
5046 5047 5048 5049 5050 5051 5052
                goto out;
            }
        }
        cur = cur->next;
    }

    ret = 0;
5053
 out:
5054 5055 5056
    return ret;
}

5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129
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 已提交
5130
static int
5131 5132
virDomainHostdevSubsysSCSIHostDefParseXML(xmlNodePtr sourcenode,
                                          virDomainHostdevSubsysSCSIPtr scsisrc)
H
Han Cheng 已提交
5133 5134 5135 5136 5137
{
    int ret = -1;
    bool got_address = false, got_adapter = false;
    xmlNodePtr cur;
    char *bus = NULL, *target = NULL, *unit = NULL;
5138
    virDomainHostdevSubsysSCSIHostPtr scsihostsrc = &scsisrc->u.host;
H
Han Cheng 已提交
5139

5140
    cur = sourcenode->children;
H
Han Cheng 已提交
5141 5142 5143 5144 5145 5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159
    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;
                }

5160
                if (virStrToLong_uip(bus, NULL, 0, &scsihostsrc->bus) < 0) {
H
Han Cheng 已提交
5161 5162 5163 5164 5165
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("cannot parse bus '%s'"), bus);
                    goto cleanup;
                }

5166
                if (virStrToLong_uip(target, NULL, 0,
5167
                                    &scsihostsrc->target) < 0) {
H
Han Cheng 已提交
5168 5169 5170 5171 5172
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("cannot parse target '%s'"), target);
                    goto cleanup;
                }

5173
                if (virStrToLong_ullp(unit, NULL, 0, &scsihostsrc->unit) < 0) {
H
Han Cheng 已提交
5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 5186
                    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;
                }
5187
                if (!(scsihostsrc->adapter = virXMLPropString(cur, "name"))) {
H
Han Cheng 已提交
5188 5189 5190 5191 5192 5193 5194 5195 5196 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210 5211
                    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;
5212
 cleanup:
H
Han Cheng 已提交
5213 5214 5215 5216 5217 5218
    VIR_FREE(bus);
    VIR_FREE(target);
    VIR_FREE(unit);
    return ret;
}

J
John Ferlan 已提交
5219 5220 5221 5222 5223 5224 5225 5226 5227 5228 5229 5230 5231 5232 5233 5234 5235 5236 5237 5238 5239 5240 5241 5242 5243 5244 5245 5246 5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264 5265 5266 5267 5268 5269 5270 5271 5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283
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;
}

5284 5285 5286 5287
static int
virDomainHostdevSubsysSCSIDefParseXML(xmlNodePtr sourcenode,
                                      virDomainHostdevSubsysSCSIPtr scsisrc)
{
J
John Ferlan 已提交
5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309
    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;
5310 5311
}

5312

5313
static int
5314 5315 5316 5317 5318
virDomainHostdevDefParseXMLSubsys(xmlNodePtr node,
                                  xmlXPathContextPtr ctxt,
                                  const char *type,
                                  virDomainHostdevDefPtr def,
                                  unsigned int flags)
5319 5320 5321
{
    xmlNodePtr sourcenode;
    char *managed = NULL;
O
Osier Yang 已提交
5322
    char *sgio = NULL;
5323
    char *rawio = NULL;
5324 5325
    char *backendStr = NULL;
    int backend;
5326
    int ret = -1;
5327
    virDomainHostdevSubsysPCIPtr pcisrc = &def->source.subsys.u.pci;
5328
    virDomainHostdevSubsysSCSIPtr scsisrc = &def->source.subsys.u.scsi;
5329 5330 5331 5332 5333 5334

    /* @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 已提交
5335
    if ((managed = virXMLPropString(node, "managed")) != NULL) {
5336
        if (STREQ(managed, "yes"))
5337
            def->managed = true;
5338 5339
    }

O
Osier Yang 已提交
5340
    sgio = virXMLPropString(node, "sgio");
5341
    rawio = virXMLPropString(node, "rawio");
O
Osier Yang 已提交
5342

5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353
    /* @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) {
5354
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
5355 5356
                           _("unknown host device source address type '%s'"),
                           type);
5357 5358 5359
            goto error;
        }
    } else {
5360 5361
        virReportError(VIR_ERR_XML_ERROR,
                       "%s", _("missing source address type"));
5362 5363 5364 5365
        goto error;
    }

    if (!(sourcenode = virXPathNode("./source", ctxt))) {
5366 5367
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Missing <source> element in hostdev device"));
5368 5369
        goto error;
    }
5370 5371 5372 5373 5374 5375 5376 5377 5378

    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 已提交
5379
    if (sgio) {
5380
        if (def->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI) {
O
Osier Yang 已提交
5381 5382 5383 5384 5385
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("sgio is only supported for scsi host device"));
            goto error;
        }

5386
        if ((scsisrc->sgio = virDomainDeviceSGIOTypeFromString(sgio)) <= 0) {
5387
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
O
Osier Yang 已提交
5388 5389 5390 5391 5392
                           _("unknown sgio mode '%s'"), sgio);
            goto error;
        }
    }

5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404 5405 5406 5407
    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;
        }
    }

5408 5409
    switch (def->source.subsys.type) {
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
5410
        if (virDomainHostdevSubsysPCIDefParseXML(sourcenode, def, flags) < 0)
5411
            goto error;
5412

5413
        backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT;
5414
        if ((backendStr = virXPathString("string(./driver/@name)", ctxt)) &&
5415
            (((backend = virDomainHostdevSubsysPCIBackendTypeFromString(backendStr)) < 0) ||
5416
             backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT)) {
5417
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
5418 5419 5420 5421
                           _("Unknown PCI device <driver name='%s'/> "
                             "has been specified"), backendStr);
            goto error;
        }
5422
        pcisrc->backend = backend;
5423

5424
        break;
5425

5426
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
5427
        if (virDomainHostdevSubsysUSBDefParseXML(sourcenode, def) < 0)
5428 5429
            goto error;
        break;
H
Han Cheng 已提交
5430 5431

    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
5432
        if (virDomainHostdevSubsysSCSIDefParseXML(sourcenode, scsisrc) < 0)
H
Han Cheng 已提交
5433 5434 5435
            goto error;
        break;

5436
    default:
5437 5438 5439
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("address type='%s' not supported in hostdev interfaces"),
                       virDomainHostdevSubsysTypeToString(def->source.subsys.type));
5440 5441
        goto error;
    }
5442

5443
    ret = 0;
5444
 error:
5445
    VIR_FREE(managed);
O
Osier Yang 已提交
5446
    VIR_FREE(sgio);
5447
    VIR_FREE(rawio);
5448
    VIR_FREE(backendStr);
5449 5450 5451
    return ret;
}

5452 5453 5454 5455
static virDomainNetIpDefPtr
virDomainNetIpParseXML(xmlNodePtr node)
{
    /* Parse the prefix in every case */
5456
    virDomainNetIpDefPtr ip = NULL, ret = NULL;
5457 5458 5459 5460 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471
    char *prefixStr = NULL;
    unsigned int prefixValue = 0;
    char *familyStr = NULL;
    int family = AF_UNSPEC;
    char *address = NULL;

    if (!(prefixStr = virXMLPropString(node, "prefix")) ||
        (virStrToLong_ui(prefixStr, NULL, 10, &prefixValue) < 0)) {
        // Don't shout, as some old config may not have a prefix
        VIR_DEBUG("Missing or invalid network prefix");
    }

    if (!(address = virXMLPropString(node, "address"))) {
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("Missing network address"));
5472
        goto cleanup;
5473 5474 5475 5476 5477 5478 5479 5480 5481 5482 5483
    }

    familyStr = virXMLPropString(node, "family");
    if (familyStr && STREQ(familyStr, "ipv4"))
        family = AF_INET;
    else if (familyStr && STREQ(familyStr, "ipv6"))
        family = AF_INET6;
    else
        family = virSocketAddrNumericFamily(address);

    if (VIR_ALLOC(ip) < 0)
5484
        goto cleanup;
5485 5486 5487 5488 5489

    if (virSocketAddrParse(&ip->address, address, family) < 0) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Failed to parse IP address: '%s'"),
                       address);
5490
        goto cleanup;
5491 5492 5493
    }
    ip->prefix = prefixValue;

5494 5495
    ret = ip;
    ip = NULL;
5496

5497
 cleanup:
5498 5499 5500 5501
    VIR_FREE(prefixStr);
    VIR_FREE(familyStr);
    VIR_FREE(address);
    VIR_FREE(ip);
5502
    return ret;
5503 5504
}

5505 5506 5507 5508 5509 5510 5511
static int
virDomainHostdevDefParseXMLCaps(xmlNodePtr node ATTRIBUTE_UNUSED,
                                xmlXPathContextPtr ctxt,
                                const char *type,
                                virDomainHostdevDefPtr def)
{
    xmlNodePtr sourcenode;
5512 5513
    xmlNodePtr *ipnodes = NULL;
    int nipnodes;
5514 5515
    xmlNodePtr *routenodes = NULL;
    int nroutenodes;
5516 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528
    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) {
5529
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
5530 5531 5532 5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 5548 5549 5550 5551 5552 5553 5554 5555 5556 5557 5558 5559 5560 5561 5562
                           _("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;
5563 5564 5565 5566 5567 5568 5569
    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;
        }
5570 5571 5572 5573 5574 5575 5576 5577 5578 5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589

        /* Parse possible IP addresses */
        if ((nipnodes = virXPathNodeSet("./ip", ctxt, &ipnodes)) < 0)
            goto error;

        if (nipnodes) {
            size_t i;
            for (i = 0; i < nipnodes; i++) {
                virDomainNetIpDefPtr ip = virDomainNetIpParseXML(ipnodes[i]);

                if (!ip)
                    goto error;

                if (VIR_APPEND_ELEMENT(def->source.caps.u.net.ips,
                                       def->source.caps.u.net.nips, ip) < 0) {
                    VIR_FREE(ip);
                    goto error;
                }
            }
        }
5590 5591 5592 5593 5594 5595 5596 5597

        /* Look for possible gateways */
        if ((nroutenodes = virXPathNodeSet("./route", ctxt, &routenodes)) < 0)
            goto error;

        if (nroutenodes) {
            size_t i;
            for (i = 0; i < nroutenodes; i++) {
5598
                virNetworkRouteDefPtr route = NULL;
5599

5600 5601 5602
                if (!(route = virNetworkRouteDefParseXML(_("Domain hostdev device"),
                                                         routenodes[i],
                                                         ctxt)))
5603 5604
                    goto error;

5605

5606 5607
                if (VIR_APPEND_ELEMENT(def->source.caps.u.net.routes,
                                       def->source.caps.u.net.nroutes, route) < 0) {
5608
                    virNetworkRouteDefFree(route);
5609 5610 5611 5612
                    goto error;
                }
            }
        }
5613
        break;
5614 5615 5616 5617 5618 5619 5620
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("address type='%s' not supported in hostdev interfaces"),
                       virDomainHostdevCapsTypeToString(def->source.caps.type));
        goto error;
    }
    ret = 0;
5621
 error:
5622
    VIR_FREE(ipnodes);
5623
    VIR_FREE(routenodes);
5624 5625 5626
    return ret;
}

5627
int
H
Han Cheng 已提交
5628 5629 5630
virDomainDeviceFindControllerModel(virDomainDefPtr def,
                                   virDomainDeviceInfoPtr info,
                                   int controllerType)
5631 5632
{
    int model = -1;
5633
    size_t i;
5634 5635 5636

    for (i = 0; i < def->ncontrollers; i++) {
        if (def->controllers[i]->type == controllerType &&
H
Han Cheng 已提交
5637
            def->controllers[i]->idx == info->addr.drive.controller)
5638 5639 5640 5641 5642 5643
            model = def->controllers[i]->model;
    }

    return model;
}

5644 5645 5646 5647 5648
virDomainDiskDefPtr
virDomainDiskFindByBusAndDst(virDomainDefPtr def,
                             int bus,
                             char *dst)
{
5649
    size_t i;
5650 5651 5652 5653

    if (!dst)
        return NULL;

5654
    for (i = 0; i < def->ndisks; i++) {
5655 5656 5657 5658 5659 5660 5661 5662 5663
        if (def->disks[i]->bus == bus &&
            STREQ(def->disks[i]->dst, dst)) {
            return def->disks[i];
        }
    }

    return NULL;
}

5664

5665
int
5666
virDomainDiskDefAssignAddress(virDomainXMLOptionPtr xmlopt,
5667 5668
                              virDomainDiskDefPtr def,
                              const virDomainDef *vmdef)
5669 5670
{
    int idx = virDiskNameToIndex(def->dst);
5671 5672 5673 5674
    if (idx < 0) {
        virReportError(VIR_ERR_XML_ERROR,
                       _("Unknown disk name '%s' and no address specified"),
                       def->dst);
5675
        return -1;
5676
    }
5677 5678

    switch (def->bus) {
5679 5680 5681 5682
    case VIR_DOMAIN_DISK_BUS_SCSI: {
        unsigned int controller;
        unsigned int unit;

5683
        def->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE;
5684

5685
        if (xmlopt->config.hasWideSCSIBus) {
5686 5687 5688 5689 5690
            /* 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.
             */
5691 5692
            controller = idx / 15;
            unit = idx % 15;
5693 5694

            /* Skip the SCSI controller at unit 7 */
5695 5696
            if (unit >= 7)
                ++unit;
5697 5698 5699
        } else {
            /* For a narrow SCSI bus we define the default mapping to be
             * 7 units per bus, 1 bus per controller, many controllers */
5700 5701
            controller = idx / 7;
            unit = idx % 7;
5702 5703
        }

5704 5705 5706 5707 5708 5709 5710 5711 5712 5713 5714
        if (virDomainDriveAddressIsUsedByHostdev(vmdef,
                                                 VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI,
                                                 controller, 0, 0, unit)) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("using disk target name '%s' conflicts with "
                             "SCSI host device address controller='%u' "
                             "bus='%u' target='%u' unit='%u"),
                           def->dst, controller, 0, 0, unit);
            return -1;
        }

5715 5716 5717 5718
        def->info.addr.drive.controller = controller;
        def->info.addr.drive.bus = 0;
        def->info.addr.drive.target = 0;
        def->info.addr.drive.unit = unit;
5719
        break;
5720
    }
5721 5722 5723 5724 5725 5726 5727 5728 5729 5730

    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 已提交
5731 5732 5733 5734 5735 5736 5737 5738 5739
    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;

5740 5741 5742 5743 5744 5745 5746 5747 5748 5749 5750 5751 5752
    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;
    }
5753 5754

    return 0;
5755 5756
}

5757 5758
static virSecurityLabelDefPtr
virSecurityLabelDefParseXML(xmlXPathContextPtr ctxt,
5759
                            unsigned int flags)
E
Eric Blake 已提交
5760 5761
{
    char *p;
5762
    virSecurityLabelDefPtr seclabel = NULL;
E
Eric Blake 已提交
5763

5764 5765 5766 5767
    p = virXPathStringLimit("string(./@model)",
                            VIR_SECURITY_MODEL_BUFLEN - 1, ctxt);

    if (!(seclabel = virSecurityLabelDefNew(p)))
5768
        goto error;
5769
    VIR_FREE(p);
E
Eric Blake 已提交
5770

5771 5772 5773
    /* set default value */
    seclabel->type = VIR_DOMAIN_SECLABEL_DYNAMIC;

5774
    p = virXPathStringLimit("string(./@type)",
5775 5776 5777 5778
                            VIR_SECURITY_LABEL_BUFLEN - 1, ctxt);
    if (p) {
        seclabel->type = virDomainSeclabelTypeFromString(p);
        if (seclabel->type <= 0) {
5779
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
5780
                           _("invalid security type '%s'"), p);
E
Eric Blake 已提交
5781 5782
            goto error;
        }
5783
    }
5784

5785 5786 5787 5788 5789
    if (seclabel->type == VIR_DOMAIN_SECLABEL_STATIC ||
        seclabel->type == VIR_DOMAIN_SECLABEL_NONE)
        seclabel->relabel = false;

    VIR_FREE(p);
5790
    p = virXPathStringLimit("string(./@relabel)",
E
Eric Blake 已提交
5791
                            VIR_SECURITY_LABEL_BUFLEN-1, ctxt);
5792
    if (p) {
E
Eric Blake 已提交
5793
        if (STREQ(p, "yes")) {
5794
            seclabel->relabel = true;
E
Eric Blake 已提交
5795
        } else if (STREQ(p, "no")) {
5796
            seclabel->relabel = false;
E
Eric Blake 已提交
5797
        } else {
5798 5799
            virReportError(VIR_ERR_XML_ERROR,
                           _("invalid security relabel value %s"), p);
5800
            goto error;
E
Eric Blake 已提交
5801 5802
        }
    }
5803
    VIR_FREE(p);
E
Eric Blake 已提交
5804

5805 5806 5807 5808 5809 5810 5811 5812 5813 5814 5815 5816
    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;
    }
5817 5818 5819 5820

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

5821
    if (STREQ_NULLABLE(seclabel->model, "none")) {
5822
        if (flags & VIR_DOMAIN_DEF_PARSE_INACTIVE) {
5823
            /* Fix older configurations */
5824 5825
            seclabel->type = VIR_DOMAIN_SECLABEL_NONE;
            seclabel->relabel = false;
5826
        } else {
5827
            if (seclabel->type != VIR_DOMAIN_SECLABEL_NONE) {
5828 5829
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("unsupported type='%s' to model 'none'"),
5830
                               virDomainSeclabelTypeToString(seclabel->type));
5831 5832 5833 5834 5835
                goto error;
            }
            /* combination of relabel='yes' and type='static'
             * is checked a few lines above. */
        }
5836
        return seclabel;
5837
    }
5838

E
Eric Blake 已提交
5839
    /* Only parse label, if using static labels, or
5840
     * if the 'live' VM XML is requested
E
Eric Blake 已提交
5841
     */
5842
    if (seclabel->type == VIR_DOMAIN_SECLABEL_STATIC ||
5843
        (!(flags & VIR_DOMAIN_DEF_PARSE_INACTIVE) &&
5844
         seclabel->type != VIR_DOMAIN_SECLABEL_NONE)) {
5845
        p = virXPathStringLimit("string(./label[1])",
E
Eric Blake 已提交
5846
                                VIR_SECURITY_LABEL_BUFLEN-1, ctxt);
5847
        if (p == NULL) {
5848 5849
            virReportError(VIR_ERR_XML_ERROR,
                           "%s", _("security label is missing"));
5850
            goto error;
E
Eric Blake 已提交
5851 5852
        }

5853
        seclabel->label = p;
5854
        p = NULL;
E
Eric Blake 已提交
5855 5856 5857
    }

    /* Only parse imagelabel, if requested live XML with relabeling */
5858
    if (seclabel->relabel &&
5859
        (!(flags & VIR_DOMAIN_DEF_PARSE_INACTIVE) &&
5860
         seclabel->type != VIR_DOMAIN_SECLABEL_NONE)) {
5861
        p = virXPathStringLimit("string(./imagelabel[1])",
E
Eric Blake 已提交
5862 5863
                                VIR_SECURITY_LABEL_BUFLEN-1, ctxt);
        if (p == NULL) {
5864 5865
            virReportError(VIR_ERR_XML_ERROR,
                           "%s", _("security imagelabel is missing"));
E
Eric Blake 已提交
5866 5867
            goto error;
        }
5868
        seclabel->imagelabel = p;
5869
        p = NULL;
E
Eric Blake 已提交
5870 5871
    }

E
Eric Blake 已提交
5872
    /* Only parse baselabel for dynamic label type */
5873
    if (seclabel->type == VIR_DOMAIN_SECLABEL_DYNAMIC) {
5874
        p = virXPathStringLimit("string(./baselabel[1])",
E
Eric Blake 已提交
5875
                                VIR_SECURITY_LABEL_BUFLEN-1, ctxt);
5876
        seclabel->baselabel = p;
5877
        p = NULL;
E
Eric Blake 已提交
5878 5879
    }

5880
    return seclabel;
E
Eric Blake 已提交
5881

5882
 error:
5883 5884
    VIR_FREE(p);
    virSecurityLabelDefFree(seclabel);
5885
    return NULL;
E
Eric Blake 已提交
5886 5887
}

5888
static int
5889
virSecurityLabelDefsParseXML(virDomainDefPtr def,
5890 5891 5892
                             xmlXPathContextPtr ctxt,
                             virCapsPtr caps,
                             unsigned int flags)
5893
{
5894
    size_t i = 0, j;
5895
    int n;
5896
    xmlNodePtr *list = NULL, saved_node;
5897
    virCapsHostPtr host = &caps->host;
5898

5899 5900 5901 5902
    /* Check args and save context */
    if (def == NULL || ctxt == NULL)
        return 0;
    saved_node = ctxt->node;
5903

5904
    /* Allocate a security labels based on XML */
5905 5906 5907
    if ((n = virXPathNodeSet("./seclabel", ctxt, &list)) < 0)
        goto error;
    if (n == 0)
5908 5909
        return 0;

5910
    if (VIR_ALLOC_N(def->seclabels, n) < 0)
5911
        goto error;
5912

5913 5914
    /* Parse each "seclabel" tag */
    for (i = 0; i < n; i++) {
5915 5916
        virSecurityLabelDefPtr seclabel;

5917
        ctxt->node = list[i];
5918
        if (!(seclabel = virSecurityLabelDefParseXML(ctxt, flags)))
5919
            goto error;
5920 5921 5922 5923

        for (j = 0; j < i; j++) {
            if (STREQ_NULLABLE(seclabel->model, def->seclabels[j]->model)) {
                virReportError(VIR_ERR_XML_DETAIL,
E
Erik Skultety 已提交
5924
                               _("seclabel for model %s is already provided"),
5925 5926 5927 5928 5929 5930 5931
                               seclabel->model);
                virSecurityLabelDefFree(seclabel);
                goto error;
            }
        }

        def->seclabels[i] = seclabel;
5932
    }
5933 5934 5935
    def->nseclabels = n;
    ctxt->node = saved_node;
    VIR_FREE(list);
5936

5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 5949
    /* 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 &&
5950
             (flags & VIR_DOMAIN_DEF_PARSE_INACTIVE))) {
5951 5952 5953
            /* Copy model from host. */
            VIR_DEBUG("Found seclabel without a model, using '%s'",
                      host->secModels[0].model);
5954
            if (VIR_STRDUP(def->seclabels[0]->model, host->secModels[0].model) < 0)
5955
                goto error;
5956 5957

            if (STREQ(def->seclabels[0]->model, "none") &&
5958
                flags & VIR_DOMAIN_DEF_PARSE_INACTIVE) {
5959 5960 5961 5962
                /* Fix older configurations */
                def->seclabels[0]->type = VIR_DOMAIN_SECLABEL_NONE;
                def->seclabels[0]->relabel = false;
            }
5963 5964 5965 5966 5967 5968 5969 5970 5971
        } else {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("missing security model in domain seclabel"));
            goto error;
        }
    }

    /* Checking missing model information */
    if (def->nseclabels > 1) {
5972
        for (; n; n--) {
5973 5974
            if (def->seclabels[n - 1]->model == NULL) {
                virReportError(VIR_ERR_XML_ERROR, "%s",
5975 5976
                               _("missing security model "
                                 "when using multiple labels"));
5977 5978
                goto error;
            }
5979 5980
        }
    }
5981

5982
    return 0;
5983

5984
 error:
5985
    ctxt->node = saved_node;
5986
    for (; i > 0; i--)
5987 5988
        virSecurityLabelDefFree(def->seclabels[i - 1]);
    VIR_FREE(def->seclabels);
5989
    def->nseclabels = 0;
5990 5991 5992
    VIR_FREE(list);
    return -1;
}
5993

5994
/* Parse the <seclabel> from a disk or character device. */
5995
static int
5996 5997
virSecurityDeviceLabelDefParseXML(virSecurityDeviceLabelDefPtr **seclabels_rtn,
                                  size_t *nseclabels_rtn,
5998
                                  virSecurityLabelDefPtr *vmSeclabels,
5999 6000
                                  int nvmSeclabels, xmlXPathContextPtr ctxt,
                                  unsigned int flags)
6001
{
6002
    virSecurityDeviceLabelDefPtr *seclabels = NULL;
6003
    size_t nseclabels = 0;
6004 6005
    int n;
    size_t i, j;
6006 6007
    xmlNodePtr *list = NULL;
    virSecurityLabelDefPtr vmDef = NULL;
6008
    char *model, *relabel, *label, *labelskip;
6009

6010 6011 6012
    if ((n = virXPathNodeSet("./seclabel", ctxt, &list)) < 0)
        goto error;
    if (n == 0)
6013 6014
        return 0;

6015
    if (VIR_ALLOC_N(seclabels, n) < 0)
6016
        goto error;
6017
    nseclabels = n;
6018
    for (i = 0; i < n; i++) {
6019
        if (VIR_ALLOC(seclabels[i]) < 0)
6020
            goto error;
6021 6022
    }

6023 6024 6025
    for (i = 0; i < n; i++) {
        /* get model associated to this override */
        model = virXMLPropString(list[i], "model");
6026 6027
        if (model) {
            /* find the security label that it's being overridden */
6028 6029 6030 6031 6032 6033
            for (j = 0; j < nvmSeclabels; j++) {
                if (STREQ(vmSeclabels[j]->model, model)) {
                    vmDef = vmSeclabels[j];
                    break;
                }
            }
6034 6035 6036 6037 6038 6039 6040 6041 6042

            /* check for duplicate seclabels */
            for (j = 0; j < i; j++) {
                if (STREQ_NULLABLE(model, seclabels[j]->model)) {
                    virReportError(VIR_ERR_XML_DETAIL,
                                   _("seclabel for model %s is already provided"), model);
                    goto error;
                }
            }
6043
            seclabels[i]->model = model;
6044 6045 6046
        }

        /* Can't use overrides if top-level doesn't allow relabeling.  */
6047
        if (vmDef && !vmDef->relabel) {
6048 6049 6050 6051 6052 6053 6054 6055 6056
            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")) {
6057
                seclabels[i]->relabel = true;
6058
            } else if (STREQ(relabel, "no")) {
6059
                seclabels[i]->relabel = false;
6060 6061 6062 6063 6064 6065 6066 6067 6068
            } else {
                virReportError(VIR_ERR_XML_ERROR,
                               _("invalid security relabel value %s"),
                               relabel);
                VIR_FREE(relabel);
                goto error;
            }
            VIR_FREE(relabel);
        } else {
6069
            seclabels[i]->relabel = true;
6070 6071
        }

6072 6073 6074
        /* labelskip is only parsed on live images */
        labelskip = virXMLPropString(list[i], "labelskip");
        seclabels[i]->labelskip = false;
6075
        if (labelskip && !(flags & VIR_DOMAIN_DEF_PARSE_INACTIVE))
6076 6077 6078
            seclabels[i]->labelskip = STREQ(labelskip, "yes");
        VIR_FREE(labelskip);

6079 6080 6081
        ctxt->node = list[i];
        label = virXPathStringLimit("string(./label)",
                                    VIR_SECURITY_LABEL_BUFLEN-1, ctxt);
6082
        seclabels[i]->label = label;
6083

6084
        if (label && !seclabels[i]->relabel) {
6085 6086 6087
            virReportError(VIR_ERR_XML_ERROR,
                           _("Cannot specify a label if relabelling is "
                             "turned off. model=%s"),
6088
                             NULLSTR(seclabels[i]->model));
6089 6090 6091 6092
            goto error;
        }
    }
    VIR_FREE(list);
6093 6094 6095 6096

    *nseclabels_rtn = nseclabels;
    *seclabels_rtn = seclabels;

6097
    return 0;
6098

6099
 error:
6100
    for (i = 0; i < nseclabels; i++)
6101 6102
        virSecurityDeviceLabelDefFree(seclabels[i]);
    VIR_FREE(seclabels);
6103 6104
    VIR_FREE(list);
    return -1;
6105 6106 6107
}


6108 6109 6110 6111 6112 6113 6114 6115 6116 6117 6118 6119
/* 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;

6120
    if (VIR_ALLOC(def) < 0)
6121 6122 6123 6124 6125
        return NULL;

    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
E
Eric Blake 已提交
6126
            if (!key && xmlStrEqual(cur->name, BAD_CAST "key")) {
6127
                key = (char *)xmlNodeGetContent(cur);
E
Eric Blake 已提交
6128 6129
            } else if (!lockspace &&
                       xmlStrEqual(cur->name, BAD_CAST "lockspace")) {
6130
                lockspace = (char *)xmlNodeGetContent(cur);
E
Eric Blake 已提交
6131 6132
            } else if (!path &&
                       xmlStrEqual(cur->name, BAD_CAST "target")) {
6133 6134 6135 6136 6137 6138 6139 6140
                path = virXMLPropString(cur, "path");
                offset = virXMLPropString(cur, "offset");
            }
        }
        cur = cur->next;
    }

    if (!key) {
6141 6142
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Missing 'key' element for lease"));
6143 6144 6145
        goto error;
    }
    if (!path) {
6146 6147
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Missing 'target' element for lease"));
6148 6149 6150 6151 6152
        goto error;
    }

    if (offset &&
        virStrToLong_ull(offset, NULL, 10, &def->offset) < 0) {
6153 6154
        virReportError(VIR_ERR_XML_ERROR,
                       _("Malformed lease target offset %s"), offset);
6155 6156 6157 6158 6159 6160 6161 6162
        goto error;
    }

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

6163
 cleanup:
6164 6165 6166 6167 6168 6169 6170 6171 6172 6173 6174 6175 6176
    VIR_FREE(lockspace);
    VIR_FREE(key);
    VIR_FREE(path);
    VIR_FREE(offset);

    return def;

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

6177 6178
static int
virDomainDiskSourcePoolDefParse(xmlNodePtr node,
6179
                                virStorageSourcePoolDefPtr *srcpool)
6180
{
6181
    char *mode = NULL;
6182
    virStorageSourcePoolDefPtr source;
6183 6184
    int ret = -1;

6185 6186 6187 6188 6189 6190 6191
    *srcpool = NULL;

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

    source->pool = virXMLPropString(node, "pool");
    source->volume = virXMLPropString(node, "volume");
6192
    mode = virXMLPropString(node, "mode");
6193 6194

    /* CD-ROM and Floppy allows no source */
6195 6196 6197 6198
    if (!source->pool && !source->volume) {
        ret = 0;
        goto cleanup;
    }
6199

6200
    if (!source->pool || !source->volume) {
6201 6202 6203 6204 6205 6206
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("'pool' and 'volume' must be specified together "
                         "for 'pool' type source"));
        goto cleanup;
    }

6207
    if (mode &&
6208
        (source->mode = virStorageSourcePoolModeTypeFromString(mode)) <= 0) {
6209
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
6210 6211 6212 6213 6214
                       _("unknown source mode '%s' for volume type disk"),
                       mode);
        goto cleanup;
    }

6215 6216
    *srcpool = source;
    source = NULL;
6217 6218
    ret = 0;

6219
 cleanup:
6220
    virStorageSourcePoolDefFree(source);
6221
    VIR_FREE(mode);
6222 6223 6224
    return ret;
}

6225

6226
int
6227
virDomainDiskSourceParse(xmlNodePtr node,
6228
                         xmlXPathContextPtr ctxt,
6229
                         virStorageSourcePtr src)
6230 6231
{
    int ret = -1;
6232
    char *protocol = NULL;
6233 6234 6235
    xmlNodePtr saveNode = ctxt->node;

    ctxt->node = node;
6236

6237
    switch ((virStorageType)src->type) {
E
Eric Blake 已提交
6238
    case VIR_STORAGE_TYPE_FILE:
6239
        src->path = virXMLPropString(node, "file");
6240
        break;
E
Eric Blake 已提交
6241
    case VIR_STORAGE_TYPE_BLOCK:
6242
        src->path = virXMLPropString(node, "dev");
6243
        break;
E
Eric Blake 已提交
6244
    case VIR_STORAGE_TYPE_DIR:
6245
        src->path = virXMLPropString(node, "dir");
6246
        break;
E
Eric Blake 已提交
6247
    case VIR_STORAGE_TYPE_NETWORK:
6248 6249 6250 6251
        if (!(protocol = virXMLPropString(node, "protocol"))) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("missing network source protocol type"));
            goto cleanup;
6252
        }
6253

6254
        if ((src->protocol = virStorageNetProtocolTypeFromString(protocol)) <= 0) {
6255
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
6256 6257
                           _("unknown protocol type '%s'"), protocol);
            goto cleanup;
6258 6259
        }

6260 6261
        if (!(src->path = virXMLPropString(node, "name")) &&
            src->protocol != VIR_STORAGE_NET_PROTOCOL_NBD) {
6262
            virReportError(VIR_ERR_XML_ERROR, "%s",
6263
                           _("missing name for disk source"));
6264
            goto cleanup;
6265
        }
6266

6267 6268 6269 6270 6271 6272 6273 6274 6275 6276 6277 6278 6279 6280 6281 6282 6283 6284 6285 6286 6287
        /* 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';
        }

6288 6289 6290
        /* snapshot currently works only for remote disks */
        src->snapshot = virXPathString("string(./snapshot/@name)", ctxt);

6291 6292 6293
        /* config file currently only works with remote disks */
        src->configFile = virXPathString("string(./config/@file)", ctxt);

6294 6295
        if (virDomainStorageHostParse(node, &src->hosts, &src->nhosts) < 0)
            goto cleanup;
6296
        break;
E
Eric Blake 已提交
6297
    case VIR_STORAGE_TYPE_VOLUME:
6298
        if (virDomainDiskSourcePoolDefParse(node, &src->srcpool) < 0)
6299
            goto cleanup;
6300
        break;
6301 6302
    case VIR_STORAGE_TYPE_NONE:
    case VIR_STORAGE_TYPE_LAST:
6303 6304
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected disk type %s"),
6305
                       virStorageTypeToString(src->type));
6306
        goto cleanup;
6307 6308
    }

6309 6310 6311
    /* 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 */
6312 6313
    if (src->path && !*src->path)
        VIR_FREE(src->path);
6314 6315 6316

    ret = 0;

6317
 cleanup:
6318
    VIR_FREE(protocol);
6319
    ctxt->node = saveNode;
6320 6321 6322 6323
    return ret;
}


6324 6325 6326 6327 6328 6329 6330 6331 6332 6333 6334 6335 6336 6337 6338 6339 6340 6341 6342 6343 6344 6345 6346 6347 6348 6349
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);
6350
    if (backingStore->type <= 0) {
6351 6352 6353 6354 6355 6356 6357 6358 6359 6360 6361 6362
        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);
6363
    if (backingStore->format <= 0) {
6364 6365 6366 6367 6368 6369 6370 6371 6372 6373 6374
        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;
    }

6375
    if (virDomainDiskSourceParse(source, ctxt, backingStore) < 0 ||
6376 6377 6378 6379 6380 6381 6382 6383 6384 6385 6386 6387 6388 6389 6390 6391
        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;
}


6392 6393
#define VENDOR_LEN  8
#define PRODUCT_LEN 16
6394

6395 6396 6397 6398
/* Parse the XML definition for a disk
 * @param node XML nodeset to parse for disk definition
 */
static virDomainDiskDefPtr
6399
virDomainDiskDefParseXML(virDomainXMLOptionPtr xmlopt,
6400
                         xmlNodePtr node,
L
Lei Li 已提交
6401
                         xmlXPathContextPtr ctxt,
6402
                         virHashTablePtr bootHash,
6403 6404
                         virSecurityLabelDefPtr* vmSeclabels,
                         int nvmSeclabels,
E
Eric Blake 已提交
6405
                         unsigned int flags)
6406
{
6407
    virDomainDiskDefPtr def;
6408
    xmlNodePtr sourceNode = NULL;
6409
    xmlNodePtr cur;
L
Lei Li 已提交
6410
    xmlNodePtr save_ctxt = ctxt->node;
6411 6412
    char *type = NULL;
    char *device = NULL;
6413
    char *snapshot = NULL;
6414
    char *rawio = NULL;
O
Osier Yang 已提交
6415
    char *sgio = NULL;
6416 6417
    char *driverName = NULL;
    char *driverType = NULL;
6418
    bool source = false;
6419
    char *target = NULL;
J
J.B. Joret 已提交
6420
    char *trans = NULL;
6421
    char *bus = NULL;
6422
    char *cachetag = NULL;
6423
    char *error_policy = NULL;
6424
    char *rerror_policy = NULL;
M
Matthias Dahl 已提交
6425
    char *iotag = NULL;
6426
    char *ioeventfd = NULL;
6427
    char *event_idx = NULL;
O
Osier Yang 已提交
6428
    char *copy_on_read = NULL;
6429
    char *driverIOThread = NULL;
6430
    char *devaddr = NULL;
6431
    virStorageEncryptionPtr encryption = NULL;
6432
    char *serial = NULL;
6433
    char *startupPolicy = NULL;
6434
    virStorageAuthDefPtr authdef = NULL;
6435
    char *tray = NULL;
6436
    char *removable = NULL;
6437 6438
    char *logical_block_size = NULL;
    char *physical_block_size = NULL;
O
Osier Yang 已提交
6439
    char *wwn = NULL;
6440 6441
    char *vendor = NULL;
    char *product = NULL;
O
Osier Yang 已提交
6442
    char *discard = NULL;
E
Eric Blake 已提交
6443 6444
    char *mirrorFormat = NULL;
    char *mirrorType = NULL;
6445
    char *domain_name = NULL;
6446 6447
    int expected_secret_usage = -1;
    int auth_secret_usage = -1;
6448
    int ret = 0;
6449

6450
    if (!(def = virDomainDiskDefNew(xmlopt)))
6451 6452
        return NULL;

J
J.B. Joret 已提交
6453 6454 6455 6456 6457
    def->geometry.cylinders = 0;
    def->geometry.heads = 0;
    def->geometry.sectors = 0;
    def->geometry.trans = VIR_DOMAIN_DISK_TRANS_DEFAULT;

V
Viktor Mihajlovski 已提交
6458 6459
    def->blockio.logical_block_size = 0;
    def->blockio.physical_block_size = 0;
6460

L
Lei Li 已提交
6461 6462
    ctxt->node = node;

6463 6464
    type = virXMLPropString(node, "type");
    if (type) {
6465
        if ((def->src->type = virStorageTypeFromString(type)) <= 0) {
6466
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
6467
                           _("unknown disk type '%s'"), type);
6468 6469 6470
            goto error;
        }
    } else {
6471
        def->src->type = VIR_STORAGE_TYPE_FILE;
6472 6473
    }

6474 6475
    snapshot = virXMLPropString(node, "snapshot");

6476
    rawio = virXMLPropString(node, "rawio");
O
Osier Yang 已提交
6477
    sgio = virXMLPropString(node, "sgio");
6478

6479 6480 6481
    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
6482
            if (!source && xmlStrEqual(cur->name, BAD_CAST "source")) {
6483 6484
                sourceNode = cur;

6485
                if (virDomainDiskSourceParse(cur, ctxt, def->src) < 0)
6486
                    goto error;
6487 6488

                source = true;
6489

6490 6491
                if (def->src->type == VIR_STORAGE_TYPE_NETWORK) {
                    if (def->src->protocol == VIR_STORAGE_NET_PROTOCOL_ISCSI)
6492
                        expected_secret_usage = VIR_SECRET_USAGE_TYPE_ISCSI;
6493
                    else if (def->src->protocol == VIR_STORAGE_NET_PROTOCOL_RBD)
6494
                        expected_secret_usage = VIR_SECRET_USAGE_TYPE_CEPH;
6495
                }
6496

6497 6498
                startupPolicy = virXMLPropString(cur, "startupPolicy");

E
Eric Blake 已提交
6499 6500
            } else if (!target &&
                       xmlStrEqual(cur->name, BAD_CAST "target")) {
6501 6502
                target = virXMLPropString(cur, "dev");
                bus = virXMLPropString(cur, "bus");
6503
                tray = virXMLPropString(cur, "tray");
6504
                removable = virXMLPropString(cur, "removable");
6505 6506 6507 6508 6509 6510

                /* HACK: Work around for compat with Xen
                 * driver in previous libvirt releases */
                if (target &&
                    STRPREFIX(target, "ioemu:"))
                    memmove(target, target+6, strlen(target)-5);
6511 6512 6513
            } else if (!domain_name &&
                       xmlStrEqual(cur->name, BAD_CAST "backenddomain")) {
                domain_name = virXMLPropString(cur, "name");
J
J.B. Joret 已提交
6514 6515 6516 6517 6518 6519 6520 6521 6522 6523 6524 6525 6526 6527 6528 6529 6530 6531 6532 6533 6534 6535 6536
            } 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) {
6537
                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
J
J.B. Joret 已提交
6538 6539 6540 6541 6542
                                       _("invalid translation value '%s'"),
                                       trans);
                        goto error;
                    }
                }
V
Viktor Mihajlovski 已提交
6543
            } else if (xmlStrEqual(cur->name, BAD_CAST "blockio")) {
6544 6545 6546 6547
                logical_block_size =
                    virXMLPropString(cur, "logical_block_size");
                if (logical_block_size &&
                    virStrToLong_ui(logical_block_size, NULL, 0,
V
Viktor Mihajlovski 已提交
6548
                                    &def->blockio.logical_block_size) < 0) {
6549 6550 6551 6552 6553 6554 6555 6556 6557
                    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 已提交
6558
                                    &def->blockio.physical_block_size) < 0) {
6559 6560 6561 6562 6563
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("invalid physical block size '%s'"),
                                   physical_block_size);
                    goto error;
                }
E
Eric Blake 已提交
6564 6565
            } else if (!driverName &&
                       xmlStrEqual(cur->name, BAD_CAST "driver")) {
6566 6567
                driverName = virXMLPropString(cur, "name");
                driverType = virXMLPropString(cur, "type");
6568 6569 6570 6571 6572 6573
                if (STREQ_NULLABLE(driverType, "aio")) {
                    /* In-place conversion to "raw", for Xen back-compat */
                    driverType[0] = 'r';
                    driverType[1] = 'a';
                    driverType[2] = 'w';
                }
6574
                cachetag = virXMLPropString(cur, "cache");
6575
                error_policy = virXMLPropString(cur, "error_policy");
6576
                rerror_policy = virXMLPropString(cur, "rerror_policy");
M
Matthias Dahl 已提交
6577
                iotag = virXMLPropString(cur, "io");
6578
                ioeventfd = virXMLPropString(cur, "ioeventfd");
6579
                event_idx = virXMLPropString(cur, "event_idx");
O
Osier Yang 已提交
6580
                copy_on_read = virXMLPropString(cur, "copy_on_read");
O
Osier Yang 已提交
6581
                discard = virXMLPropString(cur, "discard");
6582
                driverIOThread = virXMLPropString(cur, "iothread");
6583 6584
            } else if (!def->mirror &&
                       xmlStrEqual(cur->name, BAD_CAST "mirror") &&
6585
                       !(flags & VIR_DOMAIN_DEF_PARSE_INACTIVE)) {
6586
                char *ready;
E
Eric Blake 已提交
6587
                char *blockJob;
6588 6589 6590

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

E
Eric Blake 已提交
6592 6593 6594 6595 6596 6597 6598 6599 6600 6601 6602 6603 6604 6605 6606
                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 已提交
6607 6608 6609 6610 6611 6612 6613 6614 6615 6616 6617 6618 6619 6620 6621 6622 6623 6624 6625 6626 6627 6628
                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 已提交
6629 6630 6631 6632 6633 6634
                    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 已提交
6635
                    mirrorFormat = virXMLPropString(cur, "format");
6636
                }
6637 6638 6639 6640 6641 6642 6643 6644 6645
                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 已提交
6646 6647 6648 6649 6650 6651 6652 6653 6654
                }
                if (mirrorType) {
                    xmlNodePtr mirrorNode;

                    if (!(mirrorNode = virXPathNode("./mirror/source", ctxt))) {
                        virReportError(VIR_ERR_XML_ERROR, "%s",
                                       _("mirror requires source element"));
                        goto error;
                    }
6655 6656
                    if (virDomainDiskSourceParse(mirrorNode, ctxt,
                                                 def->mirror) < 0)
E
Eric Blake 已提交
6657
                        goto error;
6658
                }
6659 6660
                ready = virXMLPropString(cur, "ready");
                if (ready) {
6661 6662 6663 6664 6665 6666 6667 6668
                    if ((def->mirrorState =
                         virDomainDiskMirrorStateTypeFromString(ready)) < 0) {
                        virReportError(VIR_ERR_XML_ERROR,
                                       _("unknown mirror ready state %s"),
                                       ready);
                        VIR_FREE(ready);
                        goto error;
                    }
6669 6670
                    VIR_FREE(ready);
                }
6671 6672
            } else if (!authdef &&
                       xmlStrEqual(cur->name, BAD_CAST "auth")) {
6673 6674
                if (!(authdef = virStorageAuthDefParse(node->doc, cur)))
                    goto error;
6675 6676
                /* Disk volume types won't have the secrettype filled in until
                 * after virStorageTranslateDiskSourcePool is run
6677
                 */
6678 6679
                if (def->src->type != VIR_STORAGE_TYPE_VOLUME &&
                    (auth_secret_usage =
6680 6681 6682 6683
                     virSecretUsageTypeFromString(authdef->secrettype)) < 0) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("invalid secret type %s"),
                                   authdef->secrettype);
6684 6685
                    goto error;
                }
L
Lei Li 已提交
6686
            } else if (xmlStrEqual(cur->name, BAD_CAST "iotune")) {
6687 6688 6689 6690 6691 6692 6693 6694
                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 已提交
6695 6696 6697
                    def->blkdeviotune.total_bytes_sec = 0;
                }

6698 6699 6700 6701 6702 6703 6704 6705
                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 已提交
6706 6707 6708
                    def->blkdeviotune.read_bytes_sec = 0;
                }

6709 6710 6711 6712 6713 6714 6715 6716
                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 已提交
6717 6718 6719
                    def->blkdeviotune.write_bytes_sec = 0;
                }

6720 6721 6722 6723 6724 6725 6726 6727
                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 已提交
6728 6729 6730
                    def->blkdeviotune.total_iops_sec = 0;
                }

6731 6732 6733 6734 6735 6736 6737 6738
                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 已提交
6739 6740 6741
                    def->blkdeviotune.read_iops_sec = 0;
                }

6742 6743 6744 6745 6746 6747 6748 6749
                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 已提交
6750 6751 6752
                    def->blkdeviotune.write_iops_sec = 0;
                }

6753 6754 6755 6756 6757 6758 6759 6760 6761 6762 6763 6764 6765 6766 6767 6768 6769 6770 6771 6772 6773 6774 6775 6776 6777 6778 6779 6780 6781 6782 6783 6784 6785 6786 6787 6788 6789 6790 6791 6792 6793 6794 6795
                if (virXPathULongLong("string(./iotune/total_bytes_sec_max)",
                                      ctxt,
                                      &def->blkdeviotune.total_bytes_sec_max) < 0) {
                    def->blkdeviotune.total_bytes_sec_max = 0;
                }

                if (virXPathULongLong("string(./iotune/read_bytes_sec_max)",
                                      ctxt,
                                      &def->blkdeviotune.read_bytes_sec_max) < 0) {
                    def->blkdeviotune.read_bytes_sec_max = 0;
                }

                if (virXPathULongLong("string(./iotune/write_bytes_sec_max)",
                                      ctxt,
                                      &def->blkdeviotune.write_bytes_sec_max) < 0) {
                    def->blkdeviotune.write_bytes_sec_max = 0;
                }

                if (virXPathULongLong("string(./iotune/total_iops_sec_max)",
                                      ctxt,
                                      &def->blkdeviotune.total_iops_sec_max) < 0) {
                    def->blkdeviotune.total_iops_sec_max = 0;
                }

                if (virXPathULongLong("string(./iotune/read_iops_sec_max)",
                                      ctxt,
                                      &def->blkdeviotune.read_iops_sec_max) < 0) {
                    def->blkdeviotune.read_iops_sec_max = 0;
                }

                if (virXPathULongLong("string(./iotune/write_iops_sec_max)",
                                      ctxt,
                                      &def->blkdeviotune.write_iops_sec_max) < 0) {
                    def->blkdeviotune.write_iops_sec_max = 0;
                }

                if (virXPathULongLong("string(./iotune/size_iops_sec)",
                                      ctxt,
                                      &def->blkdeviotune.size_iops_sec) < 0) {
                    def->blkdeviotune.size_iops_sec = 0;
                }


L
Lei Li 已提交
6796 6797 6798 6799
                if ((def->blkdeviotune.total_bytes_sec &&
                     def->blkdeviotune.read_bytes_sec) ||
                    (def->blkdeviotune.total_bytes_sec &&
                     def->blkdeviotune.write_bytes_sec)) {
6800
                    virReportError(VIR_ERR_XML_ERROR, "%s",
6801 6802
                                   _("total and read/write bytes_sec "
                                     "cannot be set at the same time"));
L
Lei Li 已提交
6803 6804 6805 6806 6807 6808 6809
                    goto error;
                }

                if ((def->blkdeviotune.total_iops_sec &&
                     def->blkdeviotune.read_iops_sec) ||
                    (def->blkdeviotune.total_iops_sec &&
                     def->blkdeviotune.write_iops_sec)) {
6810
                    virReportError(VIR_ERR_XML_ERROR, "%s",
6811 6812
                                   _("total and read/write iops_sec "
                                     "cannot be set at the same time"));
L
Lei Li 已提交
6813 6814
                    goto error;
                }
6815 6816 6817 6818 6819 6820 6821 6822 6823 6824 6825 6826 6827 6828 6829 6830 6831 6832 6833 6834 6835

                if ((def->blkdeviotune.total_bytes_sec_max &&
                     def->blkdeviotune.read_bytes_sec_max) ||
                    (def->blkdeviotune.total_bytes_sec_max &&
                     def->blkdeviotune.write_bytes_sec_max)) {
                    virReportError(VIR_ERR_XML_ERROR, "%s",
                                   _("total and read/write bytes_sec_max "
                                     "cannot be set at the same time"));
                    goto error;
                }

                if ((def->blkdeviotune.total_iops_sec_max &&
                     def->blkdeviotune.read_iops_sec_max) ||
                    (def->blkdeviotune.total_iops_sec_max &&
                     def->blkdeviotune.write_iops_sec_max)) {
                    virReportError(VIR_ERR_XML_ERROR, "%s",
                                   _("total and read/write iops_sec_max "
                                     "cannot be set at the same time"));
                    goto error;
                }

6836
            } else if (xmlStrEqual(cur->name, BAD_CAST "readonly")) {
6837
                def->src->readonly = true;
6838
            } else if (xmlStrEqual(cur->name, BAD_CAST "shareable")) {
6839
                def->src->shared = true;
6840
            } else if (xmlStrEqual(cur->name, BAD_CAST "transient")) {
6841
                def->transient = true;
6842
            } else if ((flags & VIR_DOMAIN_DEF_PARSE_STATUS) &&
6843
                       xmlStrEqual(cur->name, BAD_CAST "state")) {
6844
                /* Legacy back-compat. Don't add any more attributes here */
6845
                devaddr = virXMLPropString(cur, "devaddr");
6846 6847
            } else if (encryption == NULL &&
                       xmlStrEqual(cur->name, BAD_CAST "encryption")) {
6848
                encryption = virStorageEncryptionParseNode(node->doc,
6849 6850 6851
                                                           cur);
                if (encryption == NULL)
                    goto error;
E
Eric Blake 已提交
6852 6853
            } else if (!serial &&
                       xmlStrEqual(cur->name, BAD_CAST "serial")) {
6854
                serial = (char *)xmlNodeGetContent(cur);
O
Osier Yang 已提交
6855 6856 6857 6858 6859 6860
            } else if (!wwn &&
                       xmlStrEqual(cur->name, BAD_CAST "wwn")) {
                wwn = (char *)xmlNodeGetContent(cur);

                if (!virValidateWWN(wwn))
                    goto error;
6861 6862 6863 6864 6865 6866 6867 6868 6869 6870 6871 6872 6873 6874 6875 6876 6877 6878 6879
            } 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 已提交
6880
                if (strlen(product) > PRODUCT_LEN) {
6881 6882 6883 6884 6885 6886 6887 6888 6889 6890
                    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;
                }
6891
            } else if (xmlStrEqual(cur->name, BAD_CAST "boot")) {
6892
                /* boot is parsed as part of virDomainDeviceInfoParseXML */
6893 6894 6895 6896 6897
            }
        }
        cur = cur->next;
    }

6898 6899 6900 6901 6902
    /* Disk volume types will have authentication information handled in
     * virStorageTranslateDiskSourcePool
     */
    if (def->src->type != VIR_STORAGE_TYPE_VOLUME &&
        auth_secret_usage != -1 && auth_secret_usage != expected_secret_usage) {
6903 6904
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("invalid secret type '%s'"),
6905
                       virSecretUsageTypeToString(auth_secret_usage));
6906 6907 6908
        goto error;
    }

6909 6910 6911
    device = virXMLPropString(node, "device");
    if (device) {
        if ((def->device = virDomainDiskDeviceTypeFromString(device)) < 0) {
6912
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
6913
                           _("unknown disk device '%s'"), device);
6914 6915 6916 6917 6918 6919 6920
            goto error;
        }
    } else {
        def->device = VIR_DOMAIN_DISK_DEVICE_DISK;
    }

    /* Only CDROM and Floppy devices are allowed missing source path
6921 6922
     * to indicate no media present. LUN is for raw access CD-ROMs
     * that are not attached to a physical device presently */
6923
    if (virStorageSourceIsEmpty(def->src) &&
6924
        (def->device == VIR_DOMAIN_DISK_DEVICE_DISK ||
6925
         (flags & VIR_DOMAIN_DEF_PARSE_DISK_SOURCE))) {
6926 6927
        virReportError(VIR_ERR_NO_SOURCE,
                       target ? "%s" : NULL, target);
6928 6929 6930
        goto error;
    }

6931 6932 6933 6934
    /* If source is present, check for an optional seclabel override.  */
    if (sourceNode) {
        xmlNodePtr saved_node = ctxt->node;
        ctxt->node = sourceNode;
6935 6936
        if (virSecurityDeviceLabelDefParseXML(&def->src->seclabels,
                                              &def->src->nseclabels,
6937
                                              vmSeclabels,
6938
                                              nvmSeclabels,
6939 6940
                                              ctxt,
                                              flags) < 0)
6941 6942 6943 6944
            goto error;
        ctxt->node = saved_node;
    }

6945
    if (!target && !(flags & VIR_DOMAIN_DEF_PARSE_DISK_SOURCE)) {
6946
        if (def->src->srcpool) {
6947 6948
            char *tmp;
            if (virAsprintf(&tmp, "pool = '%s', volume = '%s'",
6949
                def->src->srcpool->pool, def->src->srcpool->volume) < 0)
6950 6951 6952 6953 6954
                goto error;

            virReportError(VIR_ERR_NO_TARGET, "%s", tmp);
            VIR_FREE(tmp);
        } else {
6955
            virReportError(VIR_ERR_NO_TARGET, def->src->path ? "%s" : NULL, def->src->path);
6956
        }
6957 6958 6959
        goto error;
    }

6960
    if (!(flags & VIR_DOMAIN_DEF_PARSE_DISK_SOURCE)) {
6961 6962 6963 6964 6965 6966
        if (def->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY &&
            !STRPREFIX(target, "fd")) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Invalid floppy device name: %s"), target);
            goto error;
        }
6967

6968 6969 6970
        /* Force CDROM to be listed as read only */
        if (def->device == VIR_DOMAIN_DISK_DEVICE_CDROM)
            def->src->readonly = true;
6971

6972 6973 6974 6975 6976 6977 6978 6979 6980 6981 6982
        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;
        }
6983 6984
    }

6985
    if (snapshot) {
E
Eric Blake 已提交
6986
        def->snapshot = virDomainSnapshotLocationTypeFromString(snapshot);
6987
        if (def->snapshot <= 0) {
6988
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
6989 6990
                           _("unknown disk snapshot setting '%s'"),
                           snapshot);
6991 6992
            goto error;
        }
6993
    } else if (def->src->readonly) {
E
Eric Blake 已提交
6994
        def->snapshot = VIR_DOMAIN_SNAPSHOT_LOCATION_NONE;
6995 6996
    }

O
Osier Yang 已提交
6997 6998 6999 7000 7001 7002 7003 7004
    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;
    }

7005
    if (rawio) {
7006
        if ((def->rawio = virTristateBoolTypeFromString(rawio)) <= 0) {
O
Osier Yang 已提交
7007 7008 7009 7010 7011 7012 7013 7014
            virReportError(VIR_ERR_XML_ERROR,
                           _("unknown disk rawio setting '%s'"),
                           rawio);
            goto error;
        }
    }

    if (sgio) {
7015
        if ((def->sgio = virDomainDeviceSGIOTypeFromString(sgio)) <= 0) {
7016
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
O
Osier Yang 已提交
7017
                           _("unknown disk sgio mode '%s'"), sgio);
7018 7019 7020 7021
            goto error;
        }
    }

7022 7023
    if (bus) {
        if ((def->bus = virDomainDiskBusTypeFromString(bus)) < 0) {
7024
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
7025
                           _("unknown disk bus type '%s'"), bus);
7026 7027 7028 7029 7030
            goto error;
        }
    } else {
        if (def->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
            def->bus = VIR_DOMAIN_DISK_BUS_FDC;
7031
        } else if (!(flags & VIR_DOMAIN_DEF_PARSE_DISK_SOURCE)) {
7032 7033 7034 7035 7036 7037 7038 7039
            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;
7040 7041
            else if (STRPREFIX(target, "ubd"))
                def->bus = VIR_DOMAIN_DISK_BUS_UML;
7042 7043 7044 7045 7046
            else
                def->bus = VIR_DOMAIN_DISK_BUS_IDE;
        }
    }

7047 7048
    if (tray) {
        if ((def->tray_status = virDomainDiskTrayTypeFromString(tray)) < 0) {
7049
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
7050
                           _("unknown disk tray status '%s'"), tray);
7051 7052 7053 7054 7055
            goto error;
        }

        if (def->device != VIR_DOMAIN_DISK_DEVICE_FLOPPY &&
            def->device != VIR_DOMAIN_DISK_DEVICE_CDROM) {
7056 7057
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("tray is only valid for cdrom and floppy"));
7058 7059 7060 7061 7062 7063 7064 7065
            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;
    }

7066
    if (removable) {
J
Ján Tomko 已提交
7067
        if ((def->removable = virTristateSwitchTypeFromString(removable)) < 0) {
7068
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
7069 7070 7071 7072 7073 7074 7075 7076 7077 7078
                           _("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 {
7079
        if (def->bus == VIR_DOMAIN_DISK_BUS_USB)
J
Ján Tomko 已提交
7080
            def->removable = VIR_TRISTATE_SWITCH_ABSENT;
7081 7082
    }

7083 7084
    if (def->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY &&
        def->bus != VIR_DOMAIN_DISK_BUS_FDC) {
7085 7086
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Invalid bus type '%s' for floppy disk"), bus);
7087 7088 7089 7090
        goto error;
    }
    if (def->device != VIR_DOMAIN_DISK_DEVICE_FLOPPY &&
        def->bus == VIR_DOMAIN_DISK_BUS_FDC) {
7091 7092
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Invalid bus type '%s' for disk"), bus);
7093 7094 7095
        goto error;
    }

7096 7097
    if (cachetag &&
        (def->cachemode = virDomainDiskCacheTypeFromString(cachetag)) < 0) {
7098
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
7099
                       _("unknown disk cache mode '%s'"), cachetag);
7100 7101 7102
        goto error;
    }

7103
    if (error_policy &&
7104
        (def->error_policy = virDomainDiskErrorPolicyTypeFromString(error_policy)) <= 0) {
7105
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
7106
                       _("unknown disk error policy '%s'"), error_policy);
7107 7108 7109
        goto error;
    }

7110 7111 7112 7113
    if (rerror_policy &&
        (((def->rerror_policy
           = virDomainDiskErrorPolicyTypeFromString(rerror_policy)) <= 0) ||
         (def->rerror_policy == VIR_DOMAIN_DISK_ERROR_POLICY_ENOSPACE))) {
7114
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
7115 7116
                       _("unknown disk read error policy '%s'"),
                       rerror_policy);
7117 7118 7119
        goto error;
    }

M
Matthias Dahl 已提交
7120 7121 7122
    if (iotag) {
        if ((def->iomode = virDomainDiskIoTypeFromString(iotag)) < 0 ||
            def->iomode == VIR_DOMAIN_DISK_IO_DEFAULT) {
7123
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
7124
                           _("unknown disk io mode '%s'"), iotag);
M
Matthias Dahl 已提交
7125 7126 7127 7128
            goto error;
        }
    }

7129
    if (ioeventfd) {
7130 7131
        int val;

7132
        if (def->bus != VIR_DOMAIN_DISK_BUS_VIRTIO) {
7133
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
7134 7135
                           _("disk ioeventfd mode supported "
                             "only for virtio bus"));
7136 7137 7138
            goto error;
        }

J
Ján Tomko 已提交
7139
        if ((val = virTristateSwitchTypeFromString(ioeventfd)) <= 0) {
7140 7141 7142
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown disk ioeventfd mode '%s'"),
                           ioeventfd);
7143 7144
            goto error;
        }
7145
        def->ioeventfd = val;
7146 7147
    }

7148 7149
    if (event_idx) {
        if (def->bus != VIR_DOMAIN_DISK_BUS_VIRTIO) {
7150
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
7151 7152
                           _("disk event_idx mode supported "
                             "only for virtio bus"));
7153 7154 7155 7156
            goto error;
        }

        int idx;
J
Ján Tomko 已提交
7157
        if ((idx = virTristateSwitchTypeFromString(event_idx)) <= 0) {
7158 7159 7160
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown disk event_idx mode '%s'"),
                           event_idx);
7161 7162 7163 7164 7165
            goto error;
        }
        def->event_idx = idx;
    }

O
Osier Yang 已提交
7166 7167
    if (copy_on_read) {
        int cor;
J
Ján Tomko 已提交
7168
        if ((cor = virTristateSwitchTypeFromString(copy_on_read)) <= 0) {
7169 7170 7171
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown disk copy_on_read mode '%s'"),
                           copy_on_read);
O
Osier Yang 已提交
7172 7173 7174 7175 7176
            goto error;
        }
        def->copy_on_read = cor;
    }

O
Osier Yang 已提交
7177 7178 7179 7180 7181 7182 7183 7184
    if (discard) {
        if ((def->discard = virDomainDiskDiscardTypeFromString(discard)) <= 0) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown disk discard mode '%s'"), discard);
            goto error;
        }
    }

7185
    if (driverIOThread) {
7186 7187
        if (virStrToLong_uip(driverIOThread, NULL, 10, &def->iothread) < 0 ||
            def->iothread == 0) {
7188 7189 7190 7191 7192 7193 7194
            virReportError(VIR_ERR_XML_ERROR,
                           _("Invalid iothread attribute in disk driver "
                             "element: %s"), driverIOThread);
            goto error;
        }
    }

7195
    if (devaddr) {
7196 7197
        if (virDomainParseLegacyDeviceAddress(devaddr,
                                              &def->info.addr.pci) < 0) {
7198 7199 7200
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unable to parse devaddr parameter '%s'"),
                           devaddr);
7201 7202 7203 7204
            goto error;
        }
        def->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
    } else {
7205
        if (virDomainDeviceInfoParseXML(node, bootHash, &def->info,
7206
                                        flags | VIR_DOMAIN_DEF_PARSE_ALLOW_BOOT) < 0)
7207
            goto error;
7208 7209
    }

7210
    if (startupPolicy) {
7211
        int val;
7212

7213
        if ((val = virDomainStartupPolicyTypeFromString(startupPolicy)) <= 0) {
7214 7215 7216
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown startupPolicy value '%s'"),
                           startupPolicy);
7217 7218 7219
            goto error;
        }

7220
        if (def->src->type == VIR_STORAGE_TYPE_NETWORK) {
7221 7222 7223
            virReportError(VIR_ERR_XML_ERROR,
                           _("Setting disk %s is not allowed for "
                             "disk of network type"),
7224
                           startupPolicy);
7225 7226
            goto error;
        }
7227 7228 7229 7230 7231 7232 7233 7234 7235

        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;
        }
7236
        def->startupPolicy = val;
7237 7238
    }

7239 7240
    def->dst = target;
    target = NULL;
7241 7242
    def->src->auth = authdef;
    authdef = NULL;
7243
    def->src->driverName = driverName;
7244
    driverName = NULL;
7245
    def->src->encryption = encryption;
7246
    encryption = NULL;
7247 7248
    def->domain_name = domain_name;
    domain_name = NULL;
7249 7250
    def->serial = serial;
    serial = NULL;
O
Osier Yang 已提交
7251 7252
    def->wwn = wwn;
    wwn = NULL;
7253 7254 7255 7256
    def->vendor = vendor;
    vendor = NULL;
    def->product = product;
    product = NULL;
7257

7258
    if (driverType) {
7259 7260
        def->src->format = virStorageFileFormatTypeFromString(driverType);
        if (def->src->format <= 0) {
7261 7262 7263 7264 7265 7266
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown driver format value '%s'"),
                           driverType);
            goto error;
        }
    }
7267

7268
    if (!(flags & VIR_DOMAIN_DEF_PARSE_DISK_SOURCE)) {
7269 7270 7271
        if (virDomainDiskBackingStoreParse(ctxt, def->src) < 0)
            goto error;
    }
7272

7273
 cleanup:
7274 7275
    VIR_FREE(bus);
    VIR_FREE(type);
7276
    VIR_FREE(snapshot);
7277
    VIR_FREE(rawio);
O
Osier Yang 已提交
7278
    VIR_FREE(sgio);
7279
    VIR_FREE(target);
7280
    VIR_FREE(tray);
7281
    VIR_FREE(removable);
J
J.B. Joret 已提交
7282
    VIR_FREE(trans);
7283
    VIR_FREE(device);
7284
    virStorageAuthDefFree(authdef);
7285 7286
    VIR_FREE(driverType);
    VIR_FREE(driverName);
7287
    VIR_FREE(cachetag);
7288
    VIR_FREE(error_policy);
7289
    VIR_FREE(rerror_policy);
M
Matthias Dahl 已提交
7290
    VIR_FREE(iotag);
7291
    VIR_FREE(ioeventfd);
7292
    VIR_FREE(event_idx);
O
Osier Yang 已提交
7293
    VIR_FREE(copy_on_read);
O
Osier Yang 已提交
7294
    VIR_FREE(discard);
7295
    VIR_FREE(driverIOThread);
7296
    VIR_FREE(devaddr);
7297
    VIR_FREE(serial);
7298
    virStorageEncryptionFree(encryption);
7299
    VIR_FREE(startupPolicy);
7300 7301
    VIR_FREE(logical_block_size);
    VIR_FREE(physical_block_size);
O
Osier Yang 已提交
7302
    VIR_FREE(wwn);
7303 7304
    VIR_FREE(vendor);
    VIR_FREE(product);
E
Eric Blake 已提交
7305 7306
    VIR_FREE(mirrorType);
    VIR_FREE(mirrorFormat);
7307
    VIR_FREE(domain_name);
7308

L
Lei Li 已提交
7309
    ctxt->node = save_ctxt;
7310 7311
    return def;

7312
 error:
7313 7314 7315 7316 7317
    virDomainDiskDefFree(def);
    def = NULL;
    goto cleanup;
}

7318 7319 7320 7321 7322 7323 7324 7325 7326 7327 7328 7329 7330 7331 7332 7333 7334 7335 7336 7337 7338 7339
/**
 * virDomainParseScaledValue:
 * @xpath: XPath to memory amount
 * @units_xpath: XPath to units attribute
 * @ctxt: XPath context
 * @val: scaled value is stored here
 * @scale: default scale for @val
 * @max: maximal @val allowed
 * @required: is the value required?
 *
 * Parse a value located at @xpath within @ctxt, and store the
 * result into @val. The value is scaled by units located at
 * @units_xpath (or the 'unit' attribute under @xpath if
 * @units_xpath is NULL). If units are not present, the default
 * @scale is used. If @required is set, then the value must
 * exist; otherwise, the value is optional. The resulting value
 * is in bytes.
 *
 * Returns 1 on success,
 *         0 if the value was not present and !@required,
 *         -1 on failure after issuing error.
 */
7340 7341
static int
virDomainParseScaledValue(const char *xpath,
7342
                          const char *units_xpath,
7343 7344 7345 7346 7347 7348 7349 7350
                          xmlXPathContextPtr ctxt,
                          unsigned long long *val,
                          unsigned long long scale,
                          unsigned long long max,
                          bool required)
{
    char *xpath_full = NULL;
    char *unit = NULL;
7351
    char *bytes_str = NULL;
7352 7353 7354 7355 7356 7357
    int ret = -1;
    unsigned long long bytes;

    *val = 0;
    if (virAsprintf(&xpath_full, "string(%s)", xpath) < 0)
        goto cleanup;
7358 7359 7360 7361 7362 7363

    bytes_str = virXPathString(xpath_full, ctxt);
    if (!bytes_str) {
        if (!required) {
            ret = 0;
        } else {
7364
            virReportError(VIR_ERR_XML_ERROR,
7365
                           _("missing element or attribute '%s'"),
7366
                           xpath);
7367
        }
7368 7369 7370 7371
        goto cleanup;
    }
    VIR_FREE(xpath_full);

7372 7373
    if (virStrToLong_ullp(bytes_str, NULL, 10, &bytes) < 0) {
        virReportError(VIR_ERR_XML_ERROR,
7374
                       _("Invalid value '%s' for element or attribute '%s'"),
7375 7376 7377 7378
                       bytes_str, xpath);
        goto cleanup;
    }

7379 7380 7381 7382
    if ((units_xpath &&
         virAsprintf(&xpath_full, "string(%s)", units_xpath) < 0) ||
        (!units_xpath &&
         virAsprintf(&xpath_full, "string(%s/@unit)", xpath) < 0))
7383 7384 7385 7386 7387 7388 7389 7390
        goto cleanup;
    unit = virXPathString(xpath_full, ctxt);

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

    *val = bytes;
    ret = 1;
7391
 cleanup:
7392
    VIR_FREE(bytes_str);
7393 7394 7395 7396 7397 7398
    VIR_FREE(xpath_full);
    VIR_FREE(unit);
    return ret;
}


7399 7400 7401 7402 7403 7404 7405 7406
/**
 * virDomainParseMemory:
 * @xpath: XPath to memory amount
 * @units_xpath: XPath to units attribute
 * @ctxt: XPath context
 * @mem: scaled memory amount is stored here
 * @required: whether value is required
 * @capped: whether scaled value must fit within unsigned long
7407
 *
7408 7409 7410 7411 7412 7413 7414 7415 7416 7417 7418 7419 7420
 * Parse a memory element or attribute located at @xpath within
 * @ctxt, and store the result into @mem, in blocks of 1024. The
 * value is scaled by units located at @units_xpath (or the
 * 'unit' attribute under @xpath if @units_xpath is NULL). If
 * units are not present, he default scale of 1024 is used. If
 * @required is set, 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).
 *
 * Return 0 on success, -1 on failure after issuing error.
 */
7421
int
7422 7423 7424 7425 7426 7427
virDomainParseMemory(const char *xpath,
                     const char *units_xpath,
                     xmlXPathContextPtr ctxt,
                     unsigned long long *mem,
                     bool required,
                     bool capped)
7428 7429 7430 7431
{
    int ret = -1;
    unsigned long long bytes, max;

7432
    max = virMemoryMaxValue(capped);
7433

7434 7435
    ret = virDomainParseScaledValue(xpath, units_xpath, ctxt,
                                    &bytes, 1024, max, required);
7436 7437 7438 7439 7440
    if (ret < 0)
        goto cleanup;

    /* Yes, we really do use kibibytes for our internal sizing.  */
    *mem = VIR_DIV_UP(bytes, 1024);
7441 7442 7443 7444 7445 7446 7447

    if (*mem >= VIR_DIV_UP(max, 1024)) {
        virReportError(VIR_ERR_OVERFLOW, "%s", _("size value too large"));
        ret = -1;
        goto cleanup;
    }

7448 7449 7450 7451 7452 7453
    ret = 0;
 cleanup:
    return ret;
}


7454 7455 7456 7457 7458 7459 7460 7461 7462 7463 7464 7465 7466 7467 7468 7469 7470 7471 7472 7473 7474 7475 7476 7477 7478 7479 7480 7481 7482 7483 7484 7485 7486 7487 7488 7489 7490 7491 7492 7493 7494 7495 7496 7497
/**
 * virDomainParseMemoryLimit:
 *
 * @xpath: XPath to memory amount
 * @units_xpath: XPath to units attribute
 * @ctxt: XPath context
 * @mem: scaled memory amount is stored here
 *
 * Parse a memory element or attribute located at @xpath within @ctxt, and
 * store the result into @mem, in blocks of 1024.  The  value is scaled by
 * units located at @units_xpath (or the 'unit' attribute under @xpath if
 * @units_xpath is NULL).  If units are not present, he default scale of 1024
 * is used.  The value must not exceed VIR_DOMAIN_MEMORY_PARAM_UNLIMITED
 * once scaled.
 *
 * This helper should be used only on *_limit memory elements.
 *
 * Return 0 on success, -1 on failure after issuing error.
 */
static int
virDomainParseMemoryLimit(const char *xpath,
                          const char *units_xpath,
                          xmlXPathContextPtr ctxt,
                          unsigned long long *mem)
{
    int ret;
    unsigned long long bytes;

    ret = virDomainParseScaledValue(xpath, units_xpath, ctxt, &bytes, 1024,
                                    VIR_DOMAIN_MEMORY_PARAM_UNLIMITED << 10,
                                    false);

    if (ret < 0)
        return -1;

    if (ret == 0)
        *mem = VIR_DOMAIN_MEMORY_PARAM_UNLIMITED;
    else
        *mem = virMemoryLimitTruncate(VIR_DIV_UP(bytes, 1024));

    return 0;
}


7498 7499 7500 7501 7502 7503 7504
bool
virDomainDefHasMemoryHotplug(const virDomainDef *def)
{
    return def->mem.memory_slots > 0 || def->mem.max_memory > 0;
}


7505 7506 7507 7508 7509 7510 7511 7512 7513
/**
 * virDomainDefGetMemoryInitial:
 * @def: domain definition
 *
 * Returns the size of the initial amount of guest memory. The initial amount
 * is the memory size is either the configured amount in the <memory> element
 * or the sum of memory sizes of NUMA nodes in case NUMA is enabled in @def.
 */
unsigned long long
7514
virDomainDefGetMemoryInitial(const virDomainDef *def)
7515
{
7516
    return def->mem.initial_memory;
7517 7518 7519 7520
}


/**
7521
 * virDomainDefSetMemoryTotal:
7522 7523 7524
 * @def: domain definition
 * @size: size to set
 *
7525 7526
 * Sets the total memory size in @def. This function should be used only by
 * hypervisors that don't support memory hotplug.
7527 7528
 */
void
7529 7530
virDomainDefSetMemoryTotal(virDomainDefPtr def,
                           unsigned long long size)
7531
{
7532
    def->mem.total_memory = size;
7533 7534 7535 7536 7537 7538 7539 7540 7541 7542 7543 7544 7545 7546 7547 7548
    def->mem.initial_memory = size;
}


/**
 * virDomainDefSetMemoryInitial:
 * @def: domain definition
 * @size: size to set
 *
 * Sets the initial memory size (without memory modules) in @def.
 */
void
virDomainDefSetMemoryInitial(virDomainDefPtr def,
                             unsigned long long size)
{
    def->mem.initial_memory = size;
7549 7550 7551 7552 7553 7554 7555 7556 7557 7558 7559 7560 7561 7562
}


/**
 * virDomainDefGetMemoryActual:
 * @def: domain definition
 *
 * Returns the current maximum memory size usable by the domain described by
 * @def. This size is a sum of size returned by virDomainDefGetMemoryInitial
 * and possible additional memory devices.
 */
unsigned long long
virDomainDefGetMemoryActual(virDomainDefPtr def)
{
7563 7564 7565
    unsigned long long ret;
    size_t i;

7566 7567 7568 7569
    ret = def->mem.initial_memory;

    for (i = 0; i < def->nmems; i++)
        ret += def->mems[i]->size;
7570 7571

    return ret;
7572 7573 7574
}


7575
static int
7576
virDomainControllerModelTypeFromString(const virDomainControllerDef *def,
7577 7578 7579 7580
                                       const char *model)
{
    if (def->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI)
        return virDomainControllerModelSCSITypeFromString(model);
7581 7582
    else if (def->type == VIR_DOMAIN_CONTROLLER_TYPE_USB)
        return virDomainControllerModelUSBTypeFromString(model);
J
Ján Tomko 已提交
7583 7584
    else if (def->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI)
        return virDomainControllerModelPCITypeFromString(model);
7585 7586 7587 7588

    return -1;
}

7589 7590 7591 7592
/* Parse the XML definition for a controller
 * @param node XML nodeset to parse for controller definition
 */
static virDomainControllerDefPtr
7593
virDomainControllerDefParseXML(xmlNodePtr node,
7594
                               xmlXPathContextPtr ctxt,
E
Eric Blake 已提交
7595
                               unsigned int flags)
7596
{
7597 7598
    virDomainControllerDefPtr def = NULL;
    int type = 0;
7599
    xmlNodePtr cur = NULL;
7600
    char *typeStr = NULL;
7601
    char *idx = NULL;
7602
    char *model = NULL;
7603
    char *queues = NULL;
7604 7605
    char *cmd_per_lun = NULL;
    char *max_sectors = NULL;
7606 7607
    bool processedModel = false;
    char *modelName = NULL;
7608 7609
    bool processedTarget = false;
    char *chassisNr = NULL;
7610 7611
    char *chassis = NULL;
    char *port = NULL;
7612
    char *ioeventfd = NULL;
7613
    xmlNodePtr saved = ctxt->node;
7614
    int rc;
7615 7616

    ctxt->node = node;
7617

7618 7619 7620
    typeStr = virXMLPropString(node, "type");
    if (typeStr) {
        if ((type = virDomainControllerTypeFromString(typeStr)) < 0) {
7621
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
7622
                           _("Unknown controller type '%s'"), typeStr);
7623 7624 7625 7626
            goto error;
        }
    }

7627 7628 7629
    if (!(def = virDomainControllerDefNew(type)))
        goto error;

7630 7631
    idx = virXMLPropString(node, "index");
    if (idx) {
7632 7633
        if (virStrToLong_ui(idx, NULL, 10, &def->idx) < 0 ||
            def->idx > INT_MAX) {
7634 7635
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Cannot parse controller index %s"), idx);
7636 7637 7638 7639
            goto error;
        }
    }

7640 7641
    model = virXMLPropString(node, "model");
    if (model) {
7642
        if ((def->model = virDomainControllerModelTypeFromString(def, model)) < 0) {
7643
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
7644
                           _("Unknown model type '%s'"), model);
7645 7646 7647 7648
            goto error;
        }
    }

7649 7650 7651
    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
7652
            if (xmlStrEqual(cur->name, BAD_CAST "driver")) {
7653
                queues = virXMLPropString(cur, "queues");
7654 7655
                cmd_per_lun = virXMLPropString(cur, "cmd_per_lun");
                max_sectors = virXMLPropString(cur, "max_sectors");
7656
                ioeventfd = virXMLPropString(cur, "ioeventfd");
7657 7658 7659 7660 7661 7662 7663 7664 7665
            } else if (xmlStrEqual(cur->name, BAD_CAST "model")) {
                if (processedModel) {
                    virReportError(VIR_ERR_XML_ERROR, "%s",
                                   _("Multiple <model> elements in "
                                     "controller definition not allowed"));
                    goto error;
                }
                modelName = virXMLPropString(cur, "name");
                processedModel = true;
7666 7667 7668 7669 7670 7671 7672 7673
            } else if (xmlStrEqual(cur->name, BAD_CAST "target")) {
                if (processedTarget) {
                    virReportError(VIR_ERR_XML_ERROR, "%s",
                                   _("Multiple <target> elements in "
                                     "controller definition not allowed"));
                    goto error;
                }
                chassisNr = virXMLPropString(cur, "chassisNr");
7674 7675
                chassis = virXMLPropString(cur, "chassis");
                port = virXMLPropString(cur, "port");
7676
                processedTarget = true;
7677
            }
7678
        }
7679 7680 7681 7682 7683 7684 7685
        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;
7686 7687
    }

7688 7689 7690 7691 7692 7693 7694 7695 7696
    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);
7697
        goto error;
7698 7699
    }

7700 7701 7702
    if (ioeventfd &&
        (def->ioeventfd = virTristateSwitchTypeFromString(ioeventfd)) < 0) {
        virReportError(VIR_ERR_XML_ERROR,
7703
                       _("Malformed 'ioeventfd' value %s'"), ioeventfd);
7704 7705 7706
        goto error;
    }

7707 7708 7709 7710
    if (def->type == VIR_DOMAIN_CONTROLLER_TYPE_USB &&
        def->model == VIR_DOMAIN_CONTROLLER_MODEL_USB_NONE) {
        VIR_DEBUG("Ignoring device address for none model usb controller");
    } else if (virDomainDeviceInfoParseXML(node, NULL, &def->info, flags) < 0) {
7711
        goto error;
7712
    }
7713

7714 7715 7716 7717 7718 7719 7720
    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) {
7721 7722
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Invalid ports: %s"), ports);
7723 7724 7725 7726 7727 7728 7729 7730 7731 7732 7733
                VIR_FREE(ports);
                goto error;
            }
        }
        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) {
7734 7735
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Invalid vectors: %s"), vectors);
7736 7737 7738 7739 7740 7741 7742
                VIR_FREE(vectors);
                goto error;
            }
        }
        VIR_FREE(vectors);
        break;
    }
7743 7744 7745 7746 7747 7748 7749 7750 7751 7752 7753 7754 7755 7756 7757 7758 7759 7760 7761 7762 7763 7764
    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 已提交
7765 7766 7767
    case VIR_DOMAIN_CONTROLLER_TYPE_PCI:
        switch (def->model) {
        case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT:
7768 7769
        case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT: {
            unsigned long long bytes;
J
Ján Tomko 已提交
7770 7771
            if (def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
                virReportError(VIR_ERR_XML_ERROR, "%s",
L
Laine Stump 已提交
7772
                               _("pci-root and pcie-root controllers should not "
J
Ján Tomko 已提交
7773 7774 7775
                                 "have an address"));
                goto error;
            }
7776 7777
            if (def->idx != 0) {
                virReportError(VIR_ERR_XML_ERROR, "%s",
L
Laine Stump 已提交
7778 7779
                               _("pci-root and pcie-root controllers "
                                 "should have index 0"));
7780 7781
                goto error;
            }
7782 7783
            if ((rc = virDomainParseScaledValue("./pcihole64", NULL,
                                                ctxt, &bytes, 1024,
7784 7785
                                                1024ULL * ULONG_MAX, false)) < 0)
                goto error;
7786

7787 7788 7789 7790
            if (rc == 1)
                def->opts.pciopts.pcihole64 = true;
            def->opts.pciopts.pcihole64size = VIR_DIV_UP(bytes, 1024);
        }
J
Ján Tomko 已提交
7791
        }
7792 7793 7794 7795 7796 7797 7798 7799
        if (modelName &&
            (def->opts.pciopts.modelName
             = virDomainControllerPCIModelNameTypeFromString(modelName)) <= 0) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unknown PCI controller model name '%s'"),
                           modelName);
            goto error;
        }
7800 7801 7802 7803 7804 7805 7806 7807 7808 7809 7810 7811 7812 7813 7814 7815 7816
        if (chassisNr) {
            if (virStrToLong_i(chassisNr, NULL, 0,
                               &def->opts.pciopts.chassisNr) < 0) {
                virReportError(VIR_ERR_XML_ERROR,
                               _("Invalid chassisNr '%s' in PCI controller"),
                               chassisNr);
                goto error;
            }
            if (def->opts.pciopts.chassisNr < 0 ||
                def->opts.pciopts.chassisNr > 255) {
                virReportError(VIR_ERR_XML_ERROR,
                               _("PCI controller chassisNr '%s' out of range "
                                 "- must be 0-255"),
                               chassisNr);
                goto error;
            }
        }
7817 7818 7819 7820 7821 7822 7823 7824 7825 7826 7827 7828 7829 7830 7831 7832 7833 7834 7835 7836 7837 7838 7839 7840 7841 7842 7843 7844 7845 7846 7847 7848 7849 7850
        if (chassis) {
            if (virStrToLong_i(chassis, NULL, 0,
                               &def->opts.pciopts.chassis) < 0) {
                virReportError(VIR_ERR_XML_ERROR,
                               _("Invalid chassis '%s' in PCI controller"),
                               chassis);
                goto error;
            }
            if (def->opts.pciopts.chassis < 0 ||
                def->opts.pciopts.chassis > 255) {
                virReportError(VIR_ERR_XML_ERROR,
                               _("PCI controller chassis '%s' out of range "
                                 "- must be 0-255"),
                               chassis);
                goto error;
            }
        }
        if (port) {
            if (virStrToLong_i(port, NULL, 0,
                               &def->opts.pciopts.port) < 0) {
                virReportError(VIR_ERR_XML_ERROR,
                               _("Invalid port '%s' in PCI controller"),
                               port);
                goto error;
            }
            if (def->opts.pciopts.port < 0 ||
                def->opts.pciopts.port > 255) {
                virReportError(VIR_ERR_XML_ERROR,
                               _("PCI controller port '%s' out of range "
                                 "- must be 0-255"),
                               port);
                goto error;
            }
        }
7851
        break;
7852 7853 7854 7855 7856

    default:
        break;
    }

7857
    if (def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
7858
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO &&
7859
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW &&
7860
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390 &&
7861
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO &&
7862
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
7863 7864
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Controllers must use the 'pci' address type"));
7865 7866 7867
        goto error;
    }

7868
 cleanup:
7869
    ctxt->node = saved;
7870
    VIR_FREE(typeStr);
7871
    VIR_FREE(idx);
7872
    VIR_FREE(model);
7873
    VIR_FREE(queues);
7874 7875
    VIR_FREE(cmd_per_lun);
    VIR_FREE(max_sectors);
7876
    VIR_FREE(modelName);
7877
    VIR_FREE(chassisNr);
7878 7879
    VIR_FREE(chassis);
    VIR_FREE(port);
7880
    VIR_FREE(ioeventfd);
7881 7882 7883 7884 7885 7886 7887 7888 7889

    return def;

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

7890

7891 7892 7893 7894 7895 7896 7897 7898
void
virDomainNetGenerateMAC(virDomainXMLOptionPtr xmlopt,
                        virMacAddrPtr mac)
{
    virMacAddrGenerate(xmlopt->config.macPrefix, mac);
}


7899 7900 7901 7902
/* Parse the XML definition for a disk
 * @param node XML nodeset to parse for disk definition
 */
static virDomainFSDefPtr
7903
virDomainFSDefParseXML(xmlNodePtr node,
7904
                       xmlXPathContextPtr ctxt,
7905 7906
                       unsigned int flags)
{
7907
    virDomainFSDefPtr def;
7908
    xmlNodePtr cur, save_node = ctxt->node;
7909
    char *type = NULL;
7910
    char *fsdriver = NULL;
7911 7912
    char *source = NULL;
    char *target = NULL;
7913
    char *format = NULL;
7914
    char *accessmode = NULL;
7915
    char *wrpolicy = NULL;
7916
    char *usage = NULL;
7917
    char *units = NULL;
7918

7919 7920
    ctxt->node = node;

7921
    if (VIR_ALLOC(def) < 0)
7922 7923 7924 7925 7926
        return NULL;

    type = virXMLPropString(node, "type");
    if (type) {
        if ((def->type = virDomainFSTypeFromString(type)) < 0) {
7927
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
7928
                           _("unknown filesystem type '%s'"), type);
7929 7930 7931 7932 7933 7934
            goto error;
        }
    } else {
        def->type = VIR_DOMAIN_FS_TYPE_MOUNT;
    }

7935 7936 7937
    accessmode = virXMLPropString(node, "accessmode");
    if (accessmode) {
        if ((def->accessmode = virDomainFSAccessModeTypeFromString(accessmode)) < 0) {
7938
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
7939
                           _("unknown accessmode '%s'"), accessmode);
7940 7941 7942 7943 7944 7945
            goto error;
        }
    } else {
        def->accessmode = VIR_DOMAIN_FS_ACCESSMODE_PASSTHROUGH;
    }

7946 7947 7948
    if (virDomainParseScaledValue("./space_hard_limit[1]",
                                  NULL, ctxt, &def->space_hard_limit,
                                  1, ULLONG_MAX, false) < 0)
7949 7950
        goto error;

7951 7952 7953
    if (virDomainParseScaledValue("./space_soft_limit[1]",
                                  NULL, ctxt, &def->space_soft_limit,
                                  1, ULLONG_MAX, false) < 0)
7954 7955
        goto error;

7956 7957 7958
    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
E
Eric Blake 已提交
7959 7960
            if (!source &&
                xmlStrEqual(cur->name, BAD_CAST "source")) {
7961

7962
                if (def->type == VIR_DOMAIN_FS_TYPE_MOUNT ||
7963
                    def->type == VIR_DOMAIN_FS_TYPE_BIND) {
7964
                    source = virXMLPropString(cur, "dir");
7965
                } else if (def->type == VIR_DOMAIN_FS_TYPE_FILE) {
7966
                    source = virXMLPropString(cur, "file");
7967
                } else if (def->type == VIR_DOMAIN_FS_TYPE_BLOCK) {
7968
                    source = virXMLPropString(cur, "dev");
7969
                } else if (def->type == VIR_DOMAIN_FS_TYPE_TEMPLATE) {
7970
                    source = virXMLPropString(cur, "name");
7971
                } else if (def->type == VIR_DOMAIN_FS_TYPE_RAM) {
7972
                    usage = virXMLPropString(cur, "usage");
7973
                    units = virXMLPropString(cur, "units");
7974
                }
E
Eric Blake 已提交
7975 7976
            } else if (!target &&
                       xmlStrEqual(cur->name, BAD_CAST "target")) {
7977 7978
                target = virXMLPropString(cur, "dir");
            } else if (xmlStrEqual(cur->name, BAD_CAST "readonly")) {
7979
                def->readonly = true;
7980 7981 7982 7983 7984 7985 7986
            } 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");
7987 7988 7989 7990 7991
            }
        }
        cur = cur->next;
    }

7992
    if (fsdriver) {
7993
        if ((def->fsdriver = virDomainFSDriverTypeFromString(fsdriver)) <= 0) {
7994
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
7995
                           _("unknown fs driver type '%s'"), fsdriver);
7996 7997 7998 7999
            goto error;
        }
    }

8000 8001 8002 8003 8004 8005 8006 8007
    if (format) {
        if ((def->format = virStorageFileFormatTypeFromString(format)) <= 0) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown driver format value '%s'"), format);
            goto error;
        }
    }

8008 8009
    if (wrpolicy) {
        if ((def->wrpolicy = virDomainFSWrpolicyTypeFromString(wrpolicy)) <= 0) {
8010 8011
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown filesystem write policy '%s'"), wrpolicy);
8012 8013 8014 8015 8016 8017
            goto error;
        }
    } else {
        def->wrpolicy = VIR_DOMAIN_FS_WRPOLICY_DEFAULT;
    }

8018 8019
    if (source == NULL &&
        def->type != VIR_DOMAIN_FS_TYPE_RAM) {
8020 8021
        virReportError(VIR_ERR_NO_SOURCE,
                       target ? "%s" : NULL, target);
8022 8023 8024 8025
        goto error;
    }

    if (target == NULL) {
8026 8027
        virReportError(VIR_ERR_NO_TARGET,
                       source ? "%s" : NULL, source);
8028 8029 8030
        goto error;
    }

8031 8032
    if (def->type == VIR_DOMAIN_FS_TYPE_RAM) {
        if (!usage) {
8033 8034
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("missing 'usage' attribute for RAM filesystem"));
8035 8036 8037
            goto error;
        }
        if (virStrToLong_ull(usage, NULL, 10, &def->usage) < 0) {
8038 8039 8040
            virReportError(VIR_ERR_XML_ERROR,
                           _("cannot parse usage '%s' for RAM filesystem"),
                           usage);
8041 8042
            goto error;
        }
8043
        if (virScaleInteger(&def->usage, units,
8044
                            1024, ULLONG_MAX) < 0)
8045 8046 8047
            goto error;
    }

8048 8049 8050 8051 8052
    def->src = source;
    source = NULL;
    def->dst = target;
    target = NULL;

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

8056
 cleanup:
8057
    ctxt->node = save_node;
8058
    VIR_FREE(type);
8059
    VIR_FREE(fsdriver);
8060 8061
    VIR_FREE(target);
    VIR_FREE(source);
8062
    VIR_FREE(accessmode);
8063
    VIR_FREE(wrpolicy);
8064
    VIR_FREE(usage);
8065
    VIR_FREE(units);
8066
    VIR_FREE(format);
8067 8068 8069 8070 8071 8072 8073 8074 8075

    return def;

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

8076 8077 8078
static int
virDomainActualNetDefParseXML(xmlNodePtr node,
                              xmlXPathContextPtr ctxt,
8079 8080 8081
                              virDomainNetDefPtr parent,
                              virDomainActualNetDefPtr *def,
                              unsigned int flags)
8082 8083 8084 8085
{
    virDomainActualNetDefPtr actual = NULL;
    int ret = -1;
    xmlNodePtr save_ctxt = ctxt->node;
8086
    xmlNodePtr bandwidth_node = NULL;
8087
    xmlNodePtr vlanNode;
8088
    xmlNodePtr virtPortNode;
8089 8090
    char *type = NULL;
    char *mode = NULL;
8091
    char *addrtype = NULL;
8092
    char *trustGuestRxFilters = NULL;
8093
    char *macTableManager = NULL;
8094

8095
    if (VIR_ALLOC(actual) < 0)
8096 8097 8098 8099 8100 8101
        return -1;

    ctxt->node = node;

    type = virXMLPropString(node, "type");
    if (!type) {
8102 8103
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("missing type attribute in interface's <actual> element"));
8104 8105 8106
        goto error;
    }
    if ((actual->type = virDomainNetTypeFromString(type)) < 0) {
8107
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
8108
                       _("unknown type '%s' in interface's <actual> element"), type);
8109 8110 8111
        goto error;
    }
    if (actual->type != VIR_DOMAIN_NET_TYPE_BRIDGE &&
8112
        actual->type != VIR_DOMAIN_NET_TYPE_DIRECT &&
8113
        actual->type != VIR_DOMAIN_NET_TYPE_HOSTDEV &&
8114
        actual->type != VIR_DOMAIN_NET_TYPE_NETWORK) {
8115 8116 8117
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unsupported type '%s' in interface's <actual> element"),
                       type);
8118 8119 8120
        goto error;
    }

8121 8122 8123 8124 8125 8126 8127 8128 8129 8130
    trustGuestRxFilters = virXMLPropString(node, "trustGuestRxFilters");
    if (trustGuestRxFilters &&
        ((actual->trustGuestRxFilters
          = virTristateBoolTypeFromString(trustGuestRxFilters)) <= 0)) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("unknown trustGuestRxFilters value '%s'"),
                       trustGuestRxFilters);
        goto error;
    }

8131 8132 8133 8134 8135
    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) {
8136 8137 8138
            /* the virtualport in <actual> should always already
             * have an instanceid/interfaceid if its required,
             * so don't let the parser generate one */
8139
            if (!(actual->virtPortProfile
8140 8141 8142
                  = virNetDevVPortProfileParse(virtPortNode,
                                               VIR_VPORT_XML_REQUIRE_ALL_ATTRIBUTES |
                                               VIR_VPORT_XML_REQUIRE_TYPE))) {
8143 8144 8145 8146 8147 8148
                goto error;
            }
        } else {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("<virtualport> element unsupported for type='%s'"
                             " in interface's <actual> element"), type);
A
Ansis Atteka 已提交
8149
            goto error;
8150 8151
        }
    }
8152

8153
    if (actual->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
8154 8155 8156 8157 8158
        actual->data.direct.linkdev = virXPathString("string(./source[1]/@dev)", ctxt);

        mode = virXPathString("string(./source[1]/@mode)", ctxt);
        if (mode) {
            int m;
8159
            if ((m = virNetDevMacVLanModeTypeFromString(mode)) < 0) {
8160
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
J
Ján Tomko 已提交
8161
                               _("Unknown mode '%s' in interface <actual> element"),
8162
                               mode);
8163 8164 8165 8166
                goto error;
            }
            actual->data.direct.mode = m;
        }
8167 8168 8169 8170 8171 8172 8173 8174 8175 8176 8177 8178
    } 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 已提交
8179
        if (!addrtype && virXPathNode("./source/vendor", ctxt) &&
8180
            VIR_STRDUP(addrtype, "usb") < 0)
8181
            goto error;
8182 8183 8184
        hostdev->mode = VIR_DOMAIN_HOSTDEV_MODE_SUBSYS;
        if (virDomainHostdevDefParseXMLSubsys(node, ctxt, addrtype,
                                              hostdev, flags) < 0) {
8185 8186
            goto error;
        }
8187 8188 8189 8190 8191 8192 8193 8194 8195 8196 8197
    } 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);
8198 8199 8200
    }
    if (actual->type == VIR_DOMAIN_NET_TYPE_BRIDGE ||
        actual->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
8201
        char *brname = virXPathString("string(./source/@bridge)", ctxt);
8202 8203

        if (!brname && actual->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
8204 8205 8206 8207 8208 8209
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Missing <source> element with bridge name in "
                             "interface's <actual> element"));
            goto error;
        }
        actual->data.bridge.brname = brname;
8210 8211 8212 8213 8214 8215 8216 8217 8218 8219
        macTableManager = virXPathString("string(./source/@macTableManager)", ctxt);
        if (macTableManager &&
            (actual->data.bridge.macTableManager
             = virNetworkBridgeMACTableManagerTypeFromString(macTableManager)) <= 0) {
            virReportError(VIR_ERR_XML_ERROR,
                           _("Invalid macTableManager setting '%s' "
                             "in domain interface's <actual> element"),
                           macTableManager);
            goto error;
        }
8220 8221
    }

8222 8223
    bandwidth_node = virXPathNode("./bandwidth", ctxt);
    if (bandwidth_node &&
8224 8225 8226
        virNetDevBandwidthParse(&actual->bandwidth,
                                bandwidth_node,
                                actual->type) < 0)
8227 8228
        goto error;

8229 8230 8231 8232
    vlanNode = virXPathNode("./vlan", ctxt);
    if (vlanNode && virNetDevVlanParse(vlanNode, ctxt, &actual->vlan) < 0)
       goto error;

8233 8234 8235
    *def = actual;
    actual = NULL;
    ret = 0;
8236
 error:
8237 8238
    VIR_FREE(type);
    VIR_FREE(mode);
8239
    VIR_FREE(addrtype);
8240
    VIR_FREE(trustGuestRxFilters);
8241
    VIR_FREE(macTableManager);
8242 8243 8244 8245 8246
    virDomainActualNetDefFree(actual);

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

E
Eric Blake 已提交
8248
#define NET_MODEL_CHARS \
8249
    "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-"
E
Eric Blake 已提交
8250

8251 8252 8253 8254 8255 8256 8257 8258 8259 8260 8261 8262 8263 8264 8265 8266 8267 8268 8269 8270 8271 8272 8273 8274 8275

int
virDomainNetAppendIpAddress(virDomainNetDefPtr def,
                            const char *address,
                            int family,
                            unsigned int prefix)
{
    virDomainNetIpDefPtr ipDef = NULL;
    if (VIR_ALLOC(ipDef) < 0)
        return -1;

    if (virSocketAddrParse(&ipDef->address, address, family) < 0)
        goto error;
    ipDef->prefix = prefix;

    if (VIR_APPEND_ELEMENT(def->ips, def->nips, ipDef) < 0)
        goto error;

    return 0;

 error:
    VIR_FREE(ipDef);
    return -1;
}

8276 8277 8278 8279
/* Parse the XML definition for a network interface
 * @param node XML nodeset to parse for net definition
 * @return 0 on success, -1 on failure
 */
8280
static virDomainNetDefPtr
8281
virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt,
8282
                        xmlNodePtr node,
8283
                        xmlXPathContextPtr ctxt,
8284
                        virHashTablePtr bootHash,
E
Eric Blake 已提交
8285
                        unsigned int flags)
8286
{
8287
    virDomainNetDefPtr def;
8288
    virDomainHostdevDefPtr hostdev;
8289 8290 8291 8292
    xmlNodePtr cur;
    char *macaddr = NULL;
    char *type = NULL;
    char *network = NULL;
8293
    char *portgroup = NULL;
8294 8295 8296
    char *bridge = NULL;
    char *dev = NULL;
    char *ifname = NULL;
8297 8298
    char *ifname_guest = NULL;
    char *ifname_guest_actual = NULL;
8299 8300 8301
    char *script = NULL;
    char *address = NULL;
    char *port = NULL;
8302 8303
    char *localaddr = NULL;
    char *localport = NULL;
8304
    char *model = NULL;
8305
    char *backend = NULL;
8306
    char *txmode = NULL;
8307
    char *ioeventfd = NULL;
8308
    char *event_idx = NULL;
8309
    char *queues = NULL;
8310
    char *str = NULL;
8311
    char *filter = NULL;
D
Daniel Veillard 已提交
8312
    char *internal = NULL;
8313
    char *devaddr = NULL;
8314
    char *mode = NULL;
8315
    char *linkstate = NULL;
8316
    char *addrtype = NULL;
8317
    char *domain_name = NULL;
M
Michele Paolino 已提交
8318 8319 8320
    char *vhostuser_mode = NULL;
    char *vhostuser_path = NULL;
    char *vhostuser_type = NULL;
8321
    char *trustGuestRxFilters = NULL;
8322
    char *vhost_path = NULL;
8323
    virNWFilterHashTablePtr filterparams = NULL;
8324
    virDomainActualNetDefPtr actual = NULL;
8325
    xmlNodePtr oldnode = ctxt->node;
8326
    int ret, val;
8327 8328 8329
    size_t i;
    size_t nips = 0;
    virDomainNetIpDefPtr *ips = NULL;
8330
    size_t nroutes = 0;
8331
    virNetworkRouteDefPtr *routes = NULL;
8332

8333
    if (VIR_ALLOC(def) < 0)
8334 8335
        return NULL;

8336 8337
    ctxt->node = node;

8338 8339
    type = virXMLPropString(node, "type");
    if (type != NULL) {
S
Stefan Berger 已提交
8340
        if ((int)(def->type = virDomainNetTypeFromString(type)) < 0) {
8341
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
8342
                           _("unknown interface type '%s'"), type);
8343 8344 8345 8346 8347 8348
            goto error;
        }
    } else {
        def->type = VIR_DOMAIN_NET_TYPE_USER;
    }

8349 8350 8351 8352 8353 8354 8355 8356 8357 8358
    trustGuestRxFilters = virXMLPropString(node, "trustGuestRxFilters");
    if (trustGuestRxFilters &&
        ((def->trustGuestRxFilters
          = virTristateBoolTypeFromString(trustGuestRxFilters)) <= 0)) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("unknown trustGuestRxFilters value '%s'"),
                       trustGuestRxFilters);
        goto error;
    }

8359 8360 8361
    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
E
Eric Blake 已提交
8362
            if (!macaddr && xmlStrEqual(cur->name, BAD_CAST "mac")) {
8363
                macaddr = virXMLPropString(cur, "address");
E
Eric Blake 已提交
8364 8365 8366
            } else if (!network &&
                       def->type == VIR_DOMAIN_NET_TYPE_NETWORK &&
                       xmlStrEqual(cur->name, BAD_CAST "source")) {
8367
                network = virXMLPropString(cur, "network");
8368
                portgroup = virXMLPropString(cur, "portgroup");
E
Eric Blake 已提交
8369 8370 8371
            } else if (!internal &&
                       def->type == VIR_DOMAIN_NET_TYPE_INTERNAL &&
                       xmlStrEqual(cur->name, BAD_CAST "source")) {
D
Daniel Veillard 已提交
8372
                internal = virXMLPropString(cur, "name");
G
Guannan Ren 已提交
8373
            } else if (!bridge &&
E
Eric Blake 已提交
8374 8375
                       def->type == VIR_DOMAIN_NET_TYPE_BRIDGE &&
                       xmlStrEqual(cur->name, BAD_CAST "source")) {
8376
                bridge = virXMLPropString(cur, "bridge");
E
Eric Blake 已提交
8377
            } else if (!dev &&
8378 8379
                       (def->type == VIR_DOMAIN_NET_TYPE_ETHERNET ||
                        def->type == VIR_DOMAIN_NET_TYPE_DIRECT) &&
8380
                       xmlStrEqual(cur->name, BAD_CAST "source")) {
8381 8382
                dev  = virXMLPropString(cur, "dev");
                mode = virXMLPropString(cur, "mode");
M
Michele Paolino 已提交
8383 8384 8385 8386 8387 8388
            } 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");
8389 8390
            } else if (!def->virtPortProfile
                       && xmlStrEqual(cur->name, BAD_CAST "virtualport")) {
8391
                if (def->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
8392
                    if (!(def->virtPortProfile
8393 8394 8395 8396 8397 8398 8399 8400 8401 8402 8403 8404
                          = 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))) {
8405 8406 8407 8408 8409 8410
                        goto error;
                    }
                } else {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("<virtualport> element unsupported for"
                                     " <interface type='%s'>"), type);
8411
                    goto error;
8412
                }
G
Guannan Ren 已提交
8413
            } else if (!address &&
E
Eric Blake 已提交
8414 8415
                       (def->type == VIR_DOMAIN_NET_TYPE_SERVER ||
                        def->type == VIR_DOMAIN_NET_TYPE_CLIENT ||
8416 8417
                        def->type == VIR_DOMAIN_NET_TYPE_MCAST ||
                        def->type == VIR_DOMAIN_NET_TYPE_UDP) &&
E
Eric Blake 已提交
8418
                       xmlStrEqual(cur->name, BAD_CAST "source")) {
8419 8420
                address = virXMLPropString(cur, "address");
                port = virXMLPropString(cur, "port");
8421 8422 8423 8424 8425 8426 8427
                if (!localaddr && def->type == VIR_DOMAIN_NET_TYPE_UDP) {
                    xmlNodePtr tmpnode = ctxt->node;
                    ctxt->node = cur;
                    localaddr = virXPathString("string(./local/@address)", ctxt);
                    localport = virXPathString("string(./local/@port)", ctxt);
                    ctxt->node = tmpnode;
                }
8428 8429 8430 8431 8432 8433 8434 8435
            } else if (xmlStrEqual(cur->name, BAD_CAST "ip")) {
                virDomainNetIpDefPtr ip = NULL;

                if (!(ip = virDomainNetIpParseXML(cur)))
                    goto error;

                if (VIR_APPEND_ELEMENT(ips, nips, ip) < 0)
                    goto error;
8436
            } else if (xmlStrEqual(cur->name, BAD_CAST "route")) {
8437 8438 8439
                virNetworkRouteDefPtr route = NULL;
                if (!(route = virNetworkRouteDefParseXML(_("Domain interface"),
                                                         cur, ctxt)))
8440 8441
                    goto error;

8442 8443
                if (VIR_APPEND_ELEMENT(routes, nroutes, route) < 0) {
                    virNetworkRouteDefFree(route);
8444
                    goto error;
8445
                }
E
Eric Blake 已提交
8446
            } else if (!ifname &&
8447 8448
                       xmlStrEqual(cur->name, BAD_CAST "target")) {
                ifname = virXMLPropString(cur, "dev");
E
Eric Blake 已提交
8449
                if (ifname &&
8450
                    (flags & VIR_DOMAIN_DEF_PARSE_INACTIVE) &&
E
Eric Blake 已提交
8451
                    STRPREFIX(ifname, VIR_NET_GENERATED_PREFIX)) {
8452 8453 8454
                    /* An auto-generated target name, blank it out */
                    VIR_FREE(ifname);
                }
8455 8456 8457 8458
            } 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 已提交
8459
            } else if (!linkstate &&
8460 8461
                       xmlStrEqual(cur->name, BAD_CAST "link")) {
                linkstate = virXMLPropString(cur, "state");
E
Eric Blake 已提交
8462
            } else if (!script &&
8463 8464
                       xmlStrEqual(cur->name, BAD_CAST "script")) {
                script = virXMLPropString(cur, "path");
8465 8466 8467
            } else if (!domain_name &&
                       xmlStrEqual(cur->name, BAD_CAST "backenddomain")) {
                domain_name = virXMLPropString(cur, "name");
8468
            } else if (xmlStrEqual(cur->name, BAD_CAST "model")) {
8469
                model = virXMLPropString(cur, "type");
8470
            } else if (xmlStrEqual(cur->name, BAD_CAST "driver")) {
8471
                backend = virXMLPropString(cur, "name");
8472
                txmode = virXMLPropString(cur, "txmode");
8473
                ioeventfd = virXMLPropString(cur, "ioeventfd");
8474
                event_idx = virXMLPropString(cur, "event_idx");
8475
                queues = virXMLPropString(cur, "queues");
8476
            } else if (xmlStrEqual(cur->name, BAD_CAST "filterref")) {
8477 8478 8479 8480 8481 8482
                if (filter) {
                    virReportError(VIR_ERR_XML_ERROR, "%s",
                                   _("Invalid specification of multiple <filterref>s "
                                     "in a single <interface>"));
                    goto error;
                }
8483
                filter = virXMLPropString(cur, "filter");
8484
                virNWFilterHashTableFree(filterparams);
8485
                filterparams = virNWFilterParseParamAttributes(cur);
8486
            } else if ((flags & VIR_DOMAIN_DEF_PARSE_STATUS) &&
8487
                       xmlStrEqual(cur->name, BAD_CAST "state")) {
8488
                /* Legacy back-compat. Don't add any more attributes here */
8489
                devaddr = virXMLPropString(cur, "devaddr");
8490
            } else if (xmlStrEqual(cur->name, BAD_CAST "boot")) {
8491
                /* boot is parsed as part of virDomainDeviceInfoParseXML */
E
Eric Blake 已提交
8492
            } else if (!actual &&
8493
                       (flags & VIR_DOMAIN_DEF_PARSE_ACTUAL_NET) &&
E
Eric Blake 已提交
8494
                       def->type == VIR_DOMAIN_NET_TYPE_NETWORK &&
8495
                       xmlStrEqual(cur->name, BAD_CAST "actual")) {
8496 8497
                if (virDomainActualNetDefParseXML(cur, ctxt, def,
                                                  &actual, flags) < 0) {
8498
                    goto error;
8499
                }
8500
            } else if (xmlStrEqual(cur->name, BAD_CAST "bandwidth")) {
8501 8502 8503
                if (virNetDevBandwidthParse(&def->bandwidth,
                                            cur,
                                            def->type) < 0)
8504
                    goto error;
8505 8506 8507
            } else if (xmlStrEqual(cur->name, BAD_CAST "vlan")) {
                if (virNetDevVlanParse(cur, ctxt, &def->vlan) < 0)
                    goto error;
8508
            } else if (xmlStrEqual(cur->name, BAD_CAST "backend")) {
8509 8510 8511 8512 8513 8514
                char *tmp = NULL;

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

8515 8516
                if (!vhost_path && (tmp = virXMLPropString(cur, "vhost")))
                    vhost_path = virFileSanitizePath(tmp);
8517
                VIR_FREE(tmp);
8518 8519 8520 8521 8522 8523
            }
        }
        cur = cur->next;
    }

    if (macaddr) {
8524
        if (virMacAddrParse((const char *)macaddr, &def->mac) < 0) {
8525 8526 8527
            virReportError(VIR_ERR_XML_ERROR,
                           _("unable to parse mac address '%s'"),
                           (const char *)macaddr);
8528 8529
            goto error;
        }
8530
        if (virMacAddrIsMulticast(&def->mac)) {
8531 8532 8533
            virReportError(VIR_ERR_XML_ERROR,
                           _("expected unicast mac address, found multicast '%s'"),
                           (const char *)macaddr);
8534 8535
            goto error;
        }
8536
    } else {
8537
        virDomainNetGenerateMAC(xmlopt, &def->mac);
8538 8539
    }

8540
    if (devaddr) {
8541 8542
        if (virDomainParseLegacyDeviceAddress(devaddr,
                                              &def->info.addr.pci) < 0) {
8543 8544 8545
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unable to parse devaddr parameter '%s'"),
                           devaddr);
8546 8547 8548 8549
            goto error;
        }
        def->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
    } else {
8550
        if (virDomainDeviceInfoParseXML(node, bootHash, &def->info,
8551 8552
                                        flags | VIR_DOMAIN_DEF_PARSE_ALLOW_BOOT
                                        | VIR_DOMAIN_DEF_PARSE_ALLOW_ROM) < 0)
8553 8554 8555 8556 8557 8558
            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 &&
8559
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO &&
8560
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW &&
8561
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390 &&
8562
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO &&
8563
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
8564 8565
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Network interfaces must use 'pci' address type"));
8566 8567 8568
        goto error;
    }

8569 8570 8571
    switch (def->type) {
    case VIR_DOMAIN_NET_TYPE_NETWORK:
        if (network == NULL) {
8572 8573 8574
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("No <source> 'network' attribute "
                             "specified with <interface type='network'/>"));
8575 8576 8577 8578
            goto error;
        }
        def->data.network.name = network;
        network = NULL;
8579 8580 8581 8582
        def->data.network.portgroup = portgroup;
        portgroup = NULL;
        def->data.network.actual = actual;
        actual = NULL;
8583 8584
        break;

M
Michele Paolino 已提交
8585 8586 8587 8588 8589 8590 8591 8592 8593 8594 8595 8596 8597 8598 8599 8600 8601 8602 8603 8604 8605 8606 8607 8608 8609 8610 8611 8612 8613 8614 8615 8616 8617 8618 8619 8620 8621 8622 8623 8624 8625 8626 8627 8628 8629 8630
    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;

8631
        if (STREQ(vhostuser_mode, "server")) {
M
Michele Paolino 已提交
8632
            def->data.vhostuser->data.nix.listen = true;
8633
        } else if (STREQ(vhostuser_mode, "client")) {
M
Michele Paolino 已提交
8634
            def->data.vhostuser->data.nix.listen = false;
8635
        } else {
M
Michele Paolino 已提交
8636 8637 8638 8639 8640 8641 8642 8643
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("Wrong <source> 'mode' attribute "
                             "specified with <interface "
                             "type='vhostuser'/>"));
            goto error;
        }
        break;

8644 8645 8646 8647 8648 8649 8650 8651 8652
    case VIR_DOMAIN_NET_TYPE_ETHERNET:
        if (dev != NULL) {
            def->data.ethernet.dev = dev;
            dev = NULL;
        }
        break;

    case VIR_DOMAIN_NET_TYPE_BRIDGE:
        if (bridge == NULL) {
8653 8654 8655
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("No <source> 'bridge' attribute "
                             "specified with <interface type='bridge'/>"));
8656 8657 8658 8659 8660 8661 8662 8663 8664
            goto error;
        }
        def->data.bridge.brname = bridge;
        bridge = NULL;
        break;

    case VIR_DOMAIN_NET_TYPE_CLIENT:
    case VIR_DOMAIN_NET_TYPE_SERVER:
    case VIR_DOMAIN_NET_TYPE_MCAST:
8665
    case VIR_DOMAIN_NET_TYPE_UDP:
8666
        if (port == NULL) {
8667 8668 8669
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("No <source> 'port' attribute "
                             "specified with socket interface"));
8670 8671 8672
            goto error;
        }
        if (virStrToLong_i(port, NULL, 10, &def->data.socket.port) < 0) {
8673 8674 8675
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Cannot parse <source> 'port' attribute "
                             "with socket interface"));
8676 8677 8678 8679 8680
            goto error;
        }

        if (address == NULL) {
            if (def->type == VIR_DOMAIN_NET_TYPE_CLIENT ||
8681 8682
                def->type == VIR_DOMAIN_NET_TYPE_MCAST ||
                def->type == VIR_DOMAIN_NET_TYPE_UDP) {
8683 8684 8685
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("No <source> 'address' attribute "
                                 "specified with socket interface"));
8686 8687 8688 8689 8690 8691
                goto error;
            }
        } else {
            def->data.socket.address = address;
            address = NULL;
        }
8692 8693 8694 8695 8696 8697 8698 8699 8700 8701 8702 8703 8704 8705 8706 8707 8708 8709 8710 8711 8712 8713 8714 8715 8716 8717

        if (def->type != VIR_DOMAIN_NET_TYPE_UDP)
            break;

        if (localport == NULL) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("No <local> 'port' attribute "
                             "specified with socket interface"));
            goto error;
        }
        if (virStrToLong_i(localport, NULL, 10, &def->data.socket.localport) < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Cannot parse <local> 'port' attribute "
                             "with socket interface"));
            goto error;
        }

        if (localaddr == NULL) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("No <local> 'address' attribute "
                             "specified with socket interface"));
            goto error;
        } else {
            def->data.socket.localaddr = localaddr;
            localaddr = NULL;
        }
8718 8719
        break;

D
Daniel Veillard 已提交
8720 8721
    case VIR_DOMAIN_NET_TYPE_INTERNAL:
        if (internal == NULL) {
8722 8723 8724
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("No <source> 'name' attribute specified "
                             "with <interface type='internal'/>"));
D
Daniel Veillard 已提交
8725 8726 8727 8728 8729
            goto error;
        }
        def->data.internal.name = internal;
        internal = NULL;
        break;
8730 8731 8732

    case VIR_DOMAIN_NET_TYPE_DIRECT:
        if (dev == NULL) {
8733 8734 8735
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("No <source> 'dev' attribute specified "
                             "with <interface type='direct'/>"));
8736 8737 8738 8739
            goto error;
        }

        if (mode != NULL) {
8740
            if ((val = virNetDevMacVLanModeTypeFromString(mode)) < 0) {
8741
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
J
Ján Tomko 已提交
8742
                               _("Unknown mode has been specified"));
8743 8744
                goto error;
            }
8745
            def->data.direct.mode = val;
E
Eric Blake 已提交
8746
        } else {
8747
            def->data.direct.mode = VIR_NETDEV_MACVLAN_MODE_VEPA;
E
Eric Blake 已提交
8748
        }
8749 8750 8751 8752

        def->data.direct.linkdev = dev;
        dev = NULL;

8753
        if (flags & VIR_DOMAIN_DEF_PARSE_INACTIVE)
8754
            VIR_FREE(ifname);
8755

8756
        break;
S
Stefan Berger 已提交
8757

8758 8759 8760 8761 8762 8763 8764 8765 8766 8767 8768
    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 已提交
8769
        if (!addrtype && virXPathNode("./source/vendor", ctxt) &&
8770
            VIR_STRDUP(addrtype, "usb") < 0)
8771
            goto error;
8772 8773 8774
        hostdev->mode = VIR_DOMAIN_HOSTDEV_MODE_SUBSYS;
        if (virDomainHostdevDefParseXMLSubsys(node, ctxt, addrtype,
                                              hostdev, flags) < 0) {
8775 8776 8777 8778
            goto error;
        }
        break;

S
Stefan Berger 已提交
8779 8780 8781
    case VIR_DOMAIN_NET_TYPE_USER:
    case VIR_DOMAIN_NET_TYPE_LAST:
        break;
8782 8783
    }

8784 8785 8786 8787
    for (i = 0; i < nips; i++) {
        if (VIR_APPEND_ELEMENT(def->ips, def->nips, ips[i]) < 0)
            goto error;
    }
8788 8789
    def->nroutes = nroutes;
    def->routes = routes;
8790

8791 8792 8793 8794
    if (script != NULL) {
        def->script = script;
        script = NULL;
    }
8795 8796 8797 8798
    if (domain_name != NULL) {
        def->domain_name = domain_name;
        domain_name = NULL;
    }
8799 8800 8801 8802
    if (ifname != NULL) {
        def->ifname = ifname;
        ifname = NULL;
    }
8803 8804 8805 8806 8807 8808 8809 8810
    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;
    }
8811 8812 8813 8814 8815

    /* 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 已提交
8816
     * QEMU PPC64 supports spapr-vlan
8817 8818
     */
    if (model != NULL) {
E
Eric Blake 已提交
8819
        if (strspn(model, NET_MODEL_CHARS) < strlen(model)) {
8820 8821
            virReportError(VIR_ERR_INVALID_ARG, "%s",
                           _("Model name contains invalid characters"));
E
Eric Blake 已提交
8822
            goto error;
8823 8824 8825 8826 8827
        }
        def->model = model;
        model = NULL;
    }

8828 8829
    if (def->type != VIR_DOMAIN_NET_TYPE_HOSTDEV &&
        STREQ_NULLABLE(def->model, "virtio")) {
8830
        if (backend != NULL) {
8831 8832
            if ((val = virDomainNetBackendTypeFromString(backend)) < 0 ||
                val == VIR_DOMAIN_NET_BACKEND_TYPE_DEFAULT) {
8833
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
8834 8835 8836
                               _("Unknown interface <driver name='%s'> "
                                 "has been specified"),
                               backend);
8837 8838
                goto error;
            }
8839
            def->driver.virtio.name = val;
8840
        }
8841
        if (txmode != NULL) {
8842 8843
            if ((val = virDomainNetVirtioTxModeTypeFromString(txmode)) < 0 ||
                val == VIR_DOMAIN_NET_VIRTIO_TX_MODE_DEFAULT) {
8844
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
8845 8846 8847
                               _("Unknown interface <driver txmode='%s'> "
                                 "has been specified"),
                               txmode);
8848 8849
                goto error;
            }
8850
            def->driver.virtio.txmode = val;
8851
        }
8852
        if (ioeventfd) {
J
Ján Tomko 已提交
8853
            if ((val = virTristateSwitchTypeFromString(ioeventfd)) <= 0) {
8854 8855 8856
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("unknown interface ioeventfd mode '%s'"),
                               ioeventfd);
8857 8858
                goto error;
            }
8859
            def->driver.virtio.ioeventfd = val;
8860
        }
8861
        if (event_idx) {
8862
            if ((val = virTristateSwitchTypeFromString(event_idx)) <= 0) {
8863 8864 8865
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("unknown interface event_idx mode '%s'"),
                               event_idx);
8866 8867
                goto error;
            }
8868
            def->driver.virtio.event_idx = val;
8869
        }
8870 8871
        if (queues) {
            unsigned int q;
8872
            if (virStrToLong_uip(queues, NULL, 10, &q) < 0) {
8873 8874 8875 8876 8877
                virReportError(VIR_ERR_XML_DETAIL,
                               _("'queues' attribute must be positive number: %s"),
                               queues);
                goto error;
            }
8878 8879
            if (q > 1)
                def->driver.virtio.queues = q;
8880
        }
8881 8882 8883 8884 8885 8886 8887 8888 8889 8890 8891 8892 8893 8894 8895 8896 8897 8898 8899 8900 8901 8902 8903 8904 8905 8906 8907 8908 8909 8910 8911 8912 8913 8914 8915 8916 8917 8918 8919 8920 8921 8922 8923 8924 8925 8926 8927 8928 8929 8930 8931 8932 8933 8934 8935 8936 8937 8938 8939 8940
        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);
8941 8942 8943 8944 8945 8946 8947 8948 8949 8950
        if ((str = virXPathString("string(./driver/host/@mrg_rxbuf)", ctxt))) {
            if ((val = virTristateSwitchTypeFromString(str)) <= 0) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("unknown host mrg_rxbuf mode '%s'"),
                               str);
                goto error;
            }
            def->driver.virtio.host.mrg_rxbuf = val;
        }
        VIR_FREE(str);
8951 8952 8953 8954 8955 8956 8957 8958 8959 8960 8961 8962 8963 8964 8965 8966 8967 8968 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 8998 8999
        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;
        }
9000 9001
        def->backend.vhost = vhost_path;
        vhost_path = NULL;
9002
    }
9003

9004 9005 9006
    def->linkstate = VIR_DOMAIN_NET_INTERFACE_LINK_STATE_DEFAULT;
    if (linkstate != NULL) {
        if ((def->linkstate = virDomainNetInterfaceLinkStateTypeFromString(linkstate)) <= 0) {
9007 9008 9009
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown interface link state '%s'"),
                           linkstate);
9010 9011 9012 9013
            goto error;
        }
    }

9014 9015 9016 9017 9018 9019 9020 9021 9022 9023 9024 9025 9026 9027 9028
    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;
        }
    }

9029 9030 9031 9032
    ret = virXPathULong("string(./tune/sndbuf)", ctxt, &def->tune.sndbuf);
    if (ret >= 0) {
        def->tune.sndbuf_specified = true;
    } else if (ret == -2) {
9033 9034
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("sndbuf must be a positive integer"));
9035 9036 9037
        goto error;
    }

9038
 cleanup:
9039
    ctxt->node = oldnode;
9040 9041
    VIR_FREE(macaddr);
    VIR_FREE(network);
9042
    VIR_FREE(portgroup);
9043 9044
    VIR_FREE(address);
    VIR_FREE(port);
M
Michele Paolino 已提交
9045 9046 9047
    VIR_FREE(vhostuser_type);
    VIR_FREE(vhostuser_path);
    VIR_FREE(vhostuser_mode);
9048
    VIR_FREE(ifname);
9049 9050
    VIR_FREE(ifname_guest);
    VIR_FREE(ifname_guest_actual);
9051
    VIR_FREE(dev);
9052
    virDomainActualNetDefFree(actual);
9053 9054 9055
    VIR_FREE(script);
    VIR_FREE(bridge);
    VIR_FREE(model);
9056
    VIR_FREE(backend);
9057
    VIR_FREE(txmode);
9058
    VIR_FREE(ioeventfd);
9059
    VIR_FREE(event_idx);
9060
    VIR_FREE(queues);
9061
    VIR_FREE(str);
9062
    VIR_FREE(filter);
9063
    VIR_FREE(type);
D
Daniel Veillard 已提交
9064
    VIR_FREE(internal);
9065
    VIR_FREE(devaddr);
S
Stefan Berger 已提交
9066
    VIR_FREE(mode);
9067
    VIR_FREE(linkstate);
9068
    VIR_FREE(addrtype);
9069
    VIR_FREE(domain_name);
9070
    VIR_FREE(trustGuestRxFilters);
9071
    VIR_FREE(ips);
9072
    VIR_FREE(vhost_path);
9073 9074
    VIR_FREE(localaddr);
    VIR_FREE(localport);
9075
    virNWFilterHashTableFree(filterparams);
9076 9077 9078

    return def;

9079
 error:
9080 9081 9082 9083 9084
    virDomainNetDefFree(def);
    def = NULL;
    goto cleanup;
}

9085
static int
9086 9087
virDomainChrDefaultTargetType(int devtype)
{
9088
    switch ((virDomainChrDeviceType) devtype) {
9089
    case VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL:
9090 9091 9092
        virReportError(VIR_ERR_XML_ERROR,
                       _("target type must be specified for %s device"),
                       virDomainChrDeviceTypeToString(devtype));
9093
        return -1;
9094 9095

    case VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE:
9096
        return VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_NONE;
9097

9098
    case VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL:
9099
        return VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_ISA;
G
Guannan Ren 已提交
9100

9101
    case VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL:
9102
    case VIR_DOMAIN_CHR_DEVICE_TYPE_LAST:
9103 9104 9105 9106
        /* No target type yet*/
        break;
    }

9107
    return 0;
9108 9109 9110
}

static int
9111
virDomainChrTargetTypeFromString(virDomainChrDefPtr def,
9112
                                 int devtype,
9113 9114 9115 9116
                                 const char *targetType)
{
    int ret = -1;

9117 9118
    if (!targetType)
        return virDomainChrDefaultTargetType(devtype);
9119

9120
    switch ((virDomainChrDeviceType) devtype) {
9121
    case VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL:
9122
        ret = virDomainChrChannelTargetTypeFromString(targetType);
9123 9124
        break;

9125
    case VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE:
9126
        ret = virDomainChrConsoleTargetTypeFromString(targetType);
C
Cole Robinson 已提交
9127
        break;
9128

9129
    case VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL:
9130
        ret = virDomainChrSerialTargetTypeFromString(targetType);
G
Guannan Ren 已提交
9131 9132
        break;

9133
    case VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL:
9134
    case VIR_DOMAIN_CHR_DEVICE_TYPE_LAST:
9135
        /* No target type yet*/
9136
        ret = 0;
9137 9138 9139
        break;
    }

G
Guannan Ren 已提交
9140 9141
    def->targetTypeAttr = true;

9142 9143 9144 9145
    return ret;
}

static int
9146
virDomainChrDefParseTargetXML(virDomainChrDefPtr def,
9147 9148
                              xmlNodePtr cur,
                              unsigned int flags)
9149 9150 9151
{
    int ret = -1;
    unsigned int port;
9152 9153 9154
    char *targetType = virXMLPropString(cur, "type");
    char *addrStr = NULL;
    char *portStr = NULL;
9155
    char *stateStr = NULL;
9156 9157

    if ((def->targetType =
9158 9159
         virDomainChrTargetTypeFromString(def, def->deviceType,
                                          targetType)) < 0) {
9160
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
9161 9162
                       _("unknown target type '%s' specified for character device"),
                       targetType);
9163 9164 9165 9166 9167 9168 9169 9170 9171 9172
        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");

9173
            if (VIR_ALLOC(def->target.addr) < 0)
9174 9175
                goto error;

9176
            if (addrStr == NULL) {
9177 9178 9179
                virReportError(VIR_ERR_XML_ERROR, "%s",
                               _("guestfwd channel does not "
                                 "define a target address"));
9180 9181 9182
                goto error;
            }

9183
            if (virSocketAddrParse(def->target.addr, addrStr, AF_UNSPEC) < 0)
9184 9185
                goto error;

9186
            if (def->target.addr->data.stor.ss_family != AF_INET) {
9187 9188 9189
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               "%s", _("guestfwd channel only supports "
                                       "IPv4 addresses"));
9190 9191 9192 9193
                goto error;
            }

            if (portStr == NULL) {
9194 9195 9196
                virReportError(VIR_ERR_XML_ERROR, "%s",
                               _("guestfwd channel does "
                                 "not define a target port"));
9197 9198 9199 9200
                goto error;
            }

            if (virStrToLong_ui(portStr, NULL, 10, &port) < 0) {
9201 9202 9203
                virReportError(VIR_ERR_XML_ERROR,
                               _("Invalid port number: %s"),
                               portStr);
9204 9205 9206
                goto error;
            }

9207
            virSocketAddrSetPort(def->target.addr, port);
9208 9209 9210 9211
            break;

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

9213
            if (!(flags & VIR_DOMAIN_DEF_PARSE_INACTIVE) &&
9214 9215 9216 9217 9218 9219 9220 9221 9222 9223 9224 9225
                (stateStr = virXMLPropString(cur, "state"))) {
                int tmp;

                if ((tmp = virDomainChrDeviceStateTypeFromString(stateStr)) <= 0) {
                    virReportError(VIR_ERR_XML_ERROR,
                                   _("invalid channel state value '%s'"),
                                   stateStr);
                    goto error;
                }

                def->state = tmp;
            }
9226 9227 9228 9229 9230 9231 9232
            break;
        }
        break;

    default:
        portStr = virXMLPropString(cur, "port");
        if (portStr == NULL) {
9233 9234
            /* Set to negative value to indicate we should set it later */
            def->target.port = -1;
9235 9236 9237 9238
            break;
        }

        if (virStrToLong_ui(portStr, NULL, 10, &port) < 0) {
9239 9240 9241
            virReportError(VIR_ERR_XML_ERROR,
                           _("Invalid port number: %s"),
                           portStr);
9242 9243
            goto error;
        }
9244
        def->target.port = port;
9245 9246 9247 9248 9249
        break;
    }


    ret = 0;
9250
 error:
9251 9252 9253
    VIR_FREE(targetType);
    VIR_FREE(addrStr);
    VIR_FREE(portStr);
9254
    VIR_FREE(stateStr);
9255 9256 9257 9258

    return ret;
}

9259 9260 9261
#define SERIAL_CHANNEL_NAME_CHARS \
    "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-."

9262 9263 9264 9265 9266 9267 9268
/* 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,
9269 9270 9271 9272 9273
                              xmlNodePtr cur, unsigned int flags,
                              virDomainChrDefPtr chr_def,
                              xmlXPathContextPtr ctxt,
                              virSecurityLabelDefPtr* vmSeclabels,
                              int nvmSeclabels)
9274
{
9275 9276 9277 9278 9279 9280 9281
    char *bindHost = NULL;
    char *bindService = NULL;
    char *connectHost = NULL;
    char *connectService = NULL;
    char *path = NULL;
    char *mode = NULL;
    char *protocol = NULL;
9282
    char *channel = NULL;
9283 9284
    char *master = NULL;
    char *slave = NULL;
9285
    int remaining = 0;
9286 9287 9288 9289

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

9293
                switch ((virDomainChrType) def->type) {
9294 9295 9296 9297 9298
                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:
9299
                    /* PTY path is only parsed from live xml.  */
9300
                    if (!path  &&
9301
                        (def->type != VIR_DOMAIN_CHR_TYPE_PTY ||
9302
                         !(flags & VIR_DOMAIN_DEF_PARSE_INACTIVE)))
9303 9304 9305 9306 9307 9308
                        path = virXMLPropString(cur, "path");

                    break;

                case VIR_DOMAIN_CHR_TYPE_UDP:
                case VIR_DOMAIN_CHR_TYPE_TCP:
9309 9310
                    if (!mode || STREQ(mode, "connect")) {
                        if (!connectHost)
9311
                            connectHost = virXMLPropString(cur, "host");
9312
                        if (!connectService)
9313
                            connectService = virXMLPropString(cur, "service");
9314 9315
                    } else if (STREQ(mode, "bind")) {
                        if (!bindHost)
9316
                            bindHost = virXMLPropString(cur, "host");
9317
                        if (!bindService)
9318
                            bindService = virXMLPropString(cur, "service");
9319
                    } else {
9320
                        virReportError(VIR_ERR_INTERNAL_ERROR,
9321
                                       _("Unknown source mode '%s'"), mode);
9322
                        goto error;
9323 9324
                    }

9325
                    if (def->type == VIR_DOMAIN_CHR_TYPE_UDP)
9326
                        VIR_FREE(mode);
9327 9328
                    break;

9329 9330 9331 9332 9333
                case VIR_DOMAIN_CHR_TYPE_SPICEPORT:
                    if (!channel)
                        channel = virXMLPropString(cur, "channel");
                    break;

9334 9335 9336 9337 9338 9339 9340
                case VIR_DOMAIN_CHR_TYPE_NMDM:
                    if (!master)
                        master = virXMLPropString(cur, "master");
                    if (!slave)
                        slave = virXMLPropString(cur, "slave");
                    break;

9341 9342 9343 9344 9345 9346
                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;
9347
                }
9348 9349 9350 9351 9352 9353 9354 9355 9356

                /* 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,
9357 9358
                                                          ctxt,
                                                          flags) < 0) {
9359 9360 9361 9362 9363
                        ctxt->node = saved_node;
                        goto error;
                    }
                    ctxt->node = saved_node;
                }
9364
            } else if (xmlStrEqual(cur->name, BAD_CAST "protocol")) {
9365
                if (!protocol)
9366
                    protocol = virXMLPropString(cur, "type");
9367 9368
            } else {
                remaining++;
9369 9370 9371 9372 9373
            }
        }
        cur = cur->next;
    }

9374
    switch ((virDomainChrType) def->type) {
9375
    case VIR_DOMAIN_CHR_TYPE_NULL:
9376
    case VIR_DOMAIN_CHR_TYPE_VC:
9377 9378
    case VIR_DOMAIN_CHR_TYPE_STDIO:
    case VIR_DOMAIN_CHR_TYPE_SPICEVMC:
9379
    case VIR_DOMAIN_CHR_TYPE_LAST:
9380 9381 9382 9383 9384 9385
        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:
9386
        if (!path &&
9387
            def->type != VIR_DOMAIN_CHR_TYPE_PTY) {
9388 9389
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Missing source path attribute for char device"));
9390 9391 9392 9393 9394 9395 9396
            goto error;
        }

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

9397 9398 9399 9400 9401 9402 9403 9404 9405 9406 9407 9408 9409 9410 9411 9412 9413 9414 9415
    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;

9416
    case VIR_DOMAIN_CHR_TYPE_TCP:
9417 9418
        if (!mode || STREQ(mode, "connect")) {
            if (!connectHost) {
9419 9420
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Missing source host attribute for char device"));
9421 9422
                goto error;
            }
9423 9424

            if (!connectService) {
9425 9426
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Missing source service attribute for char device"));
9427 9428 9429 9430 9431 9432 9433
                goto error;
            }

            def->data.tcp.host = connectHost;
            connectHost = NULL;
            def->data.tcp.service = connectService;
            connectService = NULL;
9434
            def->data.tcp.listen = false;
9435
        } else {
9436
            if (!bindHost) {
9437 9438
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Missing source host attribute for char device"));
9439 9440
                goto error;
            }
9441 9442

            if (!bindService) {
9443 9444
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Missing source service attribute for char device"));
9445 9446 9447 9448 9449 9450 9451
                goto error;
            }

            def->data.tcp.host = bindHost;
            bindHost = NULL;
            def->data.tcp.service = bindService;
            bindService = NULL;
9452
            def->data.tcp.listen = true;
9453
        }
9454

9455
        if (!protocol)
9456
            def->data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_RAW;
9457 9458
        else if ((def->data.tcp.protocol =
                  virDomainChrTcpProtocolTypeFromString(protocol)) < 0) {
9459
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
9460
                           _("Unknown protocol '%s'"), protocol);
9461 9462 9463
            goto error;
        }

9464 9465 9466
        break;

    case VIR_DOMAIN_CHR_TYPE_UDP:
9467
        if (!connectService) {
9468 9469
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Missing source service attribute for char device"));
9470 9471 9472 9473 9474 9475 9476 9477 9478 9479 9480 9481 9482 9483 9484
            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:
9485 9486
        /* path can be auto generated */
        if (!path &&
9487 9488
            (!chr_def ||
             chr_def->targetType != VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO)) {
9489 9490
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Missing source path attribute for char device"));
9491 9492 9493
            goto error;
        }

9494
        def->data.nix.listen = mode != NULL && STRNEQ(mode, "connect");
9495 9496 9497 9498

        def->data.nix.path = path;
        path = NULL;
        break;
9499 9500 9501 9502 9503 9504 9505 9506 9507 9508 9509 9510 9511 9512 9513

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

9516
 cleanup:
9517 9518 9519 9520 9521 9522 9523
    VIR_FREE(mode);
    VIR_FREE(protocol);
    VIR_FREE(bindHost);
    VIR_FREE(bindService);
    VIR_FREE(connectHost);
    VIR_FREE(connectService);
    VIR_FREE(path);
9524
    VIR_FREE(channel);
9525

9526 9527
    return remaining;

9528
 error:
9529 9530 9531 9532 9533
    virDomainChrSourceDefClear(def);
    remaining = -1;
    goto cleanup;
}

M
Michal Novotny 已提交
9534 9535 9536 9537
/* Create a new character device definition and set
 * default port.
 */
virDomainChrDefPtr
9538 9539
virDomainChrDefNew(void)
{
M
Michal Novotny 已提交
9540 9541
    virDomainChrDefPtr def = NULL;

9542
    if (VIR_ALLOC(def) < 0)
M
Michal Novotny 已提交
9543 9544 9545 9546 9547 9548
        return NULL;

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

9549 9550 9551 9552 9553 9554 9555 9556 9557 9558 9559 9560 9561 9562 9563 9564 9565 9566 9567 9568 9569 9570 9571 9572 9573 9574 9575 9576 9577 9578 9579 9580 9581 9582 9583 9584 9585
/* 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>
 *
9586 9587 9588 9589 9590
 * <serial type="nmdm">
 *   <source master="/dev/nmdm0A" slave="/dev/nmdm0B"/>
 *   <target port="1">
 * </serial>
 *
9591 9592
 */
static virDomainChrDefPtr
9593
virDomainChrDefParseXML(xmlXPathContextPtr ctxt,
9594
                        xmlNodePtr node,
9595 9596
                        virSecurityLabelDefPtr* vmSeclabels,
                        int nvmSeclabels,
E
Eric Blake 已提交
9597 9598
                        unsigned int flags)
{
9599 9600 9601 9602
    xmlNodePtr cur;
    char *type = NULL;
    const char *nodeName;
    virDomainChrDefPtr def;
9603
    bool seenTarget = false;
9604

M
Michal Novotny 已提交
9605
    if (!(def = virDomainChrDefNew()))
9606 9607 9608 9609 9610 9611
        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) {
9612
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
9613 9614
                       _("unknown type presented to host for character device: %s"),
                       type);
9615 9616 9617 9618 9619
        goto error;
    }

    nodeName = (const char *) node->name;
    if ((def->deviceType = virDomainChrDeviceTypeFromString(nodeName)) < 0) {
9620
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
9621 9622
                       _("unknown character device type: %s"),
                       nodeName);
9623
        goto error;
9624 9625 9626
    }

    cur = node->children;
9627 9628 9629 9630
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
            if (xmlStrEqual(cur->name, BAD_CAST "target")) {
                seenTarget = true;
9631
                if (virDomainChrDefParseTargetXML(def, cur, flags) < 0)
9632
                    goto error;
9633 9634
            }
        }
9635
        cur = cur->next;
9636 9637
    }

9638
    if (!seenTarget &&
9639
        ((def->targetType = virDomainChrDefaultTargetType(def->deviceType)) < 0))
9640
        goto error;
9641

9642 9643 9644 9645
    if (virDomainChrSourceDefParseXML(&def->source, node->children, flags, def,
                                      ctxt, vmSeclabels, nvmSeclabels) < 0)
        goto error;

E
Eric Blake 已提交
9646 9647
    if (def->source.type == VIR_DOMAIN_CHR_TYPE_SPICEVMC) {
        if (def->targetType != VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO) {
9648 9649 9650
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("spicevmc device type only supports "
                             "virtio"));
E
Eric Blake 已提交
9651 9652 9653 9654
            goto error;
        } else {
            def->source.data.spicevmc = VIR_DOMAIN_CHR_SPICEVMC_VDAGENT;
        }
9655 9656
    }

9657 9658 9659 9660
    if (def->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL &&
        def->targetType == VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_GUESTFWD) {
        VIR_DEBUG("Ignoring device address for gustfwd channel");
    } else if (virDomainDeviceInfoParseXML(node, NULL, &def->info, flags) < 0) {
9661
        goto error;
9662 9663
    }

9664

G
Guannan Ren 已提交
9665 9666 9667 9668 9669 9670 9671 9672 9673
    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;
    }

9674
 cleanup:
9675 9676
    VIR_FREE(type);

9677 9678
    return def;

9679
 error:
9680 9681 9682 9683 9684
    virDomainChrDefFree(def);
    def = NULL;
    goto cleanup;
}

E
Eric Blake 已提交
9685 9686
static virDomainSmartcardDefPtr
virDomainSmartcardDefParseXML(xmlNodePtr node,
E
Eric Blake 已提交
9687
                              unsigned int flags)
E
Eric Blake 已提交
9688 9689 9690 9691 9692
{
    xmlNodePtr cur;
    char *mode = NULL;
    char *type = NULL;
    virDomainSmartcardDefPtr def;
9693
    size_t i;
E
Eric Blake 已提交
9694

9695
    if (VIR_ALLOC(def) < 0)
E
Eric Blake 已提交
9696 9697 9698 9699
        return NULL;

    mode = virXMLPropString(node, "mode");
    if (mode == NULL) {
9700 9701
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("missing smartcard device mode"));
E
Eric Blake 已提交
9702 9703 9704
        goto error;
    }
    if ((def->type = virDomainSmartcardTypeFromString(mode)) < 0) {
9705
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
9706 9707
                       _("unknown smartcard device mode: %s"),
                       mode);
E
Eric Blake 已提交
9708 9709 9710 9711 9712 9713 9714 9715 9716 9717 9718 9719 9720 9721
        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) {
9722 9723 9724
                    virReportError(VIR_ERR_XML_ERROR, "%s",
                                   _("host-certificates mode needs "
                                     "exactly three certificates"));
E
Eric Blake 已提交
9725 9726 9727 9728 9729 9730 9731 9732 9733 9734 9735 9736 9737 9738 9739 9740 9741
                    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 != '/') {
9742 9743 9744
                    virReportError(VIR_ERR_XML_ERROR,
                                   _("expecting absolute path: %s"),
                                   def->data.cert.database);
E
Eric Blake 已提交
9745 9746 9747 9748 9749 9750
                    goto error;
                }
            }
            cur = cur->next;
        }
        if (i < 3) {
9751 9752 9753
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("host-certificates mode needs "
                             "exactly three certificates"));
E
Eric Blake 已提交
9754 9755 9756 9757 9758 9759 9760
            goto error;
        }
        break;

    case VIR_DOMAIN_SMARTCARD_TYPE_PASSTHROUGH:
        type = virXMLPropString(node, "type");
        if (type == NULL) {
9761 9762 9763
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("passthrough mode requires a character "
                             "device type attribute"));
E
Eric Blake 已提交
9764 9765 9766
            goto error;
        }
        if ((def->data.passthru.type = virDomainChrTypeFromString(type)) < 0) {
9767
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
9768 9769
                           _("unknown type presented to host for "
                             "character device: %s"), type);
E
Eric Blake 已提交
9770 9771 9772 9773
            goto error;
        }

        cur = node->children;
9774 9775
        if (virDomainChrSourceDefParseXML(&def->data.passthru, cur, flags,
                                          NULL, NULL, NULL, 0) < 0)
E
Eric Blake 已提交
9776
            goto error;
9777 9778

        if (def->data.passthru.type == VIR_DOMAIN_CHR_TYPE_SPICEVMC) {
E
Eric Blake 已提交
9779 9780
            def->data.passthru.data.spicevmc
                = VIR_DOMAIN_CHR_SPICEVMC_SMARTCARD;
9781
        }
E
Eric Blake 已提交
9782

E
Eric Blake 已提交
9783 9784 9785
        break;

    default:
9786 9787
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("unknown smartcard mode"));
E
Eric Blake 已提交
9788 9789 9790
        goto error;
    }

9791
    if (virDomainDeviceInfoParseXML(node, NULL, &def->info, flags) < 0)
E
Eric Blake 已提交
9792 9793 9794
        goto error;
    if (def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCID) {
9795 9796
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Controllers must use the 'ccid' address type"));
E
Eric Blake 已提交
9797 9798 9799
        goto error;
    }

9800
 cleanup:
E
Eric Blake 已提交
9801 9802 9803 9804 9805
    VIR_FREE(mode);
    VIR_FREE(type);

    return def;

9806
 error:
E
Eric Blake 已提交
9807 9808 9809 9810 9811
    virDomainSmartcardDefFree(def);
    def = NULL;
    goto cleanup;
}

9812 9813 9814 9815 9816 9817 9818 9819 9820 9821 9822 9823
/* 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
9824
virDomainTPMDefParseXML(xmlNodePtr node,
9825 9826 9827 9828 9829 9830 9831 9832 9833 9834 9835 9836
                        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;

9837
    if (VIR_ALLOC(def) < 0)
9838 9839 9840 9841 9842
        return NULL;

    model = virXMLPropString(node, "model");
    if (model != NULL &&
        (int)(def->model = virDomainTPMModelTypeFromString(model)) < 0) {
9843
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
9844 9845 9846 9847 9848 9849 9850 9851 9852 9853 9854 9855 9856 9857 9858 9859 9860
                       _("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;
    }

9861 9862 9863 9864 9865 9866
    if (nbackends == 0) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("missing TPM device backend"));
        goto error;
    }

9867 9868 9869 9870 9871 9872 9873
    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) {
9874
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
9875 9876 9877 9878 9879 9880 9881 9882
                       _("Unknown TPM backend type '%s'"),
                       backend);
        goto error;
    }

    switch (def->type) {
    case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH:
        path = virXPathString("string(./backend/device/@path)", ctxt);
9883
        if (!path && VIR_STRDUP(path, VIR_DOMAIN_TPM_DEFAULT_DEVICE) < 0)
9884 9885 9886 9887 9888 9889 9890 9891 9892 9893 9894 9895
            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;

9896
 cleanup:
9897 9898 9899 9900 9901 9902 9903 9904
    VIR_FREE(type);
    VIR_FREE(path);
    VIR_FREE(model);
    VIR_FREE(backend);
    VIR_FREE(backends);
    ctxt->node = save;
    return def;

9905
 error:
9906 9907 9908 9909 9910
    virDomainTPMDefFree(def);
    def = NULL;
    goto cleanup;
}

9911 9912 9913 9914
static virDomainPanicDefPtr
virDomainPanicDefParseXML(xmlNodePtr node)
{
    virDomainPanicDefPtr panic;
9915
    char *model = NULL;
9916 9917 9918 9919 9920 9921 9922

    if (VIR_ALLOC(panic) < 0)
        return NULL;

    if (virDomainDeviceInfoParseXML(node, NULL, &panic->info, 0) < 0)
        goto error;

9923 9924 9925 9926 9927 9928 9929 9930 9931 9932
    model = virXMLPropString(node, "model");
    if (model != NULL &&
        (panic->model = virDomainPanicModelTypeFromString(model)) < 0) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("unknown panic model '%s'"), model);
        goto error;
    }

 cleanup:
    VIR_FREE(model);
9933
    return panic;
9934

9935 9936
 error:
    virDomainPanicDefFree(panic);
9937 9938
    panic = NULL;
    goto cleanup;
9939 9940
}

9941
/* Parse the XML definition for an input device */
9942
static virDomainInputDefPtr
L
Li Zhang 已提交
9943
virDomainInputDefParseXML(const virDomainDef *dom,
9944
                          xmlNodePtr node,
9945
                          xmlXPathContextPtr ctxt,
E
Eric Blake 已提交
9946 9947
                          unsigned int flags)
{
9948
    xmlNodePtr save = ctxt->node;
9949
    virDomainInputDefPtr def;
9950
    char *evdev = NULL;
9951 9952 9953
    char *type = NULL;
    char *bus = NULL;

9954
    if (VIR_ALLOC(def) < 0)
9955 9956
        return NULL;

9957 9958
    ctxt->node = node;

9959 9960 9961 9962
    type = virXMLPropString(node, "type");
    bus = virXMLPropString(node, "bus");

    if (!type) {
9963 9964
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing input device type"));
9965 9966 9967 9968
        goto error;
    }

    if ((def->type = virDomainInputTypeFromString(type)) < 0) {
9969
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
9970
                       _("unknown input device type '%s'"), type);
9971 9972 9973 9974 9975
        goto error;
    }

    if (bus) {
        if ((def->bus = virDomainInputBusTypeFromString(bus)) < 0) {
9976
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
9977
                           _("unknown input bus type '%s'"), bus);
9978 9979 9980
            goto error;
        }

9981
        if (dom->os.type == VIR_DOMAIN_OSTYPE_HVM) {
L
Li Zhang 已提交
9982 9983 9984
            if (def->bus == VIR_DOMAIN_INPUT_BUS_PS2 &&
                def->type != VIR_DOMAIN_INPUT_TYPE_MOUSE &&
                def->type != VIR_DOMAIN_INPUT_TYPE_KBD) {
9985 9986 9987
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("ps2 bus does not support %s input device"),
                               type);
9988 9989 9990
                goto error;
            }
            if (def->bus == VIR_DOMAIN_INPUT_BUS_XEN) {
9991 9992 9993
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unsupported input bus %s"),
                               bus);
9994 9995
                goto error;
            }
9996
        } else if (dom->os.type == VIR_DOMAIN_OSTYPE_XEN) {
9997
            if (def->bus != VIR_DOMAIN_INPUT_BUS_XEN) {
9998 9999 10000
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unsupported input bus %s"),
                               bus);
10001
                goto error;
10002
            }
L
Li Zhang 已提交
10003 10004
            if (def->type != VIR_DOMAIN_INPUT_TYPE_MOUSE &&
                def->type != VIR_DOMAIN_INPUT_TYPE_KBD) {
10005 10006 10007
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("xen bus does not support %s input device"),
                               type);
10008 10009
                goto error;
            }
10010
        } else {
10011 10012
            if (dom->virtType == VIR_DOMAIN_VIRT_VZ ||
                dom->virtType == VIR_DOMAIN_VIRT_PARALLELS) {
10013 10014 10015 10016 10017 10018 10019 10020 10021 10022 10023 10024 10025 10026 10027 10028 10029 10030 10031 10032 10033 10034
                if (def->bus != VIR_DOMAIN_INPUT_BUS_PARALLELS) {
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("parallels containers don't support "
                                     "input bus %s"),
                                   bus);
                    goto error;
                }

                if (def->type != VIR_DOMAIN_INPUT_TYPE_MOUSE &&
                    def->type != VIR_DOMAIN_INPUT_TYPE_KBD) {
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("parallels bus does not support "
                                     "%s input device"),
                                   type);
                    goto error;
                }
            } else {
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Input devices are not supported by this "
                                 "virtualization driver."));
                goto error;
            }
10035 10036
        }
    } else {
10037
        if (dom->os.type == VIR_DOMAIN_OSTYPE_HVM) {
L
Li Zhang 已提交
10038
            if ((def->type == VIR_DOMAIN_INPUT_TYPE_MOUSE ||
10039 10040
                def->type == VIR_DOMAIN_INPUT_TYPE_KBD) &&
                (ARCH_IS_X86(dom->os.arch) || dom->os.arch == VIR_ARCH_NONE)) {
10041
                def->bus = VIR_DOMAIN_INPUT_BUS_PS2;
10042
            } else {
10043
                def->bus = VIR_DOMAIN_INPUT_BUS_USB;
10044
            }
10045
        } else if (dom->os.type == VIR_DOMAIN_OSTYPE_XEN) {
10046
            def->bus = VIR_DOMAIN_INPUT_BUS_XEN;
10047
        } else {
10048 10049
            if ((dom->virtType == VIR_DOMAIN_VIRT_VZ ||
                 dom->virtType == VIR_DOMAIN_VIRT_PARALLELS))
10050
                def->bus = VIR_DOMAIN_INPUT_BUS_PARALLELS;
10051 10052 10053
        }
    }

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

10057 10058 10059
    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) {
10060 10061
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Invalid address for a USB device"));
10062 10063 10064
        goto error;
    }

10065 10066 10067 10068 10069 10070 10071 10072
    if ((evdev = virXPathString("string(./source/@evdev)", ctxt)))
        def->source.evdev = virFileSanitizePath(evdev);
    if (def->type == VIR_DOMAIN_INPUT_TYPE_PASSTHROUGH && !def->source.evdev) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Missing evdev path for input device passthrough"));
        goto error;
    }

10073
 cleanup:
10074
    VIR_FREE(evdev);
10075 10076 10077
    VIR_FREE(type);
    VIR_FREE(bus);

10078
    ctxt->node = save;
10079 10080
    return def;

10081
 error:
10082 10083 10084 10085 10086 10087
    virDomainInputDefFree(def);
    def = NULL;
    goto cleanup;
}


E
Eric Blake 已提交
10088
/* Parse the XML definition for a hub device */
M
Marc-André Lureau 已提交
10089 10090 10091 10092 10093 10094
static virDomainHubDefPtr
virDomainHubDefParseXML(xmlNodePtr node, unsigned int flags)
{
    virDomainHubDefPtr def;
    char *type = NULL;

10095
    if (VIR_ALLOC(def) < 0)
M
Marc-André Lureau 已提交
10096 10097 10098 10099 10100
        return NULL;

    type = virXMLPropString(node, "type");

    if (!type) {
10101 10102
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing hub device type"));
M
Marc-André Lureau 已提交
10103 10104 10105 10106
        goto error;
    }

    if ((def->type = virDomainHubTypeFromString(type)) < 0) {
10107
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
10108
                       _("unknown hub device type '%s'"), type);
M
Marc-André Lureau 已提交
10109 10110 10111
        goto error;
    }

10112
    if (virDomainDeviceInfoParseXML(node, NULL, &def->info, flags) < 0)
M
Marc-André Lureau 已提交
10113 10114
        goto error;

10115
 cleanup:
M
Marc-André Lureau 已提交
10116 10117 10118 10119
    VIR_FREE(type);

    return def;

10120
 error:
M
Marc-André Lureau 已提交
10121 10122 10123 10124 10125 10126
    virDomainHubDefFree(def);
    def = NULL;
    goto cleanup;
}


10127 10128
/* Parse the XML definition for a clock timer */
static virDomainTimerDefPtr
10129
virDomainTimerDefParseXML(xmlNodePtr node,
E
Eric Blake 已提交
10130
                          xmlXPathContextPtr ctxt)
10131 10132 10133 10134
{
    char *name = NULL;
    char *present = NULL;
    char *tickpolicy = NULL;
10135
    char *track = NULL;
10136 10137 10138 10139
    char *mode = NULL;

    virDomainTimerDefPtr def;
    xmlNodePtr oldnode = ctxt->node;
10140 10141
    xmlNodePtr catchup;
    int ret;
10142

10143
    if (VIR_ALLOC(def) < 0)
10144 10145 10146 10147 10148 10149
        return NULL;

    ctxt->node = node;

    name = virXMLPropString(node, "name");
    if (name == NULL) {
10150 10151
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing timer name"));
10152 10153 10154
        goto error;
    }
    if ((def->name = virDomainTimerNameTypeFromString(name)) < 0) {
10155
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
10156
                       _("unknown timer name '%s'"), name);
10157 10158 10159 10160 10161 10162 10163 10164 10165 10166
        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 {
10167 10168
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown timer present value '%s'"), present);
10169 10170 10171 10172 10173 10174 10175 10176
            goto error;
        }
    }

    def->tickpolicy = -1;
    tickpolicy = virXMLPropString(node, "tickpolicy");
    if (tickpolicy != NULL) {
        if ((def->tickpolicy = virDomainTimerTickpolicyTypeFromString(tickpolicy)) < 0) {
10177
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
10178
                           _("unknown timer tickpolicy '%s'"), tickpolicy);
10179 10180 10181 10182
            goto error;
        }
    }

10183 10184 10185 10186
    def->track = -1;
    track = virXMLPropString(node, "track");
    if (track != NULL) {
        if ((def->track = virDomainTimerTrackTypeFromString(track)) < 0) {
10187
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
10188
                           _("unknown timer track '%s'"), track);
10189 10190 10191 10192
            goto error;
        }
    }

10193
    ret = virXPathULong("string(./frequency)", ctxt, &def->frequency);
10194 10195
    if (ret == -1) {
        def->frequency = 0;
10196
    } else if (ret < 0) {
10197 10198
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("invalid timer frequency"));
10199 10200 10201 10202 10203 10204 10205
        goto error;
    }

    def->mode = -1;
    mode = virXMLPropString(node, "mode");
    if (mode != NULL) {
        if ((def->mode = virDomainTimerModeTypeFromString(mode)) < 0) {
10206
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
10207
                           _("unknown timer mode '%s'"), mode);
10208 10209 10210 10211
            goto error;
        }
    }

10212
    catchup = virXPathNode("./catchup", ctxt);
10213 10214 10215 10216 10217 10218
    if (catchup != NULL) {
        ret = virXPathULong("string(./catchup/@threshold)", ctxt,
                            &def->catchup.threshold);
        if (ret == -1) {
            def->catchup.threshold = 0;
        } else if (ret < 0) {
10219 10220
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("invalid catchup threshold"));
10221 10222 10223 10224 10225 10226 10227
            goto error;
        }

        ret = virXPathULong("string(./catchup/@slew)", ctxt, &def->catchup.slew);
        if (ret == -1) {
            def->catchup.slew = 0;
        } else if (ret < 0) {
10228 10229
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("invalid catchup slew"));
10230 10231 10232 10233 10234 10235 10236
            goto error;
        }

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

10243
 cleanup:
10244 10245 10246
    VIR_FREE(name);
    VIR_FREE(present);
    VIR_FREE(tickpolicy);
10247
    VIR_FREE(track);
10248 10249 10250 10251 10252
    VIR_FREE(mode);
    ctxt->node = oldnode;

    return def;

10253
 error:
10254 10255 10256 10257
    VIR_FREE(def);
    goto cleanup;
}

10258 10259

static int
10260 10261 10262
virDomainGraphicsAuthDefParseXML(xmlNodePtr node,
                                 virDomainGraphicsAuthDefPtr def,
                                 int type)
10263 10264
{
    char *validTo = NULL;
10265
    char *connected = virXMLPropString(node, "connected");
10266 10267 10268 10269 10270 10271 10272 10273 10274 10275 10276 10277 10278 10279 10280 10281 10282 10283 10284 10285 10286 10287 10288 10289

    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') {
10290 10291 10292
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot parse password validity time '%s', expect YYYY-MM-DDTHH:MM:SS"),
                           validTo);
10293 10294 10295 10296 10297 10298 10299 10300 10301 10302
            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);
10303
        def->expires = true;
10304 10305
    }

10306 10307 10308
    if (connected) {
        int action = virDomainGraphicsAuthConnectedTypeFromString(connected);
        if (action <= 0) {
10309 10310 10311
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown connected value %s"),
                           connected);
10312 10313 10314 10315 10316 10317 10318 10319
            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) {
10320 10321
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("VNC supports connected='keep' only"));
10322 10323 10324 10325 10326 10327
            return -1;
        }

        def->connected = action;
    }

10328 10329 10330
    return 0;
}

10331 10332 10333 10334 10335 10336 10337 10338 10339
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");
10340 10341
    char *fromConfig = virXMLPropString(node, "fromConfig");
    int tmp;
10342 10343

    if (!type) {
10344 10345
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("graphics listen type must be specified"));
10346 10347 10348 10349
        goto error;
    }

    if ((def->type = virDomainGraphicsListenTypeFromString(type)) < 0) {
10350
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
10351
                       _("unknown graphics listen type '%s'"), type);
10352 10353 10354 10355 10356 10357 10358
        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 已提交
10359 10360
        (def->type == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS ||
         (def->type == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NETWORK &&
10361
          !(flags & VIR_DOMAIN_DEF_PARSE_INACTIVE)))) {
10362 10363 10364 10365 10366 10367 10368
        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
10369
             * type='network' */
10370 10371
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("network attribute not allowed when listen type is not network"));
10372 10373 10374 10375 10376 10377
            goto error;
        }
        def->network = network;
        network = NULL;
    }

10378
    if (fromConfig &&
10379
        flags & VIR_DOMAIN_DEF_PARSE_STATUS) {
10380 10381 10382 10383 10384 10385 10386 10387 10388
        if (virStrToLong_i(fromConfig, NULL, 10, &tmp) < 0) {
            virReportError(VIR_ERR_XML_ERROR,
                           _("Invalid fromConfig value: %s"),
                           fromConfig);
            goto error;
        }
        def->fromConfig = tmp != 0;
    }

10389
    ret = 0;
10390
 error:
10391 10392 10393 10394 10395
    if (ret < 0)
        virDomainGraphicsListenDefClear(def);
    VIR_FREE(type);
    VIR_FREE(address);
    VIR_FREE(network);
10396
    VIR_FREE(fromConfig);
10397 10398 10399
    return ret;
}

10400

10401 10402
/* Parse the XML definition for a graphics device */
static virDomainGraphicsDefPtr
10403 10404 10405
virDomainGraphicsDefParseXML(xmlNodePtr node,
                             xmlXPathContextPtr ctxt,
                             unsigned int flags)
E
Eric Blake 已提交
10406
{
10407 10408
    virDomainGraphicsDefPtr def;
    char *type = NULL;
10409 10410 10411 10412
    int nListens;
    xmlNodePtr *listenNodes = NULL;
    char *listenAddr = NULL;
    xmlNodePtr save = ctxt->node;
10413

10414
    if (VIR_ALLOC(def) < 0)
10415 10416
        return NULL;

10417 10418
    ctxt->node = node;

10419 10420 10421
    type = virXMLPropString(node, "type");

    if (!type) {
10422 10423
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing graphics device type"));
10424 10425 10426 10427
        goto error;
    }

    if ((def->type = virDomainGraphicsTypeFromString(type)) < 0) {
10428
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
10429
                       _("unknown graphics device type '%s'"), type);
10430 10431 10432
        goto error;
    }

E
Eric Blake 已提交
10433 10434 10435
    if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC ||
        def->type == VIR_DOMAIN_GRAPHICS_TYPE_RDP ||
        def->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) {
10436 10437 10438 10439 10440 10441 10442

        /* parse the <listen> subelements for graphics types that support it */
        nListens = virXPathNodeSet("./listen", ctxt, &listenNodes);
        if (nListens < 0)
            goto error;

        if (nListens > 0) {
10443
            size_t i;
10444

10445
            if (VIR_ALLOC_N(def->listens, nListens) < 0)
10446 10447
                goto error;

10448 10449 10450
            for (i = 0; i < nListens; i++) {
                int ret = virDomainGraphicsListenDefParseXML(&def->listens[i],
                                                             listenNodes[i],
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
                                                             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;
10480
                size_t i;
10481

10482 10483
                for (i = 0; i < nListens; i++) {
                    if (virDomainGraphicsListenGetType(def, i)
10484
                        == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS) {
10485
                        found = virDomainGraphicsListenGetAddress(def, i);
10486
                        if (STREQ_NULLABLE(found, listenAddr))
10487 10488 10489 10490
                            matched = true;
                        break;
                    }
                }
10491
                if (found && !matched) {
10492 10493 10494
                    virReportError(VIR_ERR_XML_ERROR,
                                   _("graphics listen attribute %s must match address "
                                     "attribute of first listen element (found %s)"),
10495
                                   listenAddr, found);
10496
                    goto error;
10497 10498 10499 10500
                } else if (!found) {
                    /* quietly ignore listen address if none of the listens
                     * are of type address */
                    VIR_FREE(listenAddr);
10501 10502 10503 10504 10505
                }
            }
        }
    }

10506 10507
    if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
        char *port = virXMLPropString(node, "port");
M
Martin Kletzander 已提交
10508
        char *websocket = virXMLPropString(node, "websocket");
10509
        char *sharePolicy = virXMLPropString(node, "sharePolicy");
10510 10511 10512 10513
        char *autoport;

        if (port) {
            if (virStrToLong_i(port, NULL, 10, &def->data.vnc.port) < 0) {
10514 10515
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("cannot parse vnc port %s"), port);
10516 10517 10518 10519 10520 10521
                VIR_FREE(port);
                goto error;
            }
            VIR_FREE(port);
            /* Legacy compat syntax, used -1 for auto-port */
            if (def->data.vnc.port == -1) {
10522
                if (flags & VIR_DOMAIN_DEF_PARSE_INACTIVE)
10523
                    def->data.vnc.port = 0;
10524
                def->data.vnc.autoport = true;
10525 10526 10527
            }
        } else {
            def->data.vnc.port = 0;
10528
            def->data.vnc.autoport = true;
10529 10530 10531 10532
        }

        if ((autoport = virXMLPropString(node, "autoport")) != NULL) {
            if (STREQ(autoport, "yes")) {
10533
                if (flags & VIR_DOMAIN_DEF_PARSE_INACTIVE)
10534
                    def->data.vnc.port = 0;
10535
                def->data.vnc.autoport = true;
10536 10537 10538 10539
            }
            VIR_FREE(autoport);
        }

M
Martin Kletzander 已提交
10540 10541 10542 10543 10544 10545 10546 10547 10548 10549 10550 10551
        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);
        }

10552 10553 10554 10555 10556 10557 10558 10559 10560 10561 10562 10563 10564 10565 10566
        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);
        }

10567
        def->data.vnc.socket = virXMLPropString(node, "socket");
10568
        def->data.vnc.keymap = virXMLPropString(node, "keymap");
10569

10570 10571
        if (virDomainGraphicsAuthDefParseXML(node, &def->data.vnc.auth,
                                             def->type) < 0)
10572
            goto error;
10573
    } else if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) {
10574 10575 10576 10577
        char *fullscreen = virXMLPropString(node, "fullscreen");

        if (fullscreen != NULL) {
            if (STREQ(fullscreen, "yes")) {
10578
                def->data.sdl.fullscreen = true;
10579
            } else if (STREQ(fullscreen, "no")) {
10580
                def->data.sdl.fullscreen = false;
10581
            } else {
10582 10583
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unknown fullscreen value '%s'"), fullscreen);
10584 10585 10586 10587
                VIR_FREE(fullscreen);
                goto error;
            }
            VIR_FREE(fullscreen);
E
Eric Blake 已提交
10588
        } else {
10589
            def->data.sdl.fullscreen = false;
E
Eric Blake 已提交
10590
        }
10591 10592
        def->data.sdl.xauth = virXMLPropString(node, "xauth");
        def->data.sdl.display = virXMLPropString(node, "display");
10593 10594 10595 10596 10597 10598 10599 10600
    } 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) {
10601 10602
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("cannot parse rdp port %s"), port);
10603 10604 10605
                VIR_FREE(port);
                goto error;
            }
M
Michal Privoznik 已提交
10606 10607
            /* Legacy compat syntax, used -1 for auto-port */
            if (def->data.rdp.port == -1)
10608
                def->data.rdp.autoport = true;
M
Michal Privoznik 已提交
10609

10610 10611 10612
            VIR_FREE(port);
        } else {
            def->data.rdp.port = 0;
10613
            def->data.rdp.autoport = true;
10614 10615 10616
        }

        if ((autoport = virXMLPropString(node, "autoport")) != NULL) {
M
Michal Privoznik 已提交
10617
            if (STREQ(autoport, "yes"))
10618
                def->data.rdp.autoport = true;
M
Michal Privoznik 已提交
10619

10620 10621 10622
            VIR_FREE(autoport);
        }

10623
        if (def->data.rdp.autoport && (flags & VIR_DOMAIN_DEF_PARSE_INACTIVE))
M
Michal Privoznik 已提交
10624 10625
            def->data.rdp.port = 0;

10626
        if ((replaceUser = virXMLPropString(node, "replaceUser")) != NULL) {
10627
            if (STREQ(replaceUser, "yes"))
10628
                def->data.rdp.replaceUser = true;
10629 10630 10631 10632
            VIR_FREE(replaceUser);
        }

        if ((multiUser = virXMLPropString(node, "multiUser")) != NULL) {
10633
            if (STREQ(multiUser, "yes"))
10634
                def->data.rdp.multiUser = true;
10635 10636 10637 10638 10639 10640 10641 10642
            VIR_FREE(multiUser);
        }

    } else if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP) {
        char *fullscreen = virXMLPropString(node, "fullscreen");

        if (fullscreen != NULL) {
            if (STREQ(fullscreen, "yes")) {
10643
                def->data.desktop.fullscreen = true;
10644
            } else if (STREQ(fullscreen, "no")) {
10645
                def->data.desktop.fullscreen = false;
10646
            } else {
10647 10648
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unknown fullscreen value '%s'"), fullscreen);
10649 10650 10651 10652
                VIR_FREE(fullscreen);
                goto error;
            }
            VIR_FREE(fullscreen);
E
Eric Blake 已提交
10653
        } else {
10654
            def->data.desktop.fullscreen = false;
E
Eric Blake 已提交
10655
        }
10656 10657

        def->data.desktop.display = virXMLPropString(node, "display");
10658
    } else if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) {
10659
        xmlNodePtr cur;
10660 10661 10662
        char *port = virXMLPropString(node, "port");
        char *tlsPort;
        char *autoport;
10663 10664
        char *defaultMode;
        int defaultModeVal;
10665 10666 10667

        if (port) {
            if (virStrToLong_i(port, NULL, 10, &def->data.spice.port) < 0) {
10668 10669
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("cannot parse spice port %s"), port);
10670 10671 10672 10673 10674
                VIR_FREE(port);
                goto error;
            }
            VIR_FREE(port);
        } else {
10675
            def->data.spice.port = 0;
10676 10677 10678 10679 10680
        }

        tlsPort = virXMLPropString(node, "tlsPort");
        if (tlsPort) {
            if (virStrToLong_i(tlsPort, NULL, 10, &def->data.spice.tlsPort) < 0) {
10681 10682
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("cannot parse spice tlsPort %s"), tlsPort);
10683 10684 10685 10686 10687 10688 10689 10690 10691
                VIR_FREE(tlsPort);
                goto error;
            }
            VIR_FREE(tlsPort);
        } else {
            def->data.spice.tlsPort = 0;
        }

        if ((autoport = virXMLPropString(node, "autoport")) != NULL) {
M
Michal Privoznik 已提交
10692
            if (STREQ(autoport, "yes"))
10693
                def->data.spice.autoport = true;
10694 10695 10696
            VIR_FREE(autoport);
        }

10697 10698 10699 10700
        def->data.spice.defaultMode = VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_ANY;

        if ((defaultMode = virXMLPropString(node, "defaultMode")) != NULL) {
            if ((defaultModeVal = virDomainGraphicsSpiceChannelModeTypeFromString(defaultMode)) < 0) {
10701
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
10702 10703
                               _("unknown default spice channel mode %s"),
                               defaultMode);
10704 10705 10706 10707 10708 10709 10710
                VIR_FREE(defaultMode);
                goto error;
            }
            def->data.spice.defaultMode = defaultModeVal;
            VIR_FREE(defaultMode);
        }

M
Michal Privoznik 已提交
10711 10712
        if (def->data.spice.port == -1 && def->data.spice.tlsPort == -1) {
            /* Legacy compat syntax, used -1 for auto-port */
10713
            def->data.spice.autoport = true;
M
Michal Privoznik 已提交
10714 10715
        }

10716
        if (def->data.spice.autoport && (flags & VIR_DOMAIN_DEF_PARSE_INACTIVE)) {
M
Michal Privoznik 已提交
10717 10718 10719 10720
            def->data.spice.port = 0;
            def->data.spice.tlsPort = 0;
        }

10721
        def->data.spice.keymap = virXMLPropString(node, "keymap");
10722

10723 10724
        if (virDomainGraphicsAuthDefParseXML(node, &def->data.spice.auth,
                                             def->type) < 0)
10725
            goto error;
10726 10727 10728 10729 10730

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

                    if (!name || !mode) {
10737 10738
                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                       _("spice channel missing name/mode"));
E
Eric Blake 已提交
10739 10740
                        VIR_FREE(name);
                        VIR_FREE(mode);
10741 10742 10743 10744
                        goto error;
                    }

                    if ((nameval = virDomainGraphicsSpiceChannelNameTypeFromString(name)) < 0) {
10745
                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
10746 10747
                                       _("unknown spice channel name %s"),
                                       name);
E
Eric Blake 已提交
10748 10749
                        VIR_FREE(name);
                        VIR_FREE(mode);
10750 10751 10752
                        goto error;
                    }
                    if ((modeval = virDomainGraphicsSpiceChannelModeTypeFromString(mode)) < 0) {
10753
                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
10754 10755
                                       _("unknown spice channel mode %s"),
                                       mode);
E
Eric Blake 已提交
10756 10757
                        VIR_FREE(name);
                        VIR_FREE(mode);
10758 10759
                        goto error;
                    }
E
Eric Blake 已提交
10760 10761
                    VIR_FREE(name);
                    VIR_FREE(mode);
10762 10763

                    def->data.spice.channels[nameval] = modeval;
10764
                } else if (xmlStrEqual(cur->name, BAD_CAST "image")) {
10765
                    char *compression = virXMLPropString(cur, "compression");
10766 10767 10768
                    int compressionVal;

                    if (!compression) {
10769 10770
                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                       _("spice image missing compression"));
10771 10772 10773 10774 10775
                        goto error;
                    }

                    if ((compressionVal =
                         virDomainGraphicsSpiceImageCompressionTypeFromString(compression)) <= 0) {
10776 10777 10778
                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                       _("unknown spice image compression %s"),
                                       compression);
10779 10780 10781 10782 10783 10784 10785
                        VIR_FREE(compression);
                        goto error;
                    }
                    VIR_FREE(compression);

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

                    if (!compression) {
10790 10791
                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                       _("spice jpeg missing compression"));
10792 10793 10794 10795 10796
                        goto error;
                    }

                    if ((compressionVal =
                         virDomainGraphicsSpiceJpegCompressionTypeFromString(compression)) <= 0) {
10797 10798 10799
                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                       _("unknown spice jpeg compression %s"),
                                       compression);
10800 10801 10802 10803 10804 10805 10806
                        VIR_FREE(compression);
                        goto error;
                    }
                    VIR_FREE(compression);

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

                    if (!compression) {
10811 10812
                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                       _("spice zlib missing compression"));
10813 10814 10815 10816 10817
                        goto error;
                    }

                    if ((compressionVal =
                         virDomainGraphicsSpiceZlibCompressionTypeFromString(compression)) <= 0) {
10818 10819 10820
                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                       _("unknown spice zlib compression %s"),
                                       compression);
10821 10822 10823
                        VIR_FREE(compression);
                        goto error;
                    }
10824
                    VIR_FREE(compression);
10825 10826 10827

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

                    if (!compression) {
10832 10833
                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                       _("spice playback missing compression"));
10834 10835 10836 10837
                        goto error;
                    }

                    if ((compressionVal =
J
Ján Tomko 已提交
10838
                         virTristateSwitchTypeFromString(compression)) <= 0) {
10839
                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
10840
                                       _("unknown spice playback compression"));
10841 10842 10843 10844 10845 10846 10847
                        VIR_FREE(compression);
                        goto error;

                    }
                    VIR_FREE(compression);

                    def->data.spice.playback = compressionVal;
10848
                } else if (xmlStrEqual(cur->name, BAD_CAST "streaming")) {
10849
                    char *mode = virXMLPropString(cur, "mode");
10850 10851 10852
                    int modeVal;

                    if (!mode) {
10853 10854
                        virReportError(VIR_ERR_XML_ERROR, "%s",
                                       _("spice streaming missing mode"));
10855 10856 10857 10858
                        goto error;
                    }
                    if ((modeVal =
                         virDomainGraphicsSpiceStreamingModeTypeFromString(mode)) <= 0) {
10859
                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
10860
                                       _("unknown spice streaming mode"));
10861 10862 10863 10864 10865 10866 10867
                        VIR_FREE(mode);
                        goto error;

                    }
                    VIR_FREE(mode);

                    def->data.spice.streaming = modeVal;
10868
                } else if (xmlStrEqual(cur->name, BAD_CAST "clipboard")) {
10869
                    char *copypaste = virXMLPropString(cur, "copypaste");
10870 10871 10872
                    int copypasteVal;

                    if (!copypaste) {
10873 10874
                        virReportError(VIR_ERR_XML_ERROR, "%s",
                                       _("spice clipboard missing copypaste"));
10875 10876 10877 10878
                        goto error;
                    }

                    if ((copypasteVal =
J
Ján Tomko 已提交
10879
                         virTristateBoolTypeFromString(copypaste)) <= 0) {
10880
                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
10881
                                       _("unknown copypaste value '%s'"), copypaste);
10882 10883 10884 10885 10886 10887
                        VIR_FREE(copypaste);
                        goto error;
                    }
                    VIR_FREE(copypaste);

                    def->data.spice.copypaste = copypasteVal;
10888 10889 10890 10891 10892 10893 10894 10895 10896 10897 10898
                } 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 已提交
10899
                         virTristateBoolTypeFromString(enable)) <= 0) {
10900 10901 10902 10903 10904 10905 10906 10907
                        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 已提交
10908
                } else if (xmlStrEqual(cur->name, BAD_CAST "mouse")) {
10909
                    char *mode = virXMLPropString(cur, "mode");
P
Peng Zhou 已提交
10910 10911 10912
                    int modeVal;

                    if (!mode) {
10913 10914
                        virReportError(VIR_ERR_XML_ERROR, "%s",
                                       _("spice mouse missing mode"));
P
Peng Zhou 已提交
10915 10916 10917 10918
                        goto error;
                    }

                    if ((modeVal = virDomainGraphicsSpiceMouseModeTypeFromString(mode)) <= 0) {
10919
                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
10920 10921
                                       _("unknown mouse mode value '%s'"),
                                       mode);
P
Peng Zhou 已提交
10922 10923 10924 10925 10926 10927
                        VIR_FREE(mode);
                        goto error;
                    }
                    VIR_FREE(mode);

                    def->data.spice.mousemode = modeVal;
10928 10929 10930 10931
                }
            }
            cur = cur->next;
        }
10932 10933
    }

10934
 cleanup:
10935
    VIR_FREE(type);
10936 10937
    VIR_FREE(listenNodes);
    VIR_FREE(listenAddr);
10938

10939
    ctxt->node = save;
10940 10941
    return def;

10942
 error:
10943 10944 10945 10946 10947 10948
    virDomainGraphicsDefFree(def);
    def = NULL;
    goto cleanup;
}


10949
static virDomainSoundCodecDefPtr
10950
virDomainSoundCodecDefParseXML(xmlNodePtr node)
10951 10952 10953 10954
{
    char *type;
    virDomainSoundCodecDefPtr def;

10955
    if (VIR_ALLOC(def) < 0)
10956 10957 10958 10959
        return NULL;

    type = virXMLPropString(node, "type");
    if ((def->type = virDomainSoundCodecTypeFromString(type)) < 0) {
10960
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
10961
                       _("unknown codec type '%s'"), type);
10962 10963 10964
        goto error;
    }

10965
 cleanup:
10966 10967 10968 10969
    VIR_FREE(type);

    return def;

10970
 error:
10971 10972 10973 10974 10975 10976
    virDomainSoundCodecDefFree(def);
    def = NULL;
    goto cleanup;
}


10977
static virDomainSoundDefPtr
10978
virDomainSoundDefParseXML(xmlNodePtr node,
10979
                          xmlXPathContextPtr ctxt,
E
Eric Blake 已提交
10980
                          unsigned int flags)
10981
{
10982 10983
    char *model;
    virDomainSoundDefPtr def;
10984
    xmlNodePtr save = ctxt->node;
10985

10986
    if (VIR_ALLOC(def) < 0)
10987 10988
        return NULL;

10989 10990
    ctxt->node = node;

10991 10992
    model = virXMLPropString(node, "model");
    if ((def->model = virDomainSoundModelTypeFromString(model)) < 0) {
10993
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
10994
                       _("unknown sound model '%s'"), model);
10995 10996 10997
        goto error;
    }

10998 10999
    if (def->model == VIR_DOMAIN_SOUND_MODEL_ICH6 ||
        def->model == VIR_DOMAIN_SOUND_MODEL_ICH9) {
11000 11001 11002 11003 11004 11005 11006 11007 11008
        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) {
11009
            size_t i;
11010 11011 11012 11013 11014 11015

            if (VIR_ALLOC_N(def->codecs, ncodecs) < 0) {
                VIR_FREE(codecNodes);
                goto error;
            }

11016 11017
            for (i = 0; i < ncodecs; i++) {
                virDomainSoundCodecDefPtr codec = virDomainSoundCodecDefParseXML(codecNodes[i]);
11018 11019
                if (codec == NULL) {
                    VIR_FREE(codecNodes);
11020
                    goto error;
11021
                }
11022 11023 11024 11025 11026 11027 11028 11029

                codec->cad = def->ncodecs; /* that will do for now */
                def->codecs[def->ncodecs++] = codec;
            }
            VIR_FREE(codecNodes);
        }
    }

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

11033
 cleanup:
11034 11035
    VIR_FREE(model);

11036
    ctxt->node = save;
11037 11038
    return def;

11039
 error:
11040 11041 11042 11043 11044
    virDomainSoundDefFree(def);
    def = NULL;
    goto cleanup;
}

11045

R
Richard Jones 已提交
11046
static virDomainWatchdogDefPtr
11047
virDomainWatchdogDefParseXML(xmlNodePtr node,
E
Eric Blake 已提交
11048
                             unsigned int flags)
11049
{
R
Richard Jones 已提交
11050 11051 11052 11053 11054

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

11055
    if (VIR_ALLOC(def) < 0)
R
Richard Jones 已提交
11056 11057
        return NULL;

11058
    model = virXMLPropString(node, "model");
R
Richard Jones 已提交
11059
    if (model == NULL) {
11060 11061
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("watchdog must contain model name"));
R
Richard Jones 已提交
11062 11063
        goto error;
    }
11064
    def->model = virDomainWatchdogModelTypeFromString(model);
R
Richard Jones 已提交
11065
    if (def->model < 0) {
11066
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
11067
                       _("unknown watchdog model '%s'"), model);
R
Richard Jones 已提交
11068 11069 11070
        goto error;
    }

11071
    action = virXMLPropString(node, "action");
11072
    if (action == NULL) {
R
Richard Jones 已提交
11073
        def->action = VIR_DOMAIN_WATCHDOG_ACTION_RESET;
11074
    } else {
11075
        def->action = virDomainWatchdogActionTypeFromString(action);
R
Richard Jones 已提交
11076
        if (def->action < 0) {
11077
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
11078
                           _("unknown watchdog action '%s'"), action);
R
Richard Jones 已提交
11079 11080 11081 11082
            goto error;
        }
    }

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

11086
 cleanup:
11087 11088
    VIR_FREE(action);
    VIR_FREE(model);
R
Richard Jones 已提交
11089 11090 11091

    return def;

11092
 error:
11093
    virDomainWatchdogDefFree(def);
R
Richard Jones 已提交
11094 11095 11096 11097 11098
    def = NULL;
    goto cleanup;
}


11099
static virDomainRNGDefPtr
11100
virDomainRNGDefParseXML(xmlNodePtr node,
11101 11102 11103
                        xmlXPathContextPtr ctxt,
                        unsigned int flags)
{
11104 11105 11106
    char *model = NULL;
    char *backend = NULL;
    char *type = NULL;
11107 11108 11109 11110 11111
    virDomainRNGDefPtr def;
    xmlNodePtr save = ctxt->node;
    xmlNodePtr *backends = NULL;
    int nbackends;

11112
    if (VIR_ALLOC(def) < 0)
11113 11114 11115 11116 11117 11118 11119 11120
        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) {
11121
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("unknown RNG model '%s'"), model);
11122 11123 11124 11125 11126
        goto error;
    }

    ctxt->node = node;

11127 11128 11129 11130 11131 11132 11133 11134 11135 11136 11137 11138 11139
    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;
    }

11140 11141 11142 11143 11144 11145 11146 11147 11148 11149 11150 11151 11152 11153 11154 11155
    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) {
11156
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
11157 11158 11159 11160
                       _("unknown RNG backend model '%s'"), backend);
        goto error;
    }

11161
    switch ((virDomainRNGBackend) def->backend) {
11162 11163
    case VIR_DOMAIN_RNG_BACKEND_RANDOM:
        def->source.file = virXPathString("string(./backend)", ctxt);
11164 11165
        if (def->source.file &&
            STRNEQ(def->source.file, "/dev/random") &&
11166 11167 11168 11169 11170 11171
            STRNEQ(def->source.file, "/dev/hwrng")) {
            virReportError(VIR_ERR_XML_ERROR,
                           _("file '%s' is not a supported random source"),
                           def->source.file);
            goto error;
        }
11172 11173 11174 11175 11176 11177 11178 11179 11180
        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;
        }

11181
        if (VIR_ALLOC(def->source.chardev) < 0)
11182 11183 11184 11185
            goto error;

        def->source.chardev->type = virDomainChrTypeFromString(type);
        if (def->source.chardev->type < 0) {
11186
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
11187 11188 11189 11190 11191 11192 11193 11194 11195 11196 11197 11198 11199 11200 11201 11202 11203 11204
                           _("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;

11205
 cleanup:
11206 11207 11208 11209 11210 11211 11212
    VIR_FREE(model);
    VIR_FREE(backend);
    VIR_FREE(type);
    VIR_FREE(backends);
    ctxt->node = save;
    return def;

11213
 error:
11214 11215 11216 11217 11218 11219
    virDomainRNGDefFree(def);
    def = NULL;
    goto cleanup;
}


11220
static virDomainMemballoonDefPtr
11221
virDomainMemballoonDefParseXML(xmlNodePtr node,
11222
                               xmlXPathContextPtr ctxt,
E
Eric Blake 已提交
11223
                               unsigned int flags)
11224 11225 11226
{
    char *model;
    virDomainMemballoonDefPtr def;
11227
    xmlNodePtr save = ctxt->node;
11228
    unsigned int period = 0;
11229

11230
    if (VIR_ALLOC(def) < 0)
11231 11232 11233
        return NULL;

    model = virXMLPropString(node, "model");
11234
    if (model == NULL) {
11235
        virReportError(VIR_ERR_XML_ERROR, "%s",
11236
                       _("balloon memory must contain model name"));
11237 11238
        goto error;
    }
11239

11240
    if ((def->model = virDomainMemballoonModelTypeFromString(model)) < 0) {
11241
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
11242
                       _("unknown memory balloon model '%s'"), model);
11243 11244 11245
        goto error;
    }

11246
    ctxt->node = node;
11247
    if (virXPathUInt("string(./stats/@period)", ctxt, &period) < -1) {
11248 11249 11250 11251 11252
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("invalid statistics collection period"));
        goto error;
    }

11253 11254 11255 11256
    def->period = period;
    if (def->period < 0)
        def->period = 0;

11257 11258 11259
    if (def->model == VIR_DOMAIN_MEMBALLOON_MODEL_NONE)
        VIR_DEBUG("Ignoring device address for none model Memballoon");
    else if (virDomainDeviceInfoParseXML(node, NULL, &def->info, flags) < 0)
11260 11261
        goto error;

11262
 cleanup:
11263 11264
    VIR_FREE(model);

11265
    ctxt->node = save;
11266 11267
    return def;

11268
 error:
11269 11270 11271 11272 11273
    virDomainMemballoonDefFree(def);
    def = NULL;
    goto cleanup;
}

L
Li Zhang 已提交
11274
static virDomainNVRAMDefPtr
11275
virDomainNVRAMDefParseXML(xmlNodePtr node,
L
Li Zhang 已提交
11276 11277 11278 11279
                          unsigned int flags)
{
   virDomainNVRAMDefPtr def;

11280
    if (VIR_ALLOC(def) < 0)
L
Li Zhang 已提交
11281 11282 11283 11284 11285 11286 11287
        return NULL;

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

    return def;

11288
 error:
L
Li Zhang 已提交
11289 11290 11291 11292
    virDomainNVRAMDefFree(def);
    return NULL;
}

11293 11294 11295 11296 11297 11298 11299 11300 11301 11302 11303 11304 11305 11306 11307 11308 11309 11310 11311 11312 11313 11314 11315 11316
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;
    }

11317 11318
    if (virDomainParseScaledValue("./size[1]", NULL, ctxt,
                                  &def->size, 1, ULLONG_MAX, false) < 0)
11319 11320
        goto cleanup;

11321
    if ((server = virXPathNode("./server[1]", ctxt))) {
11322 11323
        def->server.enabled = true;

11324 11325
        def->server.chr.type = VIR_DOMAIN_CHR_TYPE_UNIX;
        def->server.chr.data.nix.listen = false;
11326
        if ((tmp = virXMLPropString(server, "path")))
11327
            def->server.chr.data.nix.path = virFileSanitizePath(tmp);
11328 11329 11330
        VIR_FREE(tmp);
    }

11331
    if ((msi = virXPathNode("./msi[1]", ctxt))) {
11332 11333 11334 11335 11336 11337 11338 11339 11340 11341 11342
        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);

11343 11344 11345 11346 11347 11348 11349 11350 11351 11352
        if ((tmp = virXMLPropString(msi, "ioeventfd"))) {
            int val;

            if ((val = virTristateSwitchTypeFromString(tmp)) <= 0) {
                virReportError(VIR_ERR_XML_ERROR,
                               _("invalid msi ioeventfd setting for shmem: '%s'"),
                               tmp);
                goto cleanup;
            }
            def->msi.ioeventfd = val;
11353 11354 11355 11356 11357 11358 11359 11360 11361 11362 11363 11364 11365 11366 11367 11368 11369 11370 11371 11372 11373 11374 11375 11376
        }
        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;
}

11377 11378 11379 11380 11381 11382 11383 11384 11385 11386 11387 11388 11389 11390 11391 11392 11393 11394 11395 11396 11397 11398 11399 11400 11401 11402 11403 11404 11405 11406 11407 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
static int
virSysinfoBIOSParseXML(xmlNodePtr node,
                       xmlXPathContextPtr ctxt,
                       virSysinfoBIOSDefPtr *bios)
{
    int ret = -1;
    virSysinfoBIOSDefPtr def;

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

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

    def->vendor = virXPathString("string(entry[@name='vendor'])", ctxt);
    def->version = virXPathString("string(entry[@name='version'])", ctxt);
    def->date = virXPathString("string(entry[@name='date'])", ctxt);
    def->release = virXPathString("string(entry[@name='release'])", ctxt);
    if (def->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->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 cleanup;
        }
    }

    if (!def->vendor && !def->version &&
        !def->date && !def->release) {
        virSysinfoBIOSDefFree(def);
        def = NULL;
    }

    *bios = def;
    def = NULL;
    ret = 0;
 cleanup:
    virSysinfoBIOSDefFree(def);
    return ret;
}

11436 11437 11438
static int
virSysinfoSystemParseXML(xmlNodePtr node,
                         xmlXPathContextPtr ctxt,
M
Michal Privoznik 已提交
11439
                         virSysinfoSystemDefPtr *sysdef,
11440 11441 11442 11443 11444 11445 11446 11447 11448 11449 11450 11451 11452 11453 11454 11455 11456 11457 11458 11459 11460 11461 11462 11463 11464 11465 11466 11467 11468 11469 11470 11471 11472 11473 11474 11475 11476 11477 11478 11479 11480 11481 11482 11483 11484 11485 11486 11487 11488 11489 11490 11491 11492 11493 11494 11495 11496 11497 11498 11499 11500 11501
                         unsigned char *domUUID,
                         bool uuid_generated)
{
    int ret = -1;
    virSysinfoSystemDefPtr def;
    char *tmpUUID = NULL;

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

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

    def->manufacturer =
        virXPathString("string(entry[@name='manufacturer'])", ctxt);
    def->product =
        virXPathString("string(entry[@name='product'])", ctxt);
    def->version =
        virXPathString("string(entry[@name='version'])", ctxt);
    def->serial =
        virXPathString("string(entry[@name='serial'])", ctxt);
    tmpUUID = virXPathString("string(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 cleanup;
        }
        if (uuid_generated) {
            memcpy(domUUID, uuidbuf, VIR_UUID_BUFLEN);
        } else if (memcmp(domUUID, uuidbuf, VIR_UUID_BUFLEN) != 0) {
            virReportError(VIR_ERR_XML_DETAIL, "%s",
                           _("UUID mismatch between <uuid> and "
                             "<sysinfo>"));
            goto cleanup;
        }
        /* 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->uuid, uuidstr) < 0)
            goto cleanup;
    }
    def->sku =
        virXPathString("string(entry[@name='sku'])", ctxt);
    def->family =
        virXPathString("string(entry[@name='family'])", ctxt);

    if (!def->manufacturer && !def->product && !def->version &&
        !def->serial && !def->uuid && !def->sku && !def->family) {
        virSysinfoSystemDefFree(def);
        def = NULL;
    }

M
Michal Privoznik 已提交
11502
    *sysdef = def;
11503 11504 11505 11506 11507 11508 11509 11510
    def = NULL;
    ret = 0;
 cleanup:
    virSysinfoSystemDefFree(def);
    VIR_FREE(tmpUUID);
    return ret;
}

11511 11512 11513 11514 11515 11516 11517 11518 11519 11520 11521 11522 11523 11524 11525 11526 11527 11528 11529 11530 11531 11532 11533 11534 11535 11536 11537 11538 11539 11540 11541 11542 11543 11544 11545 11546 11547 11548 11549 11550 11551 11552 11553 11554 11555 11556 11557 11558 11559 11560 11561 11562 11563 11564 11565
static int
virSysinfoBaseBoardParseXML(xmlXPathContextPtr ctxt,
                            virSysinfoBaseBoardDefPtr *baseBoard,
                            size_t *nbaseBoard)
{
    int ret = -1;
    virSysinfoBaseBoardDefPtr boards = NULL;
    size_t i, nboards = 0;
    xmlNodePtr *nodes = NULL, oldnode = ctxt->node;
    int n;

    if ((n = virXPathNodeSet("./baseBoard", ctxt, &nodes)) < 0)
        return ret;

    if (n && VIR_ALLOC_N(boards, n) < 0)
        goto cleanup;

    for (i = 0; i < n; i++) {
        virSysinfoBaseBoardDefPtr def = boards + nboards;

        ctxt->node = nodes[i];

        def->manufacturer =
            virXPathString("string(entry[@name='manufacturer'])", ctxt);
        def->product =
            virXPathString("string(entry[@name='product'])", ctxt);
        def->version =
            virXPathString("string(entry[@name='version'])", ctxt);
        def->serial =
            virXPathString("string(entry[@name='serial'])", ctxt);
        def->asset =
            virXPathString("string(entry[@name='asset'])", ctxt);
        def->location =
            virXPathString("string(entry[@name='location'])", ctxt);

        if (!def->manufacturer && !def->product && !def->version &&
            !def->serial && !def->asset && !def->location) {
            /* nada */
        } else {
            nboards++;
        }
    }

    *baseBoard = boards;
    *nbaseBoard = nboards;
    boards = NULL;
    nboards = 0;
    ret = 0;
 cleanup:
    VIR_FREE(boards);
    VIR_FREE(nodes);
    ctxt->node = oldnode;
    return ret;
}

11566
static virSysinfoDefPtr
11567
virSysinfoParseXML(xmlNodePtr node,
11568 11569 11570
                  xmlXPathContextPtr ctxt,
                  unsigned char *domUUID,
                  bool uuid_generated)
11571 11572
{
    virSysinfoDefPtr def;
11573
    xmlNodePtr oldnode, tmpnode;
11574 11575 11576
    char *type;

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

11582
    if (VIR_ALLOC(def) < 0)
11583
        return NULL;
11584 11585 11586

    type = virXMLPropString(node, "type");
    if (type == NULL) {
11587 11588
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("sysinfo must contain a type attribute"));
11589 11590
        goto error;
    }
11591
    if ((def->type = virSysinfoTypeFromString(type)) < 0) {
11592
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
11593
                       _("unknown sysinfo type '%s'"), type);
11594 11595 11596 11597
        goto error;
    }

    /* Extract BIOS related metadata */
11598 11599 11600 11601 11602
    if ((tmpnode = virXPathNode("./bios[1]", ctxt)) != NULL) {
        oldnode = ctxt->node;
        ctxt->node = tmpnode;
        if (virSysinfoBIOSParseXML(tmpnode, ctxt, &def->bios) < 0) {
            ctxt->node = oldnode;
11603 11604
            goto error;
        }
11605
        ctxt->node = oldnode;
11606
    }
11607 11608

    /* Extract system related metadata */
11609 11610 11611 11612 11613 11614
    if ((tmpnode = virXPathNode("./system[1]", ctxt)) != NULL) {
        oldnode = ctxt->node;
        ctxt->node = tmpnode;
        if (virSysinfoSystemParseXML(tmpnode, ctxt, &def->system,
                                     domUUID, uuid_generated) < 0) {
            ctxt->node = oldnode;
11615 11616
            goto error;
        }
11617
        ctxt->node = oldnode;
11618
    }
11619

11620 11621 11622 11623
    /* Extract system base board metadata */
    if (virSysinfoBaseBoardParseXML(ctxt, &def->baseBoard, &def->nbaseBoard) < 0)
        goto error;

11624
 cleanup:
11625
    VIR_FREE(type);
11626
    return def;
11627

11628
 error:
11629 11630 11631 11632
    virSysinfoDefFree(def);
    def = NULL;
    goto cleanup;
}
11633

11634
unsigned int
11635
virDomainVideoDefaultRAM(const virDomainDef *def,
11636
                         const virDomainVideoType type)
11637
{
11638 11639 11640 11641
    /* Defer setting default vram to the Xen drivers */
    if (def->virtType == VIR_DOMAIN_VIRT_XEN)
        return 0;

11642 11643 11644 11645 11646 11647
    switch (type) {
    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 已提交
11648 11649
        else if (def->virtType == VIR_DOMAIN_VIRT_VMWARE)
            return 4 * 1024;
11650
        else
11651
            return 16 * 1024;
11652 11653 11654 11655 11656 11657
        break;

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

11658
    case VIR_DOMAIN_VIDEO_TYPE_QXL:
11659
        /* QEMU use 64M as the minimal video memory for qxl device */
11660 11661
        return 64 * 1024;

11662 11663 11664 11665 11666 11667 11668
    default:
        return 0;
    }
}


int
11669
virDomainVideoDefaultType(const virDomainDef *def)
11670 11671 11672 11673 11674 11675 11676
{
    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:
11677 11678
        if (def->os.type == VIR_DOMAIN_OSTYPE_XEN ||
            def->os.type == VIR_DOMAIN_OSTYPE_LINUX)
11679
            return VIR_DOMAIN_VIDEO_TYPE_XEN;
11680
        else if ARCH_IS_PPC64(def->os.arch)
11681
            return VIR_DOMAIN_VIDEO_TYPE_VGA;
11682 11683 11684 11685 11686 11687
        else
            return VIR_DOMAIN_VIDEO_TYPE_CIRRUS;

    case VIR_DOMAIN_VIRT_VBOX:
        return VIR_DOMAIN_VIDEO_TYPE_VBOX;

M
Matthias Bolte 已提交
11688 11689 11690
    case VIR_DOMAIN_VIRT_VMWARE:
        return VIR_DOMAIN_VIDEO_TYPE_VMVGA;

11691
    case VIR_DOMAIN_VIRT_VZ:
11692
    case VIR_DOMAIN_VIRT_PARALLELS:
11693
        if (def->os.type == VIR_DOMAIN_OSTYPE_HVM)
11694
            return VIR_DOMAIN_VIDEO_TYPE_VGA;
11695 11696
        else
            return VIR_DOMAIN_VIDEO_TYPE_PARALLELS;
11697 11698 11699 11700 11701
    default:
        return -1;
    }
}

11702
static virDomainVideoAccelDefPtr
11703 11704
virDomainVideoAccelDefParseXML(xmlNodePtr node)
{
11705 11706
    xmlNodePtr cur;
    virDomainVideoAccelDefPtr def;
11707
    char *accel2d = NULL;
11708 11709
    char *accel3d = NULL;
    int val;
11710 11711 11712 11713

    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
11714
            if (!accel3d && !accel2d &&
11715
                xmlStrEqual(cur->name, BAD_CAST "acceleration")) {
11716 11717
                accel3d = virXMLPropString(cur, "accel3d");
                accel2d = virXMLPropString(cur, "accel2d");
11718 11719 11720 11721 11722
            }
        }
        cur = cur->next;
    }

11723
    if (!accel3d && !accel2d)
11724
        return NULL;
11725

11726
    if (VIR_ALLOC(def) < 0)
11727
        goto cleanup;
11728

11729
    if (accel3d) {
11730 11731 11732 11733 11734 11735
        if ((val = virTristateBoolTypeFromString(accel3d)) <= 0) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown accel3d value '%s'"), accel3d);
            goto cleanup;
        }
        def->accel3d = val;
11736 11737
    }

11738
    if (accel2d) {
11739 11740 11741 11742 11743 11744
        if ((val = virTristateBoolTypeFromString(accel2d)) <= 0) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown accel2d value '%s'"), accel2d);
            goto cleanup;
        }
        def->accel2d = val;
11745 11746
    }

11747 11748 11749
 cleanup:
    VIR_FREE(accel2d);
    VIR_FREE(accel3d);
11750 11751 11752
    return def;
}

11753
static virDomainVideoDefPtr
11754 11755
virDomainVideoDefParseXML(xmlNodePtr node,
                          const virDomainDef *dom,
E
Eric Blake 已提交
11756 11757
                          unsigned int flags)
{
11758 11759 11760 11761 11762
    virDomainVideoDefPtr def;
    xmlNodePtr cur;
    char *type = NULL;
    char *heads = NULL;
    char *vram = NULL;
11763
    char *ram = NULL;
11764
    char *vgamem = NULL;
11765
    char *primary = NULL;
11766

11767
    if (VIR_ALLOC(def) < 0)
11768 11769 11770 11771 11772
        return NULL;

    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
11773
            if (!type && !vram && !ram && !heads &&
11774 11775
                xmlStrEqual(cur->name, BAD_CAST "model")) {
                type = virXMLPropString(cur, "type");
11776
                ram = virXMLPropString(cur, "ram");
11777
                vram = virXMLPropString(cur, "vram");
11778
                vgamem = virXMLPropString(cur, "vgamem");
11779
                heads = virXMLPropString(cur, "heads");
11780

11781
                if ((primary = virXMLPropString(cur, "primary")) != NULL) {
11782 11783
                    if (STREQ(primary, "yes"))
                        def->primary = 1;
11784 11785
                    VIR_FREE(primary);
                }
11786

11787
                def->accel = virDomainVideoAccelDefParseXML(cur);
11788 11789 11790 11791 11792 11793 11794
            }
        }
        cur = cur->next;
    }

    if (type) {
        if ((def->type = virDomainVideoTypeFromString(type)) < 0) {
11795
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
11796
                           _("unknown video model '%s'"), type);
11797 11798 11799 11800
            goto error;
        }
    } else {
        if ((def->type = virDomainVideoDefaultType(dom)) < 0) {
11801 11802
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("missing video model and cannot determine default"));
11803 11804 11805 11806
            goto error;
        }
    }

11807 11808 11809 11810 11811 11812
    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;
        }
11813
        if (virStrToLong_uip(ram, NULL, 10, &def->ram) < 0) {
11814 11815 11816 11817 11818 11819 11820 11821
            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);
    }

11822
    if (vram) {
11823
        if (virStrToLong_uip(vram, NULL, 10, &def->vram) < 0) {
11824
            virReportError(VIR_ERR_XML_ERROR,
11825
                           _("cannot parse video vram '%s'"), vram);
11826 11827 11828 11829 11830 11831
            goto error;
        }
    } else {
        def->vram = virDomainVideoDefaultRAM(dom, def->type);
    }

11832 11833 11834 11835 11836 11837
    if (vgamem) {
        if (def->type != VIR_DOMAIN_VIDEO_TYPE_QXL) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("vgamem attribute only supported for type of qxl"));
            goto error;
        }
11838
        if (virStrToLong_uip(vgamem, NULL, 10, &def->vgamem) < 0) {
11839 11840 11841 11842 11843 11844
            virReportError(VIR_ERR_XML_ERROR,
                           _("cannot parse video vgamem '%s'"), vgamem);
            goto error;
        }
    }

11845
    if (heads) {
11846
        if (virStrToLong_uip(heads, NULL, 10, &def->heads) < 0) {
11847 11848
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot parse video heads '%s'"), heads);
11849 11850 11851 11852 11853 11854
            goto error;
        }
    } else {
        def->heads = 1;
    }

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

11858
    VIR_FREE(type);
11859
    VIR_FREE(ram);
11860
    VIR_FREE(vram);
11861
    VIR_FREE(vgamem);
11862 11863 11864 11865
    VIR_FREE(heads);

    return def;

11866
 error:
11867 11868
    virDomainVideoDefFree(def);
    VIR_FREE(type);
11869
    VIR_FREE(ram);
11870
    VIR_FREE(vram);
11871
    VIR_FREE(vgamem);
11872 11873 11874 11875
    VIR_FREE(heads);
    return NULL;
}

11876
static virDomainHostdevDefPtr
11877
virDomainHostdevDefParseXML(xmlNodePtr node,
11878
                            xmlXPathContextPtr ctxt,
11879
                            virHashTablePtr bootHash,
E
Eric Blake 已提交
11880
                            unsigned int flags)
11881
{
11882
    virDomainHostdevDefPtr def;
11883 11884 11885
    xmlNodePtr save = ctxt->node;
    char *mode = virXMLPropString(node, "mode");
    char *type = virXMLPropString(node, "type");
11886

11887
    ctxt->node = node;
11888

11889
    if (!(def = virDomainHostdevDefAlloc()))
11890 11891
        goto error;

11892 11893
    if (mode) {
        if ((def->mode = virDomainHostdevModeTypeFromString(mode)) < 0) {
11894
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
11895 11896 11897 11898 11899 11900 11901 11902 11903 11904 11905 11906 11907
                           _("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;
11908 11909 11910 11911 11912
    case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
        /* parse managed/mode/type, and the <source> element */
        if (virDomainHostdevDefParseXMLCaps(node, ctxt, type, def) < 0)
            goto error;
        break;
11913 11914 11915
    default:
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unexpected hostdev mode %d"), def->mode);
11916
        goto error;
11917
    }
11918

11919
    if (def->info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
11920
        if (virDomainDeviceInfoParseXML(node, bootHash, def->info,
11921 11922
                                        flags  | VIR_DOMAIN_DEF_PARSE_ALLOW_BOOT
                                        | VIR_DOMAIN_DEF_PARSE_ALLOW_ROM) < 0)
11923 11924 11925 11926 11927 11928
            goto error;
    }

    if (def->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
        switch (def->source.subsys.type) {
        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
11929 11930
            if (def->info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
                def->info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
11931 11932
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("PCI host devices must use 'pci' address type"));
11933 11934 11935
                goto error;
            }
            break;
H
Han Cheng 已提交
11936
        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
11937 11938
            if (def->info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
                def->info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
H
Han Cheng 已提交
11939
                virReportError(VIR_ERR_XML_ERROR, "%s",
11940 11941
                               _("SCSI host device must use 'drive' "
                                 "address type"));
H
Han Cheng 已提交
11942 11943
                goto error;
            }
O
Osier Yang 已提交
11944 11945
            if (virXPathBoolean("boolean(./readonly)", ctxt))
                def->readonly = true;
11946 11947
            if (virXPathBoolean("boolean(./shareable)", ctxt))
                def->shareable = true;
H
Han Cheng 已提交
11948
            break;
11949 11950 11951
        }
    }

11952
 cleanup:
11953 11954
    VIR_FREE(type);
    VIR_FREE(mode);
11955
    ctxt->node = save;
11956 11957
    return def;

11958
 error:
11959 11960 11961 11962 11963
    virDomainHostdevDefFree(def);
    def = NULL;
    goto cleanup;
}

11964

11965
static virDomainRedirdevDefPtr
11966
virDomainRedirdevDefParseXML(xmlNodePtr node,
11967
                             virHashTablePtr bootHash,
11968 11969 11970 11971 11972
                             unsigned int flags)
{
    xmlNodePtr cur;
    virDomainRedirdevDefPtr def;
    char *bus, *type = NULL;
11973
    int remaining;
11974

11975
    if (VIR_ALLOC(def) < 0)
11976 11977 11978 11979 11980
        return NULL;

    bus = virXMLPropString(node, "bus");
    if (bus) {
        if ((def->bus = virDomainRedirdevBusTypeFromString(bus)) < 0) {
11981
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
11982
                           _("unknown redirdev bus '%s'"), bus);
11983 11984 11985 11986 11987 11988 11989 11990 11991
            goto error;
        }
    } else {
        def->bus = VIR_DOMAIN_REDIRDEV_BUS_USB;
    }

    type = virXMLPropString(node, "type");
    if (type) {
        if ((def->source.chr.type = virDomainChrTypeFromString(type)) < 0) {
11992
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
11993
                           _("unknown redirdev character device type '%s'"), type);
11994 11995 11996
            goto error;
        }
    } else {
11997 11998
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing type in redirdev"));
11999 12000 12001 12002
        goto error;
    }

    cur = node->children;
12003 12004 12005 12006 12007 12008 12009
    /* 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;
12010

12011
    if (def->source.chr.type == VIR_DOMAIN_CHR_TYPE_SPICEVMC)
12012 12013
        def->source.chr.data.spicevmc = VIR_DOMAIN_CHR_SPICEVMC_USBREDIR;

12014
    if (virDomainDeviceInfoParseXML(node, bootHash, &def->info,
12015
                                    flags | VIR_DOMAIN_DEF_PARSE_ALLOW_BOOT) < 0)
12016 12017 12018 12019 12020
        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) {
12021 12022
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Invalid address for a USB device"));
12023 12024 12025 12026
        goto error;
    }


12027
 cleanup:
12028 12029 12030 12031
    VIR_FREE(bus);
    VIR_FREE(type);
    return def;

12032
 error:
12033 12034 12035 12036 12037
    virDomainRedirdevDefFree(def);
    def = NULL;
    goto cleanup;
}

12038
/*
J
Ján Tomko 已提交
12039
 * This is the helper function to convert USB device version from a
12040 12041 12042
 * 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.
J
Ján Tomko 已提交
12043 12044
 * e.g. USB version 2.0 is reported as 0x0200,
 *      USB version 4.07 as 0x0407
12045 12046
 */
static int
12047 12048
virDomainRedirFilterUSBVersionHelper(const char *version,
                                     virDomainRedirFilterUSBDevDefPtr def)
12049
{
J
Ján Tomko 已提交
12050 12051
    unsigned int major, minor;
    char *s = NULL;
12052

J
Ján Tomko 已提交
12053 12054 12055 12056
    if ((virStrToLong_ui(version, &s, 10, &major)) < 0 ||
        *s++ != '.' ||
        (virStrToLong_ui(s, NULL, 10, &minor)) < 0)
        goto error;
12057

J
Ján Tomko 已提交
12058 12059
    if (major >= 100 || minor >= 100)
        goto error;
12060

J
Ján Tomko 已提交
12061 12062 12063
    /* Treat JJ.M as JJ.M0, not JJ.0M */
    if (strlen(s) == 1)
        minor *= 10;
12064

J
Ján Tomko 已提交
12065 12066
    def->version = (major / 10) << 12 | (major % 10) << 8 |
                   (minor / 10) << 4 | (minor % 10) << 0;
12067

J
Ján Tomko 已提交
12068
    return 0;
12069

J
Ján Tomko 已提交
12070 12071 12072 12073
 error:
    virReportError(VIR_ERR_XML_ERROR,
                   _("Cannot parse USB device version %s"), version);
    return -1;
12074 12075
}

12076 12077
static virDomainRedirFilterUSBDevDefPtr
virDomainRedirFilterUSBDevDefParseXML(xmlNodePtr node)
12078 12079 12080 12081
{
    char *class;
    char *vendor = NULL, *product = NULL;
    char *version = NULL, *allow = NULL;
12082
    virDomainRedirFilterUSBDevDefPtr def;
12083

12084
    if (VIR_ALLOC(def) < 0)
12085 12086 12087 12088 12089 12090 12091 12092 12093 12094 12095 12096 12097 12098 12099 12100 12101 12102 12103 12104 12105 12106 12107 12108 12109 12110 12111 12112 12113 12114 12115 12116 12117 12118 12119 12120 12121 12122 12123 12124 12125 12126 12127 12128 12129
        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;
12130
        else if ((virDomainRedirFilterUSBVersionHelper(version, def)) < 0)
12131 12132 12133 12134 12135 12136 12137
            goto error;
    } else {
        def->version = -1;
    }

    allow = virXMLPropString(node, "allow");
    if (allow) {
12138
        if (STREQ(allow, "yes")) {
12139
            def->allow = true;
12140
        } else if (STREQ(allow, "no")) {
12141
            def->allow = false;
12142
        } else {
12143 12144 12145 12146 12147 12148 12149 12150 12151 12152
            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;
    }

12153
 cleanup:
12154 12155 12156 12157 12158 12159 12160
    VIR_FREE(class);
    VIR_FREE(vendor);
    VIR_FREE(product);
    VIR_FREE(version);
    VIR_FREE(allow);
    return def;

12161
 error:
12162 12163 12164 12165 12166 12167
    VIR_FREE(def);
    def = NULL;
    goto cleanup;
}

static virDomainRedirFilterDefPtr
12168
virDomainRedirFilterDefParseXML(xmlNodePtr node,
12169 12170 12171 12172 12173 12174 12175 12176 12177
                                xmlXPathContextPtr ctxt)
{
    int n;
    size_t i;
    xmlNodePtr *nodes = NULL;
    xmlNodePtr save = ctxt->node;
    virDomainRedirFilterDefPtr def = NULL;

    if (VIR_ALLOC(def) < 0)
12178
        goto error;
12179 12180

    ctxt->node = node;
12181
    if ((n = virXPathNodeSet("./usbdev", ctxt, &nodes)) < 0)
12182 12183 12184
        goto error;

    if (n && VIR_ALLOC_N(def->usbdevs, n) < 0)
12185
        goto error;
12186 12187

    for (i = 0; i < n; i++) {
12188 12189
        virDomainRedirFilterUSBDevDefPtr usbdev =
            virDomainRedirFilterUSBDevDefParseXML(nodes[i]);
12190 12191 12192 12193 12194 12195 12196 12197 12198 12199

        if (!usbdev)
            goto error;
        def->usbdevs[def->nusbdevs++] = usbdev;
    }
    VIR_FREE(nodes);

    ctxt->node = save;
    return def;

12200
 error:
12201 12202 12203 12204 12205
    VIR_FREE(nodes);
    virDomainRedirFilterDefFree(def);
    return NULL;
}

12206 12207 12208 12209 12210 12211 12212
static int
virDomainEventActionParseXML(xmlXPathContextPtr ctxt,
                             const char *name,
                             const char *xpath,
                             int *val,
                             int defaultVal,
                             virEventActionFromStringFunc convFunc)
12213
{
12214
    char *tmp = virXPathString(xpath, ctxt);
12215 12216 12217
    if (tmp == NULL) {
        *val = defaultVal;
    } else {
12218
        *val = convFunc(tmp);
12219
        if (*val < 0) {
12220
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
12221
                           _("unknown %s action: %s"), name, tmp);
12222 12223 12224 12225 12226 12227 12228 12229
            VIR_FREE(tmp);
            return -1;
        }
        VIR_FREE(tmp);
    }
    return 0;
}

12230 12231 12232 12233 12234 12235 12236 12237
static int
virDomainPMStateParseXML(xmlXPathContextPtr ctxt,
                         const char *xpath,
                         int *val)
{
    int ret = -1;
    char *tmp = virXPathString(xpath, ctxt);
    if (tmp) {
J
Ján Tomko 已提交
12238
        *val = virTristateBoolTypeFromString(tmp);
12239 12240 12241 12242 12243 12244 12245 12246 12247 12248 12249 12250 12251
        if (*val < 0) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown PM state value %s"), tmp);
            goto cleanup;
        }
    }

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

12252 12253 12254 12255 12256 12257 12258 12259 12260 12261 12262 12263 12264 12265 12266 12267 12268 12269 12270

static int
virDomainMemorySourceDefParseXML(xmlNodePtr node,
                                 xmlXPathContextPtr ctxt,
                                 virDomainMemoryDefPtr def)
{
    int ret = -1;
    char *nodemask = NULL;
    xmlNodePtr save = ctxt->node;
    ctxt->node = node;

    if (virDomainParseMemory("./pagesize", "./pagesize/@unit", ctxt,
                             &def->pagesize, false, false) < 0)
        goto cleanup;

    if ((nodemask = virXPathString("string(./nodemask)", ctxt))) {
        if (virBitmapParse(nodemask, 0, &def->sourceNodes,
                           VIR_DOMAIN_CPUMASK_LEN) < 0)
            goto cleanup;
12271 12272 12273 12274 12275 12276

        if (virBitmapIsAllClear(def->sourceNodes)) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Invalid value of 'nodemask': %s"), nodemask);
            goto cleanup;
        }
12277 12278 12279 12280 12281 12282 12283 12284 12285 12286 12287 12288 12289 12290 12291 12292 12293 12294 12295
    }

    ret = 0;

 cleanup:
    VIR_FREE(nodemask);
    ctxt->node = save;
    return ret;
}


static int
virDomainMemoryTargetDefParseXML(xmlNodePtr node,
                                 xmlXPathContextPtr ctxt,
                                 virDomainMemoryDefPtr def)
{
    int ret = -1;
    xmlNodePtr save = ctxt->node;
    ctxt->node = node;
12296
    int rv;
12297

12298 12299 12300 12301 12302
    /* initialize to value which marks that the user didn't specify it */
    def->targetNode = -1;

    if ((rv = virXPathInt("string(./node)", ctxt, &def->targetNode)) == -2 ||
        (rv == 0 && def->targetNode < 0)) {
12303
        virReportError(VIR_ERR_XML_ERROR, "%s",
12304
                       _("invalid value of memory device node"));
12305 12306 12307 12308 12309 12310 12311 12312 12313 12314 12315 12316 12317 12318 12319 12320 12321 12322 12323 12324 12325 12326 12327 12328 12329 12330 12331 12332 12333 12334 12335 12336 12337 12338 12339 12340 12341 12342 12343 12344 12345 12346 12347 12348 12349 12350 12351 12352 12353 12354 12355 12356 12357 12358 12359 12360 12361 12362 12363 12364 12365
        goto cleanup;
    }

    if (virDomainParseMemory("./size", "./size/@unit", ctxt,
                             &def->size, true, false) < 0)
        goto cleanup;

    ret = 0;

 cleanup:
    ctxt->node = save;
    return ret;
}


static virDomainMemoryDefPtr
virDomainMemoryDefParseXML(xmlNodePtr memdevNode,
                           xmlXPathContextPtr ctxt,
                           unsigned int flags)
{
    char *tmp = NULL;
    xmlNodePtr save = ctxt->node;
    xmlNodePtr node;
    virDomainMemoryDefPtr def;

    ctxt->node = memdevNode;

    if (VIR_ALLOC(def) < 0)
        return NULL;

    if (!(tmp = virXMLPropString(memdevNode, "model"))) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("missing memory model"));
        goto error;
    }

    if ((def->model = virDomainMemoryModelTypeFromString(tmp)) < 0) {
        virReportError(VIR_ERR_XML_ERROR,
                       _("invalid memory model '%s'"), tmp);
        goto error;
    }
    VIR_FREE(tmp);

    /* source */
    if ((node = virXPathNode("./source", ctxt)) &&
        virDomainMemorySourceDefParseXML(node, ctxt, def) < 0)
        goto error;

    /* target */
    if (!(node = virXPathNode("./target", ctxt))) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("missing <target> element for <memory> device"));
        goto error;
    }

    if (virDomainMemoryTargetDefParseXML(node, ctxt, def) < 0)
        goto error;

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

12366
    ctxt->node = save;
12367 12368 12369 12370 12371 12372 12373 12374 12375 12376
    return def;

 error:
    VIR_FREE(tmp);
    virDomainMemoryDefFree(def);
    ctxt->node = save;
    return NULL;
}


12377
virDomainDeviceDefPtr
12378
virDomainDeviceDefParse(const char *xmlStr,
12379
                        const virDomainDef *def,
12380 12381
                        virCapsPtr caps,
                        virDomainXMLOptionPtr xmlopt,
12382
                        unsigned int flags)
12383 12384 12385
{
    xmlDocPtr xml;
    xmlNodePtr node;
12386
    xmlXPathContextPtr ctxt = NULL;
12387 12388
    virDomainDeviceDefPtr dev = NULL;

12389
    if (!(xml = virXMLParseStringCtxt(xmlStr, _("(device_definition)"), &ctxt)))
12390
        goto error;
12391

12392
    node = ctxt->node;
12393

12394
    if (VIR_ALLOC(dev) < 0)
12395 12396
        goto error;

12397 12398 12399 12400 12401 12402 12403 12404 12405
    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 {
12406
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
12407 12408 12409 12410 12411 12412 12413 12414
                           _("unknown device type '%s'"),
                           node->name);
            goto error;
        }
    }

    switch ((virDomainDeviceType) dev->type) {
    case VIR_DOMAIN_DEVICE_DISK:
12415
        if (!(dev->data.disk = virDomainDiskDefParseXML(xmlopt, node, ctxt,
12416 12417
                                                        NULL, def->seclabels,
                                                        def->nseclabels,
12418
                                                        flags)))
12419
            goto error;
12420 12421
        break;
    case VIR_DOMAIN_DEVICE_LEASE:
12422 12423
        if (!(dev->data.lease = virDomainLeaseDefParseXML(node)))
            goto error;
12424 12425
        break;
    case VIR_DOMAIN_DEVICE_FS:
12426
        if (!(dev->data.fs = virDomainFSDefParseXML(node, ctxt, flags)))
12427
            goto error;
12428 12429
        break;
    case VIR_DOMAIN_DEVICE_NET:
12430
        if (!(dev->data.net = virDomainNetDefParseXML(xmlopt, node, ctxt,
12431
                                                      NULL, flags)))
12432
            goto error;
12433 12434
        break;
    case VIR_DOMAIN_DEVICE_INPUT:
12435 12436
        if (!(dev->data.input = virDomainInputDefParseXML(def, node,
                                                          ctxt, flags)))
12437
            goto error;
12438 12439
        break;
    case VIR_DOMAIN_DEVICE_SOUND:
12440
        if (!(dev->data.sound = virDomainSoundDefParseXML(node, ctxt, flags)))
12441
            goto error;
12442 12443
        break;
    case VIR_DOMAIN_DEVICE_WATCHDOG:
12444
        if (!(dev->data.watchdog = virDomainWatchdogDefParseXML(node, flags)))
R
Richard Jones 已提交
12445
            goto error;
12446 12447
        break;
    case VIR_DOMAIN_DEVICE_VIDEO:
12448
        if (!(dev->data.video = virDomainVideoDefParseXML(node, def, flags)))
12449
            goto error;
12450 12451
        break;
    case VIR_DOMAIN_DEVICE_HOSTDEV:
12452
        if (!(dev->data.hostdev = virDomainHostdevDefParseXML(node, ctxt,
12453
                                                              NULL, flags)))
12454
            goto error;
12455 12456
        break;
    case VIR_DOMAIN_DEVICE_CONTROLLER:
12457 12458
        if (!(dev->data.controller = virDomainControllerDefParseXML(node, ctxt,
                                                                    flags)))
12459
            goto error;
12460 12461
        break;
    case VIR_DOMAIN_DEVICE_GRAPHICS:
12462
        if (!(dev->data.graphics = virDomainGraphicsDefParseXML(node, ctxt, flags)))
12463
            goto error;
12464 12465
        break;
    case VIR_DOMAIN_DEVICE_HUB:
M
Marc-André Lureau 已提交
12466 12467
        if (!(dev->data.hub = virDomainHubDefParseXML(node, flags)))
            goto error;
12468 12469
        break;
    case VIR_DOMAIN_DEVICE_REDIRDEV:
12470
        if (!(dev->data.redirdev = virDomainRedirdevDefParseXML(node, NULL, flags)))
12471
            goto error;
12472 12473
        break;
    case VIR_DOMAIN_DEVICE_RNG:
12474 12475
        if (!(dev->data.rng = virDomainRNGDefParseXML(node, ctxt, flags)))
            goto error;
12476 12477
        break;
    case VIR_DOMAIN_DEVICE_CHR:
12478 12479 12480 12481 12482 12483
        if (!(dev->data.chr = virDomainChrDefParseXML(ctxt,
                                                      node,
                                                      def->seclabels,
                                                      def->nseclabels,
                                                      flags)))
            goto error;
12484 12485
        break;
    case VIR_DOMAIN_DEVICE_SMARTCARD:
12486 12487
        if (!(dev->data.smartcard = virDomainSmartcardDefParseXML(node, flags)))
            goto error;
12488 12489
        break;
    case VIR_DOMAIN_DEVICE_MEMBALLOON:
12490 12491 12492
        if (!(dev->data.memballoon = virDomainMemballoonDefParseXML(node,
                                                                    ctxt,
                                                                    flags)))
12493
            goto error;
12494 12495
        break;
    case VIR_DOMAIN_DEVICE_NVRAM:
12496 12497
        if (!(dev->data.nvram = virDomainNVRAMDefParseXML(node, flags)))
            goto error;
12498
        break;
12499 12500 12501 12502
    case VIR_DOMAIN_DEVICE_SHMEM:
        if (!(dev->data.shmem = virDomainShmemDefParseXML(node, ctxt, flags)))
            goto error;
        break;
12503 12504 12505 12506
    case VIR_DOMAIN_DEVICE_TPM:
        if (!(dev->data.tpm = virDomainTPMDefParseXML(node, ctxt, flags)))
            goto error;
        break;
12507 12508 12509 12510
    case VIR_DOMAIN_DEVICE_PANIC:
        if (!(dev->data.panic = virDomainPanicDefParseXML(node)))
            goto error;
        break;
12511 12512 12513 12514
    case VIR_DOMAIN_DEVICE_MEMORY:
        if (!(dev->data.memory = virDomainMemoryDefParseXML(node, ctxt, flags)))
            goto error;
        break;
12515 12516 12517
    case VIR_DOMAIN_DEVICE_NONE:
    case VIR_DOMAIN_DEVICE_LAST:
        break;
12518 12519
    }

12520
    /* callback to fill driver specific device aspects */
12521
    if (virDomainDeviceDefPostParse(dev, def, caps, xmlopt) < 0)
12522 12523
        goto error;

12524
 cleanup:
12525
    xmlFreeDoc(xml);
12526
    xmlXPathFreeContext(ctxt);
12527 12528
    return dev;

12529
 error:
12530
    VIR_FREE(dev);
12531
    goto cleanup;
12532
}
M
Matthias Bolte 已提交
12533 12534


12535 12536 12537 12538 12539 12540 12541 12542 12543 12544 12545 12546 12547 12548 12549 12550 12551 12552 12553 12554 12555 12556 12557
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;
    }

12558
    flags |= VIR_DOMAIN_DEF_PARSE_DISK_SOURCE;
12559 12560 12561 12562 12563 12564 12565 12566 12567 12568 12569 12570 12571 12572 12573 12574 12575
    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;
}


12576 12577 12578 12579 12580 12581 12582 12583 12584 12585 12586 12587 12588
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 已提交
12589 12590 12591
    case VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL:
        type = virDomainChrSerialTargetTypeToString(targetType);
        break;
12592 12593 12594 12595 12596 12597 12598
    default:
        break;
    }

    return type;
}

L
Laine Stump 已提交
12599 12600 12601
int
virDomainHostdevInsert(virDomainDefPtr def, virDomainHostdevDefPtr hostdev)
{
12602 12603

    return VIR_APPEND_ELEMENT(def->hostdevs, def->nhostdevs, hostdev);
L
Laine Stump 已提交
12604 12605
}

12606
virDomainHostdevDefPtr
L
Laine Stump 已提交
12607 12608
virDomainHostdevRemove(virDomainDefPtr def, size_t i)
{
12609 12610
    virDomainHostdevDefPtr hostdev = def->hostdevs[i];

12611
    VIR_DELETE_ELEMENT(def->hostdevs, i, def->nhostdevs);
12612
    return hostdev;
L
Laine Stump 已提交
12613 12614
}

12615 12616

static int
12617 12618
virDomainHostdevMatchSubsysUSB(virDomainHostdevDefPtr first,
                               virDomainHostdevDefPtr second)
12619
{
12620 12621 12622 12623
    virDomainHostdevSubsysUSBPtr first_usbsrc = &first->source.subsys.u.usb;
    virDomainHostdevSubsysUSBPtr second_usbsrc = &second->source.subsys.u.usb;

    if (first_usbsrc->bus && first_usbsrc->device) {
12624
        /* specified by bus location on host */
12625 12626
        if (first_usbsrc->bus == second_usbsrc->bus &&
            first_usbsrc->device == second_usbsrc->device)
12627 12628 12629
            return 1;
    } else {
        /* specified by product & vendor id */
12630 12631
        if (first_usbsrc->product == second_usbsrc->product &&
            first_usbsrc->vendor == second_usbsrc->vendor)
12632 12633 12634 12635 12636 12637
            return 1;
    }
    return 0;
}

static int
12638 12639
virDomainHostdevMatchSubsysPCI(virDomainHostdevDefPtr first,
                               virDomainHostdevDefPtr second)
12640
{
12641 12642 12643 12644 12645 12646 12647
    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)
12648 12649 12650 12651
        return 1;
    return 0;
}

H
Han Cheng 已提交
12652
static int
12653 12654 12655 12656 12657 12658 12659 12660 12661 12662 12663 12664
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 已提交
12665 12666 12667
        return 1;
    return 0;
}
12668

12669 12670 12671 12672 12673 12674 12675 12676 12677 12678 12679 12680 12681 12682 12683 12684
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;
}

12685 12686 12687 12688 12689 12690 12691 12692 12693 12694 12695 12696
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 已提交
12697
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
12698 12699 12700
        if (a->source.subsys.u.scsi.protocol !=
            b->source.subsys.u.scsi.protocol)
            return 0;
12701 12702 12703 12704 12705
        if (a->source.subsys.u.scsi.protocol ==
            VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_ISCSI)
            return virDomainHostdevMatchSubsysSCSIiSCSI(a, b);
        else
            return virDomainHostdevMatchSubsysSCSIHost(a, b);
12706 12707 12708 12709 12710
    }
    return 0;
}


12711 12712 12713 12714 12715 12716 12717 12718 12719 12720 12721 12722 12723 12724 12725 12726 12727
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);
}

12728 12729 12730 12731 12732 12733 12734 12735
static int
virDomainHostdevMatchCapsNet(virDomainHostdevDefPtr a,
                              virDomainHostdevDefPtr b)
{
    return STREQ_NULLABLE(a->source.caps.u.net.iface,
                          b->source.caps.u.net.iface);
}

12736 12737 12738 12739 12740 12741 12742 12743 12744 12745 12746 12747 12748

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);
12749 12750
    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_NET:
        return virDomainHostdevMatchCapsNet(a, b);
12751 12752 12753 12754 12755
    }
    return 0;
}


12756 12757 12758 12759 12760 12761 12762 12763 12764 12765
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);
12766 12767
    case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
        return virDomainHostdevMatchCaps(a, b);
12768 12769 12770 12771
    }
    return 0;
}

L
Laine Stump 已提交
12772 12773 12774 12775 12776 12777 12778 12779 12780 12781 12782
/* 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;
12783
    size_t i;
L
Laine Stump 已提交
12784 12785 12786 12787 12788

    if (!found)
        found = &local_found;
    *found = NULL;

12789
    for (i = 0; i < def->nhostdevs; i++) {
12790 12791
        if (virDomainHostdevMatch(match, def->hostdevs[i])) {
            *found = def->hostdevs[i];
L
Laine Stump 已提交
12792 12793 12794 12795 12796 12797
            break;
        }
    }
    return *found ? i : -1;
}

12798 12799 12800 12801 12802 12803 12804 12805 12806 12807 12808 12809 12810 12811 12812 12813 12814 12815 12816 12817 12818 12819
static bool
virDomainDiskControllerMatch(int controller_type, int disk_bus)
{
    if (controller_type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI &&
        disk_bus == VIR_DOMAIN_DISK_BUS_SCSI)
        return true;

    if (controller_type == VIR_DOMAIN_CONTROLLER_TYPE_FDC &&
        disk_bus == VIR_DOMAIN_DISK_BUS_FDC)
        return true;

    if (controller_type == VIR_DOMAIN_CONTROLLER_TYPE_IDE &&
        disk_bus == VIR_DOMAIN_DISK_BUS_IDE)
        return true;

    if (controller_type == VIR_DOMAIN_CONTROLLER_TYPE_SATA &&
        disk_bus == VIR_DOMAIN_DISK_BUS_SATA)
        return true;

    return false;
}

12820 12821 12822 12823 12824 12825 12826 12827 12828 12829 12830 12831
/* Return true if there's a duplicate disk[]->dst name for the same bus */
bool
virDomainDiskDefDstDuplicates(virDomainDefPtr def)
{
    size_t i, j;

    /* optimization */
    if (def->ndisks <= 1)
        return false;

    for (i = 1; i < def->ndisks; i++) {
        for (j = 0; j < i; j++) {
12832
            if (STREQ(def->disks[i]->dst, def->disks[j]->dst)) {
12833 12834 12835 12836 12837 12838 12839 12840 12841 12842 12843 12844 12845
                virReportError(VIR_ERR_XML_ERROR,
                               _("target '%s' duplicated for disk sources "
                                 "'%s' and '%s'"),
                               def->disks[i]->dst,
                               NULLSTR(virDomainDiskGetSource(def->disks[i])),
                               NULLSTR(virDomainDiskGetSource(def->disks[j])));
                return true;
            }
        }
    }
    return false;
}

12846 12847 12848 12849 12850 12851 12852 12853 12854 12855 12856 12857 12858 12859 12860 12861 12862 12863 12864 12865 12866 12867 12868 12869 12870 12871 12872 12873 12874 12875 12876 12877
int
virDomainDiskIndexByAddress(virDomainDefPtr def,
                            virDevicePCIAddressPtr pci_address,
                            unsigned int bus, unsigned int target,
                            unsigned int unit)
{
    virDomainDiskDefPtr vdisk;
    virDomainControllerDefPtr controller = NULL;
    size_t i;
    int cidx;

    if ((cidx = virDomainControllerFindByPCIAddress(def, pci_address)) >= 0)
        controller = def->controllers[cidx];

    for (i = 0; i < def->ndisks; i++) {
        vdisk = def->disks[i];
        if (vdisk->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI &&
            virDevicePCIAddressEqual(&vdisk->info.addr.pci, pci_address))
            return i;
        if (vdisk->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
            virDomainDeviceDriveAddressPtr drive = &vdisk->info.addr.drive;
            if (controller &&
                virDomainDiskControllerMatch(controller->type, vdisk->bus) &&
                drive->controller == controller->idx &&
                drive->bus == bus && drive->target == target &&
                drive->unit == unit)
                return i;
        }
    }
    return -1;
}

12878 12879 12880 12881 12882 12883 12884 12885 12886 12887 12888
virDomainDiskDefPtr
virDomainDiskByAddress(virDomainDefPtr def,
                       virDevicePCIAddressPtr pci_address,
                       unsigned int bus,
                       unsigned int target,
                       unsigned int unit)
{
    int idx = virDomainDiskIndexByAddress(def, pci_address, bus, target, unit);
    return idx < 0 ? NULL : def->disks[idx];
}

12889 12890 12891
int
virDomainDiskIndexByName(virDomainDefPtr def, const char *name,
                         bool allow_ambiguous)
12892 12893
{
    virDomainDiskDefPtr vdisk;
12894
    size_t i;
12895
    int candidate = -1;
12896

12897 12898 12899 12900
    /* 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.  */
12901 12902
    for (i = 0; i < def->ndisks; i++) {
        vdisk = def->disks[i];
12903 12904 12905
        if (*name != '/') {
            if (STREQ(vdisk->dst, name))
                return i;
12906
        } else if (STREQ_NULLABLE(virDomainDiskGetSource(vdisk), name)) {
12907 12908 12909 12910 12911 12912
            if (allow_ambiguous)
                return i;
            if (candidate >= 0)
                return -1;
            candidate = i;
        }
12913
    }
12914 12915 12916 12917 12918 12919 12920 12921 12922
    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)
{
12923
    int idx = virDomainDiskIndexByName(def, name, true);
12924

12925
    return idx < 0 ? NULL : virDomainDiskGetSource(def->disks[idx]);
12926 12927
}

12928 12929 12930 12931 12932 12933 12934 12935 12936
virDomainDiskDefPtr
virDomainDiskByName(virDomainDefPtr def,
                    const char *name,
                    bool allow_ambiguous)
{
    int idx = virDomainDiskIndexByName(def, name, allow_ambiguous);
    return idx < 0 ? NULL : def->disks[idx];
}

12937 12938
int virDomainDiskInsert(virDomainDefPtr def,
                        virDomainDiskDefPtr disk)
12939 12940
{

12941 12942 12943 12944 12945 12946
    if (VIR_REALLOC_N(def->disks, def->ndisks+1) < 0)
        return -1;

    virDomainDiskInsertPreAlloced(def, disk);

    return 0;
12947 12948
}

12949 12950 12951
void virDomainDiskInsertPreAlloced(virDomainDefPtr def,
                                   virDomainDiskDefPtr disk)
{
12952
    int idx;
12953 12954 12955 12956 12957 12958 12959 12960
    /* 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
     */
12961
    for (idx = (def->ndisks - 1); idx >= 0; idx--) {
12962 12963
        /* If bus matches and current disk is after
         * new disk, then new disk should go here */
12964 12965
        if (def->disks[idx]->bus == disk->bus &&
            (virDiskNameToIndex(def->disks[idx]->dst) >
12966
             virDiskNameToIndex(disk->dst))) {
12967 12968
            insertAt = idx;
        } else if (def->disks[idx]->bus == disk->bus &&
12969 12970 12971 12972
                   insertAt == -1) {
            /* Last disk with match bus is before the
             * new disk, then put new disk just after
             */
12973
            insertAt = idx + 1;
12974 12975 12976
        }
    }

12977 12978 12979
    /* VIR_INSERT_ELEMENT_INPLACE will never return an error here. */
    ignore_value(VIR_INSERT_ELEMENT_INPLACE(def->disks, insertAt,
                                            def->ndisks, disk));
12980 12981 12982
}


12983 12984
virDomainDiskDefPtr
virDomainDiskRemove(virDomainDefPtr def, size_t i)
12985
{
12986
    virDomainDiskDefPtr disk = def->disks[i];
12987

12988
    VIR_DELETE_ELEMENT(def->disks, i, def->ndisks);
12989
    return disk;
12990 12991
}

12992 12993
virDomainDiskDefPtr
virDomainDiskRemoveByName(virDomainDefPtr def, const char *name)
12994
{
12995 12996
    int idx = virDomainDiskIndexByName(def, name, false);
    if (idx < 0)
12997
        return NULL;
12998
    return virDomainDiskRemove(def, idx);
12999 13000
}

13001 13002
int virDomainNetInsert(virDomainDefPtr def, virDomainNetDefPtr net)
{
13003 13004 13005 13006 13007 13008 13009 13010 13011 13012
    /* 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);
13013
        return -1;
13014
    }
13015 13016 13017
    return 0;
}

13018 13019 13020 13021
/* virDomainNetFindIdx: search according to mac address and guest side
 *                      PCI address (if specified)
 *
 * Return: index of match if unique match found
13022
 *         -1 otherwise and an error is logged
13023 13024 13025
 */
int
virDomainNetFindIdx(virDomainDefPtr def, virDomainNetDefPtr net)
13026
{
13027 13028
    size_t i;
    int matchidx = -1;
13029
    char mac[VIR_MAC_STRING_BUFLEN];
13030 13031
    bool PCIAddrSpecified = virDomainDeviceAddressIsValid(&net->info,
                                                          VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI);
13032

13033 13034
    for (i = 0; i < def->nnets; i++) {
        if (virMacAddrCmp(&def->nets[i]->mac, &net->mac))
13035 13036 13037 13038 13039 13040 13041 13042 13043
            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.
             */
13044 13045 13046 13047
            virReportError(VIR_ERR_OPERATION_FAILED,
                           _("multiple devices matching mac address %s found"),
                           virMacAddrFormat(&net->mac, mac));
            return -1;
13048 13049
        }
        if (PCIAddrSpecified) {
13050
            if (virDevicePCIAddressEqual(&def->nets[i]->info.addr.pci,
13051 13052 13053 13054
                                         &net->info.addr.pci)) {
                /* exit early if the pci address was specified and
                 * it matches, as this guarantees no duplicates.
                 */
13055
                matchidx = i;
13056 13057 13058 13059
                break;
            }
        } else {
            /* no PCI address given, so there may be multiple matches */
13060
            matchidx = i;
13061 13062
        }
    }
13063
    if (matchidx < 0) {
13064 13065 13066 13067 13068 13069 13070 13071 13072 13073 13074 13075 13076 13077
        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));
        }
13078
    }
13079
    return matchidx;
13080 13081
}

13082 13083 13084 13085 13086 13087 13088 13089 13090 13091 13092 13093 13094 13095 13096 13097 13098 13099 13100 13101 13102
bool
virDomainHasNet(virDomainDefPtr def, virDomainNetDefPtr net)
{
    size_t i;
    bool PCIAddrSpecified = virDomainDeviceAddressIsValid(&net->info,
                                                          VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI);

    for (i = 0; i < def->nnets; i++) {
        if (virMacAddrCmp(&def->nets[i]->mac, &net->mac))
            continue;

        if (PCIAddrSpecified) {
            if (virDevicePCIAddressEqual(&def->nets[i]->info.addr.pci,
                                         &net->info.addr.pci))
                return true;
        } else {
            return true;
        }
    }
    return false;
}
13103

13104 13105 13106 13107
void
virDomainNetRemoveHostdev(virDomainDefPtr def,
                          virDomainNetDefPtr net)
{
13108 13109 13110 13111 13112 13113
    /* 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;
13114

13115
    if (hostdev) {
13116 13117 13118
        for (i = 0; i < def->nhostdevs; i++) {
            if (def->hostdevs[i] == hostdev) {
                virDomainHostdevRemove(def, i);
13119 13120 13121 13122
                break;
            }
        }
    }
13123 13124 13125 13126 13127 13128 13129 13130 13131
}


virDomainNetDefPtr
virDomainNetRemove(virDomainDefPtr def, size_t i)
{
    virDomainNetDefPtr net = def->nets[i];

    virDomainNetRemoveHostdev(def, net);
13132
    VIR_DELETE_ELEMENT(def->nets, i, def->nnets);
13133
    return net;
13134 13135
}

13136 13137 13138 13139 13140 13141 13142 13143 13144 13145 13146 13147 13148 13149 13150
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)
{
13151
    int idx;
13152 13153
    /* Tenatively plan to insert controller at the end. */
    int insertAt = -1;
13154
    virDomainControllerDefPtr current = NULL;
13155 13156 13157 13158 13159 13160

    /* 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
     */
13161
    for (idx = (def->ncontrollers - 1); idx >= 0; idx--) {
13162 13163 13164 13165 13166 13167 13168
        current = def->controllers[idx];
        if (current->type == controller->type) {
            if (current->idx > controller->idx) {
                /* If bus matches and current controller is after
                 * new controller, then new controller should go here
                 * */
                insertAt = idx;
13169 13170 13171 13172 13173 13174 13175 13176
            } else if (controller->info.mastertype == VIR_DOMAIN_CONTROLLER_MASTER_NONE &&
                       current->info.mastertype != VIR_DOMAIN_CONTROLLER_MASTER_NONE &&
                       current->idx == controller->idx) {
                /* If bus matches and index matches and new controller is
                 * master and current isn't a master, then new controller
                 * should go here to be placed before its companion
                 */
                insertAt = idx;
13177 13178 13179 13180 13181 13182
            } else if (insertAt == -1) {
                /* Last controller with match bus is before the
                 * new controller, then put new controller just after
                 */
                insertAt = idx + 1;
            }
13183 13184 13185
        }
    }

13186 13187 13188
    /* VIR_INSERT_ELEMENT_INPLACE will never return an error here. */
    ignore_value(VIR_INSERT_ELEMENT_INPLACE(def->controllers, insertAt,
                                            def->ncontrollers, controller));
13189 13190
}

13191 13192 13193 13194
int
virDomainControllerFind(virDomainDefPtr def,
                        int type, int idx)
{
13195
    size_t i;
13196

13197
    for (i = 0; i < def->ncontrollers; i++) {
13198 13199 13200 13201 13202 13203 13204 13205 13206
        if ((def->controllers[i]->type == type) &&
            (def->controllers[i]->idx == idx)) {
            return i;
        }
    }

    return -1;
}

13207 13208 13209 13210 13211 13212 13213 13214 13215 13216 13217 13218 13219 13220 13221 13222 13223 13224 13225 13226 13227 13228 13229 13230 13231 13232 13233 13234 13235 13236 13237 13238 13239 13240

const char *
virDomainControllerAliasFind(virDomainDefPtr def,
                             int type, int idx)
{
    int contIndex;
    const char *contTypeStr = virDomainControllerTypeToString(type);

    if (!contTypeStr) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unknown controller type %d"),
                       type);
        return NULL;
    }

    contIndex = virDomainControllerFind(def, type, idx);
    if (contIndex < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not find %s controller with index %d "
                         "required for device"),
                       contTypeStr, idx);
        return NULL;
    }
    if (!def->controllers[contIndex]->info.alias) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Device alias was not set for %s controller "
                         "with index %d "),
                       contTypeStr, idx);
        return NULL;
    }
    return def->controllers[contIndex]->info.alias;
}


13241 13242 13243 13244 13245 13246 13247 13248 13249 13250 13251 13252 13253 13254
int
virDomainControllerFindByType(virDomainDefPtr def,
                              int type)
{
    size_t i;

    for (i = 0; i < def->ncontrollers; i++) {
        if (def->controllers[i]->type == type)
            return i;
    }

    return -1;
}

13255 13256 13257 13258 13259 13260 13261 13262 13263 13264 13265 13266 13267 13268 13269 13270 13271
int
virDomainControllerFindByPCIAddress(virDomainDefPtr def,
                                    virDevicePCIAddressPtr addr)
{
    size_t i;

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

        if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI &&
            virDevicePCIAddressEqual(&info->addr.pci, addr))
            return i;
    }

    return -1;
}

13272 13273 13274 13275 13276
virDomainControllerDefPtr
virDomainControllerRemove(virDomainDefPtr def, size_t i)
{
    virDomainControllerDefPtr controller = def->controllers[i];

13277
    VIR_DELETE_ELEMENT(def->controllers, i, def->ncontrollers);
13278 13279
    return controller;
}
13280

13281 13282 13283 13284
int virDomainLeaseIndex(virDomainDefPtr def,
                        virDomainLeaseDefPtr lease)
{
    virDomainLeaseDefPtr vlease;
13285
    size_t i;
13286 13287 13288

    for (i = 0; i < def->nleases; i++) {
        vlease = def->leases[i];
L
Luyao Huang 已提交
13289 13290 13291 13292
        /* Either both must have lockspaces present which match.. */
        if (vlease->lockspace && lease->lockspace) {
            if (STRNEQ(vlease->lockspace, lease->lockspace))
                continue;
13293
        /* ...or neither must have a lockspace present */
L
Luyao Huang 已提交
13294
        } else if (vlease->lockspace || lease->lockspace) {
13295
            continue;
L
Luyao Huang 已提交
13296 13297
        }

13298 13299 13300 13301 13302 13303 13304 13305 13306
        if (STREQ(vlease->key, lease->key))
            return i;
    }
    return -1;
}


int virDomainLeaseInsertPreAlloc(virDomainDefPtr def)
{
13307
    return VIR_EXPAND_N(def->leases, def->nleases, 1);
13308 13309 13310 13311 13312 13313 13314 13315 13316 13317 13318 13319 13320 13321 13322 13323 13324 13325 13326 13327 13328 13329 13330
}

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


13331 13332
virDomainLeaseDefPtr
virDomainLeaseRemoveAt(virDomainDefPtr def, size_t i)
13333
{
13334 13335 13336

    virDomainLeaseDefPtr lease = def->leases[i];

13337
    VIR_DELETE_ELEMENT(def->leases, i, def->nleases);
13338
    return lease;
13339 13340 13341
}


13342 13343 13344
virDomainLeaseDefPtr
virDomainLeaseRemove(virDomainDefPtr def,
                     virDomainLeaseDefPtr lease)
13345
{
13346 13347
    int idx = virDomainLeaseIndex(def, lease);
    if (idx < 0)
13348
        return NULL;
13349
    return virDomainLeaseRemoveAt(def, idx);
13350 13351
}

13352
bool
13353 13354 13355 13356 13357 13358 13359 13360 13361 13362
virDomainChrEquals(virDomainChrDefPtr src,
                   virDomainChrDefPtr tgt)
{
    if (!src || !tgt)
        return src == tgt;

    if (src->deviceType != tgt->deviceType ||
        !virDomainChrSourceDefIsEqual(&src->source, &tgt->source))
        return false;

13363
    switch ((virDomainChrDeviceType) src->deviceType) {
13364 13365 13366
    case VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL:
        if (src->targetType != tgt->targetType)
            return false;
13367
        switch ((virDomainChrChannelTargetType) src->targetType) {
13368 13369 13370 13371 13372 13373 13374 13375 13376 13377 13378 13379 13380 13381 13382 13383 13384 13385 13386 13387 13388 13389 13390 13391 13392 13393 13394 13395 13396 13397 13398 13399 13400 13401 13402
        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)
{
13403 13404 13405
    virDomainChrDefPtr chr;
    const virDomainChrDef **arrPtr;
    size_t i, cnt;
13406

13407
    virDomainChrGetDomainPtrs(def, target->deviceType, &arrPtr, &cnt);
13408

13409 13410 13411
    for (i = 0; i < cnt; i++) {
        /* Cast away const */
        chr = (virDomainChrDefPtr) arrPtr[i];
13412 13413 13414 13415 13416 13417
        if (virDomainChrEquals(chr, target))
            return chr;
    }
    return NULL;
}

13418 13419 13420 13421 13422

/* Return the address within vmdef to be modified when working with a
 * chrdefptr of the given type.  */
static void
virDomainChrGetDomainPtrsInternal(virDomainDefPtr vmdef,
13423
                                  virDomainChrDeviceType type,
13424 13425
                                  virDomainChrDefPtr ***arrPtr,
                                  size_t **cntPtr)
13426
{
13427
    switch (type) {
13428 13429 13430 13431 13432 13433 13434 13435 13436 13437 13438 13439 13440 13441 13442 13443 13444 13445 13446 13447 13448
    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:
13449 13450
        *arrPtr = NULL;
        *cntPtr = NULL;
13451 13452 13453 13454
        break;
    }
}

13455

13456 13457 13458 13459
/* Return the array within vmdef that can contain a chrdefptr of the
 * given type.  */
void
virDomainChrGetDomainPtrs(const virDomainDef *vmdef,
13460
                          virDomainChrDeviceType type,
13461 13462 13463
                          const virDomainChrDef ***arrPtr,
                          size_t *cntPtr)
{
13464 13465
    virDomainChrDef ***arrVar = NULL;
    size_t *cntVar = NULL;
13466 13467 13468 13469 13470 13471 13472 13473 13474 13475 13476 13477 13478

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

13479

13480
int
13481 13482 13483 13484 13485 13486 13487 13488 13489 13490 13491 13492 13493 13494
virDomainChrPreAlloc(virDomainDefPtr vmdef,
                     virDomainChrDefPtr chr)
{
    virDomainChrDefPtr **arrPtr = NULL;
    size_t *cntPtr = NULL;

    virDomainChrGetDomainPtrsInternal(vmdef, chr->deviceType, &arrPtr, &cntPtr);

    return VIR_REALLOC_N(*arrPtr, *cntPtr + 1);
}

void
virDomainChrInsertPreAlloced(virDomainDefPtr vmdef,
                             virDomainChrDefPtr chr)
13495
{
13496 13497
    virDomainChrDefPtr **arrPtr = NULL;
    size_t *cntPtr = NULL;
13498

13499
    virDomainChrGetDomainPtrsInternal(vmdef, chr->deviceType, &arrPtr, &cntPtr);
13500

13501
    ignore_value(VIR_APPEND_ELEMENT_INPLACE(*arrPtr, *cntPtr, chr));
13502 13503 13504 13505 13506 13507
}

virDomainChrDefPtr
virDomainChrRemove(virDomainDefPtr vmdef,
                   virDomainChrDefPtr chr)
{
13508 13509
    virDomainChrDefPtr ret, **arrPtr = NULL;
    size_t i, *cntPtr = NULL;
13510

13511
    virDomainChrGetDomainPtrsInternal(vmdef, chr->deviceType, &arrPtr, &cntPtr);
13512 13513 13514 13515 13516 13517 13518 13519 13520 13521 13522 13523 13524 13525

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

13527 13528 13529 13530 13531 13532 13533 13534 13535 13536 13537 13538 13539 13540 13541 13542 13543 13544 13545 13546 13547 13548 13549 13550 13551 13552 13553 13554 13555 13556 13557 13558 13559 13560 13561 13562 13563 13564 13565 13566 13567 13568 13569 13570 13571 13572 13573 13574 13575 13576 13577 13578 13579 13580 13581 13582 13583 13584 13585 13586 13587 13588 13589 13590 13591 13592 13593 13594 13595 13596

int
virDomainRNGInsert(virDomainDefPtr def,
                   virDomainRNGDefPtr rng,
                   bool inplace)
{
    if (inplace)
        return VIR_APPEND_ELEMENT_INPLACE(def->rngs, def->nrngs, rng);
    else
        return VIR_APPEND_ELEMENT(def->rngs, def->nrngs, rng);
}


ssize_t
virDomainRNGFind(virDomainDefPtr def,
                 virDomainRNGDefPtr rng)
{
    size_t i;

    for (i = 0; i < def->nrngs; i++) {
        virDomainRNGDefPtr tmp = def->rngs[i];

        if (rng->model != tmp->model || rng->backend != tmp->backend)
            continue;

        if (rng->rate != tmp->rate || rng->period != tmp->period)
            continue;

        switch ((virDomainRNGBackend) rng->backend) {
        case VIR_DOMAIN_RNG_BACKEND_RANDOM:
            if (STRNEQ_NULLABLE(rng->source.file, tmp->source.file))
                continue;
            break;

        case VIR_DOMAIN_RNG_BACKEND_EGD:
            if (!virDomainChrSourceDefIsEqual(rng->source.chardev,
                                              tmp->source.chardev))
                continue;
            break;

        case VIR_DOMAIN_RNG_BACKEND_LAST:
            break;
        }

        if (rng->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
            !virDomainDeviceInfoAddressIsEqual(&rng->info, &tmp->info))
            continue;

        break;
    }

    if (i < def->nrngs)
        return i;

    return -1;
}


virDomainRNGDefPtr
virDomainRNGRemove(virDomainDefPtr def,
                   size_t idx)
{
    virDomainRNGDefPtr ret = def->rngs[idx];

    VIR_DELETE_ELEMENT(def->rngs, idx, def->nrngs);

    return ret;
}


13597 13598 13599 13600 13601 13602 13603 13604 13605 13606 13607 13608 13609 13610 13611 13612 13613 13614 13615 13616 13617 13618 13619 13620 13621 13622 13623 13624 13625 13626 13627 13628 13629 13630 13631 13632 13633 13634 13635 13636 13637 13638 13639 13640 13641 13642 13643 13644 13645 13646 13647 13648 13649 13650 13651 13652 13653 13654 13655 13656 13657 13658 13659 13660 13661 13662 13663 13664 13665 13666 13667 13668 13669 13670 13671 13672 13673 13674 13675 13676 13677 13678 13679 13680 13681 13682 13683 13684 13685 13686 13687 13688 13689 13690 13691 13692
static int
virDomainMemoryFindByDefInternal(virDomainDefPtr def,
                                 virDomainMemoryDefPtr mem,
                                 bool allowAddressFallback)
{
    size_t i;

    for (i = 0; i < def->nmems; i++) {
        virDomainMemoryDefPtr tmp = def->mems[i];

        /* address, if present */
        if (allowAddressFallback) {
            if (tmp->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
                continue;
        } else {
            if (mem->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
                !virDomainDeviceInfoAddressIsEqual(&tmp->info, &mem->info))
                continue;
        }

        /* alias, if present */
        if (mem->info.alias &&
            STRNEQ_NULLABLE(tmp->info.alias, mem->info.alias))
            continue;

        /* target info -> always present */
        if (tmp->model != mem->model ||
            tmp->targetNode != mem->targetNode ||
            tmp->size != mem->size)
            continue;

        /* source stuff -> match with device */
        if (tmp->pagesize != mem->pagesize)
            continue;

        if (!virBitmapEqual(tmp->sourceNodes, mem->sourceNodes))
            continue;

        break;
    }

    if (i == def->nmems)
        return -1;

    return i;
}


int
virDomainMemoryFindByDef(virDomainDefPtr def,
                         virDomainMemoryDefPtr mem)
{
    return virDomainMemoryFindByDefInternal(def, mem, false);
}


int
virDomainMemoryFindInactiveByDef(virDomainDefPtr def,
                                 virDomainMemoryDefPtr mem)
{
    int ret;

    if ((ret = virDomainMemoryFindByDefInternal(def, mem, false)) < 0)
        ret = virDomainMemoryFindByDefInternal(def, mem, true);

    return ret;
}


int
virDomainMemoryInsert(virDomainDefPtr def,
                      virDomainMemoryDefPtr mem)
{
    int id = def->nmems;

    if (mem->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
        virDomainDefHasDeviceAddress(def, &mem->info)) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Domain already contains a device with the same "
                         "address"));
        return -1;
    }

    if (VIR_APPEND_ELEMENT(def->mems, def->nmems, mem) < 0)
        return -1;

    return id;
}


virDomainMemoryDefPtr
virDomainMemoryRemove(virDomainDefPtr def,
                      int idx)
{
    virDomainMemoryDefPtr ret = def->mems[idx];
    VIR_DELETE_ELEMENT(def->mems, idx, def->nmems);
13693 13694 13695 13696 13697

    /* fix up balloon size */
    if (def->mem.cur_balloon > virDomainDefGetMemoryActual(def))
        def->mem.cur_balloon = virDomainDefGetMemoryActual(def);

13698 13699 13700 13701
    return ret;
}


13702 13703 13704 13705
char *
virDomainDefGetDefaultEmulator(virDomainDefPtr def,
                               virCapsPtr caps)
{
13706
    char *retemu;
13707
    virCapsDomainDataPtr capsdata;
13708

13709 13710 13711
    if (!(capsdata = virCapabilitiesDomainDataLookup(caps, def->os.type,
            def->os.arch, def->virtType, NULL, NULL)))
        return NULL;
13712

13713 13714
    if (VIR_STRDUP(retemu, capsdata->emulator) < 0) {
        VIR_FREE(capsdata);
13715 13716
        return NULL;
    }
13717
    VIR_FREE(capsdata);
13718 13719 13720
    return retemu;
}

13721 13722
static int
virDomainDefParseBootXML(xmlXPathContextPtr ctxt,
13723
                         virDomainDefPtr def)
13724 13725
{
    xmlNodePtr *nodes = NULL;
13726 13727
    size_t i;
    int n;
M
Martin Kletzander 已提交
13728
    char *tmp = NULL;
13729
    int ret = -1;
M
Michal Privoznik 已提交
13730
    unsigned long deviceBoot, serialPorts;
13731 13732

    if (virXPathULong("count(./devices/disk[boot]"
13733
                      "|./devices/interface[boot]"
13734 13735
                      "|./devices/hostdev[boot]"
                      "|./devices/redirdev[boot])", ctxt, &deviceBoot) < 0) {
13736 13737
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("cannot count boot devices"));
13738 13739
        goto cleanup;
    }
13740 13741

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

13745
    if (n > 0 && deviceBoot) {
13746 13747 13748
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("per-device boot elements cannot be used"
                         " together with os/boot elements"));
13749 13750 13751
        goto cleanup;
    }

13752
    for (i = 0; i < n && i < VIR_DOMAIN_BOOT_LAST; i++) {
13753 13754 13755
        int val;
        char *dev = virXMLPropString(nodes[i], "dev");
        if (!dev) {
13756 13757
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("missing boot device"));
13758 13759 13760
            goto cleanup;
        }
        if ((val = virDomainBootTypeFromString(dev)) < 0) {
13761
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
13762 13763
                           _("unknown boot device '%s'"),
                           dev);
13764 13765 13766 13767 13768 13769
            VIR_FREE(dev);
            goto cleanup;
        }
        VIR_FREE(dev);
        def->os.bootDevs[def->os.nBootDevs++] = val;
    }
13770
    if (def->os.nBootDevs == 0 && !deviceBoot) {
13771 13772 13773 13774
        def->os.nBootDevs = 1;
        def->os.bootDevs[0] = VIR_DOMAIN_BOOT_DISK;
    }

M
Martin Kletzander 已提交
13775 13776
    tmp = virXPathString("string(./os/bootmenu[1]/@enable)", ctxt);
    if (tmp) {
J
Ján Tomko 已提交
13777
        def->os.bootmenu = virTristateBoolTypeFromString(tmp);
13778 13779 13780 13781 13782
        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 已提交
13783
                     tmp);
J
Ján Tomko 已提交
13784
            def->os.bootmenu = VIR_TRISTATE_BOOL_NO;
13785
        }
M
Martin Kletzander 已提交
13786
        VIR_FREE(tmp);
13787 13788
    }

13789 13790 13791 13792 13793 13794 13795 13796 13797 13798 13799 13800 13801
    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 已提交
13802 13803 13804
    tmp = virXPathString("string(./os/bios[1]/@useserial)", ctxt);
    if (tmp) {
        if (STREQ(tmp, "yes")) {
M
Michal Privoznik 已提交
13805 13806
            if (virXPathULong("count(./devices/serial)",
                              ctxt, &serialPorts) < 0) {
13807 13808 13809
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                               _("need at least one serial port "
                                 "for useserial"));
M
Michal Privoznik 已提交
13810 13811
                goto cleanup;
            }
J
Ján Tomko 已提交
13812
            def->os.bios.useserial = VIR_TRISTATE_BOOL_YES;
M
Michal Privoznik 已提交
13813
        } else {
J
Ján Tomko 已提交
13814
            def->os.bios.useserial = VIR_TRISTATE_BOOL_NO;
M
Michal Privoznik 已提交
13815
        }
M
Martin Kletzander 已提交
13816
        VIR_FREE(tmp);
M
Michal Privoznik 已提交
13817 13818
    }

13819 13820 13821 13822 13823 13824 13825 13826 13827 13828 13829 13830 13831 13832
    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;
    }

13833 13834
    ret = 0;

13835
 cleanup:
13836
    VIR_FREE(tmp);
13837 13838 13839 13840
    VIR_FREE(nodes);
    return ret;
}

13841

G
Gao feng 已提交
13842 13843
static int virDomainIdMapEntrySort(const void *a, const void *b)
{
13844 13845
    const virDomainIdMapEntry *entrya = a;
    const virDomainIdMapEntry *entryb = b;
G
Gao feng 已提交
13846 13847 13848 13849 13850 13851 13852 13853 13854

    if (entrya->start > entryb->start)
        return 1;
    else if (entrya->start < entryb->start)
        return -1;
    else
        return 0;
}

13855 13856 13857 13858 13859 13860 13861 13862 13863
/* 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,
13864
                          xmlNodePtr *node,
13865 13866 13867 13868 13869 13870
                          size_t num)
{
    size_t i;
    virDomainIdMapEntryPtr idmap = NULL;
    xmlNodePtr save_ctxt = ctxt->node;

13871
    if (VIR_ALLOC_N(idmap, num) < 0)
13872 13873 13874 13875 13876 13877 13878
        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) {
13879 13880
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("invalid idmap start/target/count settings"));
13881 13882 13883 13884 13885
            VIR_FREE(idmap);
            goto cleanup;
        }
    }

G
Gao feng 已提交
13886 13887 13888 13889 13890 13891 13892 13893 13894 13895 13896
    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;
    }

13897
 cleanup:
13898 13899 13900 13901
    ctxt->node = save_ctxt;
    return idmap;
}

13902 13903 13904 13905 13906 13907 13908 13909 13910 13911 13912 13913 13914 13915 13916 13917 13918 13919 13920 13921 13922 13923 13924 13925 13926 13927 13928 13929 13930 13931 13932 13933 13934 13935 13936 13937 13938 13939 13940 13941 13942 13943 13944 13945
/* Parse the XML definition for an IOThread ID
 *
 * Format is :
 *
 *     <iothreads>4</iothreads>
 *     <iothreadids>
 *       <iothread id='1'/>
 *       <iothread id='3'/>
 *       <iothread id='5'/>
 *       <iothread id='7'/>
 *     </iothreadids>
 */
static virDomainIOThreadIDDefPtr
virDomainIOThreadIDDefParseXML(xmlNodePtr node,
                               xmlXPathContextPtr ctxt)
{
    virDomainIOThreadIDDefPtr iothrid;
    xmlNodePtr oldnode = ctxt->node;
    char *tmp = NULL;

    if (VIR_ALLOC(iothrid) < 0)
        return NULL;

    ctxt->node = node;

    if (!(tmp = virXPathString("string(./@id)", ctxt))) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Missing 'id' attribute in <iothread> element"));
        goto error;
    }
    if (virStrToLong_uip(tmp, NULL, 10, &iothrid->iothread_id) < 0 ||
        iothrid->iothread_id == 0) {
        virReportError(VIR_ERR_XML_ERROR,
                        _("invalid iothread 'id' value '%s'"), tmp);
        goto error;
    }

 cleanup:
    VIR_FREE(tmp);
    ctxt->node = oldnode;
    return iothrid;

 error:
    virDomainIOThreadIDDefFree(iothrid);
J
John Ferlan 已提交
13946
    iothrid = NULL;
13947 13948 13949 13950
    goto cleanup;
}


13951 13952 13953 13954 13955 13956 13957 13958 13959 13960 13961 13962 13963 13964 13965 13966 13967 13968 13969
/* Check if pin with same id already exists. */
static bool
virDomainPinIsDuplicate(virDomainPinDefPtr *def,
                        int npin,
                        int id)
{
    size_t i;

    if (!def || !npin)
        return false;

    for (i = 0; i < npin; i++) {
        if (def[i]->id == id)
            return true;
    }

    return false;
}

13970
/* Parse the XML definition for a vcpupin
13971 13972 13973 13974
 *
 * vcpupin has the form of
 *   <vcpupin vcpu='0' cpuset='0'/>
 */
13975
static virDomainPinDefPtr
13976
virDomainVcpuPinDefParseXML(xmlNodePtr node,
13977
                            xmlXPathContextPtr ctxt)
13978
{
13979
    virDomainPinDefPtr def;
13980
    xmlNodePtr oldnode = ctxt->node;
13981
    unsigned int vcpuid;
13982 13983
    char *tmp = NULL;

13984
    if (VIR_ALLOC(def) < 0)
13985 13986 13987 13988
        return NULL;

    ctxt->node = node;

13989 13990 13991
    if (!(tmp = virXPathString("string(./@vcpu)", ctxt))) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("missing vcpu id in vcpupin"));
13992 13993
        goto error;
    }
13994

13995 13996 13997
    if (virStrToLong_uip(tmp, NULL, 10, &vcpuid) < 0) {
        virReportError(VIR_ERR_XML_ERROR,
                       _("invalid setting for vcpu '%s'"), tmp);
13998 13999
        goto error;
    }
14000
    VIR_FREE(tmp);
14001 14002 14003 14004

    def->id = vcpuid;

    if (!(tmp = virXMLPropString(node, "cpuset"))) {
14005
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
14006
                           _("missing cpuset for vcpupin"));
14007

14008
        goto error;
14009
    }
14010

14011 14012 14013 14014 14015 14016 14017 14018 14019 14020 14021 14022 14023 14024 14025 14026 14027 14028
    if (virBitmapParse(tmp, 0, &def->cpumask, VIR_DOMAIN_CPUMASK_LEN) < 0)
        goto error;

 cleanup:
    VIR_FREE(tmp);
    ctxt->node = oldnode;
    return def;

 error:
    VIR_FREE(def);
    goto cleanup;
}


/* Parse the XML definition for a iothreadpin
 * and an iothreadspin has the form
 *   <iothreadpin iothread='1' cpuset='2'/>
 */
14029
static int
14030 14031
virDomainIOThreadPinDefParseXML(xmlNodePtr node,
                                xmlXPathContextPtr ctxt,
14032
                                virDomainDefPtr def)
14033
{
14034 14035
    int ret = -1;
    virDomainIOThreadIDDefPtr iothrid;
14036
    virBitmapPtr cpumask = NULL;
14037 14038 14039 14040 14041 14042
    xmlNodePtr oldnode = ctxt->node;
    unsigned int iothreadid;
    char *tmp = NULL;

    ctxt->node = node;

14043 14044 14045
    if (!(tmp = virXPathString("string(./@iothread)", ctxt))) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("missing iothread id in iothreadpin"));
14046
        goto cleanup;
14047
    }
14048

14049 14050 14051
    if (virStrToLong_uip(tmp, NULL, 10, &iothreadid) < 0) {
        virReportError(VIR_ERR_XML_ERROR,
                       _("invalid setting for iothread '%s'"), tmp);
14052
        goto cleanup;
14053 14054
    }
    VIR_FREE(tmp);
14055

14056 14057 14058
    if (iothreadid == 0) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("zero is an invalid iothread id value"));
14059
        goto cleanup;
14060
    }
14061

14062 14063 14064 14065
    if (!(iothrid = virDomainIOThreadIDFind(def, iothreadid))) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Cannot find 'iothread' : %u"),
                       iothreadid);
J
John Ferlan 已提交
14066
        goto cleanup;
14067 14068
    }

14069
    if (!(tmp = virXMLPropString(node, "cpuset"))) {
14070 14071
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("missing cpuset for iothreadpin"));
14072
        goto cleanup;
14073 14074
    }

14075 14076
    if (virBitmapParse(tmp, 0, &cpumask, VIR_DOMAIN_CPUMASK_LEN) < 0)
        goto cleanup;
14077

14078
    if (virBitmapIsAllClear(cpumask)) {
14079 14080 14081
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Invalid value of 'cpuset': %s"),
                       tmp);
14082
        goto cleanup;
14083 14084
    }

14085 14086 14087 14088 14089 14090 14091 14092 14093 14094 14095
    if (iothrid->cpumask) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("duplicate iothreadpin for same iothread '%u'"),
                       iothreadid);
        goto cleanup;
    }

    iothrid->cpumask = cpumask;
    cpumask = NULL;
    ret = 0;

14096
 cleanup:
14097
    VIR_FREE(tmp);
14098
    virBitmapFree(cpumask);
14099
    ctxt->node = oldnode;
14100
    return ret;
14101 14102
}

14103

14104 14105 14106 14107
/* Parse the XML definition for emulatorpin.
 * emulatorpin has the form of
 *   <emulatorpin cpuset='0'/>
 */
14108
static virBitmapPtr
14109 14110
virDomainEmulatorPinDefParseXML(xmlNodePtr node)
{
14111
    virBitmapPtr def = NULL;
14112 14113 14114 14115 14116
    char *tmp = NULL;

    if (!(tmp = virXMLPropString(node, "cpuset"))) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("missing cpuset for emulatorpin"));
14117
        return NULL;
14118 14119
    }

14120
    ignore_value(virBitmapParse(tmp, 0, &def, VIR_DOMAIN_CPUMASK_LEN));
14121 14122 14123 14124 14125 14126

    VIR_FREE(tmp);
    return def;
}


14127
int
14128 14129 14130 14131
virDomainDefMaybeAddController(virDomainDefPtr def,
                               int type,
                               int idx,
                               int model)
14132
{
14133
    size_t i;
14134 14135
    virDomainControllerDefPtr cont;

14136
    for (i = 0; i < def->ncontrollers; i++) {
14137 14138
        if (def->controllers[i]->type == type &&
            def->controllers[i]->idx == idx)
14139
            return 0;
14140 14141
    }

14142
    if (!(cont = virDomainControllerDefNew(type)))
14143 14144 14145
        return -1;

    cont->idx = idx;
14146
    cont->model = model;
14147

14148
    if (VIR_APPEND_ELEMENT(def->controllers, def->ncontrollers, cont) < 0) {
14149 14150 14151 14152
        VIR_FREE(cont);
        return -1;
    }

14153
    return 1;
14154 14155
}

E
Eric Blake 已提交
14156

14157 14158 14159 14160 14161 14162 14163 14164 14165 14166 14167 14168 14169 14170 14171 14172 14173 14174 14175 14176 14177 14178 14179 14180 14181 14182 14183 14184 14185
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;
}


14186 14187 14188 14189 14190 14191 14192 14193 14194 14195 14196
static int
virDomainHugepagesParseXML(xmlNodePtr node,
                           xmlXPathContextPtr ctxt,
                           virDomainHugePagePtr hugepage)
{
    int ret = -1;
    xmlNodePtr oldnode = ctxt->node;
    char *unit = NULL, *nodeset = NULL;

    ctxt->node = node;

14197 14198
    if (virDomainParseMemory("./@size", "./@unit", ctxt,
                             &hugepage->size, true, false) < 0)
14199 14200
        goto cleanup;

14201
    if (!hugepage->size) {
14202 14203 14204 14205 14206 14207 14208 14209 14210
        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;
14211 14212 14213 14214 14215 14216

        if (virBitmapIsAllClear(hugepage->nodemask)) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Invalid value of 'nodeset': %s"), nodeset);
            goto cleanup;
        }
14217 14218 14219 14220 14221 14222 14223 14224 14225 14226 14227
    }

    ret = 0;
 cleanup:
    VIR_FREE(unit);
    VIR_FREE(nodeset);
    ctxt->node = oldnode;
    return ret;
}


14228 14229 14230 14231 14232 14233 14234 14235 14236
static virDomainResourceDefPtr
virDomainResourceDefParse(xmlNodePtr node,
                          xmlXPathContextPtr ctxt)
{
    virDomainResourceDefPtr def = NULL;
    xmlNodePtr tmp = ctxt->node;

    ctxt->node = node;

14237
    if (VIR_ALLOC(def) < 0)
14238 14239 14240 14241 14242 14243 14244 14245 14246 14247 14248 14249
        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;

14250
 error:
14251 14252 14253 14254 14255
    ctxt->node = tmp;
    virDomainResourceDefFree(def);
    return NULL;
}

14256 14257 14258 14259
static int
virDomainDefMaybeAddHostdevSCSIcontroller(virDomainDefPtr def)
{
    /* Look for any hostdev scsi dev */
14260
    size_t i;
14261 14262 14263 14264 14265 14266 14267 14268 14269 14270 14271 14272
    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;
        }
    }

14273 14274 14275
    if (maxController == -1)
        return 0;

14276 14277 14278 14279 14280 14281 14282
    for (i = 0; i <= maxController; i++) {
        if (virDomainDefMaybeAddController(def, VIR_DOMAIN_CONTROLLER_TYPE_SCSI, i, -1) < 0)
            return -1;
    }

    return 0;
}
14283

14284 14285 14286 14287 14288 14289 14290 14291 14292 14293 14294 14295 14296 14297 14298 14299 14300 14301 14302 14303 14304 14305 14306 14307 14308 14309 14310 14311 14312 14313 14314 14315 14316 14317 14318 14319
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;
}

14320 14321 14322 14323 14324 14325 14326 14327
static int
virDomainThreadSchedParse(xmlNodePtr node,
                          unsigned int minid,
                          unsigned int maxid,
                          const char *name,
                          virDomainThreadSchedParamPtr sp)
{
    char *tmp = NULL;
14328
    int pol = 0;
14329 14330 14331 14332 14333 14334 14335 14336 14337

    tmp = virXMLPropString(node, name);
    if (!tmp) {
        virReportError(VIR_ERR_XML_ERROR,
                       _("Missing attribute '%s' in element '%sched'"),
                       name, name);
        goto error;
    }

14338 14339 14340 14341
    if (virBitmapParse(tmp, 0, &sp->ids, VIR_DOMAIN_CPUMASK_LEN) < 0)
        goto error;

    if (virBitmapIsAllClear(sp->ids) ||
14342 14343 14344
        virBitmapNextSetBit(sp->ids, -1) < minid ||
        virBitmapLastSetBit(sp->ids) > maxid) {

14345
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
14346 14347 14348 14349 14350 14351
                       _("Invalid value of '%s': %s"),
                       name, tmp);
        goto error;
    }
    VIR_FREE(tmp);

14352 14353 14354 14355 14356 14357 14358 14359 14360 14361 14362 14363 14364 14365 14366 14367 14368 14369 14370 14371 14372
    if (!(tmp = virXMLPropString(node, "scheduler"))) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Missing scheduler attribute"));
        goto error;
    }

    if ((pol = virProcessSchedPolicyTypeFromString(tmp)) <= 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Invalid scheduler attribute: '%s'"),
                       tmp);
        goto error;
    }
    sp->policy = pol;

    VIR_FREE(tmp);
    if (sp->policy == VIR_PROC_POLICY_FIFO ||
        sp->policy == VIR_PROC_POLICY_RR) {
        tmp = virXMLPropString(node, "priority");
        if (!tmp) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("Missing scheduler priority"));
14373 14374
            goto error;
        }
14375 14376 14377 14378
        if (virStrToLong_i(tmp, NULL, 10, &sp->priority) < 0) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("Invalid value for element priority"));
            goto error;
14379
        }
14380
        VIR_FREE(tmp);
14381 14382 14383 14384 14385 14386 14387 14388
    }

    return 0;

 error:
    VIR_FREE(tmp);
    return -1;
}
14389

14390 14391 14392 14393 14394 14395 14396

static int
virDomainVcpuParse(virDomainDefPtr def,
                   xmlXPathContextPtr ctxt)
{
    int n;
    char *tmp = NULL;
14397
    unsigned int maxvcpus;
14398 14399
    int ret = -1;

14400
    if ((n = virXPathUInt("string(./vcpu[1])", ctxt, &maxvcpus)) < 0) {
14401 14402 14403 14404 14405 14406
        if (n == -2) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("maximum vcpus count must be an integer"));
            goto cleanup;
        }

14407
        maxvcpus = 1;
14408 14409
    }

14410 14411 14412
    if (virDomainDefSetVcpusMax(def, maxvcpus) < 0)
        goto cleanup;

14413 14414 14415 14416 14417 14418 14419
    if ((n = virXPathUInt("string(./vcpu[1]/@current)", ctxt, &def->vcpus)) < 0) {
        if (n == -2) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("current vcpus count must be an integer"));
            goto cleanup;
        }

14420
        def->vcpus = maxvcpus;
14421 14422
    }

14423
    if (maxvcpus < def->vcpus) {
14424 14425
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("maxvcpus must not be less than current vcpus "
14426
                         "(%u < %u)"), maxvcpus, def->vcpus);
14427 14428 14429 14430 14431 14432 14433 14434 14435 14436 14437 14438 14439 14440 14441 14442 14443 14444 14445 14446 14447 14448 14449 14450 14451 14452 14453 14454 14455 14456 14457 14458 14459 14460 14461 14462 14463 14464 14465 14466 14467 14468
        goto cleanup;
    }

    tmp = virXPathString("string(./vcpu[1]/@placement)", ctxt);
    if (tmp) {
        if ((def->placement_mode =
             virDomainCpuPlacementModeTypeFromString(tmp)) < 0) {
             virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                            _("Unsupported CPU placement mode '%s'"),
                            tmp);
             goto cleanup;
        }
        VIR_FREE(tmp);
    } else {
        def->placement_mode = VIR_DOMAIN_CPU_PLACEMENT_MODE_STATIC;
    }

    if (def->placement_mode != VIR_DOMAIN_CPU_PLACEMENT_MODE_AUTO) {
        tmp = virXPathString("string(./vcpu[1]/@cpuset)", ctxt);
        if (tmp) {
            if (virBitmapParse(tmp, 0, &def->cpumask,
                               VIR_DOMAIN_CPUMASK_LEN) < 0)
                goto cleanup;

            if (virBitmapIsAllClear(def->cpumask)) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("Invalid value of 'cpuset': %s"), tmp);
                goto cleanup;
            }

            VIR_FREE(tmp);
        }
    }

    ret = 0;

 cleanup:
    VIR_FREE(tmp);

    return ret;
}

14469
static virDomainDefPtr
14470
virDomainDefParseXML(xmlDocPtr xml,
14471 14472
                     xmlNodePtr root,
                     xmlXPathContextPtr ctxt,
14473 14474
                     virCapsPtr caps,
                     virDomainXMLOptionPtr xmlopt,
14475
                     unsigned int flags)
14476 14477 14478
{
    xmlNodePtr *nodes = NULL, node = NULL;
    char *tmp = NULL;
14479
    size_t i, j;
J
John Ferlan 已提交
14480
    int n, virtType;
14481
    long id = -1;
14482
    virDomainDefPtr def;
14483
    bool uuid_generated = false;
14484
    virHashTablePtr bootHash = NULL;
14485 14486
    bool usb_none = false;
    bool usb_other = false;
14487
    bool usb_master = false;
14488
    bool primaryVideo = false;
14489

14490 14491
    if (flags & VIR_DOMAIN_DEF_PARSE_VALIDATE) {
        char *schema = virFileFindResource("domain.rng",
14492
                                           abs_topsrcdir "/docs/schemas",
14493 14494 14495 14496 14497 14498 14499 14500 14501 14502
                                           PKGDATADIR "/schemas");
        if (!schema)
            return NULL;
        if (virXMLValidateAgainstSchema(schema, xml) < 0) {
            VIR_FREE(schema);
            return NULL;
        }
        VIR_FREE(schema);
    }

14503
    if (!(def = virDomainDefNew()))
14504
        return NULL;
14505

14506
    if (!(flags & VIR_DOMAIN_DEF_PARSE_INACTIVE))
E
Eric Blake 已提交
14507
        if (virXPathLong("string(./@id)", ctxt, &id) < 0)
14508 14509
            id = -1;
    def->id = (int)id;
14510

14511
    /* Find out what type of virtualization to use */
14512
    if (!(tmp = virXPathString("string(./@type)", ctxt))) {
14513 14514
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing domain type attribute"));
14515 14516 14517
        goto error;
    }

J
John Ferlan 已提交
14518
    if ((virtType = virDomainVirtTypeFromString(tmp)) < 0) {
14519
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
14520
                       _("invalid domain type %s"), tmp);
14521 14522
        goto error;
    }
J
John Ferlan 已提交
14523
    def->virtType = virtType;
14524 14525
    VIR_FREE(tmp);

14526 14527 14528 14529 14530 14531 14532 14533 14534 14535 14536 14537 14538 14539 14540 14541 14542 14543 14544 14545 14546 14547 14548 14549 14550 14551 14552 14553 14554 14555 14556 14557 14558 14559 14560 14561 14562 14563 14564 14565 14566 14567 14568 14569
    def->os.bootloader = virXPathString("string(./bootloader)", ctxt);
    def->os.bootloaderArgs = virXPathString("string(./bootloader_args)", ctxt);

    tmp = virXPathString("string(./os/type[1])", ctxt);
    if (!tmp) {
        if (def->os.bootloader) {
            def->os.type = VIR_DOMAIN_OSTYPE_XEN;
        } else {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("an os <type> must be specified"));
            goto error;
        }
    } else {
        if ((def->os.type = virDomainOSTypeFromString(tmp)) < 0) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown OS type '%s'"), tmp);
            goto error;
        }
        VIR_FREE(tmp);
    }

    /*
     * 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 (def->os.type == VIR_DOMAIN_OSTYPE_LINUX &&
        def->virtType == VIR_DOMAIN_VIRT_XEN) {
        def->os.type = VIR_DOMAIN_OSTYPE_XEN;
    }

    tmp = virXPathString("string(./os/type[1]/@arch)", ctxt);
    if (tmp && !(def->os.arch = virArchFromString(tmp))) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unknown architecture %s"),
                       tmp);
        goto error;
    }
    VIR_FREE(tmp);

    def->os.machine = virXPathString("string(./os/type[1]/@machine)", ctxt);
    def->emulator = virXPathString("string(./devices/emulator[1])", ctxt);

    if (!(flags & VIR_DOMAIN_DEF_PARSE_SKIP_OSTYPE_CHECKS)) {
14570 14571 14572 14573 14574 14575 14576 14577
        /* If the logic here seems fairly arbitrary, that's because it is :)
         * This is duplicating how the code worked before
         * CapabilitiesDomainDataLookup was added. We can simplify this,
         * but it would take a bit of work because the test suite fails
         * in numerous minor ways. */
        bool use_virttype = ((def->os.arch == VIR_ARCH_NONE) ||
            !def->os.machine);
        virCapsDomainDataPtr capsdata = NULL;
14578

14579
        if (!(capsdata = virCapabilitiesDomainDataLookup(caps, def->os.type,
14580
                def->os.arch, use_virttype ? def->virtType : VIR_DOMAIN_VIRT_NONE,
14581 14582
                NULL, NULL)))
            goto error;
14583

14584 14585 14586 14587 14588 14589
        if (!def->os.arch)
            def->os.arch = capsdata->arch;
        if ((!def->os.machine &&
             VIR_STRDUP(def->os.machine, capsdata->machinetype) < 0)) {
            VIR_FREE(capsdata);
            goto error;
14590
        }
14591
        VIR_FREE(capsdata);
14592 14593
    }

14594
    /* Extract domain name */
14595
    if (!(def->name = virXPathString("string(./name[1])", ctxt))) {
14596
        virReportError(VIR_ERR_NO_NAME, NULL);
14597 14598 14599
        goto error;
    }

14600 14601 14602
    /* 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. */
14603
    tmp = virXPathString("string(./uuid[1])", ctxt);
14604
    if (!tmp) {
14605
        if (virUUIDGenerate(def->uuid)) {
14606 14607
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("Failed to generate UUID"));
14608 14609
            goto error;
        }
14610
        uuid_generated = true;
14611 14612
    } else {
        if (virUUIDParse(tmp, def->uuid) < 0) {
14613 14614
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("malformed uuid element"));
14615 14616 14617 14618 14619
            goto error;
        }
        VIR_FREE(tmp);
    }

14620 14621 14622
    /* Extract short description of domain (title) */
    def->title = virXPathString("string(./title[1])", ctxt);
    if (def->title && strchr(def->title, '\n')) {
14623 14624
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Domain title can't contain newlines"));
14625 14626 14627
        goto error;
    }

14628
    /* Extract documentation if present */
14629
    def->description = virXPathString("string(./description[1])", ctxt);
14630

E
Eric Blake 已提交
14631 14632
    /* analysis of security label, done early even though we format it
     * late, so devices can refer to this for defaults */
14633
    if (virSecurityLabelDefsParseXML(def, ctxt, caps, flags) == -1)
E
Eric Blake 已提交
14634 14635
        goto error;

14636
    /* Extract domain memory */
14637
    if (virDomainParseMemory("./memory[1]", NULL, ctxt,
14638
                             &def->mem.total_memory, false, true) < 0)
14639 14640
        goto error;

14641
    if (virDomainParseMemory("./currentMemory[1]", NULL, ctxt,
14642
                             &def->mem.cur_balloon, false, true) < 0)
E
Eric Blake 已提交
14643
        goto error;
14644

14645 14646 14647 14648 14649 14650 14651 14652 14653 14654
    if (virDomainParseMemory("./maxMemory[1]", NULL, ctxt,
                             &def->mem.max_memory, false, false) < 0)
        goto error;

    if (virXPathUInt("string(./maxMemory[1]/@slots)", ctxt, &def->mem.memory_slots) == -2) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Failed to parse memory slot count"));
        goto error;
    }

14655
    /* and info about it */
14656
    if ((tmp = virXPathString("string(./memory[1]/@dumpCore)", ctxt)) &&
J
Ján Tomko 已提交
14657
        (def->mem.dump_core = virTristateSwitchTypeFromString(tmp)) <= 0) {
14658
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
14659 14660
                       _("Invalid memory core dump attribute value '%s'"), tmp);
        goto error;
14661
    }
14662
    VIR_FREE(tmp);
14663

14664 14665 14666 14667 14668 14669 14670 14671 14672 14673 14674 14675 14676 14677 14678 14679 14680 14681 14682 14683 14684 14685 14686 14687 14688 14689 14690 14691 14692 14693 14694 14695 14696 14697 14698 14699 14700 14701 14702 14703 14704 14705 14706 14707 14708 14709 14710 14711
    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;
        }
    }
14712

14713 14714 14715
    if ((node = virXPathNode("./memoryBacking/nosharepages", ctxt)))
        def->mem.nosharepages = true;

14716 14717 14718
    if (virXPathBoolean("boolean(./memoryBacking/locked)", ctxt))
        def->mem.locked = true;

14719 14720 14721 14722 14723
    /* Extract blkio cgroup tunables */
    if (virXPathUInt("string(./blkiotune/weight)", ctxt,
                     &def->blkio.weight) < 0)
        def->blkio.weight = 0;

14724
    if ((n = virXPathNodeSet("./blkiotune/device", ctxt, &nodes)) < 0) {
14725 14726
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("cannot extract blkiotune nodes"));
14727 14728 14729
        goto error;
    }
    if (n && VIR_ALLOC_N(def->blkio.devices, n) < 0)
14730
        goto error;
14731 14732

    for (i = 0; i < n; i++) {
14733 14734
        if (virDomainBlkioDeviceParseXML(nodes[i],
                                         &def->blkio.devices[i]) < 0)
14735 14736
            goto error;
        def->blkio.ndevices++;
14737 14738 14739
        for (j = 0; j < i; j++) {
            if (STREQ(def->blkio.devices[j].path,
                      def->blkio.devices[i].path)) {
14740
                virReportError(VIR_ERR_XML_ERROR,
14741
                               _("duplicate blkio device path '%s'"),
14742
                               def->blkio.devices[i].path);
14743 14744 14745
                goto error;
            }
        }
14746 14747 14748
    }
    VIR_FREE(nodes);

14749
    /* Extract other memory tunables */
14750 14751
    if (virDomainParseMemoryLimit("./memtune/hard_limit[1]", NULL, ctxt,
                                  &def->mem.hard_limit) < 0)
E
Eric Blake 已提交
14752
        goto error;
14753

14754 14755
    if (virDomainParseMemoryLimit("./memtune/soft_limit[1]", NULL, ctxt,
                                  &def->mem.soft_limit) < 0)
E
Eric Blake 已提交
14756
        goto error;
14757

14758
    if (virDomainParseMemory("./memtune/min_guarantee[1]", NULL, ctxt,
14759
                             &def->mem.min_guarantee, false, false) < 0)
E
Eric Blake 已提交
14760
        goto error;
14761

14762 14763
    if (virDomainParseMemoryLimit("./memtune/swap_hard_limit[1]", NULL, ctxt,
                                  &def->mem.swap_hard_limit) < 0)
E
Eric Blake 已提交
14764
        goto error;
14765

14766
    if (virDomainVcpuParse(def, ctxt) < 0)
14767
        goto error;
14768

14769 14770 14771 14772 14773 14774 14775 14776 14777
    /* 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);

14778 14779 14780 14781 14782 14783 14784 14785 14786 14787 14788 14789 14790 14791 14792 14793 14794 14795 14796 14797 14798 14799 14800 14801 14802 14803
    /* Extract any iothread id's defined */
    if ((n = virXPathNodeSet("./iothreadids/iothread", ctxt, &nodes)) < 0)
        goto error;

    if (n > def->iothreads)
        def->iothreads = n;

    if (n && VIR_ALLOC_N(def->iothreadids, n) < 0)
        goto error;

    for (i = 0; i < n; i++) {
        virDomainIOThreadIDDefPtr iothrid = NULL;
        if (!(iothrid = virDomainIOThreadIDDefParseXML(nodes[i], ctxt)))
            goto error;

        if (virDomainIOThreadIDFind(def, iothrid->iothread_id)) {
            virReportError(VIR_ERR_XML_ERROR,
                           _("duplicate iothread id '%u' found"),
                           iothrid->iothread_id);
            virDomainIOThreadIDDefFree(iothrid);
            goto error;
        }
        def->iothreadids[def->niothreadids++] = iothrid;
    }
    VIR_FREE(nodes);

14804 14805
    if (virDomainIOThreadIDDefArrayInit(def) < 0)
        goto error;
14806

14807
    /* Extract cpu tunables. */
14808 14809
    if ((n = virXPathULong("string(./cputune/shares[1])", ctxt,
                           &def->cputune.shares)) < -1) {
14810 14811 14812
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("can't parse cputune shares value"));
        goto error;
14813 14814
    } else if (n == 0) {
        def->cputune.sharesSpecified = true;
14815
    }
14816

14817
    if (virXPathULongLong("string(./cputune/period[1])", ctxt,
14818 14819 14820 14821 14822
                          &def->cputune.period) < -1) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("can't parse cputune period value"));
        goto error;
    }
14823

14824 14825 14826 14827 14828 14829 14830 14831
    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;
    }

14832
    if (virXPathLongLong("string(./cputune/quota[1])", ctxt,
14833 14834 14835 14836 14837
                         &def->cputune.quota) < -1) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("can't parse cputune quota value"));
        goto error;
    }
14838

14839 14840
    if (def->cputune.quota > 0 &&
        (def->cputune.quota < 1000 ||
E
Eric Blake 已提交
14841
         def->cputune.quota > 18446744073709551LL)) {
14842 14843 14844 14845 14846 14847
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Value of cputune quota must be in range "
                         "[1000, 18446744073709551]"));
        goto error;
    }

14848
    if (virXPathULongLong("string(./cputune/emulator_period[1])", ctxt,
14849 14850 14851 14852 14853
                          &def->cputune.emulator_period) < -1) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("can't parse cputune emulator period value"));
        goto error;
    }
14854

14855 14856 14857 14858 14859 14860 14861 14862 14863
    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;
    }

14864
    if (virXPathLongLong("string(./cputune/emulator_quota[1])", ctxt,
14865 14866 14867
                         &def->cputune.emulator_quota) < -1) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("can't parse cputune emulator quota value"));
14868 14869 14870
        goto error;
    }

14871 14872
    if (def->cputune.emulator_quota > 0 &&
        (def->cputune.emulator_quota < 1000 ||
E
Eric Blake 已提交
14873
         def->cputune.emulator_quota > 18446744073709551LL)) {
14874 14875 14876 14877 14878 14879
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Value of cputune emulator_quota must be in range "
                         "[1000, 18446744073709551]"));
        goto error;
    }

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

14883
    if (n && VIR_ALLOC_N(def->cputune.vcpupin, n) < 0)
14884
        goto error;
14885

14886
    for (i = 0; i < n; i++) {
14887 14888
        virDomainPinDefPtr vcpupin;
        if (!(vcpupin = virDomainVcpuPinDefParseXML(nodes[i], ctxt)))
14889 14890
            goto error;

14891 14892 14893
        if (virDomainPinIsDuplicate(def->cputune.vcpupin,
                                    def->cputune.nvcpupin,
                                    vcpupin->id)) {
14894 14895
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("duplicate vcpupin for same vcpu"));
14896
            virDomainPinDefFree(vcpupin);
14897 14898 14899
            goto error;
        }

14900
        if (vcpupin->id >= def->vcpus) {
14901 14902 14903 14904 14905
            /* 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.
             */
14906
            VIR_WARN("Ignore vcpupin for missing vcpus");
14907
            virDomainPinDefFree(vcpupin);
14908
        } else {
14909
            def->cputune.vcpupin[def->cputune.nvcpupin++] = vcpupin;
14910
        }
14911 14912 14913
    }
    VIR_FREE(nodes);

14914 14915 14916 14917
    /* Initialize the pinning policy for vcpus which doesn't has
     * the policy specified explicitly as def->cpuset.
     */
    if (def->cpumask) {
14918
        if (VIR_REALLOC_N(def->cputune.vcpupin, def->vcpus) < 0)
14919
            goto error;
14920 14921

        for (i = 0; i < def->vcpus; i++) {
14922 14923 14924
            if (virDomainPinIsDuplicate(def->cputune.vcpupin,
                                        def->cputune.nvcpupin,
                                        i))
14925
                continue;
14926

14927
            virDomainPinDefPtr vcpupin = NULL;
14928

14929
            if (VIR_ALLOC(vcpupin) < 0)
14930 14931
                goto error;

14932 14933
            if (!(vcpupin->cpumask = virBitmapNew(VIR_DOMAIN_CPUMASK_LEN))) {
                VIR_FREE(vcpupin);
14934
                goto error;
14935
            }
14936
            virBitmapCopy(vcpupin->cpumask, def->cpumask);
14937
            vcpupin->id = i;
14938
            def->cputune.vcpupin[def->cputune.nvcpupin++] = vcpupin;
14939 14940 14941
        }
    }

T
Tang Chen 已提交
14942 14943 14944 14945 14946 14947 14948
    if ((n = virXPathNodeSet("./cputune/emulatorpin", ctxt, &nodes)) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("cannot extract emulatorpin nodes"));
        goto error;
    }

    if (n) {
14949 14950 14951 14952 14953 14954
        if (n > 1) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("only one emulatorpin is supported"));
            VIR_FREE(nodes);
            goto error;
        }
T
Tang Chen 已提交
14955

14956
        if (!(def->cputune.emulatorpin = virDomainEmulatorPinDefParseXML(nodes[0])))
14957
            goto error;
T
Tang Chen 已提交
14958 14959 14960
    }
    VIR_FREE(nodes);

14961 14962 14963 14964 14965 14966 14967

    if ((n = virXPathNodeSet("./cputune/iothreadpin", ctxt, &nodes)) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("cannot extract iothreadpin nodes"));
        goto error;
    }

14968
    for (i = 0; i < n; i++) {
14969
        if (virDomainIOThreadPinDefParseXML(nodes[i], ctxt, def) < 0)
14970
            goto error;
14971 14972 14973
    }
    VIR_FREE(nodes);

14974 14975 14976 14977 14978 14979 14980 14981 14982 14983 14984 14985 14986 14987 14988 14989 14990 14991 14992 14993 14994 14995 14996 14997 14998 14999 15000 15001 15002 15003 15004 15005 15006 15007 15008 15009
    if ((n = virXPathNodeSet("./cputune/vcpusched", ctxt, &nodes)) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("cannot extract vcpusched nodes"));
        goto error;
    }
    if (n) {
        if (VIR_ALLOC_N(def->cputune.vcpusched, n) < 0)
            goto error;
        def->cputune.nvcpusched = n;

        for (i = 0; i < def->cputune.nvcpusched; i++) {
            if (virDomainThreadSchedParse(nodes[i],
                                          0, def->maxvcpus - 1,
                                          "vcpus",
                                          &def->cputune.vcpusched[i]) < 0)
                goto error;

            for (j = 0; j < i; j++) {
                if (virBitmapOverlaps(def->cputune.vcpusched[i].ids,
                                      def->cputune.vcpusched[j].ids)) {
                    virReportError(VIR_ERR_XML_DETAIL, "%s",
                                   _("vcpusched attributes 'vcpus' "
                                     "must not overlap"));
                    goto error;
                }
            }
        }
    }
    VIR_FREE(nodes);

    if ((n = virXPathNodeSet("./cputune/iothreadsched", ctxt, &nodes)) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("cannot extract iothreadsched nodes"));
        goto error;
    }
    if (n) {
15010
        if (n > def->niothreadids) {
15011 15012 15013 15014 15015 15016 15017 15018 15019 15020
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("too many iothreadsched nodes in cputune"));
            goto error;
        }

        if (VIR_ALLOC_N(def->cputune.iothreadsched, n) < 0)
            goto error;
        def->cputune.niothreadsched = n;

        for (i = 0; i < def->cputune.niothreadsched; i++) {
15021 15022
            ssize_t pos = -1;

15023
            if (virDomainThreadSchedParse(nodes[i],
15024
                                          1, UINT_MAX,
15025 15026 15027 15028
                                          "iothreads",
                                          &def->cputune.iothreadsched[i]) < 0)
                goto error;

15029 15030 15031 15032 15033 15034 15035 15036 15037 15038
            while ((pos = virBitmapNextSetBit(def->cputune.iothreadsched[i].ids,
                                              pos)) > -1) {
                if (!virDomainIOThreadIDFind(def, pos)) {
                    virReportError(VIR_ERR_XML_DETAIL, "%s",
                                   _("iothreadsched attribute 'iothreads' "
                                     "uses undefined iothread ids"));
                    goto error;
                }
            }

15039 15040 15041 15042 15043 15044 15045 15046 15047 15048 15049 15050
            for (j = 0; j < i; j++) {
                if (virBitmapOverlaps(def->cputune.iothreadsched[i].ids,
                                      def->cputune.iothreadsched[j].ids)) {
                    virReportError(VIR_ERR_XML_DETAIL, "%s",
                                   _("iothreadsched attributes 'iothreads' "
                                     "must not overlap"));
                    goto error;
                }
            }
        }
    }
    VIR_FREE(nodes);
15051

M
Martin Kletzander 已提交
15052 15053 15054 15055 15056 15057 15058 15059 15060 15061 15062 15063 15064 15065 15066 15067 15068 15069
    /* 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;
        }

15070 15071
    }

15072
    if (virDomainNumaDefCPUParseXML(def->numa, ctxt) < 0)
15073 15074
        goto error;

15075
    if (virDomainNumaGetCPUCountTotal(def->numa) > def->maxvcpus) {
15076 15077 15078 15079
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Number of CPUs in <numa> exceeds the"
                         " <vcpu> count"));
        goto error;
M
Martin Kletzander 已提交
15080 15081
    }

15082 15083 15084 15085 15086 15087
    if (virDomainNumaGetMaxCPUID(def->numa) >= def->maxvcpus) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("CPU IDs in <numa> exceed the <vcpu> count"));
        goto error;
    }

15088
    if (virDomainNumatuneParseXML(def->numa,
15089 15090 15091
                                  def->placement_mode ==
                                  VIR_DOMAIN_CPU_PLACEMENT_MODE_STATIC,
                                  ctxt) < 0)
15092 15093
        goto error;

15094
    if (virDomainNumatuneHasPlacementAuto(def->numa) &&
15095
        !def->cpumask && !def->cputune.vcpupin &&
15096 15097
        !def->cputune.emulatorpin &&
        !virDomainIOThreadIDArrayHasPin(def))
15098 15099
        def->placement_mode = VIR_DOMAIN_CPU_PLACEMENT_MODE_AUTO;

15100 15101 15102 15103 15104 15105 15106 15107 15108 15109 15110 15111 15112 15113 15114 15115 15116
    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);

15117
    if ((n = virXPathNodeSet("./features/*", ctxt, &nodes)) < 0)
15118
        goto error;
15119

15120
    for (i = 0; i < n; i++) {
15121 15122
        int val = virDomainFeatureTypeFromString((const char *)nodes[i]->name);
        if (val < 0) {
15123
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
15124
                           _("unexpected feature '%s'"), nodes[i]->name);
15125 15126
            goto error;
        }
15127

15128
        switch ((virDomainFeature) val) {
15129 15130
        case VIR_DOMAIN_FEATURE_APIC:
            if ((tmp = virXPathString("string(./features/apic/@eoi)", ctxt))) {
15131
                int eoi;
J
Ján Tomko 已提交
15132
                if ((eoi = virTristateSwitchTypeFromString(tmp)) <= 0) {
15133
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
15134
                                   _("unknown value for attribute eoi: '%s'"),
15135 15136
                                   tmp);
                    goto error;
15137
                }
15138 15139
                def->apic_eoi = eoi;
                VIR_FREE(tmp);
15140
            }
15141 15142 15143 15144 15145 15146 15147
            /* 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:
15148
        case VIR_DOMAIN_FEATURE_KVM:
J
Ján Tomko 已提交
15149
            def->features[val] = VIR_TRISTATE_SWITCH_ON;
15150 15151
            break;

15152 15153 15154 15155 15156 15157 15158 15159 15160 15161 15162 15163
        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 已提交
15164
                def->features[val] = VIR_TRISTATE_SWITCH_ABSENT;
15165 15166 15167
            }
            ctxt->node = node;
            break;
15168 15169

        case VIR_DOMAIN_FEATURE_PMU:
15170
        case VIR_DOMAIN_FEATURE_PVSPINLOCK:
15171
        case VIR_DOMAIN_FEATURE_VMPORT:
15172 15173 15174
            node = ctxt->node;
            ctxt->node = nodes[i];
            if ((tmp = virXPathString("string(./@state)", ctxt))) {
J
Ján Tomko 已提交
15175
                if ((def->features[val] = virTristateSwitchTypeFromString(tmp)) == -1) {
15176
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
Y
Yuri Chornoivan 已提交
15177
                                   _("unknown state attribute '%s' of feature '%s'"),
15178 15179 15180
                                   tmp, virDomainFeatureTypeToString(val));
                    goto error;
                }
15181
                VIR_FREE(tmp);
15182
            } else {
J
Ján Tomko 已提交
15183
                def->features[val] = VIR_TRISTATE_SWITCH_ON;
15184 15185 15186 15187
            }
            ctxt->node = node;
            break;

M
Michal Privoznik 已提交
15188 15189 15190 15191 15192 15193 15194 15195 15196 15197 15198 15199 15200 15201 15202 15203
        case VIR_DOMAIN_FEATURE_GIC:
            node = ctxt->node;
            ctxt->node = nodes[i];
            if ((tmp = virXPathString("string(./@version)", ctxt))) {
                if (virStrToLong_uip(tmp, NULL, 10, &def->gic_version) < 0 ||
                    def->gic_version == 0) {
                    virReportError(VIR_ERR_XML_ERROR,
                                   _("malformed gic version: %s"), tmp);
                    goto error;
                }
                VIR_FREE(tmp);
            }
            def->features[val] = VIR_TRISTATE_SWITCH_ON;
            ctxt->node = node;
            break;

15204
        /* coverity[dead_error_begin] */
15205 15206
        case VIR_DOMAIN_FEATURE_LAST:
            break;
15207 15208
        }
    }
15209
    VIR_FREE(nodes);
15210

J
Ján Tomko 已提交
15211
    if (def->features[VIR_DOMAIN_FEATURE_HYPERV] == VIR_TRISTATE_SWITCH_ON) {
15212 15213 15214 15215 15216 15217 15218 15219 15220
        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) {
15221
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
15222 15223 15224 15225 15226 15227 15228
                               _("unsupported HyperV Enlightenment feature: %s"),
                               nodes[i]->name);
                goto error;
            }

            ctxt->node = nodes[i];

15229
            switch ((virDomainHyperv) feature) {
15230
                case VIR_DOMAIN_HYPERV_RELAXED:
15231
                case VIR_DOMAIN_HYPERV_VAPIC:
15232 15233 15234 15235 15236 15237 15238 15239
                    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 已提交
15240
                    if ((value = virTristateSwitchTypeFromString(tmp)) < 0) {
15241
                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
15242 15243 15244 15245 15246 15247
                                       _("invalid value of state argument "
                                         "for HyperV Enlightenment feature '%s'"),
                                       nodes[i]->name);
                        goto error;
                    }

15248
                    VIR_FREE(tmp);
15249 15250 15251
                    def->hyperv_features[feature] = value;
                    break;

15252 15253 15254 15255 15256 15257 15258 15259 15260
                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 已提交
15261
                    if ((value = virTristateSwitchTypeFromString(tmp)) < 0) {
15262
                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
15263 15264 15265 15266 15267 15268 15269
                                       _("invalid value of state argument "
                                         "for HyperV Enlightenment feature '%s'"),
                                       nodes[i]->name);
                        goto error;
                    }

                    VIR_FREE(tmp);
J
Ján Tomko 已提交
15270
                    if (value == VIR_TRISTATE_SWITCH_ON) {
15271 15272 15273 15274 15275 15276
                        if (virXPathUInt("string(./@retries)", ctxt,
                                     &def->hyperv_spinlocks) < 0) {
                            virReportError(VIR_ERR_XML_ERROR, "%s",
                                           _("invalid HyperV spinlock retry count"));
                            goto error;
                        }
15277

15278 15279 15280 15281 15282 15283
                        if (def->hyperv_spinlocks < 0xFFF) {
                            virReportError(VIR_ERR_XML_ERROR, "%s",
                                           _("HyperV spinlock retry count must be "
                                             "at least 4095"));
                            goto error;
                        }
15284 15285 15286 15287
                    }
                    def->hyperv_features[feature] = value;
                    break;

15288
                /* coverity[dead_error_begin] */
15289 15290 15291 15292 15293 15294 15295 15296
                case VIR_DOMAIN_HYPERV_LAST:
                    break;
            }
        }
        VIR_FREE(nodes);
        ctxt->node = node;
    }

15297 15298 15299 15300 15301 15302 15303 15304 15305 15306 15307 15308 15309 15310 15311 15312 15313 15314 15315 15316 15317 15318 15319 15320 15321 15322 15323 15324 15325 15326 15327 15328 15329 15330 15331 15332 15333 15334 15335 15336
    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;

15337
                /* coverity[dead_error_begin] */
15338 15339 15340 15341 15342 15343 15344 15345
                case VIR_DOMAIN_KVM_LAST:
                    break;
            }
        }
        VIR_FREE(nodes);
        ctxt->node = node;
    }

15346 15347 15348 15349 15350 15351 15352 15353 15354 15355 15356 15357 15358 15359 15360 15361
    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 已提交
15362
                if ((def->caps_features[val] = virTristateSwitchTypeFromString(tmp)) == -1) {
15363 15364 15365 15366 15367 15368 15369
                    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 已提交
15370
                def->caps_features[val] = VIR_TRISTATE_SWITCH_ON;
15371 15372 15373 15374 15375 15376
            }
            ctxt->node = node;
        }
    }
    VIR_FREE(nodes);

15377 15378 15379 15380 15381
    if (virDomainEventActionParseXML(ctxt, "on_reboot",
                                     "string(./on_reboot[1])",
                                     &def->onReboot,
                                     VIR_DOMAIN_LIFECYCLE_RESTART,
                                     virDomainLifecycleTypeFromString) < 0)
15382 15383
        goto error;

15384 15385 15386 15387 15388
    if (virDomainEventActionParseXML(ctxt, "on_poweroff",
                                     "string(./on_poweroff[1])",
                                     &def->onPoweroff,
                                     VIR_DOMAIN_LIFECYCLE_DESTROY,
                                     virDomainLifecycleTypeFromString) < 0)
15389 15390
        goto error;

15391 15392 15393 15394 15395
    if (virDomainEventActionParseXML(ctxt, "on_crash",
                                     "string(./on_crash[1])",
                                     &def->onCrash,
                                     VIR_DOMAIN_LIFECYCLE_CRASH_DESTROY,
                                     virDomainLifecycleCrashTypeFromString) < 0)
15396 15397
        goto error;

15398 15399 15400 15401 15402 15403 15404
    if (virDomainEventActionParseXML(ctxt, "on_lockfailure",
                                     "string(./on_lockfailure[1])",
                                     &def->onLockFailure,
                                     VIR_DOMAIN_LOCK_FAILURE_DEFAULT,
                                     virDomainLockFailureTypeFromString) < 0)
        goto error;

15405 15406 15407 15408 15409 15410 15411 15412 15413 15414
    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;

15415 15416
    if ((tmp = virXPathString("string(./clock/@offset)", ctxt)) &&
        (def->clock.offset = virDomainClockOffsetTypeFromString(tmp)) < 0) {
15417
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
15418 15419
                       _("unknown clock offset '%s'"), tmp);
        goto error;
15420
    }
15421 15422
    VIR_FREE(tmp);

15423
    switch (def->clock.offset) {
15424 15425 15426 15427 15428 15429 15430
    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 {
15431 15432
                if (virStrToLong_ll(tmp, NULL, 10,
                                    &def->clock.data.variable.adjustment) < 0) {
15433 15434 15435
                    virReportError(VIR_ERR_XML_ERROR,
                                   _("unknown clock adjustment '%s'"),
                                   tmp);
15436 15437 15438 15439 15440 15441 15442 15443 15444 15445 15446 15447 15448 15449 15450 15451 15452 15453
                    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;

15454 15455
    case VIR_DOMAIN_CLOCK_OFFSET_VARIABLE:
        if (virXPathLongLong("number(./clock/@adjustment)", ctxt,
15456 15457
                             &def->clock.data.variable.adjustment) < 0)
            def->clock.data.variable.adjustment = 0;
15458 15459 15460
        if (virXPathLongLong("number(./clock/@adjustment0)", ctxt,
                             &def->clock.data.variable.adjustment0) < 0)
            def->clock.data.variable.adjustment0 = 0;
15461 15462 15463
        tmp = virXPathString("string(./clock/@basis)", ctxt);
        if (tmp) {
            if ((def->clock.data.variable.basis = virDomainClockBasisTypeFromString(tmp)) < 0) {
15464
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
15465
                               _("unknown clock basis '%s'"), tmp);
15466 15467 15468 15469 15470 15471
                goto error;
            }
            VIR_FREE(tmp);
        } else {
            def->clock.data.variable.basis = VIR_DOMAIN_CLOCK_BASIS_UTC;
        }
15472 15473 15474 15475 15476
        break;

    case VIR_DOMAIN_CLOCK_OFFSET_TIMEZONE:
        def->clock.data.timezone = virXPathString("string(./clock/@timezone)", ctxt);
        if (!def->clock.data.timezone) {
15477 15478
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("missing 'timezone' attribute for clock with offset='timezone'"));
15479 15480
            goto error;
        }
15481 15482
        break;
    }
15483

15484
    if ((n = virXPathNodeSet("./clock/timer", ctxt, &nodes)) < 0)
15485
        goto error;
15486

15487
    if (n && VIR_ALLOC_N(def->clock.timers, n) < 0)
15488
        goto error;
15489

15490
    for (i = 0; i < n; i++) {
15491
        virDomainTimerDefPtr timer = virDomainTimerDefParseXML(nodes[i],
E
Eric Blake 已提交
15492
                                                               ctxt);
15493 15494 15495 15496 15497 15498 15499
        if (!timer)
            goto error;

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

15500

15501 15502 15503 15504 15505 15506 15507 15508 15509
    /*
     * 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)
     */

15510
    if (def->os.type == VIR_DOMAIN_OSTYPE_EXE) {
15511
        def->os.init = virXPathString("string(./os/init[1])", ctxt);
15512
        def->os.cmdline = virXPathString("string(./os/cmdline[1])", ctxt);
15513

15514
        if ((n = virXPathNodeSet("./os/initarg", ctxt, &nodes)) < 0)
15515 15516 15517
            goto error;

        if (VIR_ALLOC_N(def->os.initargv, n+1) < 0)
15518
            goto error;
15519
        for (i = 0; i < n; i++) {
15520 15521
            if (!nodes[i]->children ||
                !nodes[i]->children->content) {
15522 15523
                virReportError(VIR_ERR_XML_ERROR, "%s",
                               _("No data supplied for <initarg> element"));
15524 15525
                goto error;
            }
15526 15527 15528
            if (VIR_STRDUP(def->os.initargv[i],
                           (const char*) nodes[i]->children->content) < 0)
                goto error;
15529 15530 15531
        }
        def->os.initargv[n] = NULL;
        VIR_FREE(nodes);
15532 15533
    }

15534 15535 15536
    if (def->os.type == VIR_DOMAIN_OSTYPE_XEN ||
        def->os.type == VIR_DOMAIN_OSTYPE_HVM ||
        def->os.type == VIR_DOMAIN_OSTYPE_UML) {
15537 15538
        xmlNodePtr loader_node;

15539 15540 15541
        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);
15542
        def->os.dtb = virXPathString("string(./os/dtb[1])", ctxt);
15543
        def->os.root = virXPathString("string(./os/root[1])", ctxt);
15544 15545 15546 15547 15548 15549 15550 15551
        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);
15552
            def->os.loader->templt = virXPathString("string(./os/nvram[1]/@template)", ctxt);
15553
        }
15554
    }
15555

15556
    if (def->os.type == VIR_DOMAIN_OSTYPE_HVM) {
15557 15558 15559
        if (virDomainDefParseBootXML(ctxt, def) < 0)
            goto error;
        if (!(bootHash = virHashCreate(5, NULL)))
15560
            goto error;
15561 15562 15563 15564
    }


    /* analysis of the disk devices */
15565
    if ((n = virXPathNodeSet("./devices/disk", ctxt, &nodes)) < 0)
15566
        goto error;
15567

15568
    if (n && VIR_ALLOC_N(def->disks, n) < 0)
15569
        goto error;
15570

15571
    for (i = 0; i < n; i++) {
15572
        virDomainDiskDefPtr disk = virDomainDiskDefParseXML(xmlopt,
15573
                                                            nodes[i],
L
Lei Li 已提交
15574
                                                            ctxt,
15575
                                                            bootHash,
15576 15577
                                                            def->seclabels,
                                                            def->nseclabels,
15578
                                                            flags);
15579 15580 15581
        if (!disk)
            goto error;

15582
        virDomainDiskInsertPreAlloced(def, disk);
15583 15584 15585
    }
    VIR_FREE(nodes);

15586
    /* analysis of the controller devices */
15587
    if ((n = virXPathNodeSet("./devices/controller", ctxt, &nodes)) < 0)
15588
        goto error;
15589

15590
    if (n && VIR_ALLOC_N(def->controllers, n) < 0)
15591
        goto error;
15592

15593
    for (i = 0; i < n; i++) {
15594
        virDomainControllerDefPtr controller = virDomainControllerDefParseXML(nodes[i],
15595
                                                                              ctxt,
15596 15597 15598 15599
                                                                              flags);
        if (!controller)
            goto error;

15600 15601 15602 15603
        /* 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) {
15604
                    virDomainControllerDefFree(controller);
15605 15606 15607 15608 15609 15610 15611 15612
                    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) {
15613
                    virDomainControllerDefFree(controller);
15614 15615 15616 15617 15618 15619 15620
                    virReportError(VIR_ERR_XML_DETAIL, "%s",
                                   _("Can't add another USB controller: "
                                     "USB is disabled for this domain"));
                    goto error;
                }
                usb_other = true;
            }
15621 15622 15623

            if (controller->info.mastertype == VIR_DOMAIN_CONTROLLER_MASTER_NONE)
                usb_master = true;
15624 15625
        }

15626
        virDomainControllerInsertPreAlloced(def, controller);
15627 15628 15629
    }
    VIR_FREE(nodes);

15630 15631 15632 15633 15634 15635
    if (usb_other && !usb_master) {
        virReportError(VIR_ERR_XML_DETAIL, "%s",
                       _("No master USB controller specified"));
        goto error;
    }

15636 15637
    /* analysis of the resource leases */
    if ((n = virXPathNodeSet("./devices/lease", ctxt, &nodes)) < 0) {
15638 15639
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("cannot extract device leases"));
15640 15641 15642
        goto error;
    }
    if (n && VIR_ALLOC_N(def->leases, n) < 0)
15643
        goto error;
15644
    for (i = 0; i < n; i++) {
15645 15646 15647 15648 15649 15650 15651 15652
        virDomainLeaseDefPtr lease = virDomainLeaseDefParseXML(nodes[i]);
        if (!lease)
            goto error;

        def->leases[def->nleases++] = lease;
    }
    VIR_FREE(nodes);

15653
    /* analysis of the filesystems */
15654
    if ((n = virXPathNodeSet("./devices/filesystem", ctxt, &nodes)) < 0)
15655
        goto error;
15656
    if (n && VIR_ALLOC_N(def->fss, n) < 0)
15657
        goto error;
15658
    for (i = 0; i < n; i++) {
15659
        virDomainFSDefPtr fs = virDomainFSDefParseXML(nodes[i], ctxt,
15660
                                                      flags);
15661 15662 15663
        if (!fs)
            goto error;

15664
        def->fss[def->nfss++] = fs;
15665 15666 15667
    }
    VIR_FREE(nodes);

15668
    /* analysis of the network devices */
15669
    if ((n = virXPathNodeSet("./devices/interface", ctxt, &nodes)) < 0)
15670
        goto error;
15671
    if (n && VIR_ALLOC_N(def->nets, n) < 0)
15672
        goto error;
15673
    for (i = 0; i < n; i++) {
15674
        virDomainNetDefPtr net = virDomainNetDefParseXML(xmlopt,
15675
                                                         nodes[i],
15676
                                                         ctxt,
15677
                                                         bootHash,
15678
                                                         flags);
15679 15680 15681
        if (!net)
            goto error;

15682
        def->nets[def->nnets++] = net;
15683

15684 15685 15686 15687 15688 15689
        /* <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) {
15690
            goto error;
15691
        }
15692 15693 15694 15695
    }
    VIR_FREE(nodes);


E
Eric Blake 已提交
15696
    /* analysis of the smartcard devices */
15697
    if ((n = virXPathNodeSet("./devices/smartcard", ctxt, &nodes)) < 0)
E
Eric Blake 已提交
15698 15699
        goto error;
    if (n && VIR_ALLOC_N(def->smartcards, n) < 0)
15700
        goto error;
E
Eric Blake 已提交
15701

15702
    for (i = 0; i < n; i++) {
E
Eric Blake 已提交
15703 15704 15705 15706 15707 15708 15709 15710 15711 15712
        virDomainSmartcardDefPtr card = virDomainSmartcardDefParseXML(nodes[i],
                                                                      flags);
        if (!card)
            goto error;

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


15713
    /* analysis of the character devices */
15714
    if ((n = virXPathNodeSet("./devices/parallel", ctxt, &nodes)) < 0)
15715
        goto error;
15716
    if (n && VIR_ALLOC_N(def->parallels, n) < 0)
15717
        goto error;
15718

15719
    for (i = 0; i < n; i++) {
15720
        virDomainChrDefPtr chr = virDomainChrDefParseXML(ctxt,
15721
                                                         nodes[i],
15722 15723
                                                         def->seclabels,
                                                         def->nseclabels,
15724
                                                         flags);
15725 15726 15727
        if (!chr)
            goto error;

15728 15729
        if (chr->target.port == -1) {
            int maxport = -1;
15730
            for (j = 0; j < i; j++) {
15731 15732 15733 15734 15735
                if (def->parallels[j]->target.port > maxport)
                    maxport = def->parallels[j]->target.port;
            }
            chr->target.port = maxport + 1;
        }
15736
        def->parallels[def->nparallels++] = chr;
15737 15738 15739
    }
    VIR_FREE(nodes);

15740
    if ((n = virXPathNodeSet("./devices/serial", ctxt, &nodes)) < 0)
15741
        goto error;
15742

15743
    if (n && VIR_ALLOC_N(def->serials, n) < 0)
15744
        goto error;
15745

15746
    for (i = 0; i < n; i++) {
15747
        virDomainChrDefPtr chr = virDomainChrDefParseXML(ctxt,
15748
                                                         nodes[i],
15749 15750
                                                         def->seclabels,
                                                         def->nseclabels,
15751
                                                         flags);
15752 15753 15754
        if (!chr)
            goto error;

15755 15756
        if (chr->target.port == -1) {
            int maxport = -1;
15757
            for (j = 0; j < i; j++) {
15758 15759 15760 15761 15762
                if (def->serials[j]->target.port > maxport)
                    maxport = def->serials[j]->target.port;
            }
            chr->target.port = maxport + 1;
        }
15763
        def->serials[def->nserials++] = chr;
15764 15765 15766
    }
    VIR_FREE(nodes);

15767
    if ((n = virXPathNodeSet("./devices/console", ctxt, &nodes)) < 0) {
15768 15769
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("cannot extract console devices"));
15770 15771 15772
        goto error;
    }
    if (n && VIR_ALLOC_N(def->consoles, n) < 0)
15773
        goto error;
15774

15775
    for (i = 0; i < n; i++) {
15776
        virDomainChrDefPtr chr = virDomainChrDefParseXML(ctxt,
15777
                                                         nodes[i],
15778 15779
                                                         def->seclabels,
                                                         def->nseclabels,
15780
                                                         flags);
15781 15782
        if (!chr)
            goto error;
15783

15784 15785
        chr->target.port = i;
        def->consoles[def->nconsoles++] = chr;
15786
    }
15787
    VIR_FREE(nodes);
15788

15789
    if ((n = virXPathNodeSet("./devices/channel", ctxt, &nodes)) < 0)
15790 15791
        goto error;
    if (n && VIR_ALLOC_N(def->channels, n) < 0)
15792
        goto error;
15793

15794
    for (i = 0; i < n; i++) {
15795
        virDomainChrDefPtr chr = virDomainChrDefParseXML(ctxt,
15796
                                                         nodes[i],
15797 15798
                                                         def->seclabels,
                                                         def->nseclabels,
15799 15800 15801 15802 15803 15804 15805 15806
                                                         flags);
        if (!chr)
            goto error;

        def->channels[def->nchannels++] = chr;
    }
    VIR_FREE(nodes);

15807 15808

    /* analysis of the input devices */
15809
    if ((n = virXPathNodeSet("./devices/input", ctxt, &nodes)) < 0)
15810
        goto error;
15811
    if (n && VIR_ALLOC_N(def->inputs, n) < 0)
15812
        goto error;
15813

15814
    for (i = 0; i < n; i++) {
L
Li Zhang 已提交
15815
        virDomainInputDefPtr input = virDomainInputDefParseXML(def,
15816
                                                               nodes[i],
15817
                                                               ctxt,
15818
                                                               flags);
15819 15820 15821
        if (!input)
            goto error;

15822 15823
        /* Check if USB bus is required */
        if (input->bus == VIR_DOMAIN_INPUT_BUS_USB && usb_none) {
15824
            virDomainInputDefFree(input);
15825 15826 15827 15828 15829
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("Can't add USB input device. "
                             "USB bus is disabled"));
            goto error;
        }
15830 15831 15832 15833

        /* 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 ? */
15834
        if ((def->os.type == VIR_DOMAIN_OSTYPE_HVM &&
15835
             input->bus == VIR_DOMAIN_INPUT_BUS_PS2 &&
L
Li Zhang 已提交
15836 15837
             (input->type == VIR_DOMAIN_INPUT_TYPE_MOUSE ||
              input->type == VIR_DOMAIN_INPUT_TYPE_KBD)) ||
15838
            (def->os.type == VIR_DOMAIN_OSTYPE_XEN &&
15839
             input->bus == VIR_DOMAIN_INPUT_BUS_XEN &&
15840 15841
             (input->type == VIR_DOMAIN_INPUT_TYPE_MOUSE ||
              input->type == VIR_DOMAIN_INPUT_TYPE_KBD)) ||
15842
            (def->os.type == VIR_DOMAIN_OSTYPE_EXE &&
15843 15844
             (def->virtType == VIR_DOMAIN_VIRT_VZ ||
              def->virtType == VIR_DOMAIN_VIRT_PARALLELS)  &&
15845
             input->bus == VIR_DOMAIN_INPUT_BUS_PARALLELS &&
L
Li Zhang 已提交
15846 15847
             (input->type == VIR_DOMAIN_INPUT_TYPE_MOUSE ||
              input->type == VIR_DOMAIN_INPUT_TYPE_KBD))) {
15848 15849 15850 15851
            virDomainInputDefFree(input);
            continue;
        }

15852
        def->inputs[def->ninputs++] = input;
15853 15854 15855
    }
    VIR_FREE(nodes);

15856
    /* analysis of the graphics devices */
15857
    if ((n = virXPathNodeSet("./devices/graphics", ctxt, &nodes)) < 0)
15858
        goto error;
15859
    if (n && VIR_ALLOC_N(def->graphics, n) < 0)
15860
        goto error;
15861
    for (i = 0; i < n; i++) {
15862
        virDomainGraphicsDefPtr graphics = virDomainGraphicsDefParseXML(nodes[i],
15863
                                                                        ctxt,
15864
                                                                        flags);
15865 15866 15867
        if (!graphics)
            goto error;

15868
        def->graphics[def->ngraphics++] = graphics;
15869 15870 15871 15872
    }
    VIR_FREE(nodes);

    /* If graphics are enabled, there's an implicit PS2 mouse */
15873 15874
    if (def->ngraphics > 0 &&
        (ARCH_IS_X86(def->os.arch) || def->os.arch == VIR_ARCH_NONE)) {
15875
        int input_bus = VIR_DOMAIN_INPUT_BUS_XEN;
15876

15877
        if (def->os.type == VIR_DOMAIN_OSTYPE_HVM)
15878
            input_bus = VIR_DOMAIN_INPUT_BUS_PS2;
15879
        if (def->os.type == VIR_DOMAIN_OSTYPE_EXE &&
15880 15881
            (def->virtType == VIR_DOMAIN_VIRT_VZ ||
             def->virtType == VIR_DOMAIN_VIRT_PARALLELS))
15882
            input_bus = VIR_DOMAIN_INPUT_BUS_PARALLELS;
15883

15884 15885 15886
        if (virDomainDefMaybeAddInput(def,
                                      VIR_DOMAIN_INPUT_TYPE_MOUSE,
                                      input_bus) < 0)
15887
            goto error;
15888

L
Li Zhang 已提交
15889 15890 15891 15892 15893
        if (virDomainDefMaybeAddInput(def,
                                      VIR_DOMAIN_INPUT_TYPE_KBD,
                                      input_bus) < 0)
            goto error;
    }
15894 15895

    /* analysis of the sound devices */
15896
    if ((n = virXPathNodeSet("./devices/sound", ctxt, &nodes)) < 0)
15897
        goto error;
15898
    if (n && VIR_ALLOC_N(def->sounds, n) < 0)
15899
        goto error;
15900
    for (i = 0; i < n; i++) {
15901
        virDomainSoundDefPtr sound = virDomainSoundDefParseXML(nodes[i],
15902
                                                               ctxt,
15903
                                                               flags);
15904 15905 15906
        if (!sound)
            goto error;

15907
        def->sounds[def->nsounds++] = sound;
15908 15909 15910
    }
    VIR_FREE(nodes);

15911
    /* analysis of the video devices */
15912
    if ((n = virXPathNodeSet("./devices/video", ctxt, &nodes)) < 0)
15913 15914
        goto error;
    if (n && VIR_ALLOC_N(def->videos, n) < 0)
15915
        goto error;
15916
    for (i = 0; i < n; i++) {
15917
        j = def->nvideos;
15918
        virDomainVideoDefPtr video = virDomainVideoDefParseXML(nodes[j],
15919 15920 15921 15922
                                                               def,
                                                               flags);
        if (!video)
            goto error;
15923 15924 15925

        if (video->primary) {
            if (primaryVideo) {
15926
                virDomainVideoDefFree(video);
15927 15928 15929 15930 15931
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                               _("Only one primary video device is supported"));
                goto error;
            }

15932
            j = 0;
15933 15934
            primaryVideo = true;
        }
15935
        if (VIR_INSERT_ELEMENT_INPLACE(def->videos,
15936
                                       j,
15937 15938
                                       def->nvideos,
                                       video) < 0) {
15939
            virDomainVideoDefFree(video);
15940
            goto error;
15941
        }
15942 15943 15944
    }
    VIR_FREE(nodes);

15945
    /* For backwards compatibility, if no <video> tag is set but there
15946 15947 15948 15949
     * is a <graphics> tag, then we add a single video tag */
    if (def->ngraphics && !def->nvideos) {
        virDomainVideoDefPtr video;
        if (VIR_ALLOC(video) < 0)
15950
            goto error;
15951 15952
        video->type = virDomainVideoDefaultType(def);
        if (video->type < 0) {
15953 15954
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("cannot determine default video type"));
15955 15956 15957 15958 15959 15960 15961
            VIR_FREE(video);
            goto error;
        }
        video->vram = virDomainVideoDefaultRAM(def, video->type);
        video->heads = 1;
        if (VIR_ALLOC_N(def->videos, 1) < 0) {
            virDomainVideoDefFree(video);
15962
            goto error;
15963 15964 15965 15966
        }
        def->videos[def->nvideos++] = video;
    }

15967
    /* analysis of the host devices */
15968
    if ((n = virXPathNodeSet("./devices/hostdev", ctxt, &nodes)) < 0)
15969
        goto error;
15970
    if (n && VIR_REALLOC_N(def->hostdevs, def->nhostdevs + n) < 0)
15971
        goto error;
15972
    for (i = 0; i < n; i++) {
15973 15974
        virDomainHostdevDefPtr hostdev;

15975
        hostdev = virDomainHostdevDefParseXML(nodes[i], ctxt, bootHash, flags);
15976 15977 15978
        if (!hostdev)
            goto error;

15979 15980 15981 15982 15983
        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"));
15984
            virDomainHostdevDefFree(hostdev);
15985 15986 15987
            goto error;
        }

15988
        def->hostdevs[def->nhostdevs++] = hostdev;
15989 15990 15991 15992 15993 15994 15995 15996 15997

        /* For a domain definition, we need to check if the controller
         * for this hostdev exists yet and if not add it. This cannot be
         * done during virDomainHostdevAssignAddress (as part of device
         * post processing) because that will result in the failure to
         * load the controller during hostdev hotplug.
         */
        if (virDomainDefMaybeAddHostdevSCSIcontroller(def) < 0)
            goto error;
15998 15999 16000
    }
    VIR_FREE(nodes);

R
Richard Jones 已提交
16001 16002
    /* analysis of the watchdog devices */
    def->watchdog = NULL;
16003
    if ((n = virXPathNodeSet("./devices/watchdog", ctxt, &nodes)) < 0)
R
Richard Jones 已提交
16004 16005
        goto error;
    if (n > 1) {
16006 16007
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("only a single watchdog device is supported"));
R
Richard Jones 已提交
16008 16009 16010 16011
        goto error;
    }
    if (n > 0) {
        virDomainWatchdogDefPtr watchdog =
16012
            virDomainWatchdogDefParseXML(nodes[0], flags);
R
Richard Jones 已提交
16013 16014 16015 16016 16017 16018 16019
        if (!watchdog)
            goto error;

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

16020 16021
    /* analysis of the memballoon devices */
    def->memballoon = NULL;
16022
    if ((n = virXPathNodeSet("./devices/memballoon", ctxt, &nodes)) < 0)
16023 16024
        goto error;
    if (n > 1) {
16025 16026
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("only a single memory balloon device is supported"));
16027 16028 16029 16030
        goto error;
    }
    if (n > 0) {
        virDomainMemballoonDefPtr memballoon =
16031
            virDomainMemballoonDefParseXML(nodes[0], ctxt, flags);
16032 16033 16034 16035 16036 16037 16038
        if (!memballoon)
            goto error;

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

16039
    /* Parse the RNG devices */
16040 16041
    if ((n = virXPathNodeSet("./devices/rng", ctxt, &nodes)) < 0)
        goto error;
16042
    if (n && VIR_ALLOC_N(def->rngs, n) < 0)
16043
        goto error;
16044 16045 16046 16047 16048
    for (i = 0; i < n; i++) {
        virDomainRNGDefPtr rng = virDomainRNGDefParseXML(nodes[i],
                                                         ctxt,
                                                         flags);
        if (!rng)
16049
            goto error;
16050 16051

        def->rngs[def->nrngs++] = rng;
16052
    }
16053 16054 16055 16056 16057 16058 16059 16060 16061 16062 16063 16064 16065 16066 16067 16068 16069
    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);
16070

16071
    if ((n = virXPathNodeSet("./devices/nvram", ctxt, &nodes)) < 0)
L
Li Zhang 已提交
16072 16073 16074 16075 16076 16077 16078 16079 16080 16081 16082 16083 16084 16085 16086
        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 已提交
16087
    /* analysis of the hub devices */
16088
    if ((n = virXPathNodeSet("./devices/hub", ctxt, &nodes)) < 0)
M
Marc-André Lureau 已提交
16089 16090
        goto error;
    if (n && VIR_ALLOC_N(def->hubs, n) < 0)
16091
        goto error;
16092
    for (i = 0; i < n; i++) {
M
Marc-André Lureau 已提交
16093 16094 16095 16096
        virDomainHubDefPtr hub = virDomainHubDefParseXML(nodes[i], flags);
        if (!hub)
            goto error;

16097
        if (hub->type == VIR_DOMAIN_HUB_TYPE_USB && usb_none) {
16098
            virDomainHubDefFree(hub);
16099 16100 16101 16102 16103 16104
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("Can't add USB hub: "
                             "USB is disabled for this domain"));
            goto error;
        }

M
Marc-André Lureau 已提交
16105 16106 16107 16108
        def->hubs[def->nhubs++] = hub;
    }
    VIR_FREE(nodes);

16109
    /* analysis of the redirected devices */
16110
    if ((n = virXPathNodeSet("./devices/redirdev", ctxt, &nodes)) < 0)
16111 16112
        goto error;
    if (n && VIR_ALLOC_N(def->redirdevs, n) < 0)
16113
        goto error;
16114
    for (i = 0; i < n; i++) {
16115
        virDomainRedirdevDefPtr redirdev = virDomainRedirdevDefParseXML(nodes[i],
16116
                                                                        bootHash,
16117 16118 16119 16120
                                                                        flags);
        if (!redirdev)
            goto error;

16121 16122 16123 16124
        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"));
16125
            virDomainRedirdevDefFree(redirdev);
16126 16127 16128
            goto error;
        }

16129 16130 16131 16132
        def->redirdevs[def->nredirdevs++] = redirdev;
    }
    VIR_FREE(nodes);

16133
    /* analysis of the redirection filter rules */
16134
    if ((n = virXPathNodeSet("./devices/redirfilter", ctxt, &nodes)) < 0)
16135 16136 16137 16138 16139 16140 16141 16142 16143 16144 16145 16146 16147 16148 16149 16150 16151
        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 已提交
16152
    /* analysis of the panic devices */
16153
    if ((n = virXPathNodeSet("./devices/panic", ctxt, &nodes)) < 0)
H
Hu Tao 已提交
16154
        goto error;
D
Dmitry Andreev 已提交
16155
    if (n && VIR_ALLOC_N(def->panics, n) < 0)
H
Hu Tao 已提交
16156
        goto error;
D
Dmitry Andreev 已提交
16157
    for (i = 0; i < n; i++) {
H
Hu Tao 已提交
16158
        virDomainPanicDefPtr panic =
D
Dmitry Andreev 已提交
16159
            virDomainPanicDefParseXML(nodes[i]);
H
Hu Tao 已提交
16160 16161 16162
        if (!panic)
            goto error;

D
Dmitry Andreev 已提交
16163
        def->panics[def->npanics++] = panic;
H
Hu Tao 已提交
16164
    }
D
Dmitry Andreev 已提交
16165
    VIR_FREE(nodes);
H
Hu Tao 已提交
16166

16167
    /* analysis of the shmem devices */
16168
    if ((n = virXPathNodeSet("./devices/shmem", ctxt, &nodes)) < 0)
16169 16170 16171 16172 16173 16174 16175 16176 16177 16178 16179 16180 16181 16182 16183 16184
        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 已提交
16185

16186 16187 16188 16189 16190 16191 16192 16193 16194 16195 16196 16197 16198 16199 16200 16201 16202
    /* analysis of memory devices */
    if ((n = virXPathNodeSet("./devices/memory", ctxt, &nodes)) < 0)
        goto error;
    if (n && VIR_ALLOC_N(def->mems, n) < 0)
        goto error;

    for (i = 0; i < n; i++) {
        virDomainMemoryDefPtr mem = virDomainMemoryDefParseXML(nodes[i],
                                                               ctxt,
                                                               flags);
        if (!mem)
            goto error;

        def->mems[def->nmems++] = mem;
    }
    VIR_FREE(nodes);

16203 16204 16205 16206 16207 16208 16209 16210 16211 16212 16213 16214 16215 16216 16217 16218 16219 16220 16221 16222 16223 16224 16225 16226 16227 16228 16229 16230 16231 16232 16233 16234
    /* 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;
    }

16235 16236 16237
    if ((node = virXPathNode("./sysinfo[1]", ctxt)) != NULL) {
        xmlNodePtr oldnode = ctxt->node;
        ctxt->node = node;
16238 16239
        def->sysinfo = virSysinfoParseXML(node, ctxt,
                                          def->uuid, uuid_generated);
16240 16241 16242 16243 16244
        ctxt->node = oldnode;

        if (def->sysinfo == NULL)
            goto error;
    }
16245 16246

    if ((tmp = virXPathString("string(./os/smbios/@mode)", ctxt))) {
16247 16248 16249
        int mode;

        if ((mode = virDomainSmbiosModeTypeFromString(tmp)) < 0) {
16250
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
16251
                           _("unknown smbios mode '%s'"), tmp);
16252 16253 16254 16255 16256
            goto error;
        }
        def->os.smbios_mode = mode;
        VIR_FREE(tmp);
    }
16257

16258 16259 16260
    if (virDomainKeyWrapDefParseXML(def, ctxt) < 0)
        goto error;

16261
    /* Extract custom metadata */
16262
    if ((node = virXPathNode("./metadata[1]", ctxt)) != NULL)
16263 16264
        def->metadata = xmlCopyNode(node, 1);

16265 16266 16267
    /* we have to make a copy of all of the callback pointers here since
     * we won't have the virCaps structure available during free
     */
16268
    def->ns = xmlopt->ns;
16269

16270 16271 16272
    if (def->ns.parse &&
        (def->ns.parse)(xml, root, ctxt, &def->namespaceData) < 0)
        goto error;
16273

16274
    /* callback to fill driver specific domain aspects */
16275
    if (virDomainDefPostParse(def, caps, flags, xmlopt) < 0)
16276 16277
        goto error;

16278 16279 16280 16281
    /* Auto-add any implied controllers which aren't present */
    if (virDomainDefAddImplicitControllers(def) < 0)
        goto error;

16282
    virHashFree(bootHash);
16283

16284 16285
    return def;

16286
 error:
16287 16288
    VIR_FREE(tmp);
    VIR_FREE(nodes);
16289
    virHashFree(bootHash);
16290 16291 16292 16293
    virDomainDefFree(def);
    return NULL;
}

16294

16295
static virDomainObjPtr
16296
virDomainObjParseXML(xmlDocPtr xml,
16297
                     xmlXPathContextPtr ctxt,
16298 16299
                     virCapsPtr caps,
                     virDomainXMLOptionPtr xmlopt,
16300
                     unsigned int flags)
16301 16302 16303 16304 16305 16306
{
    char *tmp = NULL;
    long val;
    xmlNodePtr config;
    xmlNodePtr oldnode;
    virDomainObjPtr obj;
16307
    xmlNodePtr *nodes = NULL;
16308 16309
    size_t i;
    int n;
J
Jiri Denemark 已提交
16310 16311
    int state;
    int reason = 0;
16312

16313
    if (!(obj = virDomainObjNew(xmlopt)))
16314 16315
        return NULL;

16316
    if (!(config = virXPathNode("./domain", ctxt))) {
16317 16318
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("no domain config"));
16319 16320 16321 16322 16323
        goto error;
    }

    oldnode = ctxt->node;
    ctxt->node = config;
16324
    obj->def = virDomainDefParseXML(xml, config, ctxt, caps, xmlopt, flags);
16325 16326 16327 16328
    ctxt->node = oldnode;
    if (!obj->def)
        goto error;

16329
    if (!(tmp = virXPathString("string(./@state)", ctxt))) {
16330 16331
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing domain state"));
16332 16333
        goto error;
    }
J
Jiri Denemark 已提交
16334
    if ((state = virDomainStateTypeFromString(tmp)) < 0) {
16335
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
16336
                       _("invalid domain state '%s'"), tmp);
16337 16338 16339 16340 16341
        VIR_FREE(tmp);
        goto error;
    }
    VIR_FREE(tmp);

J
Jiri Denemark 已提交
16342 16343
    if ((tmp = virXPathString("string(./@reason)", ctxt))) {
        if ((reason = virDomainStateReasonFromString(state, tmp)) < 0) {
16344
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
16345
                           _("invalid domain state reason '%s'"), tmp);
J
Jiri Denemark 已提交
16346 16347 16348 16349 16350 16351 16352 16353
            VIR_FREE(tmp);
            goto error;
        }
        VIR_FREE(tmp);
    }

    virDomainObjSetState(obj, state, reason);

E
Eric Blake 已提交
16354
    if (virXPathLong("string(./@pid)", ctxt, &val) < 0) {
16355 16356
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("invalid pid"));
16357 16358 16359 16360
        goto error;
    }
    obj->pid = (pid_t)val;

16361
    if ((n = virXPathNodeSet("./taint", ctxt, &nodes)) < 0)
16362
        goto error;
16363
    for (i = 0; i < n; i++) {
16364 16365 16366 16367
        char *str = virXMLPropString(nodes[i], "flag");
        if (str) {
            int flag = virDomainTaintTypeFromString(str);
            if (flag < 0) {
16368
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
16369
                               _("Unknown taint flag %s"), str);
16370
                VIR_FREE(str);
16371 16372
                goto error;
            }
16373
            VIR_FREE(str);
16374 16375 16376 16377 16378
            virDomainObjTaint(obj, flag);
        }
    }
    VIR_FREE(nodes);

16379
    if (xmlopt->privateData.parse &&
16380
        xmlopt->privateData.parse(ctxt, obj, &xmlopt->config) < 0)
16381
        goto error;
16382

16383 16384
    return obj;

16385
 error:
16386
    virObjectUnref(obj);
16387
    VIR_FREE(nodes);
16388 16389 16390 16391
    return NULL;
}


J
Jiri Denemark 已提交
16392 16393 16394 16395
static virDomainDefPtr
virDomainDefParse(const char *xmlStr,
                  const char *filename,
                  virCapsPtr caps,
16396
                  virDomainXMLOptionPtr xmlopt,
E
Eric Blake 已提交
16397
                  unsigned int flags)
16398
{
J
Jiri Denemark 已提交
16399 16400
    xmlDocPtr xml;
    virDomainDefPtr def = NULL;
16401
    int keepBlanksDefault = xmlKeepBlanksDefault(0);
J
Jiri Denemark 已提交
16402

16403
    if ((xml = virXMLParse(filename, xmlStr, _("(domain_definition)")))) {
16404
        def = virDomainDefParseNode(xml, xmlDocGetRootElement(xml), caps,
16405
                                    xmlopt, flags);
J
Jiri Denemark 已提交
16406
        xmlFreeDoc(xml);
16407
    }
J
Jiri Denemark 已提交
16408

16409
    xmlKeepBlanksDefault(keepBlanksDefault);
J
Jiri Denemark 已提交
16410
    return def;
16411
}
16412

16413
virDomainDefPtr
16414 16415
virDomainDefParseString(const char *xmlStr,
                        virCapsPtr caps,
16416
                        virDomainXMLOptionPtr xmlopt,
16417
                        unsigned int flags)
16418
{
16419
    return virDomainDefParse(xmlStr, NULL, caps, xmlopt, flags);
16420 16421
}

16422
virDomainDefPtr
16423 16424
virDomainDefParseFile(const char *filename,
                      virCapsPtr caps,
16425
                      virDomainXMLOptionPtr xmlopt,
16426
                      unsigned int flags)
16427
{
16428
    return virDomainDefParse(NULL, filename, caps, xmlopt, flags);
16429 16430 16431
}


16432
virDomainDefPtr
16433
virDomainDefParseNode(xmlDocPtr xml,
16434
                      xmlNodePtr root,
16435 16436
                      virCapsPtr caps,
                      virDomainXMLOptionPtr xmlopt,
16437
                      unsigned int flags)
16438 16439 16440 16441 16442
{
    xmlXPathContextPtr ctxt = NULL;
    virDomainDefPtr def = NULL;

    if (!xmlStrEqual(root->name, BAD_CAST "domain")) {
16443 16444 16445 16446
        virReportError(VIR_ERR_XML_ERROR,
                       _("unexpected root element <%s>, "
                         "expecting <domain>"),
                       root->name);
16447 16448 16449 16450 16451
        goto cleanup;
    }

    ctxt = xmlXPathNewContext(xml);
    if (ctxt == NULL) {
16452
        virReportOOMError();
16453 16454 16455 16456
        goto cleanup;
    }

    ctxt->node = root;
16457
    def = virDomainDefParseXML(xml, root, ctxt, caps, xmlopt, flags);
16458

16459
 cleanup:
16460 16461 16462
    xmlXPathFreeContext(ctxt);
    return def;
}
16463 16464


16465
virDomainObjPtr
16466
virDomainObjParseNode(xmlDocPtr xml,
L
Laine Stump 已提交
16467
                      xmlNodePtr root,
16468 16469
                      virCapsPtr caps,
                      virDomainXMLOptionPtr xmlopt,
L
Laine Stump 已提交
16470
                      unsigned int flags)
16471 16472 16473 16474 16475
{
    xmlXPathContextPtr ctxt = NULL;
    virDomainObjPtr obj = NULL;

    if (!xmlStrEqual(root->name, BAD_CAST "domstatus")) {
16476 16477 16478 16479
        virReportError(VIR_ERR_XML_ERROR,
                       _("unexpected root element <%s>, "
                         "expecting <domstatus>"),
                       root->name);
16480 16481 16482
        goto cleanup;
    }

16483
    if (!(ctxt = xmlXPathNewContext(xml))) {
16484
        virReportOOMError();
16485 16486 16487 16488
        goto cleanup;
    }

    ctxt->node = root;
16489
    obj = virDomainObjParseXML(xml, ctxt, caps, xmlopt, flags);
16490

16491
 cleanup:
16492 16493 16494 16495
    xmlXPathFreeContext(ctxt);
    return obj;
}

H
Hu Tao 已提交
16496

16497
virDomainObjPtr
16498 16499
virDomainObjParseFile(const char *filename,
                      virCapsPtr caps,
16500
                      virDomainXMLOptionPtr xmlopt,
16501
                      unsigned int flags)
H
Hu Tao 已提交
16502 16503 16504
{
    xmlDocPtr xml;
    virDomainObjPtr obj = NULL;
16505
    int keepBlanksDefault = xmlKeepBlanksDefault(0);
H
Hu Tao 已提交
16506 16507

    if ((xml = virXMLParseFile(filename))) {
16508
        obj = virDomainObjParseNode(xml, xmlDocGetRootElement(xml),
16509
                                    caps, xmlopt, flags);
H
Hu Tao 已提交
16510 16511 16512
        xmlFreeDoc(xml);
    }

16513
    xmlKeepBlanksDefault(keepBlanksDefault);
H
Hu Tao 已提交
16514 16515 16516 16517
    return obj;
}


16518 16519 16520
static bool
virDomainTimerDefCheckABIStability(virDomainTimerDefPtr src,
                                   virDomainTimerDefPtr dst)
16521 16522
{
    if (src->name != dst->name) {
16523 16524 16525 16526
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target timer %s does not match source %s"),
                       virDomainTimerNameTypeToString(dst->name),
                       virDomainTimerNameTypeToString(src->name));
16527
        return false;
16528 16529 16530
    }

    if (src->present != dst->present) {
16531 16532 16533
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target timer presence %d does not match source %d"),
                       dst->present, src->present);
16534
        return false;
16535 16536 16537 16538
    }

    if (src->name == VIR_DOMAIN_TIMER_NAME_TSC) {
        if (src->frequency != dst->frequency) {
16539 16540 16541
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Target TSC frequency %lu does not match source %lu"),
                           dst->frequency, src->frequency);
16542
            return false;
16543 16544 16545
        }

        if (src->mode != dst->mode) {
16546 16547 16548 16549
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Target TSC mode %s does not match source %s"),
                           virDomainTimerModeTypeToString(dst->mode),
                           virDomainTimerModeTypeToString(src->mode));
16550
            return false;
16551 16552 16553
        }
    }

16554
    return true;
16555 16556 16557
}


16558 16559 16560
static bool
virDomainDeviceInfoCheckABIStability(virDomainDeviceInfoPtr src,
                                     virDomainDeviceInfoPtr dst)
16561 16562
{
    if (src->type != dst->type) {
16563 16564 16565 16566
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target device address type %s does not match source %s"),
                       virDomainDeviceAddressTypeToString(dst->type),
                       virDomainDeviceAddressTypeToString(src->type));
16567
        return false;
16568 16569
    }

16570
    switch ((virDomainDeviceAddressType) src->type) {
16571 16572 16573 16574 16575
    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) {
16576
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
16577 16578
                           _("Target device PCI address %04x:%02x:%02x.%02x "
                             "does not match source %04x:%02x:%02x.%02x"),
16579 16580 16581 16582
                           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);
16583
            return false;
16584 16585 16586 16587 16588 16589 16590
        }
        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) {
16591
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
16592 16593
                           _("Target device drive address %d:%d:%d "
                             "does not match source %d:%d:%d"),
16594 16595 16596 16597
                           dst->addr.drive.controller, dst->addr.drive.bus,
                           dst->addr.drive.unit,
                           src->addr.drive.controller, src->addr.drive.bus,
                           src->addr.drive.unit);
16598
            return false;
16599 16600 16601 16602 16603 16604 16605
        }
        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) {
16606
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
16607 16608
                           _("Target device virtio serial address %d:%d:%d "
                             "does not match source %d:%d:%d"),
16609 16610 16611 16612
                           dst->addr.vioserial.controller, dst->addr.vioserial.bus,
                           dst->addr.vioserial.port,
                           src->addr.vioserial.controller, src->addr.vioserial.bus,
                           src->addr.vioserial.port);
16613
            return false;
16614 16615 16616 16617 16618 16619
        }
        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) {
16620
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
16621 16622
                           _("Target device ccid address %d:%d "
                             "does not match source %d:%d"),
16623 16624 16625 16626
                           dst->addr.ccid.controller,
                           dst->addr.ccid.slot,
                           src->addr.ccid.controller,
                           src->addr.ccid.slot);
16627
            return false;
16628 16629
        }
        break;
H
Hu Tao 已提交
16630 16631 16632 16633 16634 16635 16636 16637 16638 16639 16640 16641 16642 16643

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

16645 16646 16647 16648 16649 16650 16651 16652 16653 16654 16655 16656 16657 16658 16659 16660 16661 16662 16663 16664
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DIMM:
        if (src->addr.dimm.slot != dst->addr.dimm.slot) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Target device dimm slot %u does not match "
                             "source %u"),
                           dst->addr.dimm.slot,
                           src->addr.dimm.slot);
            return false;
        }

        if (src->addr.dimm.base != dst->addr.dimm.base) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Target device dimm base addres '%llx' does "
                             "not match source '%llx'"),
                           dst->addr.dimm.base,
                           src->addr.dimm.base);
            return false;
        }
        break;

16665 16666 16667 16668 16669 16670 16671 16672
    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;
16673 16674
    }

16675
    return true;
16676 16677 16678
}


16679 16680 16681
static bool
virDomainDiskDefCheckABIStability(virDomainDiskDefPtr src,
                                  virDomainDiskDefPtr dst)
16682 16683
{
    if (src->device != dst->device) {
16684 16685 16686 16687
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target disk device %s does not match source %s"),
                       virDomainDiskDeviceTypeToString(dst->device),
                       virDomainDiskDeviceTypeToString(src->device));
16688
        return false;
16689 16690 16691
    }

    if (src->bus != dst->bus) {
16692 16693 16694 16695
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target disk bus %s does not match source %s"),
                       virDomainDiskBusTypeToString(dst->bus),
                       virDomainDiskBusTypeToString(src->bus));
16696
        return false;
16697 16698 16699
    }

    if (STRNEQ(src->dst, dst->dst)) {
16700 16701 16702
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target disk %s does not match source %s"),
                       dst->dst, src->dst);
16703
        return false;
16704 16705 16706
    }

    if (STRNEQ_NULLABLE(src->serial, dst->serial)) {
16707 16708 16709
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target disk serial %s does not match source %s"),
                       NULLSTR(dst->serial), NULLSTR(src->serial));
16710
        return false;
16711 16712
    }

16713 16714 16715 16716 16717 16718 16719 16720
    if (STRNEQ_NULLABLE(src->wwn, dst->wwn)) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target disk wwn '%s' does not match source '%s'"),
                       NULLSTR(dst->wwn), NULLSTR(src->wwn));
        return false;

    }

16721 16722
    if (src->src->readonly != dst->src->readonly ||
        src->src->shared != dst->src->shared) {
16723 16724
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Target disk access mode does not match source"));
16725
        return false;
16726 16727 16728
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
16729
        return false;
16730

16731
    return true;
16732 16733 16734
}


16735 16736 16737
static bool
virDomainControllerDefCheckABIStability(virDomainControllerDefPtr src,
                                        virDomainControllerDefPtr dst)
16738 16739
{
    if (src->type != dst->type) {
16740 16741 16742 16743
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target controller type %s does not match source %s"),
                       virDomainControllerTypeToString(dst->type),
                       virDomainControllerTypeToString(src->type));
16744
        return false;
16745 16746 16747
    }

    if (src->idx != dst->idx) {
16748 16749 16750
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target controller index %d does not match source %d"),
                       dst->idx, src->idx);
16751
        return false;
16752 16753 16754
    }

    if (src->model != dst->model) {
16755 16756 16757
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target controller model %d does not match source %d"),
                       dst->model, src->model);
16758
        return false;
16759 16760 16761 16762
    }

    if (src->type == VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL) {
        if (src->opts.vioserial.ports != dst->opts.vioserial.ports) {
16763 16764 16765
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Target controller ports %d does not match source %d"),
                           dst->opts.vioserial.ports, src->opts.vioserial.ports);
16766
            return false;
16767 16768 16769
        }

        if (src->opts.vioserial.vectors != dst->opts.vioserial.vectors) {
16770 16771 16772
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Target controller vectors %d does not match source %d"),
                           dst->opts.vioserial.vectors, src->opts.vioserial.vectors);
16773
            return false;
16774 16775 16776 16777
        }
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
16778
        return false;
16779

16780
    return true;
16781 16782 16783
}


16784 16785 16786
static bool
virDomainFsDefCheckABIStability(virDomainFSDefPtr src,
                                virDomainFSDefPtr dst)
16787 16788
{
    if (STRNEQ(src->dst, dst->dst)) {
16789 16790 16791
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target filesystem guest target %s does not match source %s"),
                       dst->dst, src->dst);
16792
        return false;
16793 16794 16795
    }

    if (src->readonly != dst->readonly) {
16796 16797
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Target filesystem access mode does not match source"));
16798
        return false;
16799 16800 16801
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
16802
        return false;
16803

16804
    return true;
16805 16806 16807
}


16808 16809 16810
static bool
virDomainNetDefCheckABIStability(virDomainNetDefPtr src,
                                 virDomainNetDefPtr dst)
16811
{
16812 16813 16814
    char srcmac[VIR_MAC_STRING_BUFLEN];
    char dstmac[VIR_MAC_STRING_BUFLEN];

16815
    if (virMacAddrCmp(&src->mac, &dst->mac) != 0) {
16816
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
16817 16818 16819 16820
                       _("Target network card mac %s"
                         " does not match source %s"),
                       virMacAddrFormat(&dst->mac, dstmac),
                       virMacAddrFormat(&src->mac, srcmac));
16821
        return false;
16822 16823 16824
    }

    if (STRNEQ_NULLABLE(src->model, dst->model)) {
16825 16826 16827
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target network card model %s does not match source %s"),
                       NULLSTR(dst->model), NULLSTR(src->model));
16828
        return false;
16829 16830 16831
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
16832
        return false;
16833

16834
    return true;
16835 16836 16837
}


16838 16839 16840
static bool
virDomainInputDefCheckABIStability(virDomainInputDefPtr src,
                                   virDomainInputDefPtr dst)
16841 16842
{
    if (src->type != dst->type) {
16843 16844 16845 16846
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target input device type %s does not match source %s"),
                       virDomainInputTypeToString(dst->type),
                       virDomainInputTypeToString(src->type));
16847
        return false;
16848 16849 16850
    }

    if (src->bus != dst->bus) {
16851 16852 16853 16854
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target input device bus %s does not match source %s"),
                       virDomainInputBusTypeToString(dst->bus),
                       virDomainInputBusTypeToString(src->bus));
16855
        return false;
16856 16857 16858
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
16859
        return false;
16860

16861
    return true;
16862 16863 16864
}


16865 16866 16867
static bool
virDomainSoundDefCheckABIStability(virDomainSoundDefPtr src,
                                   virDomainSoundDefPtr dst)
16868 16869
{
    if (src->model != dst->model) {
16870 16871 16872 16873
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target sound card model %s does not match source %s"),
                       virDomainSoundModelTypeToString(dst->model),
                       virDomainSoundModelTypeToString(src->model));
16874
        return false;
16875 16876 16877
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
16878
        return false;
16879

16880
    return true;
16881 16882 16883
}


16884 16885 16886
static bool
virDomainVideoDefCheckABIStability(virDomainVideoDefPtr src,
                                   virDomainVideoDefPtr dst)
16887 16888
{
    if (src->type != dst->type) {
16889 16890 16891 16892
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target video card model %s does not match source %s"),
                       virDomainVideoTypeToString(dst->type),
                       virDomainVideoTypeToString(src->type));
16893
        return false;
16894 16895
    }

16896 16897 16898 16899 16900 16901 16902
    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;
    }

16903
    if (src->vram != dst->vram) {
16904 16905 16906
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target video card vram %u does not match source %u"),
                       dst->vram, src->vram);
16907
        return false;
16908 16909
    }

16910 16911 16912 16913 16914 16915 16916
    if (src->vgamem != dst->vgamem) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target video card vgamem %u does not match source %u"),
                       dst->vgamem, src->vgamem);
        return false;
    }

16917
    if (src->heads != dst->heads) {
16918 16919 16920
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target video card heads %u does not match source %u"),
                       dst->heads, src->heads);
16921
        return false;
16922 16923 16924 16925
    }

    if ((src->accel && !dst->accel) ||
        (!src->accel && dst->accel)) {
16926 16927
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Target video card acceleration does not match source"));
16928
        return false;
16929 16930 16931
    }

    if (src->accel) {
16932
        if (src->accel->accel2d != dst->accel->accel2d) {
16933 16934
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Target video card 2d accel %u does not match source %u"),
16935
                           dst->accel->accel2d, src->accel->accel2d);
16936
            return false;
16937 16938
        }

16939
        if (src->accel->accel3d != dst->accel->accel3d) {
16940 16941
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Target video card 3d accel %u does not match source %u"),
16942
                           dst->accel->accel3d, src->accel->accel3d);
16943
            return false;
16944 16945 16946 16947
        }
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
16948
        return false;
16949

16950
    return true;
16951 16952 16953
}


16954 16955 16956
static bool
virDomainHostdevDefCheckABIStability(virDomainHostdevDefPtr src,
                                     virDomainHostdevDefPtr dst)
16957 16958
{
    if (src->mode != dst->mode) {
16959 16960 16961 16962
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target host device mode %s does not match source %s"),
                       virDomainHostdevModeTypeToString(dst->mode),
                       virDomainHostdevModeTypeToString(src->mode));
16963
        return false;
16964 16965
    }

16966 16967 16968 16969 16970 16971 16972
    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;
16973 16974
    }

16975
    if (!virDomainDeviceInfoCheckABIStability(src->info, dst->info))
16976
        return false;
16977

16978
    return true;
16979 16980 16981
}


16982 16983 16984
static bool
virDomainSmartcardDefCheckABIStability(virDomainSmartcardDefPtr src,
                                       virDomainSmartcardDefPtr dst)
16985 16986
{
    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
16987
        return false;
16988

16989
    return true;
16990 16991 16992
}


16993 16994 16995
static bool
virDomainSerialDefCheckABIStability(virDomainChrDefPtr src,
                                    virDomainChrDefPtr dst)
16996
{
16997 16998 16999 17000 17001 17002 17003 17004
    if (src->targetType != dst->targetType) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target serial type %s does not match source %s"),
                       virDomainChrSerialTargetTypeToString(dst->targetType),
                       virDomainChrSerialTargetTypeToString(src->targetType));
        return false;
    }

17005
    if (src->target.port != dst->target.port) {
17006 17007 17008
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target serial port %d does not match source %d"),
                       dst->target.port, src->target.port);
17009
        return false;
17010 17011 17012
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
17013
        return false;
17014

17015
    return true;
17016 17017 17018
}


17019 17020 17021
static bool
virDomainParallelDefCheckABIStability(virDomainChrDefPtr src,
                                      virDomainChrDefPtr dst)
17022 17023
{
    if (src->target.port != dst->target.port) {
17024
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
17025
                       _("Target parallel port %d does not match source %d"),
17026
                       dst->target.port, src->target.port);
17027
        return false;
17028 17029 17030
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
17031
        return false;
17032

17033
    return true;
17034 17035 17036
}


17037 17038 17039
static bool
virDomainChannelDefCheckABIStability(virDomainChrDefPtr src,
                                     virDomainChrDefPtr dst)
17040 17041
{
    if (src->targetType != dst->targetType) {
17042 17043 17044 17045
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target channel type %s does not match source %s"),
                       virDomainChrChannelTargetTypeToString(dst->targetType),
                       virDomainChrChannelTargetTypeToString(src->targetType));
17046
        return false;
17047 17048 17049 17050
    }

    switch (src->targetType) {
    case VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO:
17051
        if (STRNEQ_NULLABLE(src->target.name, dst->target.name)) {
17052 17053 17054
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Target channel name %s does not match source %s"),
                           NULLSTR(dst->target.name), NULLSTR(src->target.name));
17055
            return false;
17056
        }
17057 17058 17059 17060 17061 17062 17063
        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"));
17064
            return false;
17065
        }
17066 17067
        break;
    case VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_GUESTFWD:
E
Eric Blake 已提交
17068 17069
        if (memcmp(src->target.addr, dst->target.addr,
                   sizeof(*src->target.addr)) != 0) {
17070 17071
            char *saddr = virSocketAddrFormatFull(src->target.addr, true, ":");
            char *daddr = virSocketAddrFormatFull(dst->target.addr, true, ":");
17072 17073 17074
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Target channel addr %s does not match source %s"),
                           NULLSTR(daddr), NULLSTR(saddr));
17075 17076
            VIR_FREE(saddr);
            VIR_FREE(daddr);
17077
            return false;
17078 17079 17080 17081 17082
        }
        break;
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
17083
        return false;
17084

17085
    return true;
17086 17087 17088
}


17089 17090 17091
static bool
virDomainConsoleDefCheckABIStability(virDomainChrDefPtr src,
                                     virDomainChrDefPtr dst)
17092 17093
{
    if (src->targetType != dst->targetType) {
17094 17095 17096 17097
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target console type %s does not match source %s"),
                       virDomainChrConsoleTargetTypeToString(dst->targetType),
                       virDomainChrConsoleTargetTypeToString(src->targetType));
17098
        return false;
17099 17100 17101
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
17102
        return false;
17103

17104
    return true;
17105 17106 17107
}


17108 17109 17110
static bool
virDomainWatchdogDefCheckABIStability(virDomainWatchdogDefPtr src,
                                      virDomainWatchdogDefPtr dst)
17111 17112
{
    if (src->model != dst->model) {
17113 17114 17115 17116
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target watchdog model %s does not match source %s"),
                       virDomainWatchdogModelTypeToString(dst->model),
                       virDomainWatchdogModelTypeToString(src->model));
17117
        return false;
17118 17119 17120
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
17121
        return false;
17122

17123
    return true;
17124 17125 17126
}


17127 17128 17129
static bool
virDomainMemballoonDefCheckABIStability(virDomainMemballoonDefPtr src,
                                        virDomainMemballoonDefPtr dst)
17130 17131
{
    if (src->model != dst->model) {
17132 17133 17134 17135
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target balloon model %s does not match source %s"),
                       virDomainMemballoonModelTypeToString(dst->model),
                       virDomainMemballoonModelTypeToString(src->model));
17136
        return false;
17137 17138 17139
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
17140
        return false;
17141

17142
    return true;
17143 17144 17145
}


17146 17147 17148 17149 17150 17151 17152 17153 17154 17155 17156 17157 17158 17159 17160 17161 17162 17163 17164
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;
}


17165 17166 17167
static bool
virDomainHubDefCheckABIStability(virDomainHubDefPtr src,
                                 virDomainHubDefPtr dst)
M
Marc-André Lureau 已提交
17168 17169
{
    if (src->type != dst->type) {
17170 17171 17172 17173
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target hub device type %s does not match source %s"),
                       virDomainHubTypeToString(dst->type),
                       virDomainHubTypeToString(src->type));
17174
        return false;
M
Marc-André Lureau 已提交
17175 17176 17177
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
17178
        return false;
M
Marc-André Lureau 已提交
17179

17180
    return true;
M
Marc-André Lureau 已提交
17181 17182
}

17183 17184 17185 17186 17187 17188 17189 17190 17191 17192 17193 17194 17195 17196

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

17197
    switch ((virDomainRedirdevBus) src->bus) {
17198 17199 17200 17201 17202 17203 17204 17205 17206 17207 17208 17209 17210 17211 17212 17213 17214 17215 17216 17217 17218
    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;
}


17219 17220 17221 17222
static bool
virDomainRedirFilterDefCheckABIStability(virDomainRedirFilterDefPtr src,
                                         virDomainRedirFilterDefPtr dst)
{
17223
    size_t i;
17224 17225 17226 17227 17228 17229

    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);
17230
        return false;
17231 17232 17233
    }

    for (i = 0; i < src->nusbdevs; i++) {
17234 17235 17236
        virDomainRedirFilterUSBDevDefPtr srcUSBDev = src->usbdevs[i];
        virDomainRedirFilterUSBDevDefPtr dstUSBDev = dst->usbdevs[i];
        if (srcUSBDev->usbClass != dstUSBDev->usbClass) {
17237 17238
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           "%s", _("Target USB Class code does not match source"));
17239
            return false;
17240 17241
        }

17242
        if (srcUSBDev->vendor != dstUSBDev->vendor) {
17243 17244
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           "%s", _("Target USB vendor ID does not match source"));
17245
            return false;
17246 17247
        }

17248
        if (srcUSBDev->product != dstUSBDev->product) {
17249 17250
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           "%s", _("Target USB product ID does not match source"));
17251
            return false;
17252 17253
        }

17254
        if (srcUSBDev->version != dstUSBDev->version) {
17255 17256
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           "%s", _("Target USB version does not match source"));
17257
            return false;
17258 17259
        }

17260
        if (srcUSBDev->allow != dstUSBDev->allow) {
17261 17262
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Target USB allow '%s' does not match source '%s'"),
17263 17264
                             dstUSBDev->allow ? "yes" : "no",
                             srcUSBDev->allow ? "yes" : "no");
17265
            return false;
17266 17267 17268
        }
    }

17269
    return true;
17270
}
M
Marc-André Lureau 已提交
17271

17272 17273 17274 17275 17276 17277 17278

static bool
virDomainDefFeaturesCheckABIStability(virDomainDefPtr src,
                                      virDomainDefPtr dst)
{
    size_t i;

17279 17280 17281 17282 17283 17284
    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 已提交
17285 17286
                           virTristateSwitchTypeToString(src->features[i]),
                           virTristateSwitchTypeToString(dst->features[i]));
17287 17288
            return false;
        }
17289 17290 17291 17292 17293 17294 17295
    }

    /* 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 已提交
17296 17297
                       virTristateSwitchTypeToString(src->apic_eoi),
                       virTristateSwitchTypeToString(dst->apic_eoi));
17298 17299 17300
        return false;
    }

M
Michal Privoznik 已提交
17301 17302 17303 17304 17305 17306 17307 17308
    /* GIC version */
    if (src->gic_version != dst->gic_version) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Source GIC version '%u' does not match destination '%u'"),
                       src->gic_version, dst->gic_version);
        return false;
    }

17309
    /* hyperv */
J
Ján Tomko 已提交
17310
    if (src->features[VIR_DOMAIN_FEATURE_HYPERV] == VIR_TRISTATE_SWITCH_ON) {
17311
        for (i = 0; i < VIR_DOMAIN_HYPERV_LAST; i++) {
17312
            switch ((virDomainHyperv) i) {
17313 17314 17315 17316 17317 17318 17319 17320
            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 已提交
17321 17322
                                   virTristateSwitchTypeToString(src->hyperv_features[i]),
                                   virTristateSwitchTypeToString(dst->hyperv_features[i]));
17323 17324 17325 17326 17327 17328 17329 17330 17331 17332 17333 17334 17335 17336 17337 17338 17339
                    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;

17340
            /* coverity[dead_error_begin] */
17341 17342 17343 17344 17345 17346
            case VIR_DOMAIN_HYPERV_LAST:
                break;
            }
        }
    }

17347 17348 17349 17350 17351 17352 17353 17354 17355 17356 17357 17358 17359 17360 17361 17362 17363
    /* 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;

17364
            /* coverity[dead_error_begin] */
17365 17366 17367 17368 17369 17370
            case VIR_DOMAIN_KVM_LAST:
                break;
            }
        }
    }

17371 17372 17373
    return true;
}

H
Hu Tao 已提交
17374
static bool
17375 17376
virDomainPanicDefCheckABIStability(virDomainPanicDefPtr src,
                                   virDomainPanicDefPtr dst)
H
Hu Tao 已提交
17377
{
17378 17379 17380 17381 17382 17383 17384 17385
    if (src->model != dst->model) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target panic model '%s' does not match source '%s'"),
                       virDomainPanicModelTypeToString(dst->model),
                       virDomainPanicModelTypeToString(src->model));
        return false;
    }

H
Hu Tao 已提交
17386 17387 17388
    return virDomainDeviceInfoCheckABIStability(&src->info, &dst->info);
}

17389

17390 17391 17392 17393 17394 17395 17396 17397 17398 17399 17400 17401 17402 17403 17404 17405 17406 17407 17408 17409 17410 17411 17412 17413 17414 17415 17416 17417 17418 17419 17420 17421 17422 17423 17424 17425 17426 17427
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);
}


17428 17429 17430 17431 17432 17433 17434 17435 17436 17437 17438 17439 17440 17441 17442 17443 17444 17445 17446
static bool
virDomainTPMDefCheckABIStability(virDomainTPMDefPtr src,
                                 virDomainTPMDefPtr dst)
{
    if (src->type != dst->type) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Target TPM device type doesn't match source"));
        return false;
    }

    if (src->model != dst->model) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Target TPM device model doesn't match source"));
        return false;
    }

    return virDomainDeviceInfoCheckABIStability(&src->info, &dst->info);
}

17447 17448 17449 17450 17451 17452 17453 17454 17455 17456 17457 17458 17459 17460 17461
static bool
virDomainMemoryDefCheckABIStability(virDomainMemoryDefPtr src,
                                    virDomainMemoryDefPtr dst)
{
    if (src->model != dst->model) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target memory device model '%s' "
                         "doesn't match source model '%s'"),
                       virDomainMemoryModelTypeToString(dst->model),
                       virDomainMemoryModelTypeToString(src->model));
        return false;
    }

    if (src->targetNode != dst->targetNode) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
17462 17463
                       _("Target memory device targetNode '%d' "
                         "doesn't match source targetNode '%d'"),
17464 17465 17466 17467 17468 17469 17470 17471 17472 17473 17474 17475 17476 17477 17478 17479
                       dst->targetNode, src->targetNode);
        return false;
    }

    if (src->size != dst->size) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target memory device size '%llu' doesn't match "
                         "source memory device size '%llu'"),
                       dst->size, src->size);
        return false;
    }

    return virDomainDeviceInfoCheckABIStability(&src->info, &dst->info);
}


17480 17481 17482 17483
/* 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
 */
17484 17485 17486
bool
virDomainDefCheckABIStability(virDomainDefPtr src,
                              virDomainDefPtr dst)
17487
{
17488
    size_t i;
17489 17490 17491
    virErrorPtr err;
    char *strSrc;
    char *strDst;
17492 17493

    if (src->virtType != dst->virtType) {
17494 17495 17496 17497
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target domain virt type %s does not match source %s"),
                       virDomainVirtTypeToString(dst->virtType),
                       virDomainVirtTypeToString(src->virtType));
17498
        goto error;
17499 17500 17501 17502 17503 17504 17505
    }

    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);
17506 17507 17508
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target domain uuid %s does not match source %s"),
                       uuiddst, uuidsrc);
17509
        goto error;
17510 17511
    }

17512 17513 17514 17515
    /* 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
     */
17516
    if (STRNEQ_NULLABLE(src->name, dst->name)) {
17517 17518 17519
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target domain name '%s' does not match source '%s'"),
                       dst->name, src->name);
17520
        goto error;
17521 17522
    }

17523
    if (virDomainDefGetMemoryInitial(src) != virDomainDefGetMemoryInitial(dst)) {
17524 17525
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target domain max memory %lld does not match source %lld"),
17526 17527
                       virDomainDefGetMemoryInitial(dst),
                       virDomainDefGetMemoryInitial(src));
17528
        goto error;
17529 17530
    }
    if (src->mem.cur_balloon != dst->mem.cur_balloon) {
17531 17532 17533
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target domain current memory %lld does not match source %lld"),
                       dst->mem.cur_balloon, src->mem.cur_balloon);
17534
        goto error;
17535 17536
    }

17537 17538 17539
    if (!virDomainNumaCheckABIStability(src->numa, dst->numa))
        goto error;

17540 17541
    if (src->mem.memory_slots != dst->mem.memory_slots) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
17542
                       _("Target domain memory slots count '%u' doesn't match source '%u'"),
17543 17544 17545 17546 17547 17548 17549 17550 17551 17552
                       dst->mem.memory_slots, src->mem.memory_slots);
        goto error;
    }
    if (src->mem.max_memory != dst->mem.max_memory) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target maximum memory size '%llu' doesn't match source '%llu'"),
                       dst->mem.max_memory, src->mem.max_memory);
        goto error;
    }

17553
    if (src->vcpus != dst->vcpus) {
17554
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
17555
                       _("Target domain vCPU count %d does not match source %d"),
17556
                       dst->vcpus, src->vcpus);
17557
        goto error;
17558 17559
    }
    if (src->maxvcpus != dst->maxvcpus) {
17560
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
17561
                       _("Target domain vCPU max %d does not match source %d"),
17562
                       dst->maxvcpus, src->maxvcpus);
17563
        goto error;
17564 17565
    }

17566 17567 17568 17569 17570 17571 17572 17573
    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;
    }

17574
    if (src->os.type != dst->os.type) {
17575 17576
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target domain OS type %s does not match source %s"),
17577 17578
                       virDomainOSTypeToString(dst->os.type),
                       virDomainOSTypeToString(src->os.type));
17579
        goto error;
17580
    }
17581
    if (src->os.arch != dst->os.arch) {
17582 17583
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target domain architecture %s does not match source %s"),
17584 17585
                       virArchToString(dst->os.arch),
                       virArchToString(src->os.arch));
17586
        goto error;
17587
    }
17588
    if (STRNEQ_NULLABLE(src->os.machine, dst->os.machine)) {
17589
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
17590 17591
                    _("Target domain machine type %s does not match source %s"),
                    dst->os.machine, src->os.machine);
17592
        goto error;
17593 17594 17595
    }

    if (src->os.smbios_mode != dst->os.smbios_mode) {
17596 17597 17598 17599
        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));
17600
        goto error;
17601 17602
    }

17603
    if (!virDomainDefFeaturesCheckABIStability(src, dst))
17604
        goto error;
17605 17606

    if (src->clock.ntimers != dst->clock.ntimers) {
17607 17608
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Target domain timers do not match source"));
17609
        goto error;
17610 17611
    }

17612
    for (i = 0; i < src->clock.ntimers; i++) {
17613 17614
        if (!virDomainTimerDefCheckABIStability(src->clock.timers[i],
                                                dst->clock.timers[i]))
17615
            goto error;
17616 17617 17618
    }

    if (!virCPUDefIsEqual(src->cpu, dst->cpu))
17619
        goto error;
17620 17621

    if (!virSysinfoIsEqual(src->sysinfo, dst->sysinfo))
17622
        goto error;
17623 17624

    if (src->ndisks != dst->ndisks) {
17625
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
17626
                       _("Target domain disk count %zu does not match source %zu"),
17627
                       dst->ndisks, src->ndisks);
17628
        goto error;
17629 17630
    }

17631
    for (i = 0; i < src->ndisks; i++)
17632
        if (!virDomainDiskDefCheckABIStability(src->disks[i], dst->disks[i]))
17633
            goto error;
17634 17635

    if (src->ncontrollers != dst->ncontrollers) {
17636
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
17637
                       _("Target domain controller count %zu "
17638
                         "does not match source %zu"),
17639
                       dst->ncontrollers, src->ncontrollers);
17640
        goto error;
17641 17642
    }

17643
    for (i = 0; i < src->ncontrollers; i++)
17644 17645
        if (!virDomainControllerDefCheckABIStability(src->controllers[i],
                                                     dst->controllers[i]))
17646
            goto error;
17647 17648

    if (src->nfss != dst->nfss) {
17649
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
17650 17651
                       _("Target domain filesystem count %zu "
                         "does not match source %zu"),
17652
                       dst->nfss, src->nfss);
17653
        goto error;
17654 17655
    }

17656
    for (i = 0; i < src->nfss; i++)
17657
        if (!virDomainFsDefCheckABIStability(src->fss[i], dst->fss[i]))
17658
            goto error;
17659 17660

    if (src->nnets != dst->nnets) {
17661
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
17662 17663
                       _("Target domain net card count %zu "
                         "does not match source %zu"),
17664
                       dst->nnets, src->nnets);
17665
        goto error;
17666 17667
    }

17668
    for (i = 0; i < src->nnets; i++)
17669
        if (!virDomainNetDefCheckABIStability(src->nets[i], dst->nets[i]))
17670
            goto error;
17671 17672

    if (src->ninputs != dst->ninputs) {
17673
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
17674 17675
                       _("Target domain input device count %zu "
                         "does not match source %zu"),
17676
                       dst->ninputs, src->ninputs);
17677
        goto error;
17678 17679
    }

17680
    for (i = 0; i < src->ninputs; i++)
17681
        if (!virDomainInputDefCheckABIStability(src->inputs[i], dst->inputs[i]))
17682
            goto error;
17683 17684

    if (src->nsounds != dst->nsounds) {
17685
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
17686 17687
                       _("Target domain sound card count %zu "
                         "does not match source %zu"),
17688
                       dst->nsounds, src->nsounds);
17689
        goto error;
17690 17691
    }

17692
    for (i = 0; i < src->nsounds; i++)
17693
        if (!virDomainSoundDefCheckABIStability(src->sounds[i], dst->sounds[i]))
17694
            goto error;
17695 17696

    if (src->nvideos != dst->nvideos) {
17697
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
17698 17699
                       _("Target domain video card count %zu "
                         "does not match source %zu"),
17700
                       dst->nvideos, src->nvideos);
17701
        goto error;
17702 17703
    }

17704
    for (i = 0; i < src->nvideos; i++)
17705
        if (!virDomainVideoDefCheckABIStability(src->videos[i], dst->videos[i]))
17706
            goto error;
17707 17708

    if (src->nhostdevs != dst->nhostdevs) {
17709
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
17710 17711
                       _("Target domain host device count %zu "
                         "does not match source %zu"),
17712
                       dst->nhostdevs, src->nhostdevs);
17713
        goto error;
17714 17715
    }

17716
    for (i = 0; i < src->nhostdevs; i++)
17717 17718
        if (!virDomainHostdevDefCheckABIStability(src->hostdevs[i],
                                                  dst->hostdevs[i]))
17719
            goto error;
17720 17721

    if (src->nsmartcards != dst->nsmartcards) {
17722
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
17723 17724
                       _("Target domain smartcard count %zu "
                         "does not match source %zu"),
17725
                       dst->nsmartcards, src->nsmartcards);
17726
        goto error;
17727 17728
    }

17729
    for (i = 0; i < src->nsmartcards; i++)
17730 17731
        if (!virDomainSmartcardDefCheckABIStability(src->smartcards[i],
                                                    dst->smartcards[i]))
17732
            goto error;
17733 17734

    if (src->nserials != dst->nserials) {
17735
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
17736 17737
                       _("Target domain serial port count %zu "
                         "does not match source %zu"),
17738
                       dst->nserials, src->nserials);
17739
        goto error;
17740 17741
    }

17742
    for (i = 0; i < src->nserials; i++)
17743 17744
        if (!virDomainSerialDefCheckABIStability(src->serials[i],
                                                 dst->serials[i]))
17745
            goto error;
17746 17747

    if (src->nparallels != dst->nparallels) {
17748
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
17749 17750
                       _("Target domain parallel port count %zu "
                         "does not match source %zu"),
17751
                       dst->nparallels, src->nparallels);
17752
        goto error;
17753 17754
    }

17755
    for (i = 0; i < src->nparallels; i++)
17756 17757
        if (!virDomainParallelDefCheckABIStability(src->parallels[i],
                                                   dst->parallels[i]))
17758
            goto error;
17759 17760

    if (src->nchannels != dst->nchannels) {
17761
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
17762 17763
                       _("Target domain channel count %zu "
                         "does not match source %zu"),
17764
                       dst->nchannels, src->nchannels);
17765
        goto error;
17766 17767
    }

17768
    for (i = 0; i < src->nchannels; i++)
17769 17770
        if (!virDomainChannelDefCheckABIStability(src->channels[i],
                                                  dst->channels[i]))
17771
            goto error;
17772

17773
    if (src->nconsoles != dst->nconsoles) {
17774
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
17775 17776
                       _("Target domain console count %zu "
                         "does not match source %zu"),
17777
                       dst->nconsoles, src->nconsoles);
17778
        goto error;
17779 17780
    }

17781
    for (i = 0; i < src->nconsoles; i++)
17782 17783
        if (!virDomainConsoleDefCheckABIStability(src->consoles[i],
                                                  dst->consoles[i]))
17784
            goto error;
17785

M
Marc-André Lureau 已提交
17786
    if (src->nhubs != dst->nhubs) {
17787
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
17788 17789
                       _("Target domain hub device count %zu "
                         "does not match source %zu"),
17790
                       dst->nhubs, src->nhubs);
17791
        goto error;
M
Marc-André Lureau 已提交
17792 17793
    }

17794
    for (i = 0; i < src->nhubs; i++)
M
Marc-André Lureau 已提交
17795
        if (!virDomainHubDefCheckABIStability(src->hubs[i], dst->hubs[i]))
17796
            goto error;
M
Marc-André Lureau 已提交
17797

17798 17799 17800 17801
    if (src->nredirdevs != dst->nredirdevs) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target domain redirected devices count %zu "
                         "does not match source %zu"),
17802
                       dst->nredirdevs, src->nredirdevs);
17803 17804 17805 17806 17807 17808 17809 17810 17811
        goto error;
    }

    for (i = 0; i < src->nredirdevs; i++) {
        if (!virDomainRedirdevDefCheckABIStability(src->redirdevs[i],
                                                   dst->redirdevs[i]))
            goto error;
    }

17812 17813 17814
    if ((!src->redirfilter && dst->redirfilter) ||
        (src->redirfilter && !dst->redirfilter)) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
17815 17816
                       _("Target domain USB redirection filter count %d "
                         "does not match source %d"),
17817
                       dst->redirfilter ? 1 : 0, src->redirfilter ? 1 : 0);
17818
        goto error;
17819 17820 17821
    }

    if (src->redirfilter &&
17822 17823
        !virDomainRedirFilterDefCheckABIStability(src->redirfilter,
                                                  dst->redirfilter))
17824
        goto error;
17825 17826 17827

    if ((!src->watchdog && dst->watchdog) ||
        (src->watchdog && !dst->watchdog)) {
17828
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
17829 17830
                       _("Target domain watchdog count %d "
                         "does not match source %d"),
17831
                       dst->watchdog ? 1 : 0, src->watchdog ? 1 : 0);
17832
        goto error;
17833 17834 17835 17836
    }

    if (src->watchdog &&
        !virDomainWatchdogDefCheckABIStability(src->watchdog, dst->watchdog))
17837
        goto error;
17838 17839 17840

    if ((!src->memballoon && dst->memballoon) ||
        (src->memballoon && !dst->memballoon)) {
17841
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
17842 17843
                       _("Target domain memory balloon count %d "
                         "does not match source %d"),
17844
                       dst->memballoon ? 1 : 0, src->memballoon ? 1 : 0);
17845
        goto error;
17846 17847 17848
    }

    if (src->memballoon &&
17849 17850
        !virDomainMemballoonDefCheckABIStability(src->memballoon,
                                                 dst->memballoon))
17851
        goto error;
17852

17853 17854 17855 17856
    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);
17857
        goto error;
17858 17859 17860 17861 17862
    }

    for (i = 0; i < src->nrngs; i++)
        if (!virDomainRNGDefCheckABIStability(src->rngs[i], dst->rngs[i]))
            goto error;
17863

D
Dmitry Andreev 已提交
17864 17865 17866 17867
    if (src->npanics != dst->npanics) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target domain panic device count %zu "
                         "does not match source %zu"), dst->npanics, src->npanics);
17868
        goto error;
D
Dmitry Andreev 已提交
17869 17870 17871 17872 17873 17874
    }

    for (i = 0; i < src->npanics; i++) {
        if (!virDomainPanicDefCheckABIStability(src->panics[i], dst->panics[i]))
            goto error;
    }
H
Hu Tao 已提交
17875

17876 17877 17878 17879 17880 17881 17882 17883 17884 17885 17886 17887
    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;
    }

17888 17889 17890 17891 17892 17893 17894 17895 17896 17897
    if (src->tpm && dst->tpm) {
        if (!virDomainTPMDefCheckABIStability(src->tpm, dst->tpm))
            goto error;
    } else if (src->tpm || dst->tpm) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Either both target and source domains or none of "
                         "them must have TPM device present"));
        goto error;
    }

17898 17899 17900 17901 17902 17903 17904 17905 17906 17907 17908 17909
    if (src->nmems != dst->nmems) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target domain memory device count %zu "
                         "does not match source %zu"), dst->nmems, src->nmems);
        goto error;
    }

    for (i = 0; i < src->nmems; i++) {
        if (!virDomainMemoryDefCheckABIStability(src->mems[i], dst->mems[i]))
            goto error;
    }

17910 17911 17912 17913 17914 17915 17916 17917 17918 17919 17920 17921 17922 17923 17924 17925 17926 17927 17928 17929 17930 17931 17932 17933 17934 17935 17936 17937
    /* 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:
17938
    case VIR_DOMAIN_DEVICE_TPM:
17939
    case VIR_DOMAIN_DEVICE_PANIC:
17940
    case VIR_DOMAIN_DEVICE_SHMEM:
17941
    case VIR_DOMAIN_DEVICE_MEMORY:
17942 17943 17944 17945
        break;
    }
#endif

17946
    return true;
17947

17948
 error:
17949 17950 17951 17952 17953 17954 17955 17956 17957 17958 17959 17960 17961 17962
    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;
17963 17964 17965
}


17966 17967 17968 17969
static int
virDomainDefAddDiskControllersForType(virDomainDefPtr def,
                                      int controllerType,
                                      int diskBus)
17970
{
17971
    size_t i;
17972 17973
    int maxController = -1;

17974
    for (i = 0; i < def->ndisks; i++) {
17975 17976 17977 17978 17979 17980 17981 17982 17983 17984
        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;
    }

17985 17986 17987
    if (maxController == -1)
        return 0;

17988
    for (i = 0; i <= maxController; i++) {
17989
        if (virDomainDefMaybeAddController(def, controllerType, i, -1) < 0)
17990 17991 17992 17993 17994 17995 17996
            return -1;
    }

    return 0;
}


17997 17998
static int
virDomainDefMaybeAddVirtioSerialController(virDomainDefPtr def)
17999
{
C
Cole Robinson 已提交
18000
    /* Look for any virtio serial or virtio console devs */
18001
    size_t i;
18002

18003
    for (i = 0; i < def->nchannels; i++) {
18004 18005
        virDomainChrDefPtr channel = def->channels[i];

18006
        if (channel->targetType == VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO) {
18007 18008 18009 18010
            int idx = 0;
            if (channel->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL)
                idx = channel->info.addr.vioserial.controller;

18011
            if (virDomainDefMaybeAddController(def,
18012
                VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL, idx, -1) < 0)
18013 18014 18015 18016
                return -1;
        }
    }

18017
    for (i = 0; i < def->nconsoles; i++) {
18018
        virDomainChrDefPtr console = def->consoles[i];
C
Cole Robinson 已提交
18019 18020 18021 18022 18023 18024 18025 18026

        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,
18027
                VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL, idx, -1) < 0)
C
Cole Robinson 已提交
18028 18029 18030 18031
                return -1;
        }
    }

18032 18033 18034 18035
    return 0;
}


E
Eric Blake 已提交
18036 18037 18038 18039
static int
virDomainDefMaybeAddSmartcardController(virDomainDefPtr def)
{
    /* Look for any smartcard devs */
18040
    size_t i;
E
Eric Blake 已提交
18041

18042
    for (i = 0; i < def->nsmartcards; i++) {
E
Eric Blake 已提交
18043 18044 18045 18046 18047 18048 18049
        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) {
18050
            size_t j;
E
Eric Blake 已提交
18051 18052 18053 18054 18055 18056 18057 18058 18059 18060 18061 18062 18063 18064 18065 18066
            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,
18067
                                           idx, -1) < 0)
E
Eric Blake 已提交
18068 18069 18070 18071 18072 18073
            return -1;
    }

    return 0;
}

18074
/*
18075
 * Based on the declared <address/> info for any devices,
18076
 * add necessary drive controllers which are not already present
18077 18078 18079
 * in the XML. This is for compat with existing apps which will
 * not know/care about <controller> info in the XML
 */
18080 18081
int
virDomainDefAddImplicitControllers(virDomainDefPtr def)
18082 18083 18084 18085 18086 18087 18088 18089 18090 18091 18092 18093 18094 18095 18096 18097
{
    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 已提交
18098 18099 18100 18101 18102
    if (virDomainDefAddDiskControllersForType(def,
                                              VIR_DOMAIN_CONTROLLER_TYPE_SATA,
                                              VIR_DOMAIN_DISK_BUS_SATA) < 0)
        return -1;

18103 18104 18105
    if (virDomainDefMaybeAddVirtioSerialController(def) < 0)
        return -1;

E
Eric Blake 已提交
18106 18107 18108
    if (virDomainDefMaybeAddSmartcardController(def) < 0)
        return -1;

H
Han Cheng 已提交
18109 18110 18111
    if (virDomainDefMaybeAddHostdevSCSIcontroller(def) < 0)
        return -1;

18112 18113 18114
    return 0;
}

18115 18116 18117 18118 18119 18120 18121 18122 18123 18124 18125 18126 18127 18128 18129 18130 18131 18132 18133 18134 18135 18136 18137 18138 18139 18140 18141 18142 18143 18144 18145 18146 18147 18148 18149 18150 18151 18152 18153 18154 18155 18156 18157 18158 18159 18160 18161 18162 18163 18164
virDomainIOThreadIDDefPtr
virDomainIOThreadIDFind(virDomainDefPtr def,
                        unsigned int iothread_id)
{
    size_t i;

    if (!def->iothreadids || !def->niothreadids)
        return NULL;

    for (i = 0; i < def->niothreadids; i++) {
        if (iothread_id == def->iothreadids[i]->iothread_id)
            return def->iothreadids[i];
    }

    return NULL;
}

virDomainIOThreadIDDefPtr
virDomainIOThreadIDAdd(virDomainDefPtr def,
                       unsigned int iothread_id)
{
    virDomainIOThreadIDDefPtr iothrid = NULL;

    if (virDomainIOThreadIDFind(def, iothread_id)) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("cannot duplicate iothread_id '%u' in iothreadids"),
                       iothread_id);
        return NULL;
    }

    if (VIR_ALLOC(iothrid) < 0)
        goto error;

    iothrid->iothread_id = iothread_id;

    if (VIR_APPEND_ELEMENT_COPY(def->iothreadids, def->niothreadids,
                                iothrid) < 0)
        goto error;

    return iothrid;

 error:
    virDomainIOThreadIDDefFree(iothrid);
    return NULL;
}

void
virDomainIOThreadIDDel(virDomainDefPtr def,
                       unsigned int iothread_id)
{
18165 18166 18167 18168 18169 18170 18171 18172 18173 18174 18175 18176 18177 18178
    size_t i, j;

    for (i = 0; i < def->niothreadids; i++) {
        if (def->iothreadids[i]->iothread_id == iothread_id) {
            /* If we were sequential and removed a threadid in the
             * beginning or middle of the list, then unconditionally
             * clear the autofill flag so we don't lose these
             * definitions for XML formatting.
             */
            for (j = i + 1; j < def->niothreadids; j++)
                def->iothreadids[j]->autofill = false;

            virDomainIOThreadIDDefFree(def->iothreadids[i]);
            VIR_DELETE_ELEMENT(def->iothreadids, i, def->niothreadids);
18179 18180 18181 18182 18183 18184

            return;
        }
    }
}

18185 18186 18187 18188 18189 18190 18191 18192 18193 18194 18195 18196 18197 18198 18199 18200 18201 18202 18203 18204 18205 18206 18207
void
virDomainIOThreadSchedDelId(virDomainDefPtr def,
                            unsigned int iothreadid)
{
    size_t i;

    if (!def->cputune.iothreadsched || !def->cputune.niothreadsched)
        return;

    for (i = 0; i < def->cputune.niothreadsched; i++) {
        if (virBitmapIsBitSet(def->cputune.iothreadsched[i].ids, iothreadid)) {
            ignore_value(virBitmapClearBit(def->cputune.iothreadsched[i].ids,
                                           iothreadid));
            if (virBitmapIsAllClear(def->cputune.iothreadsched[i].ids)) {
                virBitmapFree(def->cputune.iothreadsched[i].ids);
                VIR_DELETE_ELEMENT(def->cputune.iothreadsched, i,
                                   def->cputune.niothreadsched);
            }
            return;
        }
    }
}

18208
virDomainPinDefPtr
18209 18210 18211
virDomainPinFind(virDomainPinDefPtr *def,
                 int npin,
                 int id)
18212
{
18213
    size_t i;
18214

18215
    if (!def || !npin)
18216 18217
        return NULL;

18218 18219
    for (i = 0; i < npin; i++) {
        if (def[i]->id == id)
18220 18221 18222 18223 18224 18225
            return def[i];
    }

    return NULL;
}

18226
int
18227 18228 18229 18230 18231
virDomainPinAdd(virDomainPinDefPtr **pindef_list,
                size_t *npin,
                unsigned char *cpumap,
                int maplen,
                int id)
18232
{
18233
    virDomainPinDefPtr pindef = NULL;
18234

18235
    if (!pindef_list)
H
Hu Tao 已提交
18236
        return -1;
18237

18238 18239 18240 18241 18242 18243
    pindef = virDomainPinFind(*pindef_list, *npin, id);
    if (pindef) {
        pindef->id = id;
        virBitmapFree(pindef->cpumask);
        pindef->cpumask = virBitmapNewData(cpumap, maplen);
        if (!pindef->cpumask)
H
Hu Tao 已提交
18244
            return -1;
18245

H
Hu Tao 已提交
18246 18247
        return 0;
    }
18248

18249
    /* No existing pindef matches id, adding a new one */
18250

18251
    if (VIR_ALLOC(pindef) < 0)
18252
        goto error;
18253

18254 18255 18256
    pindef->id = id;
    pindef->cpumask = virBitmapNewData(cpumap, maplen);
    if (!pindef->cpumask)
18257
        goto error;
18258

18259
    if (VIR_APPEND_ELEMENT(*pindef_list, *npin, pindef) < 0)
18260
        goto error;
H
Hu Tao 已提交
18261 18262

    return 0;
18263

18264
 error:
18265
    virDomainPinDefFree(pindef);
18266
    return -1;
18267 18268
}

18269
void
18270 18271 18272
virDomainPinDel(virDomainPinDefPtr **pindef_list,
                size_t *npin,
                int id)
18273 18274 18275
{
    int n;

18276 18277 18278 18279 18280
    for (n = 0; n < *npin; n++) {
        if ((*pindef_list)[n]->id == id) {
            virBitmapFree((*pindef_list)[n]->cpumask);
            VIR_FREE((*pindef_list)[n]);
            VIR_DELETE_ELEMENT(*pindef_list, n, *npin);
18281
            return;
18282 18283 18284 18285
        }
    }
}

18286

18287
static int
18288 18289 18290 18291
virDomainEventActionDefFormat(virBufferPtr buf,
                              int type,
                              const char *name,
                              virEventActionToStringFunc convFunc)
18292
{
18293
    const char *typeStr = convFunc(type);
18294
    if (!typeStr) {
18295
        virReportError(VIR_ERR_INTERNAL_ERROR,
18296
                       _("unexpected %s action: %d"), name, type);
18297 18298 18299
        return -1;
    }

18300
    virBufferAsprintf(buf, "<%s>%s</%s>\n", name, typeStr, name);
18301 18302 18303 18304 18305

    return 0;
}


18306
static void
18307
virSecurityLabelDefFormat(virBufferPtr buf,
18308
                          virSecurityLabelDefPtr def)
18309 18310 18311 18312
{
    const char *sectype = virDomainSeclabelTypeToString(def->type);

    if (!sectype)
18313 18314 18315 18316 18317
        return;

    if (def->type == VIR_DOMAIN_SECLABEL_DEFAULT)
        return;

18318 18319
    /* To avoid backward compatibility issues, suppress DAC and 'none' labels
     * that are automatically generated.
18320
     */
18321 18322
    if ((STREQ_NULLABLE(def->model, "dac") ||
         STREQ_NULLABLE(def->model, "none")) && def->implicit)
18323 18324
        return;

18325 18326 18327
    virBufferAsprintf(buf, "<seclabel type='%s'",
                      sectype);

18328
    virBufferEscapeString(buf, " model='%s'", def->model);
18329

18330 18331 18332 18333 18334
    if (def->type == VIR_DOMAIN_SECLABEL_NONE) {
        virBufferAddLit(buf, "/>\n");
        return;
    }

18335
    virBufferAsprintf(buf, " relabel='%s'",
18336
                      def->relabel ? "yes" : "no");
18337

18338 18339
    if (def->label || def->imagelabel || def->baselabel) {
        virBufferAddLit(buf, ">\n");
18340 18341
        virBufferAdjustIndent(buf, 2);
        virBufferEscapeString(buf, "<label>%s</label>\n",
18342
                              def->label);
18343
        if (def->relabel)
18344
            virBufferEscapeString(buf, "<imagelabel>%s</imagelabel>\n",
18345 18346
                                  def->imagelabel);
        if (def->type == VIR_DOMAIN_SECLABEL_DYNAMIC)
18347
            virBufferEscapeString(buf, "<baselabel>%s</baselabel>\n",
18348
                                  def->baselabel);
18349
        virBufferAdjustIndent(buf, -2);
18350
        virBufferAddLit(buf, "</seclabel>\n");
18351 18352
    } else {
        virBufferAddLit(buf, "/>\n");
18353 18354 18355 18356
    }
}


18357 18358
static void
virSecurityDeviceLabelDefFormat(virBufferPtr buf,
18359 18360
                                virSecurityDeviceLabelDefPtr def,
                                unsigned int flags)
18361
{
18362 18363
    /* For offline output, skip elements that allow labels but have no
     * label specified (possible if labelskip was ignored on input).  */
18364
    if ((flags & VIR_DOMAIN_DEF_FORMAT_INACTIVE) && !def->label && def->relabel)
18365 18366
        return;

18367
    virBufferAddLit(buf, "<seclabel");
18368 18369

    if (def->model)
18370
        virBufferEscapeString(buf, " model='%s'", def->model);
18371

18372 18373 18374
    if (def->labelskip)
        virBufferAddLit(buf, " labelskip='yes'");
    else
18375
        virBufferAsprintf(buf, " relabel='%s'", def->relabel ? "yes" : "no");
18376

18377 18378
    if (def->label) {
        virBufferAddLit(buf, ">\n");
18379 18380
        virBufferAdjustIndent(buf, 2);
        virBufferEscapeString(buf, "<label>%s</label>\n",
18381
                              def->label);
18382
        virBufferAdjustIndent(buf, -2);
18383 18384 18385 18386 18387 18388 18389
        virBufferAddLit(buf, "</seclabel>\n");
    } else {
        virBufferAddLit(buf, "/>\n");
    }
}


18390 18391 18392 18393
static int
virDomainLeaseDefFormat(virBufferPtr buf,
                        virDomainLeaseDefPtr def)
{
18394 18395 18396 18397 18398
    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);
18399 18400 18401
    if (def->offset)
        virBufferAsprintf(buf, " offset='%llu'", def->offset);
    virBufferAddLit(buf, "/>\n");
18402 18403
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</lease>\n");
18404 18405 18406 18407

    return 0;
}

18408 18409 18410
static void
virDomainDiskGeometryDefFormat(virBufferPtr buf,
                               virDomainDiskDefPtr def)
J
J.B. Joret 已提交
18411 18412 18413 18414 18415 18416 18417 18418
{
    const char *trans =
        virDomainDiskGeometryTransTypeToString(def->geometry.trans);

    if (def->geometry.cylinders > 0 &&
        def->geometry.heads > 0 &&
        def->geometry.sectors > 0) {
        virBufferAsprintf(buf,
18419
                          "<geometry cyls='%u' heads='%u' secs='%u'",
J
J.B. Joret 已提交
18420 18421 18422 18423 18424 18425 18426 18427 18428 18429
                          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");
    }
}
18430

18431 18432 18433
static void
virDomainDiskBlockIoDefFormat(virBufferPtr buf,
                              virDomainDiskDefPtr def)
18434
{
V
Viktor Mihajlovski 已提交
18435 18436
    if (def->blockio.logical_block_size > 0 ||
        def->blockio.physical_block_size > 0) {
18437
        virBufferAddLit(buf, "<blockio");
V
Viktor Mihajlovski 已提交
18438
        if (def->blockio.logical_block_size > 0) {
18439 18440
            virBufferAsprintf(buf,
                              " logical_block_size='%u'",
V
Viktor Mihajlovski 已提交
18441
                              def->blockio.logical_block_size);
18442
        }
V
Viktor Mihajlovski 已提交
18443
        if (def->blockio.physical_block_size > 0) {
18444 18445
            virBufferAsprintf(buf,
                              " physical_block_size='%u'",
V
Viktor Mihajlovski 已提交
18446
                              def->blockio.physical_block_size);
18447 18448 18449 18450 18451
        }
        virBufferAddLit(buf, "/>\n");
    }
}

18452

18453
/* virDomainSourceDefFormatSeclabel:
18454 18455 18456 18457 18458
 *
 * This function automaticaly closes the <source> element and formats any
 * possible seclabels.
 */
static void
18459 18460 18461 18462 18463
virDomainDiskSourceDefFormatSeclabel(virBufferPtr buf,
                                     size_t nseclabels,
                                     virSecurityDeviceLabelDefPtr *seclabels,
                                     unsigned int flags,
                                     bool skipSeclables)
18464 18465 18466
{
    size_t n;

18467
    if (nseclabels && !skipSeclables) {
18468
        virBufferAddLit(buf, ">\n");
18469
        virBufferAdjustIndent(buf, 2);
18470 18471
        for (n = 0; n < nseclabels; n++)
            virSecurityDeviceLabelDefFormat(buf, seclabels[n], flags);
18472 18473
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</source>\n");
18474 18475 18476 18477 18478
    } else {
        virBufferAddLit(buf, "/>\n");
    }
}

18479 18480 18481 18482 18483 18484 18485 18486 18487 18488 18489 18490 18491 18492 18493
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)
18494
{
18495
    size_t n;
18496
    char *path = NULL;
18497
    const char *startupPolicy = NULL;
18498

18499 18500 18501
    if (policy)
        startupPolicy = virDomainStartupPolicyTypeToString(policy);

18502
    if (src->path || src->nhosts > 0 || src->srcpool || startupPolicy) {
18503
        switch ((virStorageType)src->type) {
E
Eric Blake 已提交
18504
        case VIR_STORAGE_TYPE_FILE:
18505
            virBufferAddLit(buf, "<source");
18506
            virBufferEscapeString(buf, " file='%s'", src->path);
18507 18508
            virBufferEscapeString(buf, " startupPolicy='%s'", startupPolicy);

18509 18510 18511
            virDomainDiskSourceDefFormatSeclabel(buf, src->nseclabels,
                                                 src->seclabels, flags,
                                                 skipSeclabels);
18512
            break;
18513

E
Eric Blake 已提交
18514
        case VIR_STORAGE_TYPE_BLOCK:
18515
            virBufferAddLit(buf, "<source");
18516
            virBufferEscapeString(buf, " dev='%s'", src->path);
18517 18518
            virBufferEscapeString(buf, " startupPolicy='%s'", startupPolicy);

18519 18520 18521
            virDomainDiskSourceDefFormatSeclabel(buf, src->nseclabels,
                                                 src->seclabels, flags,
                                                 skipSeclabels);
18522
            break;
18523

E
Eric Blake 已提交
18524
        case VIR_STORAGE_TYPE_DIR:
18525
            virBufferAddLit(buf, "<source");
18526
            virBufferEscapeString(buf, " dir='%s'", src->path);
18527
            virBufferEscapeString(buf, " startupPolicy='%s'", startupPolicy);
18528
            virBufferAddLit(buf, "/>\n");
18529
            break;
18530

E
Eric Blake 已提交
18531
        case VIR_STORAGE_TYPE_NETWORK:
18532
            virBufferAsprintf(buf, "<source protocol='%s'",
18533
                              virStorageNetProtocolTypeToString(src->protocol));
18534 18535 18536 18537 18538 18539 18540 18541 18542 18543


            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);
18544

18545
            if (src->nhosts == 0 && !src->snapshot && !src->configFile) {
18546 18547 18548
                virBufferAddLit(buf, "/>\n");
            } else {
                virBufferAddLit(buf, ">\n");
18549
                virBufferAdjustIndent(buf, 2);
18550

18551
                for (n = 0; n < src->nhosts; n++) {
18552
                    virBufferAddLit(buf, "<host");
18553 18554 18555 18556
                    virBufferEscapeString(buf, " name='%s'",
                                          src->hosts[n].name);
                    virBufferEscapeString(buf, " port='%s'",
                                          src->hosts[n].port);
18557

18558
                    if (src->hosts[n].transport)
18559
                        virBufferAsprintf(buf, " transport='%s'",
18560
                                          virStorageNetHostTransportTypeToString(src->hosts[n].transport));
18561

18562 18563
                    virBufferEscapeString(buf, " socket='%s'",
                                          src->hosts[n].socket);
18564

18565 18566
                    virBufferAddLit(buf, "/>\n");
                }
18567 18568 18569 18570

                virBufferEscapeString(buf, "<snapshot name='%s'/>\n",
                                      src->snapshot);

18571 18572 18573
                virBufferEscapeString(buf, "<config file='%s'/>\n",
                                      src->configFile);

18574 18575
                virBufferAdjustIndent(buf, -2);
                virBufferAddLit(buf, "</source>\n");
18576 18577
            }
            break;
18578

E
Eric Blake 已提交
18579
        case VIR_STORAGE_TYPE_VOLUME:
18580
            virBufferAddLit(buf, "<source");
18581

18582 18583 18584 18585 18586
            if (src->srcpool) {
                virBufferEscapeString(buf, " pool='%s'", src->srcpool->pool);
                virBufferEscapeString(buf, " volume='%s'",
                                      src->srcpool->volume);
                if (src->srcpool->mode)
18587
                    virBufferAsprintf(buf, " mode='%s'",
18588
                                      virStorageSourcePoolModeTypeToString(src->srcpool->mode));
18589
            }
18590
            virBufferEscapeString(buf, " startupPolicy='%s'", startupPolicy);
18591

18592 18593 18594
            virDomainDiskSourceDefFormatSeclabel(buf, src->nseclabels,
                                                 src->seclabels, flags,
                                                 skipSeclabels);
18595
            break;
18596

18597
        case VIR_STORAGE_TYPE_NONE:
18598
        case VIR_STORAGE_TYPE_LAST:
18599
            virReportError(VIR_ERR_INTERNAL_ERROR,
18600
                           _("unexpected disk type %d"), src->type);
18601 18602 18603 18604 18605 18606
            return -1;
        }
    }

    return 0;
}
J
J.B. Joret 已提交
18607

18608

18609 18610 18611 18612 18613 18614 18615 18616 18617 18618
int
virDomainDiskSourceFormat(virBufferPtr buf,
                          virStorageSourcePtr src,
                          int policy,
                          unsigned int flags)
{
    return virDomainDiskSourceFormatInternal(buf, src, policy, flags, false);
}


18619 18620 18621 18622
static int
virDomainDiskBackingStoreFormat(virBufferPtr buf,
                                virStorageSourcePtr backingStore,
                                const char *backingStoreRaw,
18623
                                unsigned int idx)
18624 18625 18626 18627 18628 18629 18630 18631 18632 18633 18634 18635 18636 18637 18638 18639 18640 18641 18642 18643 18644 18645 18646 18647 18648 18649 18650
{
    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",
18651
                      type, idx);
18652 18653 18654
    virBufferAdjustIndent(buf, 2);

    virBufferAsprintf(buf, "<format type='%s'/>\n", format);
18655 18656
    /* We currently don't output seclabels for backing chain element */
    if (virDomainDiskSourceFormatInternal(buf, backingStore, 0, 0, true) < 0 ||
18657 18658 18659
        virDomainDiskBackingStoreFormat(buf,
                                        backingStore->backingStore,
                                        backingStore->backingStoreRaw,
18660
                                        idx + 1) < 0)
18661 18662 18663 18664 18665 18666 18667 18668
        return -1;

    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</backingStore>\n");
    return 0;
}


18669
static int
18670
virDomainDiskDefFormat(virBufferPtr buf,
D
Daniel P. Berrange 已提交
18671
                       virDomainDiskDefPtr def,
E
Eric Blake 已提交
18672
                       unsigned int flags)
18673
{
18674
    const char *type = virStorageTypeToString(def->src->type);
18675 18676
    const char *device = virDomainDiskDeviceTypeToString(def->device);
    const char *bus = virDomainDiskBusTypeToString(def->bus);
18677
    const char *cachemode = virDomainDiskCacheTypeToString(def->cachemode);
18678
    const char *error_policy = virDomainDiskErrorPolicyTypeToString(def->error_policy);
18679
    const char *rerror_policy = virDomainDiskErrorPolicyTypeToString(def->rerror_policy);
M
Matthias Dahl 已提交
18680
    const char *iomode = virDomainDiskIoTypeToString(def->iomode);
J
Ján Tomko 已提交
18681 18682 18683
    const char *ioeventfd = virTristateSwitchTypeToString(def->ioeventfd);
    const char *event_idx = virTristateSwitchTypeToString(def->event_idx);
    const char *copy_on_read = virTristateSwitchTypeToString(def->copy_on_read);
18684
    const char *sgio = virDomainDeviceSGIOTypeToString(def->sgio);
O
Osier Yang 已提交
18685
    const char *discard = virDomainDiskDiscardTypeToString(def->discard);
18686

18687
    if (!type || !def->src->type) {
18688
        virReportError(VIR_ERR_INTERNAL_ERROR,
18689
                       _("unexpected disk type %d"), def->src->type);
18690 18691 18692
        return -1;
    }
    if (!device) {
18693 18694
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected disk device %d"), def->device);
18695 18696 18697
        return -1;
    }
    if (!bus) {
18698 18699
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected disk bus %d"), def->bus);
18700 18701
        return -1;
    }
18702
    if (!cachemode) {
18703 18704
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected disk cache mode %d"), def->cachemode);
18705 18706
        return -1;
    }
M
Matthias Dahl 已提交
18707
    if (!iomode) {
18708 18709
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected disk io mode %d"), def->iomode);
M
Matthias Dahl 已提交
18710 18711
        return -1;
    }
O
Osier Yang 已提交
18712 18713 18714 18715 18716
    if (!sgio) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unexpected disk sgio mode '%d'"), def->sgio);
        return -1;
    }
18717

18718
    virBufferAsprintf(buf,
18719
                      "<disk type='%s' device='%s'",
18720
                      type, device);
18721 18722 18723
    if (def->rawio) {
        virBufferAsprintf(buf, " rawio='%s'",
                          virTristateBoolTypeToString(def->rawio));
18724
    }
O
Osier Yang 已提交
18725 18726 18727 18728

    if (def->sgio)
        virBufferAsprintf(buf, " sgio='%s'", sgio);

18729
    if (def->snapshot &&
18730 18731
        !(def->snapshot == VIR_DOMAIN_SNAPSHOT_LOCATION_NONE &&
          def->src->readonly))
18732
        virBufferAsprintf(buf, " snapshot='%s'",
E
Eric Blake 已提交
18733
                          virDomainSnapshotLocationTypeToString(def->snapshot));
18734
    virBufferAddLit(buf, ">\n");
18735
    virBufferAdjustIndent(buf, 2);
18736

18737
    if (def->src->driverName || def->src->format > 0 || def->cachemode ||
18738 18739
        def->error_policy || def->rerror_policy || def->iomode ||
        def->ioeventfd || def->event_idx || def->copy_on_read ||
18740
        def->discard || def->iothread) {
18741
        virBufferAddLit(buf, "<driver");
18742
        virBufferEscapeString(buf, " name='%s'", def->src->driverName);
18743
        if (def->src->format > 0)
18744
            virBufferAsprintf(buf, " type='%s'",
18745
                              virStorageFileFormatTypeToString(def->src->format));
18746
        if (def->cachemode)
18747
            virBufferAsprintf(buf, " cache='%s'", cachemode);
18748
        if (def->error_policy)
18749
            virBufferAsprintf(buf, " error_policy='%s'", error_policy);
18750 18751
        if (def->rerror_policy)
            virBufferAsprintf(buf, " rerror_policy='%s'", rerror_policy);
M
Matthias Dahl 已提交
18752
        if (def->iomode)
18753
            virBufferAsprintf(buf, " io='%s'", iomode);
18754 18755
        if (def->ioeventfd)
            virBufferAsprintf(buf, " ioeventfd='%s'", ioeventfd);
18756 18757
        if (def->event_idx)
            virBufferAsprintf(buf, " event_idx='%s'", event_idx);
O
Osier Yang 已提交
18758 18759
        if (def->copy_on_read)
            virBufferAsprintf(buf, " copy_on_read='%s'", copy_on_read);
O
Osier Yang 已提交
18760 18761
        if (def->discard)
            virBufferAsprintf(buf, " discard='%s'", discard);
18762 18763
        if (def->iothread)
            virBufferAsprintf(buf, " iothread='%u'", def->iothread);
18764
        virBufferAddLit(buf, "/>\n");
18765 18766
    }

18767 18768 18769
    if (def->src->auth) {
        if (virStorageAuthDefFormat(buf, def->src->auth) < 0)
            return -1;
18770 18771
    }

18772
    if (virDomainDiskSourceFormat(buf, def->src, def->startupPolicy,
18773
                                  flags) < 0)
18774
        return -1;
18775 18776 18777

    /* Don't format backingStore to inactive XMLs until the code for
     * persistent storage of backing chains is ready. */
18778
    if (!(flags & VIR_DOMAIN_DEF_FORMAT_INACTIVE) &&
18779 18780
        virDomainDiskBackingStoreFormat(buf, def->src->backingStore,
                                        def->src->backingStoreRaw, 1) < 0)
18781 18782
        return -1;

18783 18784
    virBufferEscapeString(buf, "<backenddomain name='%s'/>\n", def->domain_name);

J
J.B. Joret 已提交
18785
    virDomainDiskGeometryDefFormat(buf, def);
V
Viktor Mihajlovski 已提交
18786
    virDomainDiskBlockIoDefFormat(buf, def);
J
J.B. Joret 已提交
18787

18788 18789
    /* For now, mirroring is currently output-only: we only output it
     * for live domains, therefore we ignore it on input except for
18790 18791 18792 18793
     * 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. */
18794
    if (def->mirror && !(flags & VIR_DOMAIN_DEF_FORMAT_INACTIVE)) {
18795 18796 18797 18798
        const char *formatStr = NULL;

        if (def->mirror->format)
            formatStr = virStorageFileFormatTypeToString(def->mirror->format);
E
Eric Blake 已提交
18799 18800
        virBufferAsprintf(buf, "<mirror type='%s'",
                          virStorageTypeToString(def->mirror->type));
E
Eric Blake 已提交
18801 18802
        if (def->mirror->type == VIR_STORAGE_TYPE_FILE &&
            def->mirrorJob == VIR_DOMAIN_BLOCK_JOB_TYPE_COPY) {
18803 18804 18805
            virBufferEscapeString(buf, " file='%s'", def->mirror->path);
            virBufferEscapeString(buf, " format='%s'", formatStr);
        }
E
Eric Blake 已提交
18806 18807
        virBufferEscapeString(buf, " job='%s'",
                              virDomainBlockJobTypeToString(def->mirrorJob));
18808 18809 18810 18811 18812 18813
        if (def->mirrorState) {
            const char *mirror;

            mirror = virDomainDiskMirrorStateTypeToString(def->mirrorState);
            virBufferEscapeString(buf, " ready='%s'", mirror);
        }
E
Eric Blake 已提交
18814 18815
        virBufferAddLit(buf, ">\n");
        virBufferAdjustIndent(buf, 2);
18816
        virBufferEscapeString(buf, "<format type='%s'/>\n", formatStr);
E
Eric Blake 已提交
18817 18818 18819 18820
        if (virDomainDiskSourceFormat(buf, def->mirror, 0, 0) < 0)
            return -1;
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</mirror>\n");
18821 18822
    }

18823
    virBufferAsprintf(buf, "<target dev='%s' bus='%s'",
18824
                      def->dst, bus);
18825 18826
    if ((def->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY ||
         def->device == VIR_DOMAIN_DISK_DEVICE_CDROM) &&
E
Eric Blake 已提交
18827
        def->tray_status != VIR_DOMAIN_DISK_TRAY_CLOSED)
18828
        virBufferAsprintf(buf, " tray='%s'",
18829
                          virDomainDiskTrayTypeToString(def->tray_status));
18830
    if (def->bus == VIR_DOMAIN_DISK_BUS_USB &&
J
Ján Tomko 已提交
18831
        def->removable != VIR_TRISTATE_SWITCH_ABSENT) {
18832
        virBufferAsprintf(buf, " removable='%s'",
J
Ján Tomko 已提交
18833
                          virTristateSwitchTypeToString(def->removable));
18834 18835
    }
    virBufferAddLit(buf, "/>\n");
18836

L
Lei Li 已提交
18837 18838 18839 18840 18841 18842
    /*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 ||
18843 18844 18845 18846 18847 18848 18849 18850
        def->blkdeviotune.write_iops_sec ||
        def->blkdeviotune.total_bytes_sec_max ||
        def->blkdeviotune.read_bytes_sec_max ||
        def->blkdeviotune.write_bytes_sec_max ||
        def->blkdeviotune.total_iops_sec_max ||
        def->blkdeviotune.read_iops_sec_max ||
        def->blkdeviotune.write_iops_sec_max ||
        def->blkdeviotune.size_iops_sec) {
18851 18852
        virBufferAddLit(buf, "<iotune>\n");
        virBufferAdjustIndent(buf, 2);
L
Lei Li 已提交
18853
        if (def->blkdeviotune.total_bytes_sec) {
18854
            virBufferAsprintf(buf, "<total_bytes_sec>%llu</total_bytes_sec>\n",
L
Lei Li 已提交
18855 18856 18857 18858
                              def->blkdeviotune.total_bytes_sec);
        }

        if (def->blkdeviotune.read_bytes_sec) {
18859
            virBufferAsprintf(buf, "<read_bytes_sec>%llu</read_bytes_sec>\n",
L
Lei Li 已提交
18860 18861 18862 18863 18864
                              def->blkdeviotune.read_bytes_sec);

        }

        if (def->blkdeviotune.write_bytes_sec) {
18865
            virBufferAsprintf(buf, "<write_bytes_sec>%llu</write_bytes_sec>\n",
L
Lei Li 已提交
18866 18867 18868 18869
                              def->blkdeviotune.write_bytes_sec);
        }

        if (def->blkdeviotune.total_iops_sec) {
18870
            virBufferAsprintf(buf, "<total_iops_sec>%llu</total_iops_sec>\n",
L
Lei Li 已提交
18871 18872 18873 18874
                              def->blkdeviotune.total_iops_sec);
        }

        if (def->blkdeviotune.read_iops_sec) {
18875
            virBufferAsprintf(buf, "<read_iops_sec>%llu</read_iops_sec>\n",
L
Lei Li 已提交
18876 18877 18878 18879
                              def->blkdeviotune.read_iops_sec);
        }

        if (def->blkdeviotune.write_iops_sec) {
18880
            virBufferAsprintf(buf, "<write_iops_sec>%llu</write_iops_sec>\n",
L
Lei Li 已提交
18881 18882
                              def->blkdeviotune.write_iops_sec);
        }
18883 18884 18885 18886 18887 18888 18889 18890 18891 18892 18893 18894 18895 18896 18897 18898 18899 18900 18901 18902 18903 18904 18905 18906 18907 18908 18909 18910 18911 18912 18913 18914 18915 18916 18917 18918

        if (def->blkdeviotune.total_bytes_sec_max) {
            virBufferAsprintf(buf, "<total_bytes_sec_max>%llu</total_bytes_sec_max>\n",
                              def->blkdeviotune.total_bytes_sec_max);
        }

        if (def->blkdeviotune.read_bytes_sec_max) {
            virBufferAsprintf(buf, "<read_bytes_sec_max>%llu</read_bytes_sec_max>\n",
                              def->blkdeviotune.read_bytes_sec_max);
        }

        if (def->blkdeviotune.write_bytes_sec_max) {
            virBufferAsprintf(buf, "<write_bytes_sec_max>%llu</write_bytes_sec_max>\n",
                              def->blkdeviotune.write_bytes_sec_max);
        }

        if (def->blkdeviotune.total_iops_sec_max) {
            virBufferAsprintf(buf, "<total_iops_sec_max>%llu</total_iops_sec_max>\n",
                              def->blkdeviotune.total_iops_sec_max);
        }

        if (def->blkdeviotune.read_iops_sec_max) {
            virBufferAsprintf(buf, "<read_iops_sec_max>%llu</read_iops_sec_max>\n",
                              def->blkdeviotune.read_iops_sec_max);
        }

        if (def->blkdeviotune.write_iops_sec_max) {
            virBufferAsprintf(buf, "<write_iops_sec_max>%llu</write_iops_sec_max>\n",
                              def->blkdeviotune.write_iops_sec_max);
        }

        if (def->blkdeviotune.size_iops_sec) {
            virBufferAsprintf(buf, "<size_iops_sec>%llu</size_iops_sec>\n",
                              def->blkdeviotune.size_iops_sec);
        }

18919 18920
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</iotune>\n");
L
Lei Li 已提交
18921 18922
    }

18923
    if (def->src->readonly)
18924
        virBufferAddLit(buf, "<readonly/>\n");
18925
    if (def->src->shared)
18926
        virBufferAddLit(buf, "<shareable/>\n");
18927
    if (def->transient)
18928 18929 18930 18931 18932
        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);
18933 18934
    if (def->src->encryption &&
        virStorageEncryptionFormat(buf, def->src->encryption) < 0)
18935
        return -1;
18936
    if (virDomainDeviceInfoFormat(buf, &def->info,
18937
                                  flags | VIR_DOMAIN_DEF_FORMAT_ALLOW_BOOT) < 0)
18938
        return -1;
18939

18940 18941
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</disk>\n");
18942 18943 18944
    return 0;
}

18945 18946 18947 18948 18949 18950
static const char *
virDomainControllerModelTypeToString(virDomainControllerDefPtr def,
                                     int model)
{
    if (def->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI)
        return virDomainControllerModelSCSITypeToString(model);
18951 18952
    else if (def->type == VIR_DOMAIN_CONTROLLER_TYPE_USB)
        return virDomainControllerModelUSBTypeToString(model);
J
Ján Tomko 已提交
18953 18954
    else if (def->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI)
        return virDomainControllerModelPCITypeToString(model);
18955 18956 18957 18958

    return NULL;
}

18959
static int
18960
virDomainControllerDefFormat(virBufferPtr buf,
D
Daniel P. Berrange 已提交
18961
                             virDomainControllerDefPtr def,
E
Eric Blake 已提交
18962
                             unsigned int flags)
18963 18964
{
    const char *type = virDomainControllerTypeToString(def->type);
18965
    const char *model = NULL;
18966
    const char *modelName = NULL;
18967
    bool pcihole64 = false, pciModel = false, pciTarget = false;
18968 18969

    if (!type) {
18970 18971
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected controller type %d"), def->type);
18972 18973 18974
        return -1;
    }

18975
    if (def->model != -1) {
18976
        model = virDomainControllerModelTypeToString(def, def->model);
18977 18978

        if (!model) {
18979 18980
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected model type %d"), def->model);
18981 18982 18983 18984
            return -1;
        }
    }

18985
    virBufferAsprintf(buf,
18986
                      "<controller type='%s' index='%u'",
18987 18988
                      type, def->idx);

18989
    if (model)
18990 18991
        virBufferEscapeString(buf, " model='%s'", model);

18992 18993 18994
    switch (def->type) {
    case VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL:
        if (def->opts.vioserial.ports != -1) {
18995
            virBufferAsprintf(buf, " ports='%d'",
18996 18997 18998
                              def->opts.vioserial.ports);
        }
        if (def->opts.vioserial.vectors != -1) {
18999
            virBufferAsprintf(buf, " vectors='%d'",
19000 19001 19002 19003
                              def->opts.vioserial.vectors);
        }
        break;

19004 19005 19006
    case VIR_DOMAIN_CONTROLLER_TYPE_PCI:
        if (def->opts.pciopts.pcihole64)
            pcihole64 = true;
19007 19008
        if (def->opts.pciopts.modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_NONE)
            pciModel = true;
19009 19010 19011
        if (def->opts.pciopts.chassisNr != -1 ||
            def->opts.pciopts.chassis != -1 ||
            def->opts.pciopts.port != -1)
19012
            pciTarget = true;
19013 19014
        break;

19015 19016 19017 19018
    default:
        break;
    }

19019
    if (pciModel || pciTarget ||
19020
        def->queues || def->cmd_per_lun || def->max_sectors || def->ioeventfd ||
19021
        virDomainDeviceInfoNeedsFormat(&def->info, flags) || pcihole64) {
19022
        virBufferAddLit(buf, ">\n");
19023
        virBufferAdjustIndent(buf, 2);
19024

19025 19026 19027 19028 19029 19030 19031 19032 19033 19034 19035
        if (pciModel) {
            modelName = virDomainControllerPCIModelNameTypeToString(def->opts.pciopts.modelName);
            if (!modelName) {
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unexpected model name value %d"),
                               def->opts.pciopts.modelName);
                return -1;
            }
            virBufferAsprintf(buf, "<model name='%s'/>\n", modelName);
        }

19036 19037 19038 19039 19040
        if (pciTarget) {
            virBufferAddLit(buf, "<target");
            if (def->opts.pciopts.chassisNr != -1)
                virBufferAsprintf(buf, " chassisNr='%d'",
                                  def->opts.pciopts.chassisNr);
19041 19042 19043 19044 19045 19046
            if (def->opts.pciopts.chassis != -1)
                virBufferAsprintf(buf, " chassis='%d'",
                                  def->opts.pciopts.chassis);
            if (def->opts.pciopts.port != -1)
                virBufferAsprintf(buf, " port='0x%x'",
                                  def->opts.pciopts.port);
19047 19048 19049
            virBufferAddLit(buf, "/>\n");
        }

19050 19051
        if (def->queues || def->cmd_per_lun ||
            def->max_sectors || def->ioeventfd) {
19052 19053 19054
            virBufferAddLit(buf, "<driver");
            if (def->queues)
                virBufferAsprintf(buf, " queues='%u'", def->queues);
19055

19056 19057 19058 19059 19060
            if (def->cmd_per_lun)
                virBufferAsprintf(buf, " cmd_per_lun='%u'", def->cmd_per_lun);

            if (def->max_sectors)
                virBufferAsprintf(buf, " max_sectors='%u'", def->max_sectors);
19061 19062 19063 19064 19065

            if (def->ioeventfd) {
                virBufferAsprintf(buf, " ioeventfd='%s'",
                                  virTristateSwitchTypeToString(def->ioeventfd));
            }
19066 19067
            virBufferAddLit(buf, "/>\n");
        }
19068

19069
        if (virDomainDeviceInfoNeedsFormat(&def->info, flags) &&
19070
            virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
19071
            return -1;
19072

19073
        if (pcihole64) {
19074
            virBufferAsprintf(buf, "<pcihole64 unit='KiB'>%lu</"
19075 19076 19077
                              "pcihole64>\n", def->opts.pciopts.pcihole64size);
        }

19078 19079
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</controller>\n");
19080 19081 19082 19083 19084 19085 19086
    } else {
        virBufferAddLit(buf, "/>\n");
    }

    return 0;
}

19087 19088 19089 19090 19091

int
virDomainFSIndexByName(virDomainDefPtr def, const char *name)
{
    virDomainFSDefPtr fs;
19092
    size_t i;
19093 19094 19095 19096 19097 19098 19099 19100 19101 19102

    for (i = 0; i < def->nfss; i++) {
        fs = def->fss[i];
        if (STREQ(fs->dst, name))
            return i;
    }
    return -1;
}


19103
static int
19104
virDomainFSDefFormat(virBufferPtr buf,
19105
                     virDomainFSDefPtr def,
E
Eric Blake 已提交
19106
                     unsigned int flags)
19107 19108
{
    const char *type = virDomainFSTypeToString(def->type);
19109
    const char *accessmode = virDomainFSAccessModeTypeToString(def->accessmode);
19110
    const char *fsdriver = virDomainFSDriverTypeToString(def->fsdriver);
19111
    const char *wrpolicy = virDomainFSWrpolicyTypeToString(def->wrpolicy);
19112 19113

    if (!type) {
19114 19115
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected filesystem type %d"), def->type);
19116 19117 19118
        return -1;
    }

19119
   if (!accessmode) {
19120 19121
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected accessmode %d"), def->accessmode);
19122 19123 19124 19125
        return -1;
    }


19126
    virBufferAsprintf(buf,
19127
                      "<filesystem type='%s' accessmode='%s'>\n",
19128
                      type, accessmode);
19129
    virBufferAdjustIndent(buf, 2);
19130
    if (def->fsdriver) {
19131
        virBufferAsprintf(buf, "<driver type='%s'", fsdriver);
19132

19133 19134 19135 19136
        if (def->format)
            virBufferAsprintf(buf, " format='%s'",
                              virStorageFileFormatTypeToString(def->format));

19137
        /* Don't generate anything if wrpolicy is set to default */
19138
        if (def->wrpolicy)
19139 19140 19141
            virBufferAsprintf(buf, " wrpolicy='%s'", wrpolicy);

        virBufferAddLit(buf, "/>\n");
19142 19143
    }

19144 19145
    switch (def->type) {
    case VIR_DOMAIN_FS_TYPE_MOUNT:
19146
    case VIR_DOMAIN_FS_TYPE_BIND:
19147
        virBufferEscapeString(buf, "<source dir='%s'/>\n",
19148 19149
                              def->src);
        break;
19150

19151
    case VIR_DOMAIN_FS_TYPE_BLOCK:
19152
        virBufferEscapeString(buf, "<source dev='%s'/>\n",
19153 19154
                              def->src);
        break;
19155

19156
    case VIR_DOMAIN_FS_TYPE_FILE:
19157
        virBufferEscapeString(buf, "<source file='%s'/>\n",
19158 19159
                              def->src);
        break;
19160

19161
    case VIR_DOMAIN_FS_TYPE_TEMPLATE:
19162
        virBufferEscapeString(buf, "<source name='%s'/>\n",
19163 19164 19165 19166
                              def->src);
        break;

    case VIR_DOMAIN_FS_TYPE_RAM:
19167
        virBufferAsprintf(buf, "<source usage='%lld' units='KiB'/>\n",
19168 19169
                          def->usage / 1024);
        break;
19170 19171
    }

19172
    virBufferEscapeString(buf, "<target dir='%s'/>\n",
19173
                          def->dst);
19174 19175

    if (def->readonly)
19176
        virBufferAddLit(buf, "<readonly/>\n");
19177

19178 19179 19180
    if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
        return -1;

19181 19182

    if (def->space_hard_limit)
19183
        virBufferAsprintf(buf, "<space_hard_limit unit='bytes'>"
19184 19185
                          "%llu</space_hard_limit>\n", def->space_hard_limit);
    if (def->space_soft_limit) {
19186
        virBufferAsprintf(buf, "<space_soft_limit unit='bytes'>"
19187 19188
                          "%llu</space_soft_limit>\n", def->space_soft_limit);
    }
19189 19190
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</filesystem>\n");
19191 19192 19193
    return 0;
}

19194
static int
19195 19196 19197 19198 19199 19200 19201 19202 19203
virDomainNetIpsFormat(virBufferPtr buf, virDomainNetIpDefPtr *ips, size_t nips)
{
    size_t i;

    /* Output IP addresses */
    for (i = 0; i < nips; i++) {
        virSocketAddrPtr address = &ips[i]->address;
        char *ipStr = virSocketAddrFormat(address);
        const char *familyStr = NULL;
19204 19205 19206

        if (!ipStr)
            return -1;
19207 19208 19209 19210 19211 19212
        if (VIR_SOCKET_ADDR_IS_FAMILY(address, AF_INET6))
            familyStr = "ipv6";
        else if (VIR_SOCKET_ADDR_IS_FAMILY(address, AF_INET))
            familyStr = "ipv4";
        virBufferAsprintf(buf, "<ip address='%s'",
                          ipStr);
19213
        VIR_FREE(ipStr);
19214 19215 19216 19217 19218 19219
        if (familyStr)
            virBufferAsprintf(buf, " family='%s'", familyStr);
        if (ips[i]->prefix != 0)
            virBufferAsprintf(buf, " prefix='%u'", ips[i]->prefix);
        virBufferAddLit(buf, "/>\n");
    }
19220
    return 0;
19221 19222
}

19223
static int
19224
virDomainNetRoutesFormat(virBufferPtr buf,
19225
                         virNetworkRouteDefPtr *routes,
19226 19227 19228 19229
                         size_t nroutes)
{
    size_t i;

19230 19231 19232 19233
    for (i = 0; i < nroutes; i++)
        if (virNetworkRouteDefFormat(buf, routes[i]) < 0)
            return -1;
    return 0;
19234 19235
}

19236
static int
19237 19238 19239 19240
virDomainHostdevDefFormatSubsys(virBufferPtr buf,
                                virDomainHostdevDefPtr def,
                                unsigned int flags,
                                bool includeTypeInAddr)
19241
{
19242
    virDomainHostdevSubsysUSBPtr usbsrc = &def->source.subsys.u.usb;
19243
    virDomainHostdevSubsysPCIPtr pcisrc = &def->source.subsys.u.pci;
19244
    virDomainHostdevSubsysSCSIPtr scsisrc = &def->source.subsys.u.scsi;
19245
    virDomainHostdevSubsysSCSIHostPtr scsihostsrc = &scsisrc->u.host;
J
John Ferlan 已提交
19246
    virDomainHostdevSubsysSCSIiSCSIPtr iscsisrc = &scsisrc->u.iscsi;
19247

19248
    if (def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI &&
19249 19250 19251
        pcisrc->backend != VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT) {
        const char *backend =
            virDomainHostdevSubsysPCIBackendTypeToString(pcisrc->backend);
19252 19253 19254 19255

        if (!backend) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected pci hostdev driver name type %d"),
19256
                           pcisrc->backend);
19257 19258 19259 19260 19261
            return -1;
        }
        virBufferAsprintf(buf, "<driver name='%s'/>\n", backend);
    }

19262
    virBufferAddLit(buf, "<source");
J
John Ferlan 已提交
19263 19264 19265 19266 19267 19268
    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);
        }
19269
        if (usbsrc->autoAddress && (flags & VIR_DOMAIN_DEF_FORMAT_MIGRATABLE))
J
John Ferlan 已提交
19270 19271
            virBufferAddLit(buf, " autoAddress='yes'");

19272
        if (def->missing && !(flags & VIR_DOMAIN_DEF_FORMAT_INACTIVE))
J
John Ferlan 已提交
19273
            virBufferAddLit(buf, " missing='yes'");
19274
    }
19275

J
John Ferlan 已提交
19276 19277 19278 19279 19280 19281 19282 19283
    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);
    }
19284

19285 19286
    virBufferAddLit(buf, ">\n");

19287
    virBufferAdjustIndent(buf, 2);
E
Eric Blake 已提交
19288
    switch (def->source.subsys.type) {
19289
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
19290 19291 19292 19293 19294
        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) {
19295
            virBufferAsprintf(buf, "<address %sbus='%d' device='%d'/>\n",
19296
                              includeTypeInAddr ? "type='usb' " : "",
19297
                              usbsrc->bus, usbsrc->device);
19298 19299 19300
        }
        break;
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
19301
        if (virDevicePCIAddressFormat(buf, pcisrc->addr,
19302 19303 19304
                                      includeTypeInAddr) != 0)
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("PCI address Formatting failed"));
19305

19306
        if ((flags & VIR_DOMAIN_DEF_FORMAT_PCI_ORIG_STATES) &&
19307 19308 19309
            (def->origstates.states.pci.unbind_from_stub ||
             def->origstates.states.pci.remove_slot ||
             def->origstates.states.pci.reprobe)) {
19310
            virBufferAddLit(buf, "<origstates>\n");
19311
            virBufferAdjustIndent(buf, 2);
19312
            if (def->origstates.states.pci.unbind_from_stub)
19313
                virBufferAddLit(buf, "<unbind/>\n");
19314
            if (def->origstates.states.pci.remove_slot)
19315
                virBufferAddLit(buf, "<removeslot/>\n");
19316
            if (def->origstates.states.pci.reprobe)
19317 19318
                virBufferAddLit(buf, "<reprobe/>\n");
            virBufferAdjustIndent(buf, -2);
19319
            virBufferAddLit(buf, "</origstates>\n");
19320 19321
        }
        break;
H
Han Cheng 已提交
19322
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
J
John Ferlan 已提交
19323 19324 19325 19326 19327 19328 19329 19330 19331
        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,
19332
                              "<address %sbus='%u' target='%u' unit='%llu'/>\n",
J
John Ferlan 已提交
19333 19334 19335 19336
                              includeTypeInAddr ? "type='scsi' " : "",
                              scsihostsrc->bus, scsihostsrc->target,
                              scsihostsrc->unit);
        }
H
Han Cheng 已提交
19337
        break;
19338
    default:
19339 19340 19341
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected hostdev type %d"),
                       def->source.subsys.type);
19342 19343 19344
        return -1;
    }

J
John Ferlan 已提交
19345 19346 19347 19348 19349 19350 19351
    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;
    }

19352
    virBufferAdjustIndent(buf, -2);
19353
    virBufferAddLit(buf, "</source>\n");
J
John Ferlan 已提交
19354

19355 19356 19357
    return 0;
}

19358 19359 19360 19361 19362 19363 19364
static int
virDomainHostdevDefFormatCaps(virBufferPtr buf,
                              virDomainHostdevDefPtr def)
{
    virBufferAddLit(buf, "<source>\n");

    virBufferAdjustIndent(buf, 2);
E
Eric Blake 已提交
19365
    switch (def->source.caps.type) {
19366 19367 19368 19369 19370 19371 19372 19373
    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;
19374 19375 19376 19377
    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_NET:
        virBufferEscapeString(buf, "<interface>%s</interface>\n",
                              def->source.caps.u.net.iface);
        break;
19378 19379 19380 19381 19382 19383 19384 19385 19386
    default:
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected hostdev type %d"),
                       def->source.caps.type);
        return -1;
    }

    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</source>\n");
19387 19388

    if (def->source.caps.type == VIR_DOMAIN_HOSTDEV_CAPS_TYPE_NET) {
19389 19390 19391
        if (virDomainNetIpsFormat(buf, def->source.caps.u.net.ips,
                                 def->source.caps.u.net.nips) < 0)
            return -1;
19392 19393 19394
        if (virDomainNetRoutesFormat(buf, def->source.caps.u.net.routes,
                                     def->source.caps.u.net.nroutes) < 0)
            return -1;
19395 19396
    }

19397 19398 19399
    return 0;
}

19400 19401 19402 19403 19404
/* 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.
 */
19405
static int
19406 19407 19408 19409
virDomainActualNetDefContentsFormat(virBufferPtr buf,
                                    virDomainNetDefPtr def,
                                    bool inSubelement,
                                    unsigned int flags)
19410
{
19411
    int actualType = virDomainNetGetActualType(def);
19412

19413
    if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
19414
        if (virDomainHostdevDefFormatSubsys(buf, virDomainNetGetActualHostdev(def),
19415
                                            flags, true) < 0) {
19416 19417
            return -1;
        }
19418 19419 19420 19421 19422
    } else {
        virBufferAddLit(buf, "<source");
        if (def->type == VIR_DOMAIN_NET_TYPE_NETWORK && !inSubelement) {
            /* When we're putting our output into the <actual>
             * subelement rather than the main <interface>, the
19423 19424 19425 19426 19427 19428 19429
             * network name and portgroup don't need to be included in
             * the <source> here because the main interface element's
             * <source> has the same info already. If we've been
             * called to output directly into the main element's
             * <source> though (the case here - "!inSubElement"), we
             * *do* need to output network/portgroup, because the
             * caller won't have done it).
19430
             */
19431 19432 19433 19434
            virBufferEscapeString(buf, " network='%s'",
                                  def->data.network.name);
            virBufferEscapeString(buf, " portgroup='%s'",
                                  def->data.network.portgroup);
19435
        }
19436 19437
        if (actualType == VIR_DOMAIN_NET_TYPE_BRIDGE ||
            actualType == VIR_DOMAIN_NET_TYPE_NETWORK) {
19438 19439
            int macTableManager = virDomainNetGetActualBridgeMACTableManager(def);

19440 19441 19442 19443 19444 19445
            /* actualType == NETWORK includes the name of the bridge
             * that is used by the network, whether we are
             * "inSubElement" or not.
             */
            virBufferEscapeString(buf, " bridge='%s'",
                                  virDomainNetGetActualBridgeName(def));
19446 19447 19448 19449
            if (macTableManager) {
                virBufferAsprintf(buf, " macTableManager='%s'",
                                  virNetworkBridgeMACTableManagerTypeToString(macTableManager));
            }
19450 19451 19452 19453 19454 19455 19456 19457 19458 19459 19460 19461 19462 19463 19464 19465 19466
        } else if (actualType == VIR_DOMAIN_NET_TYPE_DIRECT) {
            const char *mode;

            virBufferEscapeString(buf, " dev='%s'",
                                  virDomainNetGetActualDirectDev(def));
            mode = virNetDevMacVLanModeTypeToString(virDomainNetGetActualDirectMode(def));
            if (!mode) {
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unexpected source mode %d"),
                               virDomainNetGetActualDirectMode(def));
                return -1;
            }
            virBufferAsprintf(buf, " mode='%s'", mode);
        }

        virBufferAddLit(buf, "/>\n");
    }
19467 19468
    if (flags & VIR_DOMAIN_DEF_FORMAT_STATUS &&
        def->data.network.actual && def->data.network.actual->class_id) {
19469 19470
        virBufferAsprintf(buf, "<class id='%u'/>\n",
                          def->data.network.actual->class_id);
19471
    }
19472

19473
    if (virNetDevVlanFormat(virDomainNetGetActualVlan(def), buf) < 0)
19474
        return -1;
19475
    if (virNetDevVPortProfileFormat(virDomainNetGetActualVirtPortProfile(def), buf) < 0)
19476
        return -1;
19477
    if (virNetDevBandwidthFormat(virDomainNetGetActualBandwidth(def), buf) < 0)
19478
        return -1;
19479 19480 19481 19482 19483 19484 19485 19486 19487 19488 19489 19490
    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)
{
19491 19492
    unsigned int type;
    const char *typeStr;
19493 19494 19495

    if (!def)
        return 0;
19496 19497
    type = virDomainNetGetActualType(def);
    typeStr = virDomainNetTypeToString(type);
19498

19499 19500 19501 19502 19503 19504 19505 19506 19507 19508 19509 19510
    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'");
    }
19511 19512 19513
    if (def->trustGuestRxFilters)
        virBufferAsprintf(buf, " trustGuestRxFilters='%s'",
                          virTristateBoolTypeToString(def->trustGuestRxFilters));
19514 19515 19516
    virBufferAddLit(buf, ">\n");

    virBufferAdjustIndent(buf, 2);
19517
    if (virDomainActualNetDefContentsFormat(buf, def, true, flags) < 0)
19518
       return -1;
19519 19520
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</actual>\n");
19521
    return 0;
19522 19523
}

19524

19525 19526 19527 19528 19529 19530 19531 19532 19533 19534 19535 19536 19537 19538 19539 19540 19541 19542 19543 19544 19545 19546 19547 19548 19549 19550 19551 19552 19553 19554 19555 19556 19557 19558 19559 19560 19561 19562 19563 19564 19565 19566 19567 19568 19569 19570 19571 19572 19573 19574 19575 19576 19577 19578 19579 19580 19581 19582 19583 19584 19585 19586 19587 19588
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));
    }
19589 19590 19591 19592
    if (def->driver.virtio.host.mrg_rxbuf) {
        virBufferAsprintf(&buf, "mrg_rxbuf='%s' ",
                          virTristateSwitchTypeToString(def->driver.virtio.host.mrg_rxbuf));
    }
19593 19594 19595 19596 19597 19598 19599 19600 19601 19602
    virBufferTrim(&buf, " ", -1);

    if (virBufferCheckError(&buf) < 0)
        return -1;

    *outstr = virBufferContentAndReset(&buf);
    return 0;
}


19603 19604 19605 19606 19607 19608 19609 19610 19611 19612 19613 19614 19615 19616 19617 19618 19619 19620 19621 19622 19623 19624 19625 19626 19627 19628 19629 19630 19631 19632 19633 19634 19635 19636
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;
}


19637
int
19638
virDomainNetDefFormat(virBufferPtr buf,
19639
                      virDomainNetDefPtr def,
E
Eric Blake 已提交
19640
                      unsigned int flags)
19641
{
19642
    unsigned int actualType = virDomainNetGetActualType(def);
19643
    bool publicActual = false;
19644 19645
    const char *typeStr;
    virDomainHostdevDefPtr hostdef = NULL;
19646
    char macstr[VIR_MAC_STRING_BUFLEN];
19647

19648 19649 19650 19651 19652 19653
    /* publicActual is true if we should report the current state in
     * def->data.network.actual *instead of* the config (*not* in
     * addition to)
     */
    if (def->type == VIR_DOMAIN_NET_TYPE_NETWORK &&
        def->data.network.actual &&
19654 19655 19656
        !(flags & (VIR_DOMAIN_DEF_FORMAT_INACTIVE |
                   VIR_DOMAIN_DEF_FORMAT_ACTUAL_NET |
                   VIR_DOMAIN_DEF_FORMAT_MIGRATABLE)))
19657 19658
        publicActual = true;

19659 19660 19661 19662 19663 19664 19665 19666 19667 19668 19669 19670 19671 19672 19673 19674
    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;
19675 19676
    }

19677
    virBufferAsprintf(buf, "<interface type='%s'", typeStr);
19678
    if (hostdef && hostdef->managed)
19679
        virBufferAddLit(buf, " managed='yes'");
19680 19681 19682
    if (def->trustGuestRxFilters)
        virBufferAsprintf(buf, " trustGuestRxFilters='%s'",
                          virTristateBoolTypeToString(def->trustGuestRxFilters));
19683
    virBufferAddLit(buf, ">\n");
19684

19685
    virBufferAdjustIndent(buf, 2);
19686 19687
    virBufferAsprintf(buf, "<mac address='%s'/>\n",
                      virMacAddrFormat(&def->mac, macstr));
19688

19689 19690 19691 19692 19693 19694 19695
    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)
19696
         */
19697
        if (virDomainActualNetDefContentsFormat(buf, def, false, flags) < 0)
19698
            return -1;
19699 19700 19701 19702 19703 19704 19705 19706 19707 19708 19709 19710 19711 19712 19713
    } 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");
19714

19715 19716 19717 19718
            /* ONLY for internal status storage - format the ActualNetDef
             * as a subelement of <interface> so that no persistent config
             * data is overwritten.
             */
19719
            if ((flags & VIR_DOMAIN_DEF_FORMAT_ACTUAL_NET) &&
19720 19721 19722
                (virDomainActualNetDefFormat(buf, def, flags) < 0))
                return -1;
            break;
19723

19724 19725 19726 19727
        case VIR_DOMAIN_NET_TYPE_ETHERNET:
            virBufferEscapeString(buf, "<source dev='%s'/>\n",
                                  def->data.ethernet.dev);
            break;
19728

M
Michele Paolino 已提交
19729 19730 19731 19732 19733
        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);
19734 19735 19736
                virBufferAsprintf(buf, " mode='%s'",
                                  def->data.vhostuser->data.nix.listen ?
                                  "server"  : "client");
M
Michele Paolino 已提交
19737 19738 19739 19740
                virBufferAddLit(buf, "/>\n");
            }
            break;

19741 19742 19743 19744
        case VIR_DOMAIN_NET_TYPE_BRIDGE:
            virBufferEscapeString(buf, "<source bridge='%s'/>\n",
                                  def->data.bridge.brname);
            break;
D
Daniel Veillard 已提交
19745

19746 19747 19748
        case VIR_DOMAIN_NET_TYPE_SERVER:
        case VIR_DOMAIN_NET_TYPE_CLIENT:
        case VIR_DOMAIN_NET_TYPE_MCAST:
19749
        case VIR_DOMAIN_NET_TYPE_UDP:
19750
            if (def->data.socket.address) {
19751 19752 19753
                virBufferAsprintf(buf, "<source address='%s' port='%d'",
                                  def->data.socket.address,
                                  def->data.socket.port);
19754
            } else {
19755
                virBufferAsprintf(buf, "<source port='%d'",
19756 19757
                                  def->data.socket.port);
            }
19758 19759 19760 19761 19762 19763 19764 19765 19766 19767 19768 19769 19770 19771

            if (def->type != VIR_DOMAIN_NET_TYPE_UDP) {
                virBufferAddLit(buf, "/>\n");
                break;
            }

            virBufferAddLit(buf, ">\n");
            virBufferAdjustIndent(buf, 2);

            virBufferAsprintf(buf, "<local address='%s' port='%d'/>\n",
                              def->data.socket.localaddr,
                              def->data.socket.localport);
            virBufferAdjustIndent(buf, -2);
            virBufferAddLit(buf, "</source>\n");
19772
            break;
D
Daniel Veillard 已提交
19773

19774 19775 19776 19777
        case VIR_DOMAIN_NET_TYPE_INTERNAL:
            virBufferEscapeString(buf, "<source name='%s'/>\n",
                                  def->data.internal.name);
            break;
S
Stefan Berger 已提交
19778

19779 19780 19781 19782 19783 19784 19785 19786 19787 19788 19789 19790 19791 19792 19793 19794 19795 19796
        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;
19797 19798
        }

19799 19800 19801 19802 19803 19804
        if (virNetDevVlanFormat(&def->vlan, buf) < 0)
            return -1;
        if (virNetDevVPortProfileFormat(def->virtPortProfile, buf) < 0)
            return -1;
        if (virNetDevBandwidthFormat(def->bandwidth, buf) < 0)
            return -1;
19805 19806
    }

19807 19808
    if (virDomainNetIpsFormat(buf, def->ips, def->nips) < 0)
        return -1;
19809 19810
    if (virDomainNetRoutesFormat(buf, def->routes, def->nroutes) < 0)
        return -1;
19811

19812
    virBufferEscapeString(buf, "<script path='%s'/>\n",
19813
                          def->script);
19814
    virBufferEscapeString(buf, "<backenddomain name='%s'/>\n", def->domain_name);
19815
    if (def->ifname &&
19816
        !((flags & VIR_DOMAIN_DEF_FORMAT_INACTIVE) &&
19817 19818
          (STRPREFIX(def->ifname, VIR_NET_GENERATED_PREFIX)))) {
        /* Skip auto-generated target names for inactive config. */
19819
        virBufferEscapeString(buf, "<target dev='%s'/>\n", def->ifname);
19820
    }
19821 19822 19823 19824 19825 19826 19827 19828 19829 19830 19831
    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");
    }
19832
    if (def->model) {
19833
        virBufferEscapeString(buf, "<model type='%s'/>\n",
19834
                              def->model);
19835
        if (STREQ(def->model, "virtio")) {
19836 19837
            char *str = NULL, *gueststr = NULL, *hoststr = NULL;
            int rc = 0;
19838

19839 19840 19841 19842
            if (virDomainVirtioNetDriverFormat(&str, def) < 0 ||
                virDomainVirtioNetGuestOptsFormat(&gueststr, def) < 0 ||
                virDomainVirtioNetHostOptsFormat(&hoststr, def) < 0)
                rc = -1;
19843

19844 19845 19846 19847 19848 19849 19850 19851 19852 19853 19854 19855 19856 19857 19858 19859
            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");
            }
19860
            VIR_FREE(str);
19861 19862 19863 19864 19865
            VIR_FREE(hoststr);
            VIR_FREE(gueststr);

            if (rc < 0)
                return -1;
19866 19867
        }
    }
19868 19869 19870 19871 19872 19873
    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");
    }
19874
    if (def->filter) {
19875 19876 19877
        if (virNWFilterFormatParamAttributes(buf, def->filterparams,
                                             def->filter) < 0)
            return -1;
19878
    }
19879

19880
    if (def->tune.sndbuf_specified) {
19881
        virBufferAddLit(buf,   "<tune>\n");
19882 19883 19884
        virBufferAdjustIndent(buf, 2);
        virBufferAsprintf(buf, "<sndbuf>%lu</sndbuf>\n", def->tune.sndbuf);
        virBufferAdjustIndent(buf, -2);
19885
        virBufferAddLit(buf,   "</tune>\n");
19886 19887
    }

19888 19889
    if (def->linkstate) {
        virBufferAsprintf(buf, "<link state='%s'/>\n",
19890
                          virDomainNetInterfaceLinkStateTypeToString(def->linkstate));
19891
    }
19892
    if (virDomainDeviceInfoFormat(buf, &def->info,
19893 19894
                                  flags | VIR_DOMAIN_DEF_FORMAT_ALLOW_BOOT
                                  | VIR_DOMAIN_DEF_FORMAT_ALLOW_ROM) < 0)
19895 19896
        return -1;

19897 19898
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</interface>\n");
19899 19900 19901 19902
    return 0;
}


19903 19904
/* Assumes that "<device" has already been generated, and starts
 * output at " type='type'>". */
19905
static int
19906
virDomainChrSourceDefFormat(virBufferPtr buf,
J
Ján Tomko 已提交
19907
                            virDomainChrDefPtr chr_def,
19908 19909
                            virDomainChrSourceDefPtr def,
                            bool tty_compat,
E
Eric Blake 已提交
19910
                            unsigned int flags)
19911 19912
{
    const char *type = virDomainChrTypeToString(def->type);
J
Ján Tomko 已提交
19913 19914 19915 19916 19917 19918 19919
    size_t nseclabels = 0;
    virSecurityDeviceLabelDefPtr *seclabels = NULL;

    if (chr_def) {
        nseclabels = chr_def->nseclabels;
        seclabels = chr_def->seclabels;
    }
19920

19921
    if (!type) {
19922 19923
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected char type %d"), def->type);
19924
        return -1;
19925 19926
    }

19927
    /* Compat with legacy <console tty='/dev/pts/5'/> syntax */
19928
    virBufferAsprintf(buf, " type='%s'", type);
19929
    if (tty_compat) {
C
Cole Robinson 已提交
19930
        virBufferEscapeString(buf, " tty='%s'",
19931 19932
                              def->data.file.path);
    }
C
Cole Robinson 已提交
19933
    virBufferAddLit(buf, ">\n");
19934

19935
    switch ((virDomainChrType)def->type) {
19936 19937 19938
    case VIR_DOMAIN_CHR_TYPE_NULL:
    case VIR_DOMAIN_CHR_TYPE_VC:
    case VIR_DOMAIN_CHR_TYPE_STDIO:
19939
    case VIR_DOMAIN_CHR_TYPE_SPICEVMC:
19940
    case VIR_DOMAIN_CHR_TYPE_LAST:
19941 19942 19943 19944 19945 19946 19947 19948
        /* 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 ||
19949
            (def->data.file.path &&
19950
             !(flags & VIR_DOMAIN_DEF_FORMAT_INACTIVE))) {
J
Ján Tomko 已提交
19951
            virBufferEscapeString(buf, "<source path='%s'",
19952
                                  def->data.file.path);
J
Ján Tomko 已提交
19953
            virDomainSourceDefFormatSeclabel(buf, nseclabels, seclabels, flags);
19954 19955 19956
        }
        break;

19957
    case VIR_DOMAIN_CHR_TYPE_NMDM:
19958 19959 19960
        virBufferEscapeString(buf, "<source master='%s' ",
                              def->data.nmdm.master);
        virBufferEscapeString(buf, "slave='%s'/>\n", def->data.nmdm.slave);
19961 19962
        break;

19963 19964 19965
    case VIR_DOMAIN_CHR_TYPE_UDP:
        if (def->data.udp.bindService &&
            def->data.udp.bindHost) {
19966 19967 19968 19969
            virBufferEscapeString(buf, "<source mode='bind' host='%s' ",
                                  def->data.udp.bindHost);
            virBufferEscapeString(buf, "service='%s'/>\n",
                                  def->data.udp.bindService);
19970
        } else if (def->data.udp.bindHost) {
19971 19972
            virBufferEscapeString(buf, "<source mode='bind' host='%s'/>\n",
                                  def->data.udp.bindHost);
19973
        } else if (def->data.udp.bindService) {
19974 19975
            virBufferEscapeString(buf, "<source mode='bind' service='%s'/>\n",
                                  def->data.udp.bindService);
19976 19977 19978 19979
        }

        if (def->data.udp.connectService &&
            def->data.udp.connectHost) {
19980 19981 19982 19983
            virBufferEscapeString(buf, "<source mode='connect' host='%s' ",
                                  def->data.udp.connectHost);
            virBufferEscapeString(buf, "service='%s'/>\n",
                                  def->data.udp.connectService);
19984
        } else if (def->data.udp.connectHost) {
19985 19986
            virBufferEscapeString(buf, "<source mode='connect' host='%s'/>\n",
                                  def->data.udp.connectHost);
19987
        } else if (def->data.udp.connectService) {
19988 19989
            virBufferEscapeString(buf, "<source mode='connect' service='%s'/>\n",
                                  def->data.udp.connectService);
19990 19991 19992 19993
        }
        break;

    case VIR_DOMAIN_CHR_TYPE_TCP:
19994 19995 19996 19997
        virBufferAsprintf(buf, "<source mode='%s' ",
                          def->data.tcp.listen ? "bind" : "connect");
        virBufferEscapeString(buf, "host='%s' ", def->data.tcp.host);
        virBufferEscapeString(buf, "service='%s'/>\n", def->data.tcp.service);
19998
        virBufferAsprintf(buf, "<protocol type='%s'/>\n",
19999 20000
                          virDomainChrTcpProtocolTypeToString(
                              def->data.tcp.protocol));
20001 20002 20003
        break;

    case VIR_DOMAIN_CHR_TYPE_UNIX:
20004
        virBufferAsprintf(buf, "<source mode='%s'",
20005
                          def->data.nix.listen ? "bind" : "connect");
20006
        virBufferEscapeString(buf, " path='%s'", def->data.nix.path);
J
Ján Tomko 已提交
20007
        virDomainSourceDefFormatSeclabel(buf, nseclabels, seclabels, flags);
20008
        break;
20009 20010

    case VIR_DOMAIN_CHR_TYPE_SPICEPORT:
20011 20012
        virBufferEscapeString(buf, "<source channel='%s'/>\n",
                              def->data.spiceport.channel);
20013 20014
        break;

20015 20016
    }

20017 20018 20019 20020 20021 20022
    return 0;
}

static int
virDomainChrDefFormat(virBufferPtr buf,
                      virDomainChrDefPtr def,
E
Eric Blake 已提交
20023
                      unsigned int flags)
20024 20025 20026 20027 20028 20029 20030 20031 20032
{
    const char *elementName = virDomainChrDeviceTypeToString(def->deviceType);
    const char *targetType = virDomainChrTargetTypeToString(def->deviceType,
                                                            def->targetType);
    bool tty_compat;

    int ret = 0;

    if (!elementName) {
20033 20034 20035
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected char device type %d"),
                       def->deviceType);
20036 20037 20038
        return -1;
    }

20039 20040
    virBufferAsprintf(buf, "<%s", elementName);
    virBufferAdjustIndent(buf, 2);
20041 20042 20043
    tty_compat = (def->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE &&
                  def->target.port == 0 &&
                  def->source.type == VIR_DOMAIN_CHR_TYPE_PTY &&
20044
                  !(flags & VIR_DOMAIN_DEF_FORMAT_INACTIVE) &&
20045
                  def->source.data.file.path);
J
Ján Tomko 已提交
20046
    if (virDomainChrSourceDefFormat(buf, def, &def->source, tty_compat, flags) < 0)
20047 20048
        return -1;

20049
    /* Format <target> block */
20050
    switch (def->deviceType) {
20051 20052
    case VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL: {
        if (!targetType) {
20053 20054
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Could not format channel target type"));
20055 20056
            return -1;
        }
20057
        virBufferAsprintf(buf, "<target type='%s'", targetType);
20058 20059 20060

        switch (def->targetType) {
        case VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_GUESTFWD: {
20061
            int port = virSocketAddrGetPort(def->target.addr);
20062
            if (port < 0) {
20063 20064
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Unable to format guestfwd port"));
20065 20066
                return -1;
            }
20067

20068
            char *addr = virSocketAddrFormat(def->target.addr);
20069
            if (addr == NULL)
20070
                return -1;
20071

20072
            virBufferAsprintf(buf, " address='%s' port='%d'",
20073 20074 20075
                              addr, port);
            VIR_FREE(addr);
            break;
20076 20077
        }

20078
        case VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO:
20079
            if (def->target.name)
20080
                virBufferEscapeString(buf, " name='%s'", def->target.name);
20081 20082

            if (def->state != VIR_DOMAIN_CHR_DEVICE_STATE_DEFAULT &&
20083
                !(flags & VIR_DOMAIN_DEF_PARSE_INACTIVE)) {
20084 20085 20086
                virBufferAsprintf(buf, " state='%s'",
                                  virDomainChrDeviceStateTypeToString(def->state));
            }
20087 20088 20089
            break;
        }

20090 20091
        virBufferAddLit(buf, "/>\n");
        break;
20092
    }
20093

20094
    case VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE:
20095
        virBufferAsprintf(buf,
20096
                          "<target type='%s' port='%d'/>\n",
20097 20098 20099 20100 20101
                          virDomainChrTargetTypeToString(def->deviceType,
                                                         def->targetType),
                          def->target.port);
        break;

G
Guannan Ren 已提交
20102 20103 20104
    case VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL:
        if (def->targetTypeAttr) {
            virBufferAsprintf(buf,
20105
                              "<target type='%s' port='%d'/>\n",
G
Guannan Ren 已提交
20106 20107 20108 20109 20110
                              virDomainChrTargetTypeToString(def->deviceType,
                                                             def->targetType),
                              def->target.port);
            break;
        }
20111
    default:
20112
        virBufferAsprintf(buf, "<target port='%d'/>\n",
20113
                          def->target.port);
20114
        break;
20115
    }
20116

20117
    if (virDomainDeviceInfoNeedsFormat(&def->info, flags)) {
20118 20119 20120
        if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
            return -1;
    }
20121

20122 20123
    virBufferAdjustIndent(buf, -2);
    virBufferAsprintf(buf, "</%s>\n", elementName);
20124

20125
    return ret;
20126 20127
}

E
Eric Blake 已提交
20128 20129 20130
static int
virDomainSmartcardDefFormat(virBufferPtr buf,
                            virDomainSmartcardDefPtr def,
E
Eric Blake 已提交
20131
                            unsigned int flags)
E
Eric Blake 已提交
20132 20133 20134 20135 20136
{
    const char *mode = virDomainSmartcardTypeToString(def->type);
    size_t i;

    if (!mode) {
20137 20138
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected smartcard type %d"), def->type);
E
Eric Blake 已提交
20139 20140 20141
        return -1;
    }

20142 20143
    virBufferAsprintf(buf, "<smartcard mode='%s'", mode);
    virBufferAdjustIndent(buf, 2);
E
Eric Blake 已提交
20144 20145
    switch (def->type) {
    case VIR_DOMAIN_SMARTCARD_TYPE_HOST:
20146
        if (!virDomainDeviceInfoNeedsFormat(&def->info, flags)) {
20147
            virBufferAdjustIndent(buf, -2);
E
Eric Blake 已提交
20148 20149 20150
            virBufferAddLit(buf, "/>\n");
            return 0;
        }
20151
        virBufferAddLit(buf, ">\n");
E
Eric Blake 已提交
20152 20153 20154 20155 20156
        break;

    case VIR_DOMAIN_SMARTCARD_TYPE_HOST_CERTIFICATES:
        virBufferAddLit(buf, ">\n");
        for (i = 0; i < VIR_DOMAIN_SMARTCARD_NUM_CERTIFICATES; i++)
20157
            virBufferEscapeString(buf, "<certificate>%s</certificate>\n",
E
Eric Blake 已提交
20158
                                  def->data.cert.file[i]);
20159
        virBufferEscapeString(buf, "<database>%s</database>\n",
20160
                              def->data.cert.database);
E
Eric Blake 已提交
20161 20162 20163
        break;

    case VIR_DOMAIN_SMARTCARD_TYPE_PASSTHROUGH:
J
Ján Tomko 已提交
20164
        if (virDomainChrSourceDefFormat(buf, NULL, &def->data.passthru, false,
E
Eric Blake 已提交
20165 20166 20167 20168 20169
                                        flags) < 0)
            return -1;
        break;

    default:
20170 20171
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected smartcard type %d"), def->type);
E
Eric Blake 已提交
20172 20173 20174 20175
        return -1;
    }
    if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
        return -1;
20176 20177
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</smartcard>\n");
E
Eric Blake 已提交
20178 20179 20180
    return 0;
}

20181 20182 20183 20184 20185 20186 20187
static int
virDomainSoundCodecDefFormat(virBufferPtr buf,
                             virDomainSoundCodecDefPtr def)
{
    const char *type = virDomainSoundCodecTypeToString(def->type);

    if (!type) {
20188 20189
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected codec type %d"), def->type);
20190 20191 20192
        return -1;
    }

20193
    virBufferAsprintf(buf, "<codec type='%s'/>\n",  type);
20194 20195 20196 20197

    return 0;
}

20198 20199 20200 20201 20202
static int
virDomainTPMDefFormat(virBufferPtr buf,
                      virDomainTPMDefPtr def,
                      unsigned int flags)
{
20203
    virBufferAsprintf(buf, "<tpm model='%s'>\n",
20204
                      virDomainTPMModelTypeToString(def->model));
20205 20206
    virBufferAdjustIndent(buf, 2);
    virBufferAsprintf(buf, "<backend type='%s'>\n",
20207
                      virDomainTPMBackendTypeToString(def->type));
20208
    virBufferAdjustIndent(buf, 2);
20209 20210 20211

    switch (def->type) {
    case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH:
20212
        virBufferEscapeString(buf, "<device path='%s'/>\n",
20213 20214 20215 20216 20217 20218
                              def->data.passthrough.source.data.file.path);
        break;
    case VIR_DOMAIN_TPM_TYPE_LAST:
        break;
    }

20219 20220
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</backend>\n");
20221

20222
    if (virDomainDeviceInfoNeedsFormat(&def->info, flags)) {
20223 20224 20225 20226
        if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
            return -1;
    }

20227 20228
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</tpm>\n");
20229 20230 20231 20232 20233

    return 0;
}


20234
static int
20235
virDomainSoundDefFormat(virBufferPtr buf,
D
Daniel P. Berrange 已提交
20236
                        virDomainSoundDefPtr def,
E
Eric Blake 已提交
20237
                        unsigned int flags)
20238 20239
{
    const char *model = virDomainSoundModelTypeToString(def->model);
20240
    bool children = false;
20241
    size_t i;
20242 20243

    if (!model) {
20244 20245
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected sound model %d"), def->model);
20246 20247 20248
        return -1;
    }

20249
    virBufferAsprintf(buf, "<sound model='%s'",  model);
20250

20251 20252 20253
    for (i = 0; i < def->ncodecs; i++) {
        if (!children) {
            virBufferAddLit(buf, ">\n");
20254
            virBufferAdjustIndent(buf, 2);
20255 20256 20257 20258 20259
            children = true;
        }
        virDomainSoundCodecDefFormat(buf, def->codecs[i]);
    }

20260
    if (virDomainDeviceInfoNeedsFormat(&def->info, flags)) {
20261 20262
        if (!children) {
            virBufferAddLit(buf, ">\n");
20263
            virBufferAdjustIndent(buf, 2);
20264 20265
            children = true;
        }
D
Daniel P. Berrange 已提交
20266
        if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
20267
            return -1;
20268 20269 20270
    }

    if (children) {
20271 20272
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</sound>\n");
20273 20274 20275 20276
    } else {
        virBufferAddLit(buf, "/>\n");
    }

20277 20278 20279
    return 0;
}

20280

20281 20282 20283
static int
virDomainMemballoonDefFormat(virBufferPtr buf,
                             virDomainMemballoonDefPtr def,
E
Eric Blake 已提交
20284
                             unsigned int flags)
20285 20286
{
    const char *model = virDomainMemballoonModelTypeToString(def->model);
20287 20288
    virBuffer childrenBuf = VIR_BUFFER_INITIALIZER;
    int indent = virBufferGetIndent(buf, false);
20289 20290

    if (!model) {
20291 20292
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected memballoon model %d"), def->model);
20293 20294 20295
        return -1;
    }

20296
    virBufferAsprintf(buf, "<memballoon model='%s'", model);
20297
    virBufferAdjustIndent(&childrenBuf, indent + 2);
20298

20299
    if (def->period)
20300
        virBufferAsprintf(&childrenBuf, "<stats period='%i'/>\n", def->period);
20301

20302 20303 20304 20305
    if (virDomainDeviceInfoNeedsFormat(&def->info, flags) &&
        virDomainDeviceInfoFormat(&childrenBuf, &def->info, flags) < 0) {
        virBufferFreeAndReset(&childrenBuf);
        return -1;
20306 20307
    }

20308
    if (!virBufferUse(&childrenBuf)) {
20309
        virBufferAddLit(buf, "/>\n");
20310 20311 20312
    } else {
        virBufferAddLit(buf, ">\n");
        virBufferAddBuffer(buf, &childrenBuf);
20313
        virBufferAddLit(buf, "</memballoon>\n");
20314
    }
20315

20316 20317 20318
    return 0;
}

L
Li Zhang 已提交
20319 20320 20321 20322 20323
static int
virDomainNVRAMDefFormat(virBufferPtr buf,
                        virDomainNVRAMDefPtr def,
                        unsigned int flags)
{
20324 20325
    virBufferAddLit(buf, "<nvram>\n");
    virBufferAdjustIndent(buf, 2);
20326
    if (virDomainDeviceInfoNeedsFormat(&def->info, flags) &&
L
Li Zhang 已提交
20327 20328 20329
        virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
        return -1;

20330 20331
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</nvram>\n");
L
Li Zhang 已提交
20332 20333 20334 20335

    return 0;
}

20336

R
Richard Jones 已提交
20337
static int
20338
virDomainWatchdogDefFormat(virBufferPtr buf,
D
Daniel P. Berrange 已提交
20339
                           virDomainWatchdogDefPtr def,
E
Eric Blake 已提交
20340
                           unsigned int flags)
R
Richard Jones 已提交
20341
{
20342 20343
    const char *model = virDomainWatchdogModelTypeToString(def->model);
    const char *action = virDomainWatchdogActionTypeToString(def->action);
R
Richard Jones 已提交
20344 20345

    if (!model) {
20346 20347
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected watchdog model %d"), def->model);
R
Richard Jones 已提交
20348 20349 20350 20351
        return -1;
    }

    if (!action) {
20352 20353
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected watchdog action %d"), def->action);
R
Richard Jones 已提交
20354 20355 20356
        return -1;
    }

20357
    virBufferAsprintf(buf, "<watchdog model='%s' action='%s'",
R
Richard Jones 已提交
20358 20359
                      model, action);

20360
    if (virDomainDeviceInfoNeedsFormat(&def->info, flags)) {
20361
        virBufferAddLit(buf, ">\n");
20362
        virBufferAdjustIndent(buf, 2);
D
Daniel P. Berrange 已提交
20363
        if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
20364
            return -1;
20365 20366
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</watchdog>\n");
20367 20368 20369 20370
    } else {
        virBufferAddLit(buf, "/>\n");
    }

R
Richard Jones 已提交
20371 20372 20373
    return 0;
}

H
Hu Tao 已提交
20374
static int virDomainPanicDefFormat(virBufferPtr buf,
20375
                                   virDomainPanicDefPtr def)
H
Hu Tao 已提交
20376
{
20377 20378
    virBuffer childrenBuf = VIR_BUFFER_INITIALIZER;
    int indent = virBufferGetIndent(buf, false);
H
Hu Tao 已提交
20379

20380
    virBufferAddLit(buf, "<panic");
20381 20382 20383 20384 20385

    if (def->model)
        virBufferAsprintf(buf, " model='%s'",
                          virDomainPanicModelTypeToString(def->model));

20386 20387 20388 20389 20390 20391 20392 20393 20394 20395 20396
    virBufferAdjustIndent(&childrenBuf, indent + 2);
    if (virDomainDeviceInfoFormat(&childrenBuf, &def->info, 0) < 0)
        return -1;
    if (virBufferUse(&childrenBuf)) {
        virBufferAddLit(buf, ">\n");
        virBufferAddBuffer(buf, &childrenBuf);
        virBufferAddLit(buf, "</panic>\n");
    } else {
        virBufferAddLit(buf, "/>\n");
    }
    virBufferFreeAndReset(&childrenBuf);
H
Hu Tao 已提交
20397 20398
    return 0;
}
R
Richard Jones 已提交
20399

20400 20401 20402 20403 20404
static int
virDomainShmemDefFormat(virBufferPtr buf,
                        virDomainShmemDefPtr def,
                        unsigned int flags)
{
M
Martin Kletzander 已提交
20405
    virBufferEscapeString(buf, "<shmem name='%s'", def->name);
20406 20407 20408 20409

    if (!def->size &&
        !def->server.enabled &&
        !def->msi.enabled &&
20410
        !virDomainDeviceInfoNeedsFormat(&def->info, flags)) {
20411 20412 20413 20414 20415 20416 20417 20418 20419
        virBufferAddLit(buf, "/>\n");
        return 0;
    } else {
        virBufferAddLit(buf, ">\n");
    }

    virBufferAdjustIndent(buf, 2);

    if (def->size)
M
Martin Kletzander 已提交
20420
        virBufferAsprintf(buf, "<size unit='M'>%llu</size>\n", def->size >> 20);
20421 20422 20423

    if (def->server.enabled) {
        virBufferAddLit(buf, "<server");
20424
        virBufferEscapeString(buf, " path='%s'", def->server.chr.data.nix.path);
20425 20426 20427 20428 20429 20430 20431 20432 20433 20434 20435 20436 20437 20438 20439 20440 20441 20442 20443 20444 20445 20446
        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;
}

20447 20448 20449 20450 20451 20452 20453 20454
static int
virDomainRNGDefFormat(virBufferPtr buf,
                      virDomainRNGDefPtr def,
                      unsigned int flags)
{
    const char *model = virDomainRNGModelTypeToString(def->model);
    const char *backend = virDomainRNGBackendTypeToString(def->backend);

20455 20456
    virBufferAsprintf(buf, "<rng model='%s'>\n", model);
    virBufferAdjustIndent(buf, 2);
20457
    if (def->rate) {
20458
        virBufferAsprintf(buf, "<rate bytes='%u'", def->rate);
20459 20460 20461 20462
        if (def->period)
            virBufferAsprintf(buf, " period='%u'", def->period);
        virBufferAddLit(buf, "/>\n");
    }
20463
    virBufferAsprintf(buf, "<backend model='%s'", backend);
20464

20465
    switch ((virDomainRNGBackend) def->backend) {
20466
    case VIR_DOMAIN_RNG_BACKEND_RANDOM:
20467
        virBufferEscapeString(buf, ">%s</backend>\n", def->source.file);
20468 20469 20470 20471
        break;

    case VIR_DOMAIN_RNG_BACKEND_EGD:
        virBufferAdjustIndent(buf, 2);
J
Ján Tomko 已提交
20472
        if (virDomainChrSourceDefFormat(buf, NULL, def->source.chardev,
20473 20474 20475
                                        false, flags) < 0)
            return -1;
        virBufferAdjustIndent(buf, -2);
20476
        virBufferAddLit(buf, "</backend>\n");
20477 20478 20479 20480 20481

    case VIR_DOMAIN_RNG_BACKEND_LAST:
        break;
    }

20482
    if (virDomainDeviceInfoNeedsFormat(&def->info, flags)) {
20483 20484 20485 20486
        if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
            return -1;
    }

20487 20488
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</rng>\n");
20489 20490 20491 20492 20493 20494 20495 20496 20497
    return 0;
}

void
virDomainRNGDefFree(virDomainRNGDefPtr def)
{
    if (!def)
        return;

20498
    switch ((virDomainRNGBackend) def->backend) {
20499 20500 20501 20502 20503 20504 20505 20506 20507 20508
    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 已提交
20509
    virDomainDeviceInfoClear(&def->info);
20510 20511 20512
    VIR_FREE(def);
}

20513 20514 20515 20516 20517 20518 20519 20520 20521 20522 20523 20524 20525 20526 20527 20528 20529 20530 20531 20532 20533 20534 20535 20536 20537 20538 20539 20540 20541 20542 20543 20544 20545 20546 20547 20548 20549 20550 20551 20552 20553 20554 20555 20556

static int
virDomainMemorySourceDefFormat(virBufferPtr buf,
                               virDomainMemoryDefPtr def)
{
    char *bitmap = NULL;
    int ret = -1;

    if (!def->pagesize && !def->sourceNodes)
        return 0;

    virBufferAddLit(buf, "<source>\n");
    virBufferAdjustIndent(buf, 2);

    if (def->sourceNodes) {
        if (!(bitmap = virBitmapFormat(def->sourceNodes)))
            goto cleanup;

        virBufferAsprintf(buf, "<nodemask>%s</nodemask>\n", bitmap);
    }

    if (def->pagesize)
        virBufferAsprintf(buf, "<pagesize unit='KiB'>%llu</pagesize>\n",
                          def->pagesize);

    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</source>\n");

    ret = 0;

 cleanup:
    VIR_FREE(bitmap);
    return ret;
}


static void
virDomainMemoryTargetDefFormat(virBufferPtr buf,
                               virDomainMemoryDefPtr def)
{
    virBufferAddLit(buf, "<target>\n");
    virBufferAdjustIndent(buf, 2);

    virBufferAsprintf(buf, "<size unit='KiB'>%llu</size>\n", def->size);
20557 20558
    if (def->targetNode >= 0)
        virBufferAsprintf(buf, "<node>%d</node>\n", def->targetNode);
20559 20560 20561 20562 20563 20564 20565 20566 20567 20568 20569 20570 20571 20572 20573 20574 20575 20576 20577 20578 20579 20580 20581 20582 20583 20584 20585 20586 20587 20588

    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</target>\n");
}

static int
virDomainMemoryDefFormat(virBufferPtr buf,
                         virDomainMemoryDefPtr def,
                         unsigned int flags)
{
    const char *model = virDomainMemoryModelTypeToString(def->model);

    virBufferAsprintf(buf, "<memory model='%s'>\n", model);
    virBufferAdjustIndent(buf, 2);

    if (virDomainMemorySourceDefFormat(buf, def) < 0)
        return -1;

    virDomainMemoryTargetDefFormat(buf, def);

    if (virDomainDeviceInfoNeedsFormat(&def->info, flags)) {
        if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
            return -1;
    }

    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</memory>\n");
    return 0;
}

20589 20590 20591 20592
static void
virDomainVideoAccelDefFormat(virBufferPtr buf,
                             virDomainVideoAccelDefPtr def)
{
20593 20594 20595 20596 20597 20598 20599 20600 20601
    virBufferAddLit(buf, "<acceleration");
    if (def->accel3d) {
        virBufferAsprintf(buf, " accel3d='%s'",
                          virTristateBoolTypeToString(def->accel3d));
    }
    if (def->accel2d) {
        virBufferAsprintf(buf, " accel2d='%s'",
                          virTristateBoolTypeToString(def->accel2d));
    }
20602 20603 20604 20605
    virBufferAddLit(buf, "/>\n");
}


20606
static int
20607
virDomainVideoDefFormat(virBufferPtr buf,
D
Daniel P. Berrange 已提交
20608
                        virDomainVideoDefPtr def,
E
Eric Blake 已提交
20609
                        unsigned int flags)
20610 20611 20612 20613
{
    const char *model = virDomainVideoTypeToString(def->type);

    if (!model) {
20614 20615
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected video model %d"), def->type);
20616 20617 20618
        return -1;
    }

20619 20620 20621
    virBufferAddLit(buf, "<video>\n");
    virBufferAdjustIndent(buf, 2);
    virBufferAsprintf(buf, "<model type='%s'",
20622
                      model);
20623 20624
    if (def->ram)
        virBufferAsprintf(buf, " ram='%u'", def->ram);
20625
    if (def->vram)
20626
        virBufferAsprintf(buf, " vram='%u'", def->vram);
20627 20628
    if (def->vgamem)
        virBufferAsprintf(buf, " vgamem='%u'", def->vgamem);
20629
    if (def->heads)
20630
        virBufferAsprintf(buf, " heads='%u'", def->heads);
20631 20632
    if (def->primary)
        virBufferAddLit(buf, " primary='yes'");
20633 20634
    if (def->accel) {
        virBufferAddLit(buf, ">\n");
20635
        virBufferAdjustIndent(buf, 2);
20636
        virDomainVideoAccelDefFormat(buf, def->accel);
20637 20638
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</model>\n");
20639 20640 20641 20642
    } else {
        virBufferAddLit(buf, "/>\n");
    }

D
Daniel P. Berrange 已提交
20643
    if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
20644 20645
        return -1;

20646 20647
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</video>\n");
20648 20649 20650
    return 0;
}

20651
static int
20652
virDomainInputDefFormat(virBufferPtr buf,
20653
                        virDomainInputDefPtr def,
E
Eric Blake 已提交
20654
                        unsigned int flags)
20655 20656 20657 20658 20659
{
    const char *type = virDomainInputTypeToString(def->type);
    const char *bus = virDomainInputBusTypeToString(def->bus);

    if (!type) {
20660 20661
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected input type %d"), def->type);
20662 20663 20664
        return -1;
    }
    if (!bus) {
20665 20666
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected input bus type %d"), def->bus);
20667 20668 20669
        return -1;
    }

20670
    virBufferAsprintf(buf, "<input type='%s' bus='%s'",
20671 20672
                      type, bus);

20673 20674
    if (virDomainDeviceInfoNeedsFormat(&def->info, flags) ||
        def->type == VIR_DOMAIN_INPUT_TYPE_PASSTHROUGH) {
20675
        virBufferAddLit(buf, ">\n");
20676
        virBufferAdjustIndent(buf, 2);
20677
        virBufferEscapeString(buf, "<source evdev='%s'/>\n", def->source.evdev);
20678 20679
        if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
            return -1;
20680 20681
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</input>\n");
20682 20683 20684 20685
    } else {
        virBufferAddLit(buf, "/>\n");
    }

20686 20687 20688 20689
    return 0;
}


20690 20691 20692 20693 20694 20695 20696
static int
virDomainTimerDefFormat(virBufferPtr buf,
                        virDomainTimerDefPtr def)
{
    const char *name = virDomainTimerNameTypeToString(def->name);

    if (!name) {
20697 20698
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected timer name %d"), def->name);
20699 20700
        return -1;
    }
20701
    virBufferAsprintf(buf, "<timer name='%s'", name);
20702 20703 20704 20705 20706 20707 20708 20709 20710 20711 20712

    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) {
20713 20714 20715
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected timer tickpolicy %d"),
                           def->tickpolicy);
20716 20717
            return -1;
        }
20718
        virBufferAsprintf(buf, " tickpolicy='%s'", tickpolicy);
20719 20720 20721 20722
    }

    if ((def->name == VIR_DOMAIN_TIMER_NAME_PLATFORM)
        || (def->name == VIR_DOMAIN_TIMER_NAME_RTC)) {
20723 20724 20725 20726
        if (def->track != -1) {
            const char *track
                = virDomainTimerTrackTypeToString(def->track);
            if (!track) {
20727 20728 20729
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unexpected timer track %d"),
                               def->track);
20730 20731
                return -1;
            }
20732
            virBufferAsprintf(buf, " track='%s'", track);
20733 20734 20735 20736
        }
    }

    if (def->name == VIR_DOMAIN_TIMER_NAME_TSC) {
20737
        if (def->frequency > 0)
20738
            virBufferAsprintf(buf, " frequency='%lu'", def->frequency);
20739 20740 20741 20742 20743

        if (def->mode != -1) {
            const char *mode
                = virDomainTimerModeTypeToString(def->mode);
            if (!mode) {
20744 20745 20746
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unexpected timer mode %d"),
                               def->mode);
20747 20748
                return -1;
            }
20749
            virBufferAsprintf(buf, " mode='%s'", mode);
20750 20751 20752
        }
    }

E
Eric Blake 已提交
20753 20754
    if (def->catchup.threshold == 0 && def->catchup.slew == 0 &&
        def->catchup.limit == 0) {
20755 20756
        virBufferAddLit(buf, "/>\n");
    } else {
20757
        virBufferAddLit(buf, ">\n");
20758 20759
        virBufferAdjustIndent(buf, 2);
        virBufferAddLit(buf, "<catchup");
20760
        if (def->catchup.threshold > 0)
20761
            virBufferAsprintf(buf, " threshold='%lu'", def->catchup.threshold);
20762
        if (def->catchup.slew > 0)
20763
            virBufferAsprintf(buf, " slew='%lu'", def->catchup.slew);
20764
        if (def->catchup.limit > 0)
20765
            virBufferAsprintf(buf, " limit='%lu'", def->catchup.limit);
20766
        virBufferAddLit(buf, "/>\n");
20767 20768
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</timer>\n");
20769
    }
20770 20771 20772 20773

    return 0;
}

20774 20775 20776 20777 20778 20779 20780 20781
static void
virDomainGraphicsAuthDefFormatAttr(virBufferPtr buf,
                                   virDomainGraphicsAuthDefPtr def,
                                   unsigned int flags)
{
    if (!def->passwd)
        return;

20782
    if (flags & VIR_DOMAIN_DEF_FORMAT_SECURE)
20783 20784 20785 20786 20787 20788 20789 20790
        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);
20791
        virBufferAsprintf(buf, " passwdValidTo='%s'", strbuf);
20792
    }
20793 20794 20795 20796

    if (def->connected)
        virBufferEscapeString(buf, " connected='%s'",
                              virDomainGraphicsAuthConnectedTypeToString(def->connected));
20797 20798
}

20799 20800 20801 20802 20803 20804

static void
virDomainGraphicsListenDefFormat(virBufferPtr buf,
                                 virDomainGraphicsListenDefPtr def,
                                 unsigned int flags)
{
20805 20806
    /* If generating migratable XML, skip listen address
     * dragged in from config file */
20807
    if ((flags & VIR_DOMAIN_DEF_FORMAT_MIGRATABLE) && def->fromConfig)
20808 20809
        return;

20810
    virBufferAddLit(buf, "<listen");
20811 20812 20813 20814 20815 20816
    if (def->type) {
        virBufferAsprintf(buf, " type='%s'",
                          virDomainGraphicsListenTypeToString(def->type));
    }

    if (def->address &&
E
Eric Blake 已提交
20817 20818
        (def->type == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS ||
         (def->type == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NETWORK &&
20819
          !(flags & VIR_DOMAIN_DEF_FORMAT_INACTIVE)))) {
20820 20821 20822 20823 20824 20825 20826
        /* 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)) {
20827
        virBufferEscapeString(buf, " network='%s'", def->network);
20828 20829
    }

20830
    if (flags & VIR_DOMAIN_DEF_FORMAT_STATUS)
20831 20832
        virBufferAsprintf(buf, " fromConfig='%d'", def->fromConfig);

20833 20834 20835 20836
    virBufferAddLit(buf, "/>\n");
}


20837
static int
20838
virDomainGraphicsDefFormat(virBufferPtr buf,
20839
                           virDomainGraphicsDefPtr def,
E
Eric Blake 已提交
20840
                           unsigned int flags)
20841 20842
{
    const char *type = virDomainGraphicsTypeToString(def->type);
20843
    const char *listenAddr = NULL;
20844
    bool children = false;
20845
    size_t i;
20846 20847

    if (!type) {
20848 20849
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected net type %d"), def->type);
20850 20851 20852
        return -1;
    }

20853 20854 20855 20856
    /* find the first listen subelement with a valid address and
    * duplicate its address attribute as the listen attribute of
    * <graphics>. This is done to improve backward compatibility.
    */
20857
    for (i = 0; i < def->nListens; i++) {
20858 20859 20860 20861
        if (flags & VIR_DOMAIN_DEF_FORMAT_MIGRATABLE &&
            def->listens[i].fromConfig)
            continue;

20862 20863 20864 20865 20866 20867 20868
        if (def->listens[i].type == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NETWORK &&
            flags & (VIR_DOMAIN_DEF_FORMAT_INACTIVE |
                     VIR_DOMAIN_DEF_FORMAT_MIGRATABLE))
            continue;

        if ((listenAddr = virDomainGraphicsListenGetAddress(def, i)))
            break;
20869 20870
    }

20871
    virBufferAsprintf(buf, "<graphics type='%s'", type);
20872 20873 20874

    switch (def->type) {
    case VIR_DOMAIN_GRAPHICS_TYPE_VNC:
20875
        if (def->data.vnc.socket) {
20876
            virBufferEscapeString(buf, " socket='%s'", def->data.vnc.socket);
20877 20878
        } else {
            if (def->data.vnc.port &&
20879
                (!def->data.vnc.autoport || !(flags & VIR_DOMAIN_DEF_FORMAT_INACTIVE)))
20880
                virBufferAsprintf(buf, " port='%d'",
20881 20882 20883
                                  def->data.vnc.port);
            else if (def->data.vnc.autoport)
                virBufferAddLit(buf, " port='-1'");
20884

20885
            virBufferAsprintf(buf, " autoport='%s'",
20886
                              def->data.vnc.autoport ? "yes" : "no");
20887

M
Martin Kletzander 已提交
20888 20889 20890
            if (def->data.vnc.websocket)
                virBufferAsprintf(buf, " websocket='%d'", def->data.vnc.websocket);

20891 20892
            if (listenAddr)
                virBufferAsprintf(buf, " listen='%s'", listenAddr);
20893
        }
20894 20895 20896 20897 20898

        if (def->data.vnc.keymap)
            virBufferEscapeString(buf, " keymap='%s'",
                                  def->data.vnc.keymap);

20899 20900 20901 20902 20903
        if (def->data.vnc.sharePolicy)
            virBufferAsprintf(buf, " sharePolicy='%s'",
                              virDomainGraphicsVNCSharePolicyTypeToString(
                              def->data.vnc.sharePolicy));

20904
        virDomainGraphicsAuthDefFormatAttr(buf, &def->data.vnc.auth, flags);
20905 20906 20907 20908 20909 20910 20911 20912 20913 20914
        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);
20915 20916 20917
        if (def->data.sdl.fullscreen)
            virBufferAddLit(buf, " fullscreen='yes'");

20918
        break;
20919 20920 20921

    case VIR_DOMAIN_GRAPHICS_TYPE_RDP:
        if (def->data.rdp.port)
20922
            virBufferAsprintf(buf, " port='%d'",
20923 20924 20925 20926 20927
                              def->data.rdp.port);
        else if (def->data.rdp.autoport)
            virBufferAddLit(buf, " port='0'");

        if (def->data.rdp.autoport)
20928
            virBufferAddLit(buf, " autoport='yes'");
20929 20930

        if (def->data.rdp.replaceUser)
20931
            virBufferAddLit(buf, " replaceUser='yes'");
20932 20933

        if (def->data.rdp.multiUser)
20934
            virBufferAddLit(buf, " multiUser='yes'");
20935

20936 20937
        if (listenAddr)
            virBufferAsprintf(buf, " listen='%s'", listenAddr);
20938 20939 20940 20941 20942 20943 20944 20945 20946 20947 20948 20949 20950

        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;

20951 20952
    case VIR_DOMAIN_GRAPHICS_TYPE_SPICE:
        if (def->data.spice.port)
20953
            virBufferAsprintf(buf, " port='%d'",
20954 20955 20956
                              def->data.spice.port);

        if (def->data.spice.tlsPort)
20957
            virBufferAsprintf(buf, " tlsPort='%d'",
20958 20959
                              def->data.spice.tlsPort);

20960
        virBufferAsprintf(buf, " autoport='%s'",
20961 20962
                          def->data.spice.autoport ? "yes" : "no");

20963 20964
        if (listenAddr)
            virBufferAsprintf(buf, " listen='%s'", listenAddr);
20965 20966 20967 20968 20969

        if (def->data.spice.keymap)
            virBufferEscapeString(buf, " keymap='%s'",
                                  def->data.spice.keymap);

20970 20971 20972 20973
        if (def->data.spice.defaultMode != VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_ANY)
            virBufferAsprintf(buf, " defaultMode='%s'",
              virDomainGraphicsSpiceChannelModeTypeToString(def->data.spice.defaultMode));

20974
        virDomainGraphicsAuthDefFormatAttr(buf, &def->data.spice.auth, flags);
20975 20976
        break;

20977 20978
    }

20979 20980 20981 20982
    for (i = 0; i < def->nListens; i++) {
        if (virDomainGraphicsListenGetType(def, i)
            == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NONE)
            continue;
20983
        if (flags & VIR_DOMAIN_DEF_FORMAT_MIGRATABLE &&
20984 20985
            def->listens[i].fromConfig)
            continue;
20986 20987
        if (!children) {
            virBufferAddLit(buf, ">\n");
20988
            virBufferAdjustIndent(buf, 2);
20989
            children = true;
20990 20991 20992 20993
        }
        virDomainGraphicsListenDefFormat(buf, &def->listens[i], flags);
    }

20994
    if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) {
20995
        for (i = 0; i < VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_LAST; i++) {
20996 20997 20998 20999 21000 21001
            int mode = def->data.spice.channels[i];
            if (mode == VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_ANY)
                continue;

            if (!children) {
                virBufferAddLit(buf, ">\n");
21002
                virBufferAdjustIndent(buf, 2);
21003
                children = true;
21004 21005
            }

21006
            virBufferAsprintf(buf, "<channel name='%s' mode='%s'/>\n",
21007 21008 21009
                              virDomainGraphicsSpiceChannelNameTypeToString(i),
                              virDomainGraphicsSpiceChannelModeTypeToString(mode));
        }
21010 21011
        if (!children && (def->data.spice.image || def->data.spice.jpeg ||
                          def->data.spice.zlib || def->data.spice.playback ||
P
Peng Zhou 已提交
21012
                          def->data.spice.streaming || def->data.spice.copypaste ||
21013
                          def->data.spice.mousemode || def->data.spice.filetransfer)) {
21014
            virBufferAddLit(buf, ">\n");
21015
            virBufferAdjustIndent(buf, 2);
21016
            children = true;
21017
        }
21018
        if (def->data.spice.image)
21019
            virBufferAsprintf(buf, "<image compression='%s'/>\n",
21020 21021
                              virDomainGraphicsSpiceImageCompressionTypeToString(def->data.spice.image));
        if (def->data.spice.jpeg)
21022
            virBufferAsprintf(buf, "<jpeg compression='%s'/>\n",
21023 21024
                              virDomainGraphicsSpiceJpegCompressionTypeToString(def->data.spice.jpeg));
        if (def->data.spice.zlib)
21025
            virBufferAsprintf(buf, "<zlib compression='%s'/>\n",
21026 21027
                              virDomainGraphicsSpiceZlibCompressionTypeToString(def->data.spice.zlib));
        if (def->data.spice.playback)
21028
            virBufferAsprintf(buf, "<playback compression='%s'/>\n",
J
Ján Tomko 已提交
21029
                              virTristateSwitchTypeToString(def->data.spice.playback));
21030
        if (def->data.spice.streaming)
21031
            virBufferAsprintf(buf, "<streaming mode='%s'/>\n",
21032
                              virDomainGraphicsSpiceStreamingModeTypeToString(def->data.spice.streaming));
P
Peng Zhou 已提交
21033
        if (def->data.spice.mousemode)
21034
            virBufferAsprintf(buf, "<mouse mode='%s'/>\n",
P
Peng Zhou 已提交
21035
                              virDomainGraphicsSpiceMouseModeTypeToString(def->data.spice.mousemode));
21036
        if (def->data.spice.copypaste)
21037
            virBufferAsprintf(buf, "<clipboard copypaste='%s'/>\n",
J
Ján Tomko 已提交
21038
                              virTristateBoolTypeToString(def->data.spice.copypaste));
21039
        if (def->data.spice.filetransfer)
21040
            virBufferAsprintf(buf, "<filetransfer enable='%s'/>\n",
J
Ján Tomko 已提交
21041
                              virTristateBoolTypeToString(def->data.spice.filetransfer));
21042 21043 21044
    }

    if (children) {
21045 21046
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</graphics>\n");
21047 21048 21049
    } else {
        virBufferAddLit(buf, "/>\n");
    }
21050 21051 21052 21053

    return 0;
}

21054 21055

static int
21056
virDomainHostdevDefFormat(virBufferPtr buf,
D
Daniel P. Berrange 已提交
21057
                          virDomainHostdevDefPtr def,
E
Eric Blake 已提交
21058
                          unsigned int flags)
21059 21060
{
    const char *mode = virDomainHostdevModeTypeToString(def->mode);
21061
    virDomainHostdevSubsysSCSIPtr scsisrc = &def->source.subsys.u.scsi;
21062 21063
    const char *type;

21064
    if (!mode) {
21065 21066
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected hostdev mode %d"), def->mode);
21067 21068 21069
        return -1;
    }

21070 21071 21072 21073 21074 21075 21076 21077 21078 21079
    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;
21080 21081 21082 21083 21084 21085 21086 21087 21088
    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;
21089
    default:
21090
        virReportError(VIR_ERR_INTERNAL_ERROR,
21091
                       _("unexpected hostdev mode %d"), def->mode);
21092 21093 21094
        return -1;
    }

21095
    virBufferAsprintf(buf, "<hostdev mode='%s' type='%s'",
21096
                      mode, type);
O
Osier Yang 已提交
21097 21098
    if (def->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
        virBufferAsprintf(buf, " managed='%s'",
21099
                          def->managed ? "yes" : "no");
O
Osier Yang 已提交
21100

21101 21102
        if (def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI &&
            scsisrc->sgio)
O
Osier Yang 已提交
21103
            virBufferAsprintf(buf, " sgio='%s'",
21104
                              virDomainDeviceSGIOTypeToString(scsisrc->sgio));
21105 21106 21107 21108 21109 21110

        if (def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI &&
            scsisrc->rawio) {
            virBufferAsprintf(buf, " rawio='%s'",
                              virTristateBoolTypeToString(scsisrc->rawio));
        }
O
Osier Yang 已提交
21111 21112
    }
    virBufferAddLit(buf, ">\n");
21113
    virBufferAdjustIndent(buf, 2);
21114

21115 21116 21117 21118 21119
    switch (def->mode) {
    case VIR_DOMAIN_HOSTDEV_MODE_SUBSYS:
        if (virDomainHostdevDefFormatSubsys(buf, def, flags, false) < 0)
            return -1;
        break;
21120 21121 21122 21123
    case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
        if (virDomainHostdevDefFormatCaps(buf, def) < 0)
            return -1;
        break;
21124
    }
O
Osier Yang 已提交
21125 21126 21127

    if (def->readonly)
        virBufferAddLit(buf, "<readonly/>\n");
21128 21129
    if (def->shareable)
        virBufferAddLit(buf, "<shareable/>\n");
21130

21131
    if (virDomainDeviceInfoFormat(buf, def->info,
21132 21133
                                  flags | VIR_DOMAIN_DEF_FORMAT_ALLOW_BOOT
                                  | VIR_DOMAIN_DEF_FORMAT_ALLOW_ROM) < 0)
21134 21135
        return -1;

21136 21137
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</hostdev>\n");
21138 21139 21140 21141

    return 0;
}

21142 21143 21144 21145 21146 21147 21148 21149 21150
static int
virDomainRedirdevDefFormat(virBufferPtr buf,
                           virDomainRedirdevDefPtr def,
                           unsigned int flags)
{
    const char *bus;

    bus = virDomainRedirdevBusTypeToString(def->bus);

21151 21152
    virBufferAsprintf(buf, "<redirdev bus='%s'", bus);
    virBufferAdjustIndent(buf, 2);
J
Ján Tomko 已提交
21153
    if (virDomainChrSourceDefFormat(buf, NULL, &def->source.chr, false, flags) < 0)
21154
        return -1;
21155
    if (virDomainDeviceInfoFormat(buf, &def->info,
21156
                                  flags | VIR_DOMAIN_DEF_FORMAT_ALLOW_BOOT) < 0)
21157
        return -1;
21158 21159
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</redirdev>\n");
21160 21161
    return 0;
}
21162

21163 21164 21165 21166 21167 21168
static int
virDomainRedirFilterDefFormat(virBufferPtr buf,
                              virDomainRedirFilterDefPtr filter)
{
    size_t i;

21169 21170 21171 21172
    /* no need format an empty redirfilter */
    if (filter->nusbdevs == 0)
        return 0;

21173 21174
    virBufferAddLit(buf, "<redirfilter>\n");
    virBufferAdjustIndent(buf, 2);
21175
    for (i = 0; i < filter->nusbdevs; i++) {
21176
        virDomainRedirFilterUSBDevDefPtr usbdev = filter->usbdevs[i];
21177
        virBufferAddLit(buf, "<usbdev");
21178 21179 21180 21181 21182 21183 21184 21185 21186 21187
        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)
21188
            virBufferAsprintf(buf, " version='%d.%02d'",
21189 21190 21191 21192 21193 21194 21195 21196
                                 ((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");

    }
21197 21198
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</redirfilter>\n");
21199 21200 21201
    return 0;
}

M
Marc-André Lureau 已提交
21202 21203
static int
virDomainHubDefFormat(virBufferPtr buf,
21204 21205
                      virDomainHubDefPtr def,
                      unsigned int flags)
M
Marc-André Lureau 已提交
21206 21207 21208 21209
{
    const char *type = virDomainHubTypeToString(def->type);

    if (!type) {
21210 21211
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected hub type %d"), def->type);
M
Marc-André Lureau 已提交
21212 21213 21214
        return -1;
    }

21215
    virBufferAsprintf(buf, "<hub type='%s'", type);
M
Marc-André Lureau 已提交
21216

21217
    if (virDomainDeviceInfoNeedsFormat(&def->info, flags)) {
M
Marc-André Lureau 已提交
21218
        virBufferAddLit(buf, ">\n");
21219
        virBufferAdjustIndent(buf, 2);
M
Marc-André Lureau 已提交
21220 21221
        if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
            return -1;
21222 21223
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</hub>\n");
M
Marc-André Lureau 已提交
21224 21225 21226 21227 21228 21229 21230
    } else {
        virBufferAddLit(buf, "/>\n");
    }

    return 0;
}

21231 21232 21233 21234 21235

static void
virDomainResourceDefFormat(virBufferPtr buf,
                           virDomainResourceDefPtr def)
{
21236 21237 21238 21239 21240
    virBufferAddLit(buf, "<resource>\n");
    virBufferAdjustIndent(buf, 2);
    virBufferEscapeString(buf, "<partition>%s</partition>\n", def->partition);
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</resource>\n");
21241 21242 21243
}


21244 21245 21246 21247 21248 21249 21250 21251 21252 21253 21254 21255 21256 21257 21258 21259 21260 21261 21262 21263 21264 21265 21266 21267 21268 21269 21270 21271 21272 21273 21274 21275 21276 21277 21278 21279 21280 21281 21282 21283 21284 21285 21286 21287 21288 21289 21290
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");
}

21291 21292 21293 21294 21295 21296 21297 21298 21299 21300 21301 21302 21303 21304 21305
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);
21306 21307 21308 21309 21310 21311 21312 21313
    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");
    }
21314
}
21315

21316 21317 21318 21319 21320 21321 21322 21323 21324 21325 21326 21327 21328 21329 21330 21331 21332 21333
static void
virDomainKeyWrapDefFormat(virBufferPtr buf, virDomainKeyWrapDefPtr keywrap)
{
    virBufferAddLit(buf, "<keywrap>\n");
    virBufferAdjustIndent(buf, 2);

    if (keywrap->aes)
        virBufferAsprintf(buf, "<cipher name='aes' state='%s'/>\n",
                          virTristateSwitchTypeToString(keywrap->aes));

    if (keywrap->dea)
        virBufferAsprintf(buf, "<cipher name='dea' state='%s'/>\n",
                          virTristateSwitchTypeToString(keywrap->dea));

    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</keywrap>\n");
}

21334 21335 21336 21337 21338 21339
static bool
virDomainDefHasCapabilitiesFeatures(virDomainDefPtr def)
{
    size_t i;

    for (i = 0; i < VIR_DOMAIN_CAPS_FEATURE_LAST; i++) {
J
Ján Tomko 已提交
21340
        if (def->caps_features[i] != VIR_TRISTATE_SWITCH_ABSENT)
21341 21342 21343 21344 21345 21346
            return true;
    }

    return false;
}

21347 21348 21349
/* This internal version appends to an existing buffer
 * (possibly with auto-indent), rather than flattening
 * to string.
21350 21351
 * Return -1 on failure.  */
int
21352
virDomainDefFormatInternal(virDomainDefPtr def,
21353 21354
                           unsigned int flags,
                           virBufferPtr buf)
21355 21356 21357
{
    unsigned char *uuid;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
21358
    const char *type = NULL;
H
Hu Tao 已提交
21359
    int n;
21360
    size_t i;
21361 21362
    virBuffer childrenBuf = VIR_BUFFER_INITIALIZER;
    int indent;
21363

21364 21365 21366 21367 21368
    virCheckFlags(VIR_DOMAIN_DEF_FORMAT_COMMON_FLAGS |
                  VIR_DOMAIN_DEF_FORMAT_STATUS |
                  VIR_DOMAIN_DEF_FORMAT_ACTUAL_NET |
                  VIR_DOMAIN_DEF_FORMAT_PCI_ORIG_STATES |
                  VIR_DOMAIN_DEF_FORMAT_CLOCK_ADJUST,
21369
                  -1);
21370

21371
    if (!(type = virDomainVirtTypeToString(def->virtType))) {
21372 21373
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected domain type %d"), def->virtType);
21374
        goto error;
21375 21376
    }

21377
    if (def->id == -1)
21378
        flags |= VIR_DOMAIN_DEF_FORMAT_INACTIVE;
21379

21380
    virBufferAsprintf(buf, "<domain type='%s'", type);
21381
    if (!(flags & VIR_DOMAIN_DEF_FORMAT_INACTIVE))
21382
        virBufferAsprintf(buf, " id='%d'", def->id);
21383
    if (def->namespaceData && def->ns.href)
21384 21385
        virBufferAsprintf(buf, " %s", (def->ns.href)());
    virBufferAddLit(buf, ">\n");
21386
    virBufferAdjustIndent(buf, 2);
21387

21388
    virBufferEscapeString(buf, "<name>%s</name>\n", def->name);
21389 21390 21391

    uuid = def->uuid;
    virUUIDFormat(uuid, uuidstr);
21392
    virBufferAsprintf(buf, "<uuid>%s</uuid>\n", uuidstr);
21393

21394
    virBufferEscapeString(buf, "<title>%s</title>\n", def->title);
21395

21396
    virBufferEscapeString(buf, "<description>%s</description>\n",
21397
                          def->description);
21398

21399 21400 21401 21402 21403 21404 21405 21406 21407 21408 21409 21410 21411
    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,
21412
                        virBufferGetIndent(buf, false) / 2, 1) < 0) {
21413 21414
            xmlBufferFree(xmlbuf);
            xmlIndentTreeOutput = oldIndentTreeOutput;
21415
            goto error;
21416
        }
21417
        virBufferAsprintf(buf, "%s\n", (char *) xmlBufferContent(xmlbuf));
21418 21419 21420 21421
        xmlBufferFree(xmlbuf);
        xmlIndentTreeOutput = oldIndentTreeOutput;
    }

21422
    if (virDomainDefHasMemoryHotplug(def)) {
21423 21424 21425 21426 21427
        virBufferAsprintf(buf,
                          "<maxMemory slots='%u' unit='KiB'>%llu</maxMemory>\n",
                          def->mem.memory_slots, def->mem.max_memory);
    }

21428
    virBufferAddLit(buf, "<memory");
21429 21430
    if (def->mem.dump_core)
        virBufferAsprintf(buf, " dumpCore='%s'",
J
Ján Tomko 已提交
21431
                          virTristateSwitchTypeToString(def->mem.dump_core));
21432
    virBufferAsprintf(buf, " unit='KiB'>%llu</memory>\n",
21433
                      virDomainDefGetMemoryActual(def));
21434

21435
    virBufferAsprintf(buf, "<currentMemory unit='KiB'>%llu</currentMemory>\n",
21436 21437
                      def->mem.cur_balloon);

21438 21439 21440 21441 21442 21443
    /* start format blkiotune */
    indent = virBufferGetIndent(buf, false);
    virBufferAdjustIndent(&childrenBuf, indent + 2);
    if (def->blkio.weight)
        virBufferAsprintf(&childrenBuf, "<weight>%u</weight>\n",
                          def->blkio.weight);
21444

21445 21446
    for (n = 0; n < def->blkio.ndevices; n++) {
        virBlkioDevicePtr dev = &def->blkio.devices[n];
21447

21448 21449 21450 21451 21452 21453 21454 21455 21456 21457 21458 21459 21460 21461 21462 21463 21464 21465 21466 21467 21468 21469 21470 21471 21472 21473 21474 21475
        if (!dev->weight && !dev->riops && !dev->wiops &&
            !dev->rbps && !dev->wbps)
            continue;
        virBufferAddLit(&childrenBuf, "<device>\n");
        virBufferAdjustIndent(&childrenBuf, 2);
        virBufferEscapeString(&childrenBuf, "<path>%s</path>\n",
                              dev->path);
        if (dev->weight)
            virBufferAsprintf(&childrenBuf, "<weight>%u</weight>\n",
                              dev->weight);
        if (dev->riops)
            virBufferAsprintf(&childrenBuf, "<read_iops_sec>%u</read_iops_sec>\n",
                              dev->riops);
        if (dev->wiops)
            virBufferAsprintf(&childrenBuf, "<write_iops_sec>%u</write_iops_sec>\n",
                              dev->wiops);
        if (dev->rbps)
            virBufferAsprintf(&childrenBuf, "<read_bytes_sec>%llu</read_bytes_sec>\n",
                              dev->rbps);
        if (dev->wbps)
            virBufferAsprintf(&childrenBuf, "<write_bytes_sec>%llu</write_bytes_sec>\n",
                              dev->wbps);
        virBufferAdjustIndent(&childrenBuf, -2);
        virBufferAddLit(&childrenBuf, "</device>\n");
    }
    if (virBufferUse(&childrenBuf)) {
        virBufferAddLit(buf, "<blkiotune>\n");
        virBufferAddBuffer(buf, &childrenBuf);
21476
        virBufferAddLit(buf, "</blkiotune>\n");
21477
    }
21478
    virBufferFreeAndReset(&childrenBuf);
21479

21480
    /* add memtune only if there are any */
21481 21482 21483
    if (virMemoryLimitIsSet(def->mem.hard_limit) ||
        virMemoryLimitIsSet(def->mem.soft_limit) ||
        virMemoryLimitIsSet(def->mem.swap_hard_limit) ||
21484
        def->mem.min_guarantee) {
21485 21486
        virBufferAddLit(buf, "<memtune>\n");
        virBufferAdjustIndent(buf, 2);
21487
        if (virMemoryLimitIsSet(def->mem.hard_limit)) {
21488
            virBufferAsprintf(buf, "<hard_limit unit='KiB'>"
21489 21490
                              "%llu</hard_limit>\n", def->mem.hard_limit);
        }
21491
        if (virMemoryLimitIsSet(def->mem.soft_limit)) {
21492
            virBufferAsprintf(buf, "<soft_limit unit='KiB'>"
21493 21494 21495
                              "%llu</soft_limit>\n", def->mem.soft_limit);
        }
        if (def->mem.min_guarantee) {
21496
            virBufferAsprintf(buf, "<min_guarantee unit='KiB'>"
21497 21498
                              "%llu</min_guarantee>\n", def->mem.min_guarantee);
        }
21499
        if (virMemoryLimitIsSet(def->mem.swap_hard_limit)) {
21500
            virBufferAsprintf(buf, "<swap_hard_limit unit='KiB'>"
21501 21502
                              "%llu</swap_hard_limit>\n", def->mem.swap_hard_limit);
        }
21503 21504
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</memtune>\n");
21505
    }
21506

21507
    if (def->mem.nhugepages || def->mem.nosharepages || def->mem.locked) {
21508 21509
        virBufferAddLit(buf, "<memoryBacking>\n");
        virBufferAdjustIndent(buf, 2);
21510 21511
        if (def->mem.nhugepages)
            virDomainHugepagesFormat(buf, def->mem.hugepages, def->mem.nhugepages);
21512
        if (def->mem.nosharepages)
21513
            virBufferAddLit(buf, "<nosharepages/>\n");
21514
        if (def->mem.locked)
21515 21516 21517
            virBufferAddLit(buf, "<locked/>\n");
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</memoryBacking>\n");
21518
    }
21519

21520
    virBufferAddLit(buf, "<vcpu");
21521 21522
    virBufferAsprintf(buf, " placement='%s'",
                      virDomainCpuPlacementModeTypeToString(def->placement_mode));
H
Hu Tao 已提交
21523 21524

    if (def->cpumask && !virBitmapIsAllSet(def->cpumask)) {
21525
        char *cpumask = NULL;
H
Hu Tao 已提交
21526
        if ((cpumask = virBitmapFormat(def->cpumask)) == NULL)
21527
            goto error;
21528
        virBufferAsprintf(buf, " cpuset='%s'", cpumask);
21529 21530
        VIR_FREE(cpumask);
    }
21531
    if (virDomainDefHasVcpusOffline(def))
21532 21533
        virBufferAsprintf(buf, " current='%u'", def->vcpus);
    virBufferAsprintf(buf, ">%u</vcpu>\n", def->maxvcpus);
21534

21535
    if (def->niothreadids > 0) {
21536 21537 21538 21539 21540 21541 21542 21543 21544 21545 21546 21547 21548 21549 21550 21551 21552 21553 21554 21555
        virBufferAsprintf(buf, "<iothreads>%u</iothreads>\n",
                          def->iothreads);
        /* Only print out iothreadids if we read at least one */
        for (i = 0; i < def->niothreadids; i++) {
            if (!def->iothreadids[i]->autofill)
                break;
        }
        if (i < def->niothreadids) {
            virBufferAddLit(buf, "<iothreadids>\n");
            virBufferAdjustIndent(buf, 2);
            for (i = 0; i < def->niothreadids; i++) {
                if (def->iothreadids[i]->autofill)
                    continue;
                virBufferAsprintf(buf, "<iothread id='%u'/>\n",
                                  def->iothreadids[i]->iothread_id);
            }
            virBufferAdjustIndent(buf, -2);
            virBufferAddLit(buf, "</iothreadids>\n");
        }
    }
21556

21557 21558 21559
    /* start format cputune */
    indent = virBufferGetIndent(buf, false);
    virBufferAdjustIndent(&childrenBuf, indent + 2);
21560
    if (def->cputune.sharesSpecified)
21561
        virBufferAsprintf(&childrenBuf, "<shares>%lu</shares>\n",
21562
                          def->cputune.shares);
21563
    if (def->cputune.period)
21564
        virBufferAsprintf(&childrenBuf, "<period>%llu</period>\n",
21565 21566
                          def->cputune.period);
    if (def->cputune.quota)
21567
        virBufferAsprintf(&childrenBuf, "<quota>%lld</quota>\n",
21568
                          def->cputune.quota);
21569 21570

    if (def->cputune.emulator_period)
21571
        virBufferAsprintf(&childrenBuf, "<emulator_period>%llu"
21572 21573 21574 21575
                          "</emulator_period>\n",
                          def->cputune.emulator_period);

    if (def->cputune.emulator_quota)
21576
        virBufferAsprintf(&childrenBuf, "<emulator_quota>%lld"
21577 21578 21579
                          "</emulator_quota>\n",
                          def->cputune.emulator_quota);

21580
    for (i = 0; i < def->cputune.nvcpupin; i++) {
P
Peter Krempa 已提交
21581 21582
        char *cpumask;
        /* Ignore the vcpupin which inherit from "cpuset of "<vcpu>." */
21583
        if (virBitmapEqual(def->cpumask, def->cputune.vcpupin[i]->cpumask))
21584
            continue;
21585

21586
        virBufferAsprintf(&childrenBuf, "<vcpupin vcpu='%u' ",
21587
                          def->cputune.vcpupin[i]->id);
21588

21589
        if (!(cpumask = virBitmapFormat(def->cputune.vcpupin[i]->cpumask)))
21590
            goto error;
21591

21592
        virBufferAsprintf(&childrenBuf, "cpuset='%s'/>\n", cpumask);
21593
        VIR_FREE(cpumask);
21594 21595
    }

T
Tang Chen 已提交
21596
    if (def->cputune.emulatorpin) {
P
Peter Krempa 已提交
21597
        char *cpumask;
21598
        virBufferAddLit(&childrenBuf, "<emulatorpin ");
T
Tang Chen 已提交
21599

21600
        if (!(cpumask = virBitmapFormat(def->cputune.emulatorpin)))
21601
            goto error;
T
Tang Chen 已提交
21602

21603
        virBufferAsprintf(&childrenBuf, "cpuset='%s'/>\n", cpumask);
T
Tang Chen 已提交
21604 21605
        VIR_FREE(cpumask);
    }
21606

21607
    for (i = 0; i < def->niothreadids; i++) {
21608
        char *cpumask;
21609 21610 21611

        /* Ignore iothreadids with no cpumask */
        if (!def->iothreadids[i]->cpumask)
21612 21613
            continue;

21614
        virBufferAsprintf(&childrenBuf, "<iothreadpin iothread='%u' ",
21615
                          def->iothreadids[i]->iothread_id);
21616

21617
        if (!(cpumask = virBitmapFormat(def->iothreadids[i]->cpumask)))
21618 21619
            goto error;

21620
        virBufferAsprintf(&childrenBuf, "cpuset='%s'/>\n", cpumask);
21621 21622 21623
        VIR_FREE(cpumask);
    }

21624 21625 21626 21627 21628 21629
    for (i = 0; i < def->cputune.nvcpusched; i++) {
        virDomainThreadSchedParamPtr sp = &def->cputune.vcpusched[i];
        char *ids = NULL;

        if (!(ids = virBitmapFormat(sp->ids)))
            goto error;
21630
        virBufferAsprintf(&childrenBuf, "<vcpusched vcpus='%s' scheduler='%s'",
21631
                          ids, virProcessSchedPolicyTypeToString(sp->policy));
21632 21633
        VIR_FREE(ids);

21634 21635
        if (sp->policy == VIR_PROC_POLICY_FIFO ||
            sp->policy == VIR_PROC_POLICY_RR)
21636 21637
            virBufferAsprintf(&childrenBuf, " priority='%d'", sp->priority);
        virBufferAddLit(&childrenBuf, "/>\n");
21638 21639 21640 21641 21642 21643 21644 21645
    }

    for (i = 0; i < def->cputune.niothreadsched; i++) {
        virDomainThreadSchedParamPtr sp = &def->cputune.iothreadsched[i];
        char *ids = NULL;

        if (!(ids = virBitmapFormat(sp->ids)))
            goto error;
21646
        virBufferAsprintf(&childrenBuf, "<iothreadsched iothreads='%s' scheduler='%s'",
21647
                          ids, virProcessSchedPolicyTypeToString(sp->policy));
21648 21649
        VIR_FREE(ids);

21650 21651
        if (sp->policy == VIR_PROC_POLICY_FIFO ||
            sp->policy == VIR_PROC_POLICY_RR)
21652 21653
            virBufferAsprintf(&childrenBuf, " priority='%d'", sp->priority);
        virBufferAddLit(&childrenBuf, "/>\n");
21654 21655
    }

21656 21657 21658
    if (virBufferUse(&childrenBuf)) {
        virBufferAddLit(buf, "<cputune>\n");
        virBufferAddBuffer(buf, &childrenBuf);
21659
        virBufferAddLit(buf, "</cputune>\n");
21660 21661
    }
    virBufferFreeAndReset(&childrenBuf);
21662

21663
    if (virDomainNumatuneFormatXML(buf, def->numa) < 0)
21664
        goto error;
21665

21666 21667 21668
    if (def->resource)
        virDomainResourceDefFormat(buf, def->resource);

21669
    if (def->sysinfo)
21670
        ignore_value(virSysinfoFormat(buf, def->sysinfo));
21671

21672
    if (def->os.bootloader) {
21673
        virBufferEscapeString(buf, "<bootloader>%s</bootloader>\n",
21674
                              def->os.bootloader);
21675
        virBufferEscapeString(buf,
21676
                              "<bootloader_args>%s</bootloader_args>\n",
21677
                              def->os.bootloaderArgs);
21678 21679
    }

21680 21681 21682
    virBufferAddLit(buf, "<os>\n");
    virBufferAdjustIndent(buf, 2);
    virBufferAddLit(buf, "<type");
21683
    if (def->os.arch)
21684
        virBufferAsprintf(buf, " arch='%s'", virArchToString(def->os.arch));
21685
    if (def->os.machine)
21686
        virBufferAsprintf(buf, " machine='%s'", def->os.machine);
21687 21688 21689 21690 21691 21692
    /*
     * 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 &&
21693 21694 21695
        def->os.type == VIR_DOMAIN_OSTYPE_XEN)
        virBufferAsprintf(buf, ">%s</type>\n",
                          virDomainOSTypeToString(VIR_DOMAIN_OSTYPE_LINUX));
21696
    else
21697 21698
        virBufferAsprintf(buf, ">%s</type>\n",
                          virDomainOSTypeToString(def->os.type));
21699

21700
    virBufferEscapeString(buf, "<init>%s</init>\n",
21701
                          def->os.init);
21702
    for (i = 0; def->os.initargv && def->os.initargv[i]; i++)
21703
        virBufferEscapeString(buf, "<initarg>%s</initarg>\n",
21704
                              def->os.initargv[i]);
21705 21706
    if (def->os.loader)
        virDomainLoaderDefFormat(buf, def->os.loader);
21707
    virBufferEscapeString(buf, "<kernel>%s</kernel>\n",
21708
                          def->os.kernel);
21709
    virBufferEscapeString(buf, "<initrd>%s</initrd>\n",
21710
                          def->os.initrd);
21711
    virBufferEscapeString(buf, "<cmdline>%s</cmdline>\n",
21712
                          def->os.cmdline);
21713
    virBufferEscapeString(buf, "<dtb>%s</dtb>\n",
21714
                          def->os.dtb);
21715
    virBufferEscapeString(buf, "<root>%s</root>\n",
21716
                          def->os.root);
21717 21718

    if (!def->os.bootloader) {
21719
        for (n = 0; n < def->os.nBootDevs; n++) {
21720 21721 21722
            const char *boottype =
                virDomainBootTypeToString(def->os.bootDevs[n]);
            if (!boottype) {
21723 21724 21725
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unexpected boot device type %d"),
                               def->os.bootDevs[n]);
21726
                goto error;
21727
            }
21728
            virBufferAsprintf(buf, "<boot dev='%s'/>\n", boottype);
21729
        }
21730

21731 21732
        if (def->os.bootmenu) {
            virBufferAsprintf(buf, "<bootmenu enable='%s'",
J
Ján Tomko 已提交
21733
                              virTristateBoolTypeToString(def->os.bootmenu));
21734 21735 21736 21737
            if (def->os.bm_timeout_set)
                virBufferAsprintf(buf, " timeout='%u'", def->os.bm_timeout);
            virBufferAddLit(buf, "/>\n");
        }
M
Michal Privoznik 已提交
21738

21739
        if (def->os.bios.useserial || def->os.bios.rt_set) {
21740
            virBufferAddLit(buf, "<bios");
21741 21742
            if (def->os.bios.useserial)
                virBufferAsprintf(buf, " useserial='%s'",
J
Ján Tomko 已提交
21743
                                  virTristateBoolTypeToString(def->os.bios.useserial));
21744 21745 21746 21747
            if (def->os.bios.rt_set)
                virBufferAsprintf(buf, " rebootTimeout='%d'", def->os.bios.rt_delay);

            virBufferAddLit(buf, "/>\n");
M
Michal Privoznik 已提交
21748
        }
21749 21750
    }

21751 21752 21753 21754 21755
    if (def->os.smbios_mode) {
        const char *mode;

        mode = virDomainSmbiosModeTypeToString(def->os.smbios_mode);
        if (mode == NULL) {
21756 21757
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected smbios mode %d"), def->os.smbios_mode);
21758
            goto error;
21759
        }
21760
        virBufferAsprintf(buf, "<smbios mode='%s'/>\n", mode);
21761 21762
    }

21763 21764
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</os>\n");
21765

21766 21767

    if (def->idmap.uidmap) {
21768 21769
        virBufferAddLit(buf, "<idmap>\n");
        virBufferAdjustIndent(buf, 2);
21770 21771
        for (i = 0; i < def->idmap.nuidmap; i++) {
            virBufferAsprintf(buf,
21772
                              "<uid start='%u' target='%u' count='%u'/>\n",
21773 21774 21775 21776 21777 21778
                              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,
21779
                              "<gid start='%u' target='%u' count='%u'/>\n",
21780 21781 21782 21783
                              def->idmap.gidmap[i].start,
                              def->idmap.gidmap[i].target,
                              def->idmap.gidmap[i].count);
        }
21784 21785
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</idmap>\n");
21786 21787
    }

21788
    for (i = 0; i < VIR_DOMAIN_FEATURE_LAST; i++) {
J
Ján Tomko 已提交
21789
        if (def->features[i] != VIR_TRISTATE_SWITCH_ABSENT)
21790 21791
            break;
    }
21792

21793 21794
    if (i != VIR_DOMAIN_FEATURE_LAST ||
        virDomainDefHasCapabilitiesFeatures(def)) {
21795 21796
        virBufferAddLit(buf, "<features>\n");
        virBufferAdjustIndent(buf, 2);
21797

21798
        for (i = 0; i < VIR_DOMAIN_FEATURE_LAST; i++) {
21799 21800 21801 21802 21803 21804 21805
            const char *name = virDomainFeatureTypeToString(i);
            size_t j;

            if (!name) {
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unexpected feature %zu"), i);
                goto error;
21806
            }
21807

21808
            switch ((virDomainFeature) i) {
21809 21810 21811 21812 21813
            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 已提交
21814 21815
                switch ((virTristateSwitch) def->features[i]) {
                case VIR_TRISTATE_SWITCH_ABSENT:
21816 21817
                    break;

J
Ján Tomko 已提交
21818
                case VIR_TRISTATE_SWITCH_ON:
21819
                   virBufferAsprintf(buf, "<%s/>\n", name);
21820 21821
                   break;

J
Ján Tomko 已提交
21822 21823
                case VIR_TRISTATE_SWITCH_LAST:
                case VIR_TRISTATE_SWITCH_OFF:
21824 21825 21826 21827 21828 21829 21830 21831
                   virReportError(VIR_ERR_INTERNAL_ERROR,
                                 _("Unexpected state of feature '%s'"), name);

                   goto error;
                   break;
                }

                break;
21832

21833
            case VIR_DOMAIN_FEATURE_PMU:
21834
            case VIR_DOMAIN_FEATURE_PVSPINLOCK:
21835
            case VIR_DOMAIN_FEATURE_VMPORT:
J
Ján Tomko 已提交
21836 21837 21838
                switch ((virTristateSwitch) def->features[i]) {
                case VIR_TRISTATE_SWITCH_LAST:
                case VIR_TRISTATE_SWITCH_ABSENT:
21839 21840
                    break;

J
Ján Tomko 已提交
21841
                case VIR_TRISTATE_SWITCH_ON:
21842
                   virBufferAsprintf(buf, "<%s state='on'/>\n", name);
21843 21844
                   break;

J
Ján Tomko 已提交
21845
                case VIR_TRISTATE_SWITCH_OFF:
21846
                   virBufferAsprintf(buf, "<%s state='off'/>\n", name);
21847 21848 21849 21850 21851
                   break;
                }

                break;

21852
            case VIR_DOMAIN_FEATURE_APIC:
J
Ján Tomko 已提交
21853
                if (def->features[i] == VIR_TRISTATE_SWITCH_ON) {
21854
                    virBufferAddLit(buf, "<apic");
21855 21856
                    if (def->apic_eoi) {
                        virBufferAsprintf(buf, " eoi='%s'",
J
Ján Tomko 已提交
21857
                                          virTristateSwitchTypeToString(def->apic_eoi));
21858
                    }
21859
                    virBufferAddLit(buf, "/>\n");
21860 21861
                }
                break;
21862

21863
            case VIR_DOMAIN_FEATURE_HYPERV:
J
Ján Tomko 已提交
21864
                if (def->features[i] != VIR_TRISTATE_SWITCH_ON)
21865
                    break;
21866

21867 21868
                virBufferAddLit(buf, "<hyperv>\n");
                virBufferAdjustIndent(buf, 2);
21869
                for (j = 0; j < VIR_DOMAIN_HYPERV_LAST; j++) {
21870
                    switch ((virDomainHyperv) j) {
21871 21872 21873
                    case VIR_DOMAIN_HYPERV_RELAXED:
                    case VIR_DOMAIN_HYPERV_VAPIC:
                        if (def->hyperv_features[j])
21874
                            virBufferAsprintf(buf, "<%s state='%s'/>\n",
21875
                                              virDomainHypervTypeToString(j),
J
Ján Tomko 已提交
21876
                                              virTristateSwitchTypeToString(
21877 21878 21879 21880 21881 21882 21883
                                                  def->hyperv_features[j]));
                        break;

                    case VIR_DOMAIN_HYPERV_SPINLOCKS:
                        if (def->hyperv_features[j] == 0)
                            break;

21884
                        virBufferAsprintf(buf, "<spinlocks state='%s'",
J
Ján Tomko 已提交
21885
                                          virTristateSwitchTypeToString(
21886
                                              def->hyperv_features[j]));
J
Ján Tomko 已提交
21887
                        if (def->hyperv_features[j] == VIR_TRISTATE_SWITCH_ON)
21888 21889 21890 21891 21892
                            virBufferAsprintf(buf, " retries='%d'",
                                              def->hyperv_spinlocks);
                        virBufferAddLit(buf, "/>\n");
                        break;

21893
                    /* coverity[dead_error_begin] */
21894 21895 21896
                    case VIR_DOMAIN_HYPERV_LAST:
                        break;
                    }
21897
                }
21898 21899
                virBufferAdjustIndent(buf, -2);
                virBufferAddLit(buf, "</hyperv>\n");
21900 21901
                break;

21902 21903 21904 21905 21906 21907 21908 21909 21910 21911 21912 21913 21914 21915 21916 21917
            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;

21918
                    /* coverity[dead_error_begin] */
21919 21920 21921 21922 21923 21924 21925 21926
                    case VIR_DOMAIN_KVM_LAST:
                        break;
                    }
                }
                virBufferAdjustIndent(buf, -2);
                virBufferAddLit(buf, "</kvm>\n");
                break;

21927 21928 21929 21930 21931 21932 21933 21934 21935
            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 已提交
21936
                    if (def->caps_features[j] != VIR_TRISTATE_SWITCH_ABSENT)
21937 21938
                        virBufferAsprintf(buf, "<%s state='%s'/>\n",
                                          virDomainCapsFeatureTypeToString(j),
J
Ján Tomko 已提交
21939
                                          virTristateSwitchTypeToString(
21940 21941 21942 21943 21944 21945
                                              def->caps_features[j]));
                }
                virBufferAdjustIndent(buf, -2);
                virBufferAddLit(buf, "</capabilities>\n");
                break;

M
Michal Privoznik 已提交
21946 21947 21948 21949 21950 21951 21952 21953 21954 21955
            case VIR_DOMAIN_FEATURE_GIC:
                if (def->features[i] == VIR_TRISTATE_SWITCH_ON) {
                    virBufferAddLit(buf, "<gic");
                    if (def->gic_version)
                        virBufferAsprintf(buf, " version='%u'",
                                          def->gic_version);
                    virBufferAddLit(buf, "/>\n");
                }
                break;

21956
            /* coverity[dead_error_begin] */
21957 21958
            case VIR_DOMAIN_FEATURE_LAST:
                break;
21959 21960 21961
            }
        }

21962 21963
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</features>\n");
21964 21965
    }

21966
    if (virCPUDefFormatBufFull(buf, def->cpu, def->numa,
21967
                               !!(flags & VIR_DOMAIN_DEF_FORMAT_UPDATE_CPU)) < 0)
21968
        goto error;
21969

21970
    virBufferAsprintf(buf, "<clock offset='%s'",
21971
                      virDomainClockOffsetTypeToString(def->clock.offset));
21972
    switch (def->clock.offset) {
21973 21974 21975 21976 21977
    case VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME:
    case VIR_DOMAIN_CLOCK_OFFSET_UTC:
        if (def->clock.data.utc_reset)
            virBufferAddLit(buf, " adjustment='reset'");
        break;
21978
    case VIR_DOMAIN_CLOCK_OFFSET_VARIABLE:
21979 21980 21981
        virBufferAsprintf(buf, " adjustment='%lld' basis='%s'",
                          def->clock.data.variable.adjustment,
                          virDomainClockBasisTypeToString(def->clock.data.variable.basis));
21982
        if (flags & VIR_DOMAIN_DEF_FORMAT_CLOCK_ADJUST) {
21983 21984 21985 21986
            if (def->clock.data.variable.adjustment0)
                virBufferAsprintf(buf, " adjustment0='%lld'",
                                  def->clock.data.variable.adjustment0);
        }
21987 21988
        break;
    case VIR_DOMAIN_CLOCK_OFFSET_TIMEZONE:
21989
        virBufferEscapeString(buf, " timezone='%s'", def->clock.data.timezone);
21990 21991
        break;
    }
21992
    if (def->clock.ntimers == 0) {
21993
        virBufferAddLit(buf, "/>\n");
21994
    } else {
21995
        virBufferAddLit(buf, ">\n");
21996
        virBufferAdjustIndent(buf, 2);
21997
        for (n = 0; n < def->clock.ntimers; n++) {
21998
            if (virDomainTimerDefFormat(buf, def->clock.timers[n]) < 0)
21999
                goto error;
22000
        }
22001 22002
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</clock>\n");
22003
    }
22004

22005 22006 22007
    if (virDomainEventActionDefFormat(buf, def->onPoweroff,
                                      "on_poweroff",
                                      virDomainLifecycleTypeToString) < 0)
22008
        goto error;
22009 22010 22011
    if (virDomainEventActionDefFormat(buf, def->onReboot,
                                      "on_reboot",
                                      virDomainLifecycleTypeToString) < 0)
22012
        goto error;
22013 22014 22015
    if (virDomainEventActionDefFormat(buf, def->onCrash,
                                      "on_crash",
                                      virDomainLifecycleCrashTypeToString) < 0)
22016
        goto error;
22017 22018 22019 22020
    if (def->onLockFailure != VIR_DOMAIN_LOCK_FAILURE_DEFAULT &&
        virDomainEventActionDefFormat(buf, def->onLockFailure,
                                      "on_lockfailure",
                                      virDomainLockFailureTypeToString) < 0)
22021
        goto error;
22022

22023
    if (def->pm.s3 || def->pm.s4) {
22024 22025
        virBufferAddLit(buf, "<pm>\n");
        virBufferAdjustIndent(buf, 2);
22026
        if (def->pm.s3) {
22027
            virBufferAsprintf(buf, "<suspend-to-mem enabled='%s'/>\n",
J
Ján Tomko 已提交
22028
                              virTristateBoolTypeToString(def->pm.s3));
22029 22030
        }
        if (def->pm.s4) {
22031
            virBufferAsprintf(buf, "<suspend-to-disk enabled='%s'/>\n",
J
Ján Tomko 已提交
22032
                              virTristateBoolTypeToString(def->pm.s4));
22033
        }
22034 22035
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</pm>\n");
22036 22037
    }

22038 22039
    virBufferAddLit(buf, "<devices>\n");
    virBufferAdjustIndent(buf, 2);
22040

22041
    virBufferEscapeString(buf, "<emulator>%s</emulator>\n",
22042
                          def->emulator);
22043

22044
    for (n = 0; n < def->ndisks; n++)
22045
        if (virDomainDiskDefFormat(buf, def->disks[n], flags) < 0)
22046
            goto error;
22047

22048
    for (n = 0; n < def->ncontrollers; n++)
22049
        if (virDomainControllerDefFormat(buf, def->controllers[n], flags) < 0)
22050
            goto error;
22051

22052
    for (n = 0; n < def->nleases; n++)
22053
        if (virDomainLeaseDefFormat(buf, def->leases[n]) < 0)
22054
            goto error;
22055

22056
    for (n = 0; n < def->nfss; n++)
22057
        if (virDomainFSDefFormat(buf, def->fss[n], flags) < 0)
22058
            goto error;
22059

22060
    for (n = 0; n < def->nnets; n++)
22061
        if (virDomainNetDefFormat(buf, def->nets[n], flags) < 0)
22062
            goto error;
22063

22064
    for (n = 0; n < def->nsmartcards; n++)
22065
        if (virDomainSmartcardDefFormat(buf, def->smartcards[n], flags) < 0)
22066
            goto error;
E
Eric Blake 已提交
22067

22068
    for (n = 0; n < def->nserials; n++)
22069
        if (virDomainChrDefFormat(buf, def->serials[n], flags) < 0)
22070
            goto error;
22071

22072
    for (n = 0; n < def->nparallels; n++)
22073
        if (virDomainChrDefFormat(buf, def->parallels[n], flags) < 0)
22074
            goto error;
22075

22076
    for (n = 0; n < def->nconsoles; n++) {
22077 22078 22079 22080
        virDomainChrDef console;
        /* Back compat, ignore the console element for hvm guests
         * if it is type == serial
         */
22081
        if (def->os.type == VIR_DOMAIN_OSTYPE_HVM &&
22082 22083
            (def->consoles[n]->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL ||
             def->consoles[n]->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_NONE) &&
22084 22085 22086
            (n < def->nserials)) {
            memcpy(&console, def->serials[n], sizeof(console));
            console.deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE;
G
Guannan Ren 已提交
22087
            console.targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL;
22088 22089 22090 22091
        } else {
            memcpy(&console, def->consoles[n], sizeof(console));
        }
        if (virDomainChrDefFormat(buf, &console, flags) < 0)
22092
            goto error;
22093
    }
22094 22095 22096 22097
    /* The back-compat console device stub is added when parsing the domain XML
     * and handled above, this is for formatting definitions created via other
     * means.
     */
22098
    if (def->os.type == VIR_DOMAIN_OSTYPE_HVM &&
22099 22100
        def->nconsoles == 0 &&
        def->nserials > 0) {
22101
        virDomainChrDef console;
22102
        memcpy(&console, def->serials[n], sizeof(console));
22103
        console.deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE;
22104
        console.targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL;
22105
        if (virDomainChrDefFormat(buf, &console, flags) < 0)
22106
            goto error;
22107 22108
    }

22109
    for (n = 0; n < def->nchannels; n++)
22110
        if (virDomainChrDefFormat(buf, def->channels[n], flags) < 0)
22111
            goto error;
22112

22113
    for (n = 0; n < def->ninputs; n++)
22114 22115
        if ((def->inputs[n]->bus == VIR_DOMAIN_INPUT_BUS_USB ||
             def->inputs[n]->bus == VIR_DOMAIN_INPUT_BUS_VIRTIO) &&
22116
            virDomainInputDefFormat(buf, def->inputs[n], flags) < 0)
22117
            goto error;
22118

22119 22120 22121 22122 22123
    if (def->tpm) {
        if (virDomainTPMDefFormat(buf, def->tpm, flags) < 0)
            goto error;
    }

22124
    if (def->ngraphics > 0) {
L
Li Zhang 已提交
22125
        /* If graphics is enabled, add the implicit mouse/keyboard */
22126 22127
        if ((ARCH_IS_X86(def->os.arch)) || def->os.arch == VIR_ARCH_NONE) {
            virDomainInputDef autoInput = {
22128 22129
                .type = VIR_DOMAIN_INPUT_TYPE_MOUSE,
                .info = { .alias = NULL },
22130
            };
22131

22132
            if (def->os.type == VIR_DOMAIN_OSTYPE_HVM)
22133
                autoInput.bus = VIR_DOMAIN_INPUT_BUS_PS2;
22134
            else if (def->os.type == VIR_DOMAIN_OSTYPE_EXE &&
22135 22136
                     (def->virtType == VIR_DOMAIN_VIRT_VZ ||
                      def->virtType == VIR_DOMAIN_VIRT_PARALLELS))
22137 22138 22139 22140
                autoInput.bus = VIR_DOMAIN_INPUT_BUS_PARALLELS;
            else
               autoInput.bus = VIR_DOMAIN_INPUT_BUS_XEN;

L
Li Zhang 已提交
22141 22142
            if (virDomainInputDefFormat(buf, &autoInput, flags) < 0)
                goto error;
22143

22144
            if (!(flags & VIR_DOMAIN_DEF_FORMAT_MIGRATABLE)) {
22145 22146 22147 22148
                autoInput.type = VIR_DOMAIN_INPUT_TYPE_KBD;
                if (virDomainInputDefFormat(buf, &autoInput, flags) < 0)
                    goto error;
            }
L
Li Zhang 已提交
22149 22150
        }

22151
        for (n = 0; n < def->ngraphics; n++)
22152
            if (virDomainGraphicsDefFormat(buf, def->graphics[n], flags) < 0)
22153
                goto error;
22154 22155
    }

22156
    for (n = 0; n < def->nsounds; n++)
22157
        if (virDomainSoundDefFormat(buf, def->sounds[n], flags) < 0)
22158
            goto error;
22159

22160
    for (n = 0; n < def->nvideos; n++)
22161
        if (virDomainVideoDefFormat(buf, def->videos[n], flags) < 0)
22162
            goto error;
22163

22164
    for (n = 0; n < def->nhostdevs; n++) {
22165 22166 22167 22168
        /* 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 已提交
22169 22170
        if (def->hostdevs[n]->parent.type == VIR_DOMAIN_DEVICE_NONE &&
            virDomainHostdevDefFormat(buf, def->hostdevs[n], flags) < 0) {
22171
            goto error;
22172 22173
        }
    }
22174

22175
    for (n = 0; n < def->nredirdevs; n++)
22176
        if (virDomainRedirdevDefFormat(buf, def->redirdevs[n], flags) < 0)
22177
            goto error;
22178

22179 22180 22181
    if (def->redirfilter)
        virDomainRedirFilterDefFormat(buf, def->redirfilter);

22182
    for (n = 0; n < def->nhubs; n++)
22183
        if (virDomainHubDefFormat(buf, def->hubs[n], flags) < 0)
22184
            goto error;
M
Marc-André Lureau 已提交
22185

R
Richard Jones 已提交
22186
    if (def->watchdog)
22187
        virDomainWatchdogDefFormat(buf, def->watchdog, flags);
R
Richard Jones 已提交
22188

22189
    if (def->memballoon)
22190
        virDomainMemballoonDefFormat(buf, def->memballoon, flags);
22191

22192 22193 22194 22195
    for (n = 0; n < def->nrngs; n++) {
        if (virDomainRNGDefFormat(buf, def->rngs[n], flags))
            goto error;
    }
22196

L
Li Zhang 已提交
22197 22198 22199
    if (def->nvram)
        virDomainNVRAMDefFormat(buf, def->nvram, flags);

D
Dmitry Andreev 已提交
22200 22201 22202
    for (n = 0; n < def->npanics; n++)
        if (virDomainPanicDefFormat(buf, def->panics[n]) < 0)
            goto error;
H
Hu Tao 已提交
22203

22204 22205 22206 22207
    for (n = 0; n < def->nshmems; n++)
        if (virDomainShmemDefFormat(buf, def->shmems[n], flags) < 0)
            goto error;

22208 22209 22210 22211
    for (n = 0; n < def->nmems; n++)
        if (virDomainMemoryDefFormat(buf, def->mems[n], flags) < 0)
            goto error;

22212 22213
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</devices>\n");
22214

22215
    for (n = 0; n < def->nseclabels; n++)
22216
        virSecurityLabelDefFormat(buf, def->seclabels[n]);
22217

22218
    if (def->namespaceData && def->ns.format) {
22219
        if ((def->ns.format)(buf, def->namespaceData) < 0)
22220
            goto error;
22221 22222
    }

22223 22224 22225
    if (def->keywrap)
        virDomainKeyWrapDefFormat(buf, def->keywrap);

22226
    virBufferAdjustIndent(buf, -2);
22227
    virBufferAddLit(buf, "</domain>\n");
22228

22229 22230
    if (virBufferCheckError(buf) < 0)
        goto error;
22231

22232
    return 0;
22233

22234
 error:
22235
    virBufferFreeAndReset(buf);
22236
    virBufferFreeAndReset(&childrenBuf);
22237
    return -1;
22238 22239
}

22240 22241 22242 22243 22244 22245 22246 22247 22248 22249 22250 22251 22252 22253 22254 22255 22256
unsigned int virDomainDefFormatConvertXMLFlags(unsigned int flags)
{
    unsigned int formatFlags = 0;

    if (flags & VIR_DOMAIN_XML_SECURE)
        formatFlags |= VIR_DOMAIN_DEF_FORMAT_SECURE;
    if (flags & VIR_DOMAIN_XML_INACTIVE)
        formatFlags |= VIR_DOMAIN_DEF_FORMAT_INACTIVE;
    if (flags & VIR_DOMAIN_XML_UPDATE_CPU)
        formatFlags |= VIR_DOMAIN_DEF_FORMAT_UPDATE_CPU;
    if (flags & VIR_DOMAIN_XML_MIGRATABLE)
        formatFlags |= VIR_DOMAIN_DEF_FORMAT_MIGRATABLE;

    return formatFlags;
}


22257 22258 22259
char *
virDomainDefFormat(virDomainDefPtr def, unsigned int flags)
{
22260 22261
    virBuffer buf = VIR_BUFFER_INITIALIZER;

22262
    virCheckFlags(VIR_DOMAIN_DEF_FORMAT_COMMON_FLAGS, NULL);
22263 22264 22265 22266
    if (virDomainDefFormatInternal(def, flags, &buf) < 0)
        return NULL;

    return virBufferContentAndReset(&buf);
22267 22268
}

22269

22270
char *
22271
virDomainObjFormat(virDomainXMLOptionPtr xmlopt,
22272 22273
                   virDomainObjPtr obj,
                   unsigned int flags)
22274 22275
{
    virBuffer buf = VIR_BUFFER_INITIALIZER;
J
Jiri Denemark 已提交
22276 22277
    int state;
    int reason;
22278
    size_t i;
22279

J
Jiri Denemark 已提交
22280
    state = virDomainObjGetState(obj, &reason);
22281
    virBufferAsprintf(&buf, "<domstatus state='%s' reason='%s' pid='%lld'>\n",
J
Jiri Denemark 已提交
22282 22283
                      virDomainStateTypeToString(state),
                      virDomainStateReasonToString(state, reason),
22284
                      (long long)obj->pid);
22285
    virBufferAdjustIndent(&buf, 2);
22286

22287
    for (i = 0; i < VIR_DOMAIN_TAINT_LAST; i++) {
22288
        if (obj->taint & (1 << i))
22289
            virBufferAsprintf(&buf, "<taint flag='%s'/>\n",
22290 22291 22292
                              virDomainTaintTypeToString(i));
    }

22293
    if (xmlopt->privateData.format &&
22294
        xmlopt->privateData.format(&buf, obj) < 0)
22295
        goto error;
22296

22297
    if (virDomainDefFormatInternal(obj->def, flags, &buf) < 0)
22298 22299
        goto error;

22300
    virBufferAdjustIndent(&buf, -2);
22301 22302
    virBufferAddLit(&buf, "</domstatus>\n");

22303 22304
    if (virBufferCheckError(&buf) < 0)
        goto error;
22305 22306 22307

    return virBufferContentAndReset(&buf);

22308
 error:
22309
    virBufferFreeAndReset(&buf);
22310 22311 22312
    return NULL;
}

22313 22314 22315
static bool
virDomainDefHasUSB(virDomainDefPtr def)
{
22316
    size_t i;
22317 22318 22319 22320 22321 22322 22323 22324 22325 22326 22327 22328 22329 22330 22331 22332 22333 22334 22335 22336 22337 22338 22339 22340 22341 22342 22343 22344 22345 22346 22347

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

22348 22349 22350 22351 22352 22353 22354 22355 22356 22357 22358 22359 22360 22361 22362 22363 22364
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;
}

22365 22366 22367 22368 22369 22370 22371 22372 22373 22374 22375 22376 22377 22378 22379 22380 22381 22382 22383 22384 22385 22386 22387 22388 22389 22390 22391 22392

/**
 * virDomainDefGetDiskByWWN:
 * @def: domain definition
 * @wwn: wwn of a disk to find
 *
 * Returns a disk definition pointer corresponding to the given WWN identifier
 * or NULL either if @wwn was NULL or if disk with given WWN is not present in
 * the domain definition.
 */
static virDomainDiskDefPtr
virDomainDefGetDiskByWWN(virDomainDefPtr def,
                         const char *wwn)
{
    size_t i;

    if (!wwn)
        return NULL;

    for (i = 0; i < def->ndisks; i++) {
        if (STREQ_NULLABLE(def->disks[i]->wwn, wwn))
            return def->disks[i];
    }

    return NULL;
}


22393 22394
int
virDomainDefCompatibleDevice(virDomainDefPtr def,
22395 22396
                             virDomainDeviceDefPtr dev,
                             virDomainDeviceAction action)
22397
{
22398 22399
    virDomainDeviceInfoPtr info = virDomainDeviceGetInfo(dev);

22400 22401 22402
    if (action != VIR_DOMAIN_DEVICE_ACTION_ATTACH)
        return 0;

22403
    if (!virDomainDefHasUSB(def) &&
22404
        def->os.type != VIR_DOMAIN_OSTYPE_EXE &&
22405 22406 22407 22408 22409 22410 22411
        virDomainDeviceIsUSB(dev)) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Device configuration is not compatible: "
                         "Domain has no USB bus support"));
        return -1;
    }

22412 22413 22414 22415 22416 22417 22418 22419 22420 22421 22422 22423 22424
    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;
    }

22425 22426 22427 22428 22429 22430 22431 22432 22433 22434 22435
    if (dev->type == VIR_DOMAIN_DEVICE_MEMORY) {
        unsigned long long sz = dev->data.memory->size;

        if ((virDomainDefGetMemoryActual(def) + sz) > def->mem.max_memory) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Attaching memory device with size '%llu' would "
                             "exceed domain's maxMemory config"), sz);
            return -1;
        }
    }

22436 22437 22438 22439 22440 22441 22442 22443 22444
    if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
        if (!!virDomainDefGetDiskByWWN(def, dev->data.disk->wwn)) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Domain already has a disk with wwn '%s'"),
                           dev->data.disk->wwn);
            return -1;
        }
    }

22445 22446 22447
    return 0;
}

22448 22449 22450 22451
int
virDomainSaveXML(const char *configDir,
                 virDomainDefPtr def,
                 const char *xml)
22452
{
J
Ján Tomko 已提交
22453
    char uuidstr[VIR_UUID_STRING_BUFLEN];
22454
    char *configFile = NULL;
22455
    int ret = -1;
22456

22457 22458 22459
    if (!configDir)
        return 0;

22460
    if ((configFile = virDomainConfigFile(configDir, def->name)) == NULL)
22461 22462
        goto cleanup;

22463
    if (virFileMakePath(configDir) < 0) {
22464
        virReportSystemError(errno,
22465 22466
                             _("cannot create config directory '%s'"),
                             configDir);
22467 22468 22469
        goto cleanup;
    }

J
Ján Tomko 已提交
22470 22471 22472 22473
    virUUIDFormat(def->uuid, uuidstr);
    ret = virXMLSaveFile(configFile,
                         virXMLPickShellSafeComment(def->name, uuidstr), "edit",
                         xml);
22474

22475
 cleanup:
R
Ryota Ozaki 已提交
22476
    VIR_FREE(configFile);
22477 22478 22479
    return ret;
}

22480 22481 22482
int
virDomainSaveConfig(const char *configDir,
                    virDomainDefPtr def)
22483 22484 22485
{
    int ret = -1;
    char *xml;
22486

22487
    if (!(xml = virDomainDefFormat(def, VIR_DOMAIN_DEF_FORMAT_SECURE)))
22488 22489
        goto cleanup;

22490
    if (virDomainSaveXML(configDir, def, xml))
22491 22492 22493
        goto cleanup;

    ret = 0;
22494
 cleanup:
22495
    VIR_FREE(xml);
22496 22497 22498
    return ret;
}

22499
int
22500
virDomainSaveStatus(virDomainXMLOptionPtr xmlopt,
22501 22502
                    const char *statusDir,
                    virDomainObjPtr obj)
22503
{
22504 22505 22506 22507 22508
    unsigned int flags = (VIR_DOMAIN_DEF_FORMAT_SECURE |
                          VIR_DOMAIN_DEF_FORMAT_STATUS |
                          VIR_DOMAIN_DEF_FORMAT_ACTUAL_NET |
                          VIR_DOMAIN_DEF_FORMAT_PCI_ORIG_STATES |
                          VIR_DOMAIN_DEF_FORMAT_CLOCK_ADJUST);
22509

22510 22511 22512
    int ret = -1;
    char *xml;

22513
    if (!(xml = virDomainObjFormat(xmlopt, obj, flags)))
22514 22515
        goto cleanup;

22516
    if (virDomainSaveXML(statusDir, obj->def, xml))
22517 22518 22519
        goto cleanup;

    ret = 0;
22520
 cleanup:
22521 22522 22523 22524
    VIR_FREE(xml);
    return ret;
}

22525

22526 22527 22528 22529
int
virDomainDeleteConfig(const char *configDir,
                      const char *autostartDir,
                      virDomainObjPtr dom)
22530
{
22531 22532 22533
    char *configFile = NULL, *autostartLink = NULL;
    int ret = -1;

22534
    if ((configFile = virDomainConfigFile(configDir, dom->def->name)) == NULL)
22535
        goto cleanup;
22536 22537
    if ((autostartLink = virDomainConfigFile(autostartDir,
                                             dom->def->name)) == NULL)
22538
        goto cleanup;
22539 22540

    /* Not fatal if this doesn't work */
22541
    unlink(autostartLink);
22542
    dom->autostart = 0;
22543

22544 22545
    if (unlink(configFile) < 0 &&
        errno != ENOENT) {
22546
        virReportSystemError(errno,
22547 22548
                             _("cannot remove config %s"),
                             configFile);
22549
        goto cleanup;
22550 22551
    }

22552 22553
    ret = 0;

22554
 cleanup:
22555 22556 22557
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
    return ret;
22558
}
22559

22560 22561 22562
char
*virDomainConfigFile(const char *dir,
                     const char *name)
22563
{
22564
    char *ret;
22565

22566
    ignore_value(virAsprintf(&ret, "%s/%s.xml", dir, name));
22567 22568 22569
    return ret;
}

22570 22571
/* 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 已提交
22572
 *                                               hdd => (1,1), vdaa => (0,26))
22573 22574 22575 22576 22577
 * @param disk The disk device
 * @param busIdx parsed bus number
 * @param devIdx parsed device number
 * @return 0 on success, -1 on failure
 */
22578
int
22579
virDiskNameToBusDeviceIndex(virDomainDiskDefPtr disk,
22580
                            int *busIdx,
22581 22582
                            int *devIdx)
{
22583 22584

    int idx = virDiskNameToIndex(disk->dst);
22585
    if (idx < 0)
22586 22587 22588 22589 22590 22591 22592 22593 22594 22595 22596 22597 22598 22599 22600
        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:
22601
        case VIR_DOMAIN_DISK_BUS_SD:
22602 22603 22604 22605 22606 22607 22608 22609
        default:
            *busIdx = 0;
            *devIdx = idx;
            break;
    }

    return 0;
}
22610

22611 22612 22613 22614 22615 22616 22617 22618 22619 22620 22621 22622 22623 22624 22625 22626
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;
}

22627
virDomainFSDefPtr
22628
virDomainGetFilesystemForTarget(virDomainDefPtr def,
22629
                                const char *target)
22630
{
22631
    size_t i;
22632

22633
    for (i = 0; i < def->nfss; i++) {
22634
        if (STREQ(def->fss[i]->dst, target))
22635 22636 22637 22638 22639 22640
            return def->fss[i];
    }

    return NULL;
}

22641

22642 22643 22644 22645 22646
int
virDomainChrDefForeach(virDomainDefPtr def,
                       bool abortOnError,
                       virDomainChrDefIterator iter,
                       void *opaque)
22647
{
22648
    size_t i;
22649 22650
    int rc = 0;

22651
    for (i = 0; i < def->nserials; i++) {
22652 22653 22654 22655 22656 22657 22658 22659 22660
        if ((iter)(def,
                   def->serials[i],
                   opaque) < 0)
            rc = -1;

        if (abortOnError && rc != 0)
            goto done;
    }

22661
    for (i = 0; i < def->nparallels; i++) {
22662 22663 22664 22665 22666 22667 22668 22669 22670
        if ((iter)(def,
                   def->parallels[i],
                   opaque) < 0)
            rc = -1;

        if (abortOnError && rc != 0)
            goto done;
    }

22671
    for (i = 0; i < def->nchannels; i++) {
22672 22673 22674 22675 22676 22677 22678 22679
        if ((iter)(def,
                   def->channels[i],
                   opaque) < 0)
            rc = -1;

        if (abortOnError && rc != 0)
            goto done;
    }
22680
    for (i = 0; i < def->nconsoles; i++) {
22681
        if ((iter)(def,
22682
                   def->consoles[i],
22683 22684 22685 22686 22687 22688 22689
                   opaque) < 0)
            rc = -1;

        if (abortOnError && rc != 0)
            goto done;
    }

22690
 done:
22691 22692 22693 22694
    return rc;
}


22695 22696 22697 22698 22699
int
virDomainSmartcardDefForeach(virDomainDefPtr def,
                             bool abortOnError,
                             virDomainSmartcardDefIterator iter,
                             void *opaque)
E
Eric Blake 已提交
22700
{
22701
    size_t i;
E
Eric Blake 已提交
22702 22703
    int rc = 0;

22704
    for (i = 0; i < def->nsmartcards; i++) {
E
Eric Blake 已提交
22705 22706 22707 22708 22709 22710 22711 22712 22713
        if ((iter)(def,
                   def->smartcards[i],
                   opaque) < 0)
            rc = -1;

        if (abortOnError && rc != 0)
            goto done;
    }

22714
 done:
E
Eric Blake 已提交
22715 22716 22717 22718
    return rc;
}


22719
/* Call iter(disk, name, depth, opaque) for each element of disk and
22720
 * its backing chain in the pre-populated disk->src.backingStore.
22721 22722 22723
 * ignoreOpenFailure determines whether to warn about a chain that
 * mentions a backing file without also having metadata on that
 * file.  */
22724 22725 22726 22727 22728
int
virDomainDiskDefForeachPath(virDomainDiskDefPtr disk,
                            bool ignoreOpenFailure,
                            virDomainDiskDefPathIterator iter,
                            void *opaque)
22729 22730 22731
{
    int ret = -1;
    size_t depth = 0;
22732
    virStorageSourcePtr tmp;
22733
    char *brokenRaw = NULL;
22734

22735
    if (!ignoreOpenFailure) {
22736
        if (virStorageFileChainGetBroken(disk->src, &brokenRaw) < 0)
22737
            goto cleanup;
22738

22739
        if (brokenRaw) {
22740
            virReportError(VIR_ERR_INTERNAL_ERROR,
22741
                           _("unable to visit backing chain file %s"),
22742
                           brokenRaw);
22743 22744
            goto cleanup;
        }
22745 22746
    }

22747
    for (tmp = disk->src; tmp; tmp = tmp->backingStore) {
22748 22749 22750 22751 22752 22753 22754 22755 22756 22757
        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++;
22758
    }
22759 22760 22761

    ret = 0;

22762
 cleanup:
22763
    VIR_FREE(brokenRaw);
22764 22765
    return ret;
}
22766 22767


22768 22769 22770 22771
/* 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).  */
22772
virDomainDefPtr
22773 22774
virDomainDefCopy(virDomainDefPtr src,
                 virCapsPtr caps,
22775
                 virDomainXMLOptionPtr xmlopt,
22776
                 bool migratable)
22777 22778
{
    char *xml;
22779
    virDomainDefPtr ret;
22780 22781
    unsigned int format_flags = VIR_DOMAIN_DEF_FORMAT_SECURE;
    unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
22782

22783
    if (migratable)
22784
        format_flags |= VIR_DOMAIN_DEF_FORMAT_INACTIVE | VIR_DOMAIN_DEF_FORMAT_MIGRATABLE;
22785

22786
    /* Easiest to clone via a round-trip through XML.  */
22787
    if (!(xml = virDomainDefFormat(src, format_flags)))
22788 22789
        return NULL;

22790
    ret = virDomainDefParseString(xml, caps, xmlopt, parse_flags);
22791 22792 22793 22794

    VIR_FREE(xml);
    return ret;
}
J
Jiri Denemark 已提交
22795

22796
virDomainDefPtr
22797 22798 22799
virDomainObjCopyPersistentDef(virDomainObjPtr dom,
                              virCapsPtr caps,
                              virDomainXMLOptionPtr xmlopt)
22800 22801 22802
{
    virDomainDefPtr cur;

22803
    cur = virDomainObjGetPersistentDef(caps, xmlopt, dom);
22804
    return virDomainDefCopy(cur, caps, xmlopt, false);
22805 22806
}

J
Jiri Denemark 已提交
22807 22808 22809 22810 22811 22812 22813 22814 22815 22816 22817 22818 22819 22820 22821 22822 22823

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 已提交
22824 22825 22826 22827 22828 22829 22830 22831 22832 22833 22834 22835 22836 22837 22838 22839 22840 22841 22842 22843 22844 22845 22846 22847 22848 22849
    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 已提交
22850 22851 22852 22853 22854 22855 22856 22857 22858 22859 22860 22861 22862 22863 22864 22865 22866 22867 22868 22869 22870 22871 22872 22873 22874 22875 22876 22877 22878 22879 22880 22881 22882
    }

    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);
22883 22884 22885 22886
    case VIR_DOMAIN_PMSUSPENDED:
        return virDomainPMSuspendedReasonTypeToString(reason);
    case VIR_DOMAIN_LAST:
        break;
J
Jiri Denemark 已提交
22887
    }
22888 22889
    VIR_WARN("Unexpected domain state: %d", state);
    return NULL;
J
Jiri Denemark 已提交
22890 22891 22892 22893 22894 22895 22896 22897 22898 22899 22900 22901 22902 22903 22904 22905 22906 22907 22908 22909 22910
}


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);
22911 22912 22913 22914
    case VIR_DOMAIN_PMSUSPENDED:
        return virDomainPMSuspendedReasonTypeFromString(reason);
    case VIR_DOMAIN_LAST:
        break;
J
Jiri Denemark 已提交
22915
    }
22916 22917
    VIR_WARN("Unexpected domain state: %d", state);
    return -1;
J
Jiri Denemark 已提交
22918
}
22919 22920 22921 22922 22923 22924 22925 22926 22927 22928 22929 22930 22931 22932 22933 22934 22935 22936


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

22937
const char *
22938 22939 22940 22941
virDomainNetGetActualBridgeName(virDomainNetDefPtr iface)
{
    if (iface->type == VIR_DOMAIN_NET_TYPE_BRIDGE)
        return iface->data.bridge.brname;
22942 22943
    if (iface->type == VIR_DOMAIN_NET_TYPE_NETWORK &&
        iface->data.network.actual &&
22944 22945
        (iface->data.network.actual->type == VIR_DOMAIN_NET_TYPE_BRIDGE ||
         iface->data.network.actual->type == VIR_DOMAIN_NET_TYPE_NETWORK))
22946 22947
        return iface->data.network.actual->data.bridge.brname;
    return NULL;
22948 22949
}

22950 22951 22952 22953 22954 22955 22956 22957 22958 22959 22960
int
virDomainNetGetActualBridgeMACTableManager(virDomainNetDefPtr iface)
{
    if (iface->type == VIR_DOMAIN_NET_TYPE_NETWORK &&
        iface->data.network.actual &&
        (iface->data.network.actual->type == VIR_DOMAIN_NET_TYPE_BRIDGE ||
         iface->data.network.actual->type == VIR_DOMAIN_NET_TYPE_NETWORK))
        return iface->data.network.actual->data.bridge.macTableManager;
    return 0;
}

22961
const char *
22962 22963 22964 22965
virDomainNetGetActualDirectDev(virDomainNetDefPtr iface)
{
    if (iface->type == VIR_DOMAIN_NET_TYPE_DIRECT)
        return iface->data.direct.linkdev;
22966 22967
    if (iface->type == VIR_DOMAIN_NET_TYPE_NETWORK &&
        iface->data.network.actual &&
22968
        iface->data.network.actual->type == VIR_DOMAIN_NET_TYPE_DIRECT)
22969 22970
        return iface->data.network.actual->data.direct.linkdev;
    return NULL;
22971 22972 22973 22974 22975 22976 22977
}

int
virDomainNetGetActualDirectMode(virDomainNetDefPtr iface)
{
    if (iface->type == VIR_DOMAIN_NET_TYPE_DIRECT)
        return iface->data.direct.mode;
22978 22979
    if (iface->type == VIR_DOMAIN_NET_TYPE_NETWORK &&
        iface->data.network.actual &&
22980
        iface->data.network.actual->type == VIR_DOMAIN_NET_TYPE_DIRECT)
22981 22982
        return iface->data.network.actual->data.direct.mode;
    return 0;
22983 22984
}

22985 22986 22987 22988 22989
virDomainHostdevDefPtr
virDomainNetGetActualHostdev(virDomainNetDefPtr iface)
{
    if (iface->type == VIR_DOMAIN_NET_TYPE_HOSTDEV)
        return &iface->data.hostdev.def;
E
Eric Blake 已提交
22990
    if (iface->type == VIR_DOMAIN_NET_TYPE_NETWORK &&
22991
        iface->data.network.actual &&
22992
        iface->data.network.actual->type == VIR_DOMAIN_NET_TYPE_HOSTDEV)
22993 22994 22995 22996
        return &iface->data.network.actual->data.hostdev.def;
    return NULL;
}

22997
virNetDevVPortProfilePtr
22998
virDomainNetGetActualVirtPortProfile(virDomainNetDefPtr iface)
22999
{
A
Ansis Atteka 已提交
23000 23001 23002
    switch (iface->type) {
    case VIR_DOMAIN_NET_TYPE_DIRECT:
    case VIR_DOMAIN_NET_TYPE_BRIDGE:
23003
    case VIR_DOMAIN_NET_TYPE_HOSTDEV:
23004
        return iface->virtPortProfile;
A
Ansis Atteka 已提交
23005 23006 23007 23008 23009 23010
    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:
23011
        case VIR_DOMAIN_NET_TYPE_HOSTDEV:
23012
            return iface->data.network.actual->virtPortProfile;
A
Ansis Atteka 已提交
23013 23014 23015 23016
        default:
            return NULL;
        }
    default:
23017
        return NULL;
A
Ansis Atteka 已提交
23018
    }
23019
}
23020

23021
virNetDevBandwidthPtr
23022 23023
virDomainNetGetActualBandwidth(virDomainNetDefPtr iface)
{
23024 23025 23026
    /* if there is an ActualNetDef, *always* return
     * its bandwidth rather than the NetDef's bandwidth.
     */
E
Eric Blake 已提交
23027
    if (iface->type == VIR_DOMAIN_NET_TYPE_NETWORK &&
23028
        iface->data.network.actual)
23029 23030 23031
        return iface->data.network.actual->bandwidth;
    return iface->bandwidth;
}
23032

23033 23034 23035
virNetDevVlanPtr
virDomainNetGetActualVlan(virDomainNetDefPtr iface)
{
23036 23037 23038 23039 23040
    virNetDevVlanPtr vlan = &iface->vlan;

    /* if there is an ActualNetDef, *always* return
     * its vlan rather than the NetDef's vlan.
     */
23041
    if (iface->type == VIR_DOMAIN_NET_TYPE_NETWORK &&
23042 23043 23044 23045 23046 23047
        iface->data.network.actual)
        vlan = &iface->data.network.actual->vlan;

    if (vlan->nTags > 0)
        return vlan;
    return NULL;
23048
}
23049

23050 23051 23052 23053 23054 23055 23056 23057 23058 23059 23060 23061

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


23062
/* Return listens[i] from the appropriate union for the graphics
23063
 * type, or NULL if this is an unsuitable type, or the index is out of
23064
 * bounds. If force0 is TRUE, i == 0, and there is no listen array,
23065 23066
 * allocate one with a single item. */
static virDomainGraphicsListenDefPtr
23067
virDomainGraphicsGetListen(virDomainGraphicsDefPtr def, size_t i, bool force0)
23068
{
E
Eric Blake 已提交
23069 23070 23071
    if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC ||
        def->type == VIR_DOMAIN_GRAPHICS_TYPE_RDP ||
        def->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) {
23072

23073
        if (!def->listens && (i == 0) && force0) {
23074
            if (VIR_ALLOC(def->listens) >= 0)
23075 23076 23077
                def->nListens = 1;
        }

23078
        if (!def->listens || (def->nListens <= i))
23079 23080
            return NULL;

23081
        return &def->listens[i];
23082 23083 23084 23085 23086 23087 23088 23089 23090 23091 23092 23093 23094 23095 23096 23097 23098 23099 23100 23101 23102
    }

    /* 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
23103
virDomainGraphicsListenGetType(virDomainGraphicsDefPtr def, size_t i)
23104 23105
{
    virDomainGraphicsListenDefPtr listenInfo
23106
        = virDomainGraphicsGetListen(def, i, false);
23107 23108 23109 23110 23111 23112 23113 23114 23115 23116 23117

    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
23118
virDomainGraphicsListenSetType(virDomainGraphicsDefPtr def, size_t i, int val)
23119 23120
{
    virDomainGraphicsListenDefPtr listenInfo
23121
        = virDomainGraphicsGetListen(def, i, true);
23122 23123 23124 23125 23126 23127 23128 23129 23130

    if (!listenInfo)
        return -1;
    listenInfo->type = val;
    return 0;
}


const char *
23131
virDomainGraphicsListenGetAddress(virDomainGraphicsDefPtr def, size_t i)
23132 23133
{
    virDomainGraphicsListenDefPtr listenInfo
23134
        = virDomainGraphicsGetListen(def, i, false);
23135

23136
    /* even a network can have a listen address */
23137
    if (!listenInfo ||
23138 23139
        !(listenInfo->type == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS ||
          listenInfo->type == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NETWORK))
23140 23141 23142 23143 23144 23145
        return NULL;
    return listenInfo->address;
}


/* Make a copy of up to len characters of address, and store it in
23146
 * listens[i].address. If setType is true, set the listen's type
23147 23148 23149
 * to 'address', otherwise leave type alone. */
int
virDomainGraphicsListenSetAddress(virDomainGraphicsDefPtr def,
23150
                                  size_t i, const char *address,
23151 23152 23153
                                  int len, bool setType)
{
    virDomainGraphicsListenDefPtr listenInfo
23154
        = virDomainGraphicsGetListen(def, i, true);
23155 23156 23157 23158 23159 23160 23161 23162

    if (!listenInfo)
        return -1;

    if (setType)
        listenInfo->type = VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS;

    if (!address) {
23163
        VIR_FREE(listenInfo->address);
23164 23165 23166
        return 0;
    }

23167
    if (VIR_STRNDUP(listenInfo->address, address, len) < 0)
23168 23169 23170 23171 23172 23173
        return -1;
    return 0;
}


const char *
23174
virDomainGraphicsListenGetNetwork(virDomainGraphicsDefPtr def, size_t i)
23175 23176
{
    virDomainGraphicsListenDefPtr listenInfo
23177
        = virDomainGraphicsGetListen(def, i, false);
23178 23179 23180 23181 23182 23183 23184 23185 23186

    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
23187
 * listens[i].network */
23188 23189
int
virDomainGraphicsListenSetNetwork(virDomainGraphicsDefPtr def,
23190
                                  size_t i, const char *network, int len)
23191 23192
{
    virDomainGraphicsListenDefPtr listenInfo
23193
        = virDomainGraphicsGetListen(def, i, true);
23194 23195 23196 23197 23198 23199 23200

    if (!listenInfo)
        return -1;

    listenInfo->type = VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NETWORK;

    if (!network) {
23201
        VIR_FREE(listenInfo->network);
23202 23203 23204
        return 0;
    }

23205
    if (VIR_STRNDUP(listenInfo->network, network, len) < 0)
23206 23207 23208
        return -1;
    return 0;
}
23209 23210 23211 23212 23213 23214 23215 23216 23217 23218 23219 23220 23221 23222 23223

/**
 * 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;
23224
    virMacAddr mac;
23225
    size_t i;
23226

23227
    if (virMacAddrParse(device, &mac) == 0)
23228 23229 23230 23231
        isMac = true;

    if (isMac) {
        for (i = 0; i < def->nnets; i++) {
23232
            if (virMacAddrCmp(&mac, &def->nets[i]->mac) == 0) {
23233 23234 23235 23236 23237 23238 23239 23240 23241 23242 23243 23244 23245 23246 23247
                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;
}
23248 23249 23250 23251 23252 23253 23254 23255

/**
 * 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
23256
 * DeviceDef that are valid when just the flag VIR_DOMAIN_DEF_PARSE_INACTIVE is
23257 23258 23259 23260 23261 23262 23263
 * 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
23264
virDomainDeviceDefCopy(virDomainDeviceDefPtr src,
23265
                       const virDomainDef *def,
23266 23267
                       virCapsPtr caps,
                       virDomainXMLOptionPtr xmlopt)
23268 23269 23270
{
    virDomainDeviceDefPtr ret = NULL;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
23271
    int flags = VIR_DOMAIN_DEF_FORMAT_INACTIVE | VIR_DOMAIN_DEF_FORMAT_SECURE;
23272 23273 23274
    char *xmlStr = NULL;
    int rc = -1;

23275
    switch ((virDomainDeviceType) src->type) {
23276 23277 23278 23279 23280 23281 23282 23283 23284 23285 23286 23287 23288 23289 23290 23291 23292 23293 23294 23295 23296 23297 23298 23299 23300 23301 23302 23303 23304 23305 23306 23307 23308 23309 23310 23311 23312 23313 23314
    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;
23315 23316 23317
    case VIR_DOMAIN_DEVICE_RNG:
        rc = virDomainRNGDefFormat(&buf, src->data.rng, flags);
        break;
23318 23319 23320
    case VIR_DOMAIN_DEVICE_CHR:
        rc = virDomainChrDefFormat(&buf, src->data.chr, flags);
        break;
23321 23322 23323
    case VIR_DOMAIN_DEVICE_TPM:
        rc = virDomainTPMDefFormat(&buf, src->data.tpm, flags);
        break;
23324 23325 23326
    case VIR_DOMAIN_DEVICE_PANIC:
        rc = virDomainPanicDefFormat(&buf, src->data.panic);
        break;
23327 23328 23329
    case VIR_DOMAIN_DEVICE_MEMORY:
        rc = virDomainMemoryDefFormat(&buf, src->data.memory, flags);
        break;
23330 23331 23332
    case VIR_DOMAIN_DEVICE_NONE:
    case VIR_DOMAIN_DEVICE_SMARTCARD:
    case VIR_DOMAIN_DEVICE_MEMBALLOON:
L
Li Zhang 已提交
23333
    case VIR_DOMAIN_DEVICE_NVRAM:
23334
    case VIR_DOMAIN_DEVICE_SHMEM:
23335
    case VIR_DOMAIN_DEVICE_LAST:
23336 23337 23338 23339
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Copying definition of '%d' type "
                         "is not implemented yet."),
                       src->type);
23340 23341 23342 23343 23344 23345 23346
        goto cleanup;
    }

    if (rc < 0)
        goto cleanup;

    xmlStr = virBufferContentAndReset(&buf);
23347 23348
    ret = virDomainDeviceDefParse(xmlStr, def, caps, xmlopt,
                                  VIR_DOMAIN_DEF_PARSE_INACTIVE);
23349

23350
 cleanup:
23351 23352 23353
    VIR_FREE(xmlStr);
    return ret;
}
O
Osier Yang 已提交
23354 23355


23356 23357 23358
virSecurityLabelDefPtr
virDomainDefGetSecurityLabelDef(virDomainDefPtr def, const char *model)
{
23359
    size_t i;
23360
    virSecurityLabelDefPtr seclabel = NULL;
23361 23362 23363 23364 23365 23366 23367 23368 23369 23370 23371

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

23372
    return seclabel;
23373 23374 23375
}


23376 23377 23378
virSecurityDeviceLabelDefPtr
virDomainChrDefGetSecurityLabelDef(virDomainChrDefPtr def, const char *model)
{
23379
    size_t i;
23380 23381 23382 23383 23384 23385 23386 23387 23388 23389 23390

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

23391 23392 23393 23394 23395 23396 23397 23398 23399 23400 23401 23402 23403 23404 23405 23406 23407 23408 23409 23410 23411 23412 23413 23414

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,
23415 23416
                       virDomainDeviceDefPtr dev,
                       bool reportError)
23417 23418 23419 23420 23421 23422 23423 23424
{
    virDomainDefFindDeviceCallbackData data = { devAlias, dev };

    dev->type = VIR_DOMAIN_DEVICE_NONE;
    virDomainDeviceInfoIterateInternal(def, virDomainDefFindDeviceCallback,
                                       true, &data);

    if (dev->type == VIR_DOMAIN_DEVICE_NONE) {
23425 23426 23427 23428 23429 23430
        if (reportError) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("no device found with alias %s"), devAlias);
        } else {
            VIR_DEBUG("no device found with alias %s", devAlias);
        }
23431 23432 23433 23434 23435
        return -1;
    }

    return 0;
}
23436 23437 23438 23439 23440 23441 23442 23443 23444 23445 23446

/**
 * 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
23447 23448
virDomainDiskSourceIsBlockType(virStorageSourcePtr src,
                               bool report)
23449
{
23450 23451 23452 23453 23454
    if (!src->path) {
        if (report)
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("source path not found for device='lun' "
                             "using type='%d'"), src->type);
23455
        return false;
23456
    }
23457

23458
    if (src->type == VIR_STORAGE_TYPE_BLOCK)
23459 23460 23461 23462 23463
        return true;

    /* For volume types, check the srcpool.
     * If it's a block type source pool, then it's possible
     */
23464 23465 23466
    if (src->type == VIR_STORAGE_TYPE_VOLUME &&
        src->srcpool &&
        src->srcpool->voltype == VIR_STORAGE_VOL_BLOCK) {
23467 23468 23469 23470
        /* 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.
         */
23471
         if (src->srcpool->pooltype == VIR_STORAGE_POOL_ISCSI &&
23472 23473 23474 23475 23476
             src->srcpool->mode == VIR_STORAGE_SOURCE_POOL_MODE_DIRECT) {
             if (report)
                 virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                                _("disk device='lun' for iSCSI is not "
                                  "supported with mode='direct'."));
23477
             return false;
23478
         }
23479

23480 23481
        return true;
    }
23482 23483 23484 23485
    if (report)
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("disk device='lun' is only valid for block "
                         "type disk source"));
23486 23487
    return false;
}
23488 23489 23490 23491 23492 23493 23494 23495 23496 23497 23498 23499 23500 23501 23502 23503


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

23504 23505 23506 23507 23508 23509
    if (type >= VIR_DOMAIN_METADATA_LAST) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("unknown metadata type '%d'"), type);
        goto cleanup;
    }

23510 23511 23512 23513 23514 23515 23516 23517 23518
    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:
23519 23520
        if (VIR_STRDUP(ret, def->description) < 0)
            goto cleanup;
23521 23522 23523
        break;

    case VIR_DOMAIN_METADATA_TITLE:
23524 23525
        if (VIR_STRDUP(ret, def->title) < 0)
            goto cleanup;
23526 23527 23528
        break;

    case VIR_DOMAIN_METADATA_ELEMENT:
23529 23530 23531 23532 23533
        if (!def->metadata)
            break;

        if (virXMLExtractNamespaceXML(def->metadata, uri, &ret) < 0)
            goto cleanup;
23534 23535
        break;

23536
    /* coverity[dead_error_begin] */
23537
    case VIR_DOMAIN_METADATA_LAST:
23538 23539 23540
        break;
    }

23541
    if (!ret)
23542 23543 23544
        virReportError(VIR_ERR_NO_DOMAIN_METADATA, "%s",
                       _("Requested metadata element is not present"));

23545
 cleanup:
23546 23547
    return ret;
}
23548

23549 23550 23551 23552 23553

static int
virDomainDefSetMetadata(virDomainDefPtr def,
                        int type,
                        const char *metadata,
23554 23555
                        const char *key,
                        const char *uri)
23556
{
23557 23558
    xmlDocPtr doc = NULL;
    xmlNodePtr old;
23559
    xmlNodePtr new = NULL;
23560
    char *tmp;
23561 23562
    int ret = -1;

23563 23564 23565 23566 23567 23568
    if (type >= VIR_DOMAIN_METADATA_LAST) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("unknown metadata type '%d'"), type);
        goto cleanup;
    }

23569 23570
    switch ((virDomainMetadataType) type) {
    case VIR_DOMAIN_METADATA_DESCRIPTION:
23571
        if (VIR_STRDUP(tmp, metadata) < 0)
23572
            goto cleanup;
23573 23574 23575

        VIR_FREE(def->description);
        def->description = tmp;
23576 23577 23578
        break;

    case VIR_DOMAIN_METADATA_TITLE:
23579
        if (VIR_STRDUP(tmp, metadata) < 0)
23580
            goto cleanup;
23581 23582 23583

        VIR_FREE(def->title);
        def->title = tmp;
23584 23585 23586
        break;

    case VIR_DOMAIN_METADATA_ELEMENT:
23587 23588 23589 23590 23591 23592 23593 23594 23595 23596 23597 23598 23599 23600 23601 23602 23603 23604 23605 23606 23607 23608 23609 23610 23611 23612 23613
        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);
        }

23614 23615
        if (new &&
            !(xmlAddChild(def->metadata, new))) {
23616 23617 23618 23619
            xmlFreeNode(new);
            virReportOOMError();
            goto cleanup;
        }
23620 23621
        break;

23622
    /* coverity[dead_error_begin] */
23623
    case VIR_DOMAIN_METADATA_LAST:
23624 23625 23626 23627 23628
        break;
    }

    ret = 0;

23629
 cleanup:
23630
    xmlFreeDoc(doc);
23631 23632 23633 23634
    return ret;
}


23635 23636 23637 23638
int
virDomainObjSetMetadata(virDomainObjPtr vm,
                        int type,
                        const char *metadata,
23639 23640
                        const char *key,
                        const char *uri,
23641 23642
                        virCapsPtr caps,
                        virDomainXMLOptionPtr xmlopt,
23643
                        const char *stateDir,
23644 23645 23646 23647 23648 23649 23650 23651 23652 23653
                        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)
23654
        return -1;
23655

23656
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
23657 23658
        if (virDomainDefSetMetadata(vm->def, type, metadata, key, uri) < 0)
            return -1;
23659

23660 23661 23662 23663
        if (virDomainSaveStatus(xmlopt, stateDir, vm) < 0)
            return -1;
    }

23664
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
23665 23666
        if (virDomainDefSetMetadata(persistentDef, type, metadata, key,
                                    uri) < 0)
23667
            return -1;
23668 23669

        if (virDomainSaveConfig(configDir, persistentDef) < 0)
23670
            return -1;
23671 23672
    }

23673
    return 0;
23674
}
23675 23676 23677 23678 23679 23680 23681 23682


bool
virDomainDefNeedsPlacementAdvice(virDomainDefPtr def)
{
    if (def->placement_mode == VIR_DOMAIN_CPU_PLACEMENT_MODE_AUTO)
        return true;

23683
    if (virDomainNumatuneHasPlacementAuto(def->numa))
23684 23685 23686 23687
        return true;

    return false;
}
23688 23689 23690


int
23691
virDomainDefCheckDuplicateDiskInfo(virDomainDefPtr def)
23692 23693 23694 23695 23696
{
    size_t i;
    size_t j;

    for (i = 0; i < def->ndisks; i++) {
23697
        if (def->disks[i]->wwn || def->disks[i]->serial) {
23698
            for (j = i + 1; j < def->ndisks; j++) {
23699 23700
                if (def->disks[i]->wwn &&
                    STREQ_NULLABLE(def->disks[i]->wwn,
23701 23702 23703 23704 23705 23706 23707
                                   def->disks[j]->wwn)) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("Disks '%s' and '%s' have identical WWN"),
                                   def->disks[i]->dst,
                                   def->disks[j]->dst);
                    return -1;
                }
23708 23709 23710 23711 23712 23713 23714 23715 23716 23717

                if (def->disks[i]->serial &&
                    STREQ_NULLABLE(def->disks[i]->serial,
                                   def->disks[j]->serial)) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("Disks '%s' and '%s' have identical serial"),
                                   def->disks[i]->dst,
                                   def->disks[j]->dst);
                    return -1;
                }
23718 23719 23720 23721 23722 23723
            }
        }
    }

    return 0;
}