domain_conf.c 756.7 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
virDomainDiskDefPtr
1288
virDomainDiskDefNew(virDomainXMLOptionPtr xmlopt)
1289 1290 1291
{
    virDomainDiskDefPtr ret;

1292 1293
    if (VIR_ALLOC(ret) < 0)
        return NULL;
1294

1295
    if (VIR_ALLOC(ret->src) < 0)
1296 1297
        goto error;

1298 1299 1300 1301 1302
    if (xmlopt &&
        xmlopt->privateData.diskNew &&
        !(ret->privateData = xmlopt->privateData.diskNew()))
        goto error;

1303
    return ret;
1304 1305

 error:
1306
    virDomainDiskDefFree(ret);
1307
    return NULL;
1308 1309 1310
}


1311 1312 1313 1314 1315 1316
void
virDomainDiskDefFree(virDomainDiskDefPtr def)
{
    if (!def)
        return;

1317
    virStorageSourceFree(def->src);
1318 1319
    VIR_FREE(def->serial);
    VIR_FREE(def->dst);
1320
    virStorageSourceFree(def->mirror);
1321 1322 1323
    VIR_FREE(def->wwn);
    VIR_FREE(def->vendor);
    VIR_FREE(def->product);
1324
    VIR_FREE(def->domain_name);
1325
    virDomainDeviceInfoClear(&def->info);
1326
    virObjectUnref(def->privateData);
1327

1328 1329 1330
    VIR_FREE(def);
}

1331

1332 1333 1334
int
virDomainDiskGetType(virDomainDiskDefPtr def)
{
1335
    return def->src->type;
1336 1337 1338 1339 1340 1341
}


void
virDomainDiskSetType(virDomainDiskDefPtr def, int type)
{
1342
    def->src->type = type;
1343 1344 1345 1346
}


const char *
1347
virDomainDiskGetSource(virDomainDiskDef const *def)
1348
{
1349
    return def->src->path;
1350 1351 1352 1353 1354 1355 1356
}


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

1359
    ret = VIR_STRDUP(def->src->path, src);
1360
    if (ret < 0)
1361
        def->src->path = tmp;
1362 1363 1364 1365 1366 1367 1368 1369 1370
    else
        VIR_FREE(tmp);
    return ret;
}


const char *
virDomainDiskGetDriver(virDomainDiskDefPtr def)
{
1371
    return def->src->driverName;
1372 1373 1374 1375 1376 1377 1378
}


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

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


int
virDomainDiskGetFormat(virDomainDiskDefPtr def)
{
1393
    return def->src->format;
1394 1395 1396 1397 1398 1399
}


void
virDomainDiskSetFormat(virDomainDiskDefPtr def, int format)
{
1400
    def->src->format = format;
1401 1402 1403
}


1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421
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:
1422
        def->opts.pciopts.chassisNr = -1;
1423 1424
        def->opts.pciopts.chassis = -1;
        def->opts.pciopts.port = -1;
1425
        break;
1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439
    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;
}


1440 1441 1442 1443 1444 1445 1446 1447 1448 1449
void virDomainControllerDefFree(virDomainControllerDefPtr def)
{
    if (!def)
        return;

    virDomainDeviceInfoClear(&def->info);

    VIR_FREE(def);
}

1450 1451 1452 1453 1454 1455 1456
void virDomainFSDefFree(virDomainFSDefPtr def)
{
    if (!def)
        return;

    VIR_FREE(def->src);
    VIR_FREE(def->dst);
1457
    virDomainDeviceInfoClear(&def->info);
1458 1459 1460 1461

    VIR_FREE(def);
}

1462 1463 1464 1465 1466 1467 1468 1469
void
virDomainActualNetDefFree(virDomainActualNetDefPtr def)
{
    if (!def)
        return;

    switch (def->type) {
    case VIR_DOMAIN_NET_TYPE_BRIDGE:
1470
    case VIR_DOMAIN_NET_TYPE_NETWORK:
1471 1472 1473 1474 1475
        VIR_FREE(def->data.bridge.brname);
        break;
    case VIR_DOMAIN_NET_TYPE_DIRECT:
        VIR_FREE(def->data.direct.linkdev);
        break;
1476 1477 1478
    case VIR_DOMAIN_NET_TYPE_HOSTDEV:
        virDomainHostdevDefClear(&def->data.hostdev.def);
        break;
1479 1480 1481 1482
    default:
        break;
    }

1483
    VIR_FREE(def->virtPortProfile);
1484
    virNetDevBandwidthFree(def->bandwidth);
1485
    virNetDevVlanClear(&def->vlan);
1486 1487 1488
    VIR_FREE(def);
}

1489 1490
void virDomainNetDefFree(virDomainNetDefPtr def)
{
1491 1492
    size_t i;

1493 1494 1495 1496 1497 1498 1499 1500 1501 1502
    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 已提交
1503 1504 1505 1506
    case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
        virDomainChrSourceDefFree(def->data.vhostuser);
        break;

1507 1508 1509
    case VIR_DOMAIN_NET_TYPE_SERVER:
    case VIR_DOMAIN_NET_TYPE_CLIENT:
    case VIR_DOMAIN_NET_TYPE_MCAST:
1510
    case VIR_DOMAIN_NET_TYPE_UDP:
1511
        VIR_FREE(def->data.socket.address);
1512
        VIR_FREE(def->data.socket.localaddr);
1513 1514 1515 1516
        break;

    case VIR_DOMAIN_NET_TYPE_NETWORK:
        VIR_FREE(def->data.network.name);
1517 1518
        VIR_FREE(def->data.network.portgroup);
        virDomainActualNetDefFree(def->data.network.actual);
1519 1520 1521 1522 1523
        break;

    case VIR_DOMAIN_NET_TYPE_BRIDGE:
        VIR_FREE(def->data.bridge.brname);
        break;
D
Daniel Veillard 已提交
1524 1525 1526 1527

    case VIR_DOMAIN_NET_TYPE_INTERNAL:
        VIR_FREE(def->data.internal.name);
        break;
1528 1529 1530 1531

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

1533 1534 1535 1536
    case VIR_DOMAIN_NET_TYPE_HOSTDEV:
        virDomainHostdevDefClear(&def->data.hostdev.def);
        break;

S
Stefan Berger 已提交
1537 1538 1539
    case VIR_DOMAIN_NET_TYPE_USER:
    case VIR_DOMAIN_NET_TYPE_LAST:
        break;
1540 1541
    }

1542 1543
    VIR_FREE(def->backend.tap);
    VIR_FREE(def->backend.vhost);
1544
    VIR_FREE(def->virtPortProfile);
1545
    VIR_FREE(def->script);
1546
    VIR_FREE(def->domain_name);
1547
    VIR_FREE(def->ifname);
1548 1549
    VIR_FREE(def->ifname_guest);
    VIR_FREE(def->ifname_guest_actual);
1550

1551 1552 1553 1554
    for (i = 0; i < def->nips; i++)
        VIR_FREE(def->ips[i]);
    VIR_FREE(def->ips);

1555
    for (i = 0; i < def->nroutes; i++)
1556
        virNetworkRouteDefFree(def->routes[i]);
1557 1558
    VIR_FREE(def->routes);

1559
    virDomainDeviceInfoClear(&def->info);
1560

1561 1562 1563
    VIR_FREE(def->filter);
    virNWFilterHashTableFree(def->filterparams);

1564
    virNetDevBandwidthFree(def->bandwidth);
1565
    virNetDevVlanClear(&def->vlan);
1566

1567 1568 1569
    VIR_FREE(def);
}

1570
void ATTRIBUTE_NONNULL(1)
1571
virDomainChrSourceDefClear(virDomainChrSourceDefPtr def)
1572 1573 1574 1575 1576 1577 1578 1579 1580
{
    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;

1581 1582 1583 1584 1585
    case VIR_DOMAIN_CHR_TYPE_NMDM:
        VIR_FREE(def->data.nmdm.master);
        VIR_FREE(def->data.nmdm.slave);
        break;

1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600
    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;
1601 1602 1603 1604

    case VIR_DOMAIN_CHR_TYPE_SPICEPORT:
        VIR_FREE(def->data.spiceport.channel);
        break;
1605
    }
1606 1607
}

1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623
/* 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:
1624
        if (VIR_STRDUP(dest->data.file.path, src->data.file.path) < 0)
1625 1626 1627 1628
            return -1;
        break;

    case VIR_DOMAIN_CHR_TYPE_UDP:
1629
        if (VIR_STRDUP(dest->data.udp.bindHost, src->data.udp.bindHost) < 0)
1630 1631
            return -1;

1632
        if (VIR_STRDUP(dest->data.udp.bindService, src->data.udp.bindService) < 0)
1633 1634
            return -1;

1635
        if (VIR_STRDUP(dest->data.udp.connectHost, src->data.udp.connectHost) < 0)
1636 1637
            return -1;

1638
        if (VIR_STRDUP(dest->data.udp.connectService, src->data.udp.connectService) < 0)
1639 1640 1641 1642
            return -1;
        break;

    case VIR_DOMAIN_CHR_TYPE_TCP:
1643
        if (VIR_STRDUP(dest->data.tcp.host, src->data.tcp.host) < 0)
1644 1645
            return -1;

1646
        if (VIR_STRDUP(dest->data.tcp.service, src->data.tcp.service) < 0)
1647 1648 1649 1650
            return -1;
        break;

    case VIR_DOMAIN_CHR_TYPE_UNIX:
1651
        if (VIR_STRDUP(dest->data.nix.path, src->data.nix.path) < 0)
1652 1653
            return -1;
        break;
1654 1655 1656 1657 1658 1659 1660 1661

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

S
Stefan Berger 已提交
1664 1665
    dest->type = src->type;

1666 1667 1668
    return 0;
}

1669 1670 1671 1672 1673 1674 1675 1676 1677
void virDomainChrSourceDefFree(virDomainChrSourceDefPtr def)
{
    if (!def)
        return;

    virDomainChrSourceDefClear(def);

    VIR_FREE(def);
}
1678

1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692
/* 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;

1693
    switch ((virDomainChrType)src->type) {
1694 1695 1696 1697 1698 1699
    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;
1700 1701 1702 1703
    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;
1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720
    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;

1721 1722 1723 1724 1725
    case VIR_DOMAIN_CHR_TYPE_SPICEPORT:
        return STREQ_NULLABLE(src->data.spiceport.channel,
                              tgt->data.spiceport.channel);
        break;

J
Ján Tomko 已提交
1726 1727 1728
    case VIR_DOMAIN_CHR_TYPE_SPICEVMC:
        return src->data.spicevmc == tgt->data.spicevmc;

1729
    case VIR_DOMAIN_CHR_TYPE_NULL:
1730 1731
    case VIR_DOMAIN_CHR_TYPE_VC:
    case VIR_DOMAIN_CHR_TYPE_STDIO:
1732 1733
    case VIR_DOMAIN_CHR_TYPE_LAST:
        break;
1734 1735
    }

J
Ján Tomko 已提交
1736
    return true;
1737 1738
}

1739 1740
void virDomainChrDefFree(virDomainChrDefPtr def)
{
1741 1742
    size_t i;

1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763
    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);
1764 1765
    virDomainDeviceInfoClear(&def->info);

1766 1767 1768 1769 1770 1771
    if (def->seclabels) {
        for (i = 0; i < def->nseclabels; i++)
            virSecurityDeviceLabelDefFree(def->seclabels[i]);
        VIR_FREE(def->seclabels);
    }

1772 1773 1774
    VIR_FREE(def);
}

E
Eric Blake 已提交
1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803
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);
}

1804 1805 1806 1807 1808 1809 1810 1811
void virDomainSoundCodecDefFree(virDomainSoundCodecDefPtr def)
{
    if (!def)
        return;

    VIR_FREE(def);
}

1812 1813 1814 1815 1816
void virDomainSoundDefFree(virDomainSoundDefPtr def)
{
    if (!def)
        return;

1817 1818
    virDomainDeviceInfoClear(&def->info);

1819
    size_t i;
1820
    for (i = 0; i < def->ncodecs; i++)
1821 1822 1823
        virDomainSoundCodecDefFree(def->codecs[i]);
    VIR_FREE(def->codecs);

1824 1825 1826
    VIR_FREE(def);
}

1827 1828 1829 1830 1831 1832 1833 1834 1835 1836
void virDomainMemballoonDefFree(virDomainMemballoonDefPtr def)
{
    if (!def)
        return;

    virDomainDeviceInfoClear(&def->info);

    VIR_FREE(def);
}

L
Li Zhang 已提交
1837 1838 1839 1840 1841 1842 1843 1844 1845 1846
void virDomainNVRAMDefFree(virDomainNVRAMDefPtr def)
{
    if (!def)
        return;

    virDomainDeviceInfoClear(&def->info);

    VIR_FREE(def);
}

R
Richard Jones 已提交
1847 1848 1849 1850 1851
void virDomainWatchdogDefFree(virDomainWatchdogDefPtr def)
{
    if (!def)
        return;

1852 1853
    virDomainDeviceInfoClear(&def->info);

R
Richard Jones 已提交
1854 1855 1856
    VIR_FREE(def);
}

1857 1858 1859 1860 1861 1862
void virDomainShmemDefFree(virDomainShmemDefPtr def)
{
    if (!def)
        return;

    virDomainDeviceInfoClear(&def->info);
1863
    virDomainChrSourceDefClear(&def->server.chr);
1864 1865 1866 1867
    VIR_FREE(def->name);
    VIR_FREE(def);
}

1868 1869 1870 1871 1872
void virDomainVideoDefFree(virDomainVideoDefPtr def)
{
    if (!def)
        return;

1873 1874
    virDomainDeviceInfoClear(&def->info);

1875
    VIR_FREE(def->accel);
1876 1877 1878
    VIR_FREE(def);
}

1879 1880 1881 1882
virDomainHostdevDefPtr virDomainHostdevDefAlloc(void)
{
    virDomainHostdevDefPtr def = NULL;

1883 1884
    if (VIR_ALLOC(def) < 0 ||
        VIR_ALLOC(def->info) < 0)
1885 1886 1887 1888
        VIR_FREE(def);
    return def;
}

1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899
static void
virDomainHostdevSubsysSCSIiSCSIClear(virDomainHostdevSubsysSCSIiSCSIPtr iscsisrc)
{
    if (!iscsisrc)
        return;
    VIR_FREE(iscsisrc->path);
    virStorageNetHostDefFree(iscsisrc->nhosts, iscsisrc->hosts);
    virStorageAuthDefFree(iscsisrc->auth);
    iscsisrc->auth = NULL;
}

1900 1901
void virDomainHostdevDefClear(virDomainHostdevDefPtr def)
{
1902 1903
    size_t i;

1904 1905 1906 1907 1908 1909 1910
    if (!def)
        return;

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

1911 1912 1913 1914 1915
    /* If there is a parent device object, it will handle freeing
     * def->info.
     */
    if (def->parent.type == VIR_DOMAIN_DEVICE_NONE)
        virDomainDeviceInfoFree(def->info);
1916

H
Han Cheng 已提交
1917 1918
    switch (def->mode) {
    case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
1919 1920 1921 1922 1923 1924 1925
        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;
1926 1927
        case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_NET:
            VIR_FREE(def->source.caps.u.net.iface);
1928 1929 1930
            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);
1931
            for (i = 0; i < def->source.caps.u.net.nroutes; i++)
1932
                virNetworkRouteDefFree(def->source.caps.u.net.routes[i]);
1933
            VIR_FREE(def->source.caps.u.net.routes);
1934
            break;
1935
        }
H
Han Cheng 已提交
1936 1937
        break;
    case VIR_DOMAIN_HOSTDEV_MODE_SUBSYS:
1938 1939 1940 1941 1942 1943 1944 1945 1946
        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 已提交
1947
        break;
1948
    }
1949 1950
}

1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967
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);
}

1968 1969 1970 1971 1972
void virDomainHostdevDefFree(virDomainHostdevDefPtr def)
{
    if (!def)
        return;

1973 1974 1975
    /* free all subordinate objects */
    virDomainHostdevDefClear(def);

1976 1977 1978 1979 1980
    /* If there is a parent device object, it will handle freeing
     * the memory.
     */
    if (def->parent.type == VIR_DOMAIN_DEVICE_NONE)
        VIR_FREE(def);
1981 1982
}

M
Marc-André Lureau 已提交
1983 1984 1985 1986 1987 1988 1989 1990 1991
void virDomainHubDefFree(virDomainHubDefPtr def)
{
    if (!def)
        return;

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

1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002
void virDomainRedirdevDefFree(virDomainRedirdevDefPtr def)
{
    if (!def)
        return;

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

    VIR_FREE(def);
}

2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016
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);
}

2017 2018 2019 2020 2021 2022 2023 2024 2025 2026
void virDomainMemoryDefFree(virDomainMemoryDefPtr def)
{
    if (!def)
        return;

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

2027 2028 2029 2030 2031
void virDomainDeviceDefFree(virDomainDeviceDefPtr def)
{
    if (!def)
        return;

2032
    switch ((virDomainDeviceType) def->type) {
2033 2034 2035
    case VIR_DOMAIN_DEVICE_DISK:
        virDomainDiskDefFree(def->data.disk);
        break;
2036 2037 2038
    case VIR_DOMAIN_DEVICE_LEASE:
        virDomainLeaseDefFree(def->data.lease);
        break;
2039 2040 2041 2042 2043 2044 2045 2046 2047
    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;
2048 2049 2050
    case VIR_DOMAIN_DEVICE_VIDEO:
        virDomainVideoDefFree(def->data.video);
        break;
2051 2052 2053
    case VIR_DOMAIN_DEVICE_HOSTDEV:
        virDomainHostdevDefFree(def->data.hostdev);
        break;
R
Richard Jones 已提交
2054 2055 2056
    case VIR_DOMAIN_DEVICE_WATCHDOG:
        virDomainWatchdogDefFree(def->data.watchdog);
        break;
2057 2058 2059
    case VIR_DOMAIN_DEVICE_CONTROLLER:
        virDomainControllerDefFree(def->data.controller);
        break;
2060 2061 2062
    case VIR_DOMAIN_DEVICE_GRAPHICS:
        virDomainGraphicsDefFree(def->data.graphics);
        break;
M
Marc-André Lureau 已提交
2063 2064 2065
    case VIR_DOMAIN_DEVICE_HUB:
        virDomainHubDefFree(def->data.hub);
        break;
2066 2067 2068
    case VIR_DOMAIN_DEVICE_REDIRDEV:
        virDomainRedirdevDefFree(def->data.redirdev);
        break;
2069 2070 2071
    case VIR_DOMAIN_DEVICE_RNG:
        virDomainRNGDefFree(def->data.rng);
        break;
2072 2073 2074
    case VIR_DOMAIN_DEVICE_CHR:
        virDomainChrDefFree(def->data.chr);
        break;
2075
    case VIR_DOMAIN_DEVICE_FS:
2076 2077
        virDomainFSDefFree(def->data.fs);
        break;
2078
    case VIR_DOMAIN_DEVICE_SMARTCARD:
2079 2080
        virDomainSmartcardDefFree(def->data.smartcard);
        break;
2081
    case VIR_DOMAIN_DEVICE_MEMBALLOON:
2082 2083
        virDomainMemballoonDefFree(def->data.memballoon);
        break;
L
Li Zhang 已提交
2084
    case VIR_DOMAIN_DEVICE_NVRAM:
2085 2086
        virDomainNVRAMDefFree(def->data.nvram);
        break;
2087 2088 2089
    case VIR_DOMAIN_DEVICE_SHMEM:
        virDomainShmemDefFree(def->data.shmem);
        break;
2090 2091 2092
    case VIR_DOMAIN_DEVICE_TPM:
        virDomainTPMDefFree(def->data.tpm);
        break;
2093 2094 2095
    case VIR_DOMAIN_DEVICE_PANIC:
        virDomainPanicDefFree(def->data.panic);
        break;
2096 2097 2098
    case VIR_DOMAIN_DEVICE_MEMORY:
        virDomainMemoryDefFree(def->data.memory);
        break;
2099
    case VIR_DOMAIN_DEVICE_LAST:
2100
    case VIR_DOMAIN_DEVICE_NONE:
2101
        break;
2102 2103 2104 2105 2106
    }

    VIR_FREE(def);
}

2107 2108 2109 2110 2111 2112
static void
virDomainClockDefClear(virDomainClockDefPtr def)
{
    if (def->offset == VIR_DOMAIN_CLOCK_OFFSET_TIMEZONE)
        VIR_FREE(def->data.timezone);

2113
    size_t i;
2114 2115 2116 2117 2118
    for (i = 0; i < def->ntimers; i++)
        VIR_FREE(def->timers[i]);
    VIR_FREE(def->timers);
}

2119
virDomainPinDefPtr *
2120
virDomainPinDefCopy(virDomainPinDefPtr *src, int npin)
2121
{
2122
    size_t i;
2123
    virDomainPinDefPtr *ret = NULL;
2124

2125
    if (VIR_ALLOC_N(ret, npin) < 0)
2126
        goto error;
2127

2128
    for (i = 0; i < npin; i++) {
2129
        if (VIR_ALLOC(ret[i]) < 0)
2130
            goto error;
2131
        ret[i]->id = src[i]->id;
H
Hu Tao 已提交
2132
        if ((ret[i]->cpumask = virBitmapNewCopy(src[i]->cpumask)) == NULL)
2133
            goto error;
2134 2135 2136 2137
    }

    return ret;

2138
 error:
2139
    if (ret) {
2140
        for (i = 0; i < npin; i++) {
2141
            if (ret[i]) {
H
Hu Tao 已提交
2142
                virBitmapFree(ret[i]->cpumask);
2143 2144 2145 2146
                VIR_FREE(ret[i]);
            }
        }
        VIR_FREE(ret);
2147 2148 2149 2150 2151
    }

    return NULL;
}

2152

2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165
static bool
virDomainIOThreadIDArrayHasPin(virDomainDefPtr def)
{
    size_t i;

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


2166 2167 2168 2169 2170
void
virDomainIOThreadIDDefFree(virDomainIOThreadIDDefPtr def)
{
    if (!def)
        return;
2171
    virBitmapFree(def->cpumask);
2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191
    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);
}


2192 2193 2194 2195
static int
virDomainIOThreadIDDefArrayInit(virDomainDefPtr def)
{
    int retval = -1;
2196 2197 2198 2199
    size_t i;
    ssize_t nxt = -1;
    virDomainIOThreadIDDefPtr iothrid = NULL;
    virBitmapPtr thrmap = NULL;
2200 2201 2202 2203 2204 2205 2206

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

2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221
    /* 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;
2222

2223 2224 2225 2226 2227 2228
    /* 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;
2229
        }
2230 2231 2232 2233 2234
        if (VIR_ALLOC(iothrid) < 0)
            goto error;
        iothrid->iothread_id = nxt;
        iothrid->autofill = true;
        def->iothreadids[def->niothreadids++] = iothrid;
2235
    }
2236

2237 2238 2239
    retval = 0;

 error:
2240
    virBitmapFree(thrmap);
2241 2242 2243 2244
    return retval;
}


2245
void
2246
virDomainPinDefFree(virDomainPinDefPtr def)
H
Hu Tao 已提交
2247 2248 2249 2250 2251 2252 2253 2254
{
    if (def) {
        virBitmapFree(def->cpumask);
        VIR_FREE(def);
    }
}

void
2255 2256
virDomainPinDefArrayFree(virDomainPinDefPtr *def,
                         int npin)
2257
{
2258
    size_t i;
2259

2260
    if (!def)
2261 2262
        return;

2263
    for (i = 0; i < npin; i++)
2264
        virDomainPinDefFree(def[i]);
2265 2266 2267 2268

    VIR_FREE(def);
}

2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279

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

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

H
Hu Tao 已提交
2280 2281 2282 2283 2284 2285 2286 2287 2288
void
virDomainPanicDefFree(virDomainPanicDefPtr panic)
{
    if (!panic)
        return;

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

2290 2291 2292 2293 2294 2295 2296 2297
void
virDomainLoaderDefFree(virDomainLoaderDefPtr loader)
{
    if (!loader)
        return;

    VIR_FREE(loader->path);
    VIR_FREE(loader->nvram);
2298
    VIR_FREE(loader->templt);
2299 2300 2301
    VIR_FREE(loader);
}

2302 2303
void virDomainDefFree(virDomainDefPtr def)
{
2304
    size_t i;
2305

2306 2307 2308
    if (!def)
        return;

2309 2310
    virDomainResourceDefFree(def->resource);

2311 2312 2313 2314 2315 2316
    /* 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().
     */
2317
    for (i = 0; i < def->nhostdevs; i++)
2318 2319 2320
        virDomainHostdevDefFree(def->hostdevs[i]);
    VIR_FREE(def->hostdevs);

2321
    for (i = 0; i < def->nleases; i++)
2322 2323 2324
        virDomainLeaseDefFree(def->leases[i]);
    VIR_FREE(def->leases);

2325
    for (i = 0; i < def->ngraphics; i++)
2326 2327
        virDomainGraphicsDefFree(def->graphics[i]);
    VIR_FREE(def->graphics);
2328

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

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

2337
    for (i = 0; i < def->ncontrollers; i++)
2338 2339 2340
        virDomainControllerDefFree(def->controllers[i]);
    VIR_FREE(def->controllers);

2341
    for (i = 0; i < def->nfss; i++)
2342 2343 2344
        virDomainFSDefFree(def->fss[i]);
    VIR_FREE(def->fss);

2345
    for (i = 0; i < def->nnets; i++)
2346 2347
        virDomainNetDefFree(def->nets[i]);
    VIR_FREE(def->nets);
2348

2349
    for (i = 0; i < def->nsmartcards; i++)
E
Eric Blake 已提交
2350 2351 2352
        virDomainSmartcardDefFree(def->smartcards[i]);
    VIR_FREE(def->smartcards);

2353
    for (i = 0; i < def->nserials; i++)
2354 2355 2356
        virDomainChrDefFree(def->serials[i]);
    VIR_FREE(def->serials);

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

2361
    for (i = 0; i < def->nchannels; i++)
2362 2363 2364
        virDomainChrDefFree(def->channels[i]);
    VIR_FREE(def->channels);

2365
    for (i = 0; i < def->nconsoles; i++)
2366 2367
        virDomainChrDefFree(def->consoles[i]);
    VIR_FREE(def->consoles);
2368

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

2373
    for (i = 0; i < def->nvideos; i++)
2374 2375 2376
        virDomainVideoDefFree(def->videos[i]);
    VIR_FREE(def->videos);

2377
    for (i = 0; i < def->nhubs; i++)
M
Marc-André Lureau 已提交
2378 2379 2380
        virDomainHubDefFree(def->hubs[i]);
    VIR_FREE(def->hubs);

2381
    for (i = 0; i < def->nredirdevs; i++)
2382 2383 2384
        virDomainRedirdevDefFree(def->redirdevs[i]);
    VIR_FREE(def->redirdevs);

2385 2386 2387
    for (i = 0; i < def->nrngs; i++)
        virDomainRNGDefFree(def->rngs[i]);
    VIR_FREE(def->rngs);
2388

2389 2390 2391 2392
    for (i = 0; i < def->nmems; i++)
        virDomainMemoryDefFree(def->mems[i]);
    VIR_FREE(def->mems);

2393 2394
    virDomainTPMDefFree(def->tpm);

D
Dmitry Andreev 已提交
2395 2396 2397
    for (i = 0; i < def->npanics; i++)
        virDomainPanicDefFree(def->panics[i]);
    VIR_FREE(def->panics);
H
Hu Tao 已提交
2398

2399 2400 2401
    VIR_FREE(def->idmap.uidmap);
    VIR_FREE(def->idmap.gidmap);

2402
    VIR_FREE(def->os.machine);
2403
    VIR_FREE(def->os.init);
2404
    for (i = 0; def->os.initargv && def->os.initargv[i]; i++)
2405 2406
        VIR_FREE(def->os.initargv[i]);
    VIR_FREE(def->os.initargv);
2407 2408 2409
    VIR_FREE(def->os.kernel);
    VIR_FREE(def->os.initrd);
    VIR_FREE(def->os.cmdline);
2410
    VIR_FREE(def->os.dtb);
2411
    VIR_FREE(def->os.root);
2412
    virDomainLoaderDefFree(def->os.loader);
2413 2414 2415
    VIR_FREE(def->os.bootloader);
    VIR_FREE(def->os.bootloaderArgs);

2416
    virDomainClockDefClear(&def->clock);
2417

2418
    VIR_FREE(def->name);
2419
    virBitmapFree(def->cpumask);
2420
    VIR_FREE(def->emulator);
2421
    VIR_FREE(def->description);
2422
    VIR_FREE(def->title);
2423

2424 2425
    virBlkioDeviceArrayClear(def->blkio.devices,
                             def->blkio.ndevices);
2426 2427
    VIR_FREE(def->blkio.devices);

R
Richard Jones 已提交
2428 2429
    virDomainWatchdogDefFree(def->watchdog);

C
Chris Lalancette 已提交
2430
    virDomainMemballoonDefFree(def->memballoon);
L
Li Zhang 已提交
2431
    virDomainNVRAMDefFree(def->nvram);
C
Chris Lalancette 已提交
2432

2433 2434 2435 2436
    for (i = 0; i < def->mem.nhugepages; i++)
        virBitmapFree(def->mem.hugepages[i].nodemask);
    VIR_FREE(def->mem.hugepages);

2437 2438 2439
    for (i = 0; i < def->nseclabels; i++)
        virSecurityLabelDefFree(def->seclabels[i]);
    VIR_FREE(def->seclabels);
2440

2441 2442
    virCPUDefFree(def->cpu);

2443 2444
    virDomainIOThreadIDDefArrayFree(def->iothreadids, def->niothreadids);

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

2447
    virBitmapFree(def->cputune.emulatorpin);
2448

2449 2450 2451 2452 2453 2454 2455 2456
    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);

2457
    virDomainNumaFree(def->numa);
O
Osier Yang 已提交
2458

2459 2460
    virSysinfoDefFree(def->sysinfo);

2461 2462
    virDomainRedirFilterDefFree(def->redirfilter);

2463 2464 2465 2466
    for (i = 0; i < def->nshmems; i++)
        virDomainShmemDefFree(def->shmems[i]);
    VIR_FREE(def->shmems);

2467 2468
    VIR_FREE(def->keywrap);

2469 2470 2471
    if (def->namespaceData && def->ns.free)
        (def->ns.free)(def->namespaceData);

2472 2473
    xmlFreeNode(def->metadata);

2474 2475 2476
    VIR_FREE(def);
}

2477
static void virDomainObjDispose(void *obj)
2478
{
2479
    virDomainObjPtr dom = obj;
2480

2481
    VIR_DEBUG("obj=%p", dom);
2482
    virCondDestroy(&dom->cond);
2483 2484 2485
    virDomainDefFree(dom->def);
    virDomainDefFree(dom->newDef);

2486 2487 2488
    if (dom->privateDataFreeFunc)
        (dom->privateDataFreeFunc)(dom->privateData);

2489
    virDomainSnapshotObjListFree(dom->snapshots);
2490 2491
}

2492
virDomainObjPtr
2493
virDomainObjNew(virDomainXMLOptionPtr xmlopt)
2494 2495 2496
{
    virDomainObjPtr domain;

2497 2498 2499
    if (virDomainObjInitialize() < 0)
        return NULL;

2500
    if (!(domain = virObjectLockableNew(virDomainObjClass)))
2501 2502
        return NULL;

2503 2504 2505 2506 2507 2508
    if (virCondInit(&domain->cond) < 0) {
        virReportSystemError(errno, "%s",
                             _("failed to initialize domain condition"));
        goto error;
    }

2509
    if (xmlopt->privateData.alloc) {
2510
        if (!(domain->privateData = (xmlopt->privateData.alloc)()))
2511
            goto error;
2512
        domain->privateDataFreeFunc = xmlopt->privateData.free;
2513 2514 2515 2516 2517
    }

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

2518
    virObjectLock(domain);
J
Jiri Denemark 已提交
2519 2520
    virDomainObjSetState(domain, VIR_DOMAIN_SHUTOFF,
                                 VIR_DOMAIN_SHUTOFF_UNKNOWN);
2521

2522
    VIR_DEBUG("obj=%p", domain);
2523
    return domain;
2524

2525
 error:
2526 2527
    virObjectUnref(domain);
    return NULL;
2528 2529
}

2530

2531 2532 2533 2534 2535
virDomainDefPtr
virDomainDefNew(void)
{
    virDomainDefPtr ret;

2536 2537 2538 2539 2540
    if (VIR_ALLOC(ret) < 0)
        return NULL;

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

2542 2543 2544 2545
    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;

2546
    return ret;
2547 2548 2549 2550

 error:
    virDomainDefFree(ret);
    return NULL;
2551 2552 2553 2554 2555 2556 2557
}


virDomainDefPtr
virDomainDefNewFull(const char *name,
                    const unsigned char *uuid,
                    int id)
2558 2559 2560
{
    virDomainDefPtr def;

2561
    if (!(def = virDomainDefNew()))
2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575
        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;
}


2576
void virDomainObjAssignDef(virDomainObjPtr domain,
2577
                           virDomainDefPtr def,
2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589
                           bool live,
                           virDomainDefPtr *oldDef)
{
    if (oldDef)
        *oldDef = NULL;
    if (virDomainObjIsActive(domain)) {
        if (oldDef)
            *oldDef = domain->newDef;
        else
            virDomainDefFree(domain->newDef);
        domain->newDef = def;
    } else {
2590
        if (live) {
2591 2592 2593 2594 2595
            /* save current configuration to be restored on domain shutdown */
            if (!domain->newDef)
                domain->newDef = domain->def;
            else
                virDomainDefFree(domain->def);
2596 2597
            domain->def = def;
        } else {
2598 2599 2600 2601
            if (oldDef)
                *oldDef = domain->def;
            else
                virDomainDefFree(domain->def);
2602 2603 2604 2605 2606
            domain->def = def;
        }
    }
}

2607

M
Michal Privoznik 已提交
2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629
/**
 * 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;
}

2630

2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649
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;
}


2650 2651 2652 2653 2654 2655 2656 2657
/**
 * 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
 */
2658 2659 2660 2661
int
virDomainObjWaitUntil(virDomainObjPtr vm,
                      unsigned long long whenms)
{
2662 2663 2664 2665 2666 2667 2668
    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;
2669 2670 2671 2672 2673
    }
    return 0;
}


2674 2675 2676 2677 2678
/*
 * 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 已提交
2679
 * @param xmlopt pointer to XML parser configuration object
2680
 * @param domain domain object pointer
2681 2682 2683 2684
 * @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.
2685 2686 2687 2688
 * @return 0 on success, -1 on failure
 */
int
virDomainObjSetDefTransient(virCapsPtr caps,
2689
                            virDomainXMLOptionPtr xmlopt,
2690 2691
                            virDomainObjPtr domain,
                            bool live)
2692 2693 2694
{
    int ret = -1;

2695
    if (!virDomainObjIsActive(domain) && !live)
2696 2697 2698 2699 2700 2701 2702 2703
        return 0;

    if (!domain->persistent)
        return 0;

    if (domain->newDef)
        return 0;

2704
    if (!(domain->newDef = virDomainDefCopy(domain->def, caps, xmlopt, false)))
2705 2706 2707
        goto out;

    ret = 0;
2708
 out:
2709 2710 2711
    return ret;
}

2712 2713 2714 2715 2716
/*
 * Return the persistent domain configuration. If domain is transient,
 * return the running config.
 *
 * @param caps pointer to capabilities info
W
Wang Rui 已提交
2717
 * @param xmlopt pointer to XML parser configuration object
2718 2719 2720 2721 2722
 * @param domain domain object pointer
 * @return NULL on error, virDOmainDefPtr on success
 */
virDomainDefPtr
virDomainObjGetPersistentDef(virCapsPtr caps,
2723
                             virDomainXMLOptionPtr xmlopt,
2724 2725
                             virDomainObjPtr domain)
{
2726
    if (virDomainObjSetDefTransient(caps, xmlopt, domain, false) < 0)
2727 2728 2729 2730 2731 2732 2733 2734
        return NULL;

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

2735 2736 2737

/**
 * virDomainObjUpdateModificationImpact:
2738
 *
2739 2740 2741 2742 2743 2744 2745 2746 2747
 * @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.
2748 2749
 */
int
2750 2751
virDomainObjUpdateModificationImpact(virDomainObjPtr vm,
                                     unsigned int *flags)
2752
{
2753
    bool isActive = virDomainObjIsActive(vm);
2754 2755 2756 2757 2758 2759 2760 2761 2762 2763

    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)) {
2764 2765
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("domain is not running"));
2766
        return -1;
2767 2768 2769
    }

    if (*flags & VIR_DOMAIN_AFFECT_CONFIG) {
2770
        if (!vm->persistent) {
2771
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
2772 2773
                           _("transient domains do not have any "
                             "persistent config"));
2774
            return -1;
2775
        }
2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799
    }

    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) {
2800
        if (!(*persistentDef = virDomainObjGetPersistentDef(caps, xmlopt, dom))) {
2801 2802
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Get persistent config failed"));
2803
            return -1;
2804 2805 2806
        }
    }

2807 2808
    return 0;
}
2809

2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837

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

2838
    if (persDef)
2839 2840 2841 2842 2843
        *persDef = NULL;

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

2844 2845
    if (virDomainObjIsActive(vm)) {
        if (liveDef && (flags & VIR_DOMAIN_AFFECT_LIVE))
2846 2847
            *liveDef = vm->def;

2848
        if (persDef && (flags & VIR_DOMAIN_AFFECT_CONFIG))
2849
            *persDef = vm->newDef;
2850 2851 2852 2853 2854 2855
    } else {
        if (persDef)
            *persDef = vm->def;
    }

    return 0;
2856 2857
}

2858

2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894
/**
 * 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;
}


2895 2896 2897 2898 2899 2900 2901
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;
}
2902

2903 2904 2905 2906 2907 2908 2909 2910
int virDomainDeviceAddressIsValid(virDomainDeviceInfoPtr info,
                                  int type)
{
    if (info->type != type)
        return 0;

    switch (info->type) {
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI:
2911
        return virDevicePCIAddressIsValid(&info->addr.pci, false);
2912 2913

    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE:
2914
        return 1;
2915

2916
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390:
2917
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO:
2918 2919 2920 2921 2922
        return 1;

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

2923
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB:
2924
        return 1;
2925 2926 2927 2928 2929
    }

    return 0;
}

2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963
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;
2964 2965
    case VIR_DOMAIN_DEVICE_SHMEM:
        return &device->data.shmem->info;
2966 2967
    case VIR_DOMAIN_DEVICE_RNG:
        return &device->data.rng->info;
2968 2969
    case VIR_DOMAIN_DEVICE_TPM:
        return &device->data.tpm->info;
2970 2971
    case VIR_DOMAIN_DEVICE_PANIC:
        return &device->data.panic->info;
2972 2973
    case VIR_DOMAIN_DEVICE_MEMORY:
        return &device->data.memory->info;
2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984

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

2985
static bool
2986
virDomainDeviceInfoNeedsFormat(virDomainDeviceInfoPtr info, unsigned int flags)
2987 2988
{
    if (info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
2989
        return true;
2990
    if (info->alias && !(flags & VIR_DOMAIN_DEF_FORMAT_INACTIVE))
2991 2992 2993
        return true;
    if (info->mastertype != VIR_DOMAIN_CONTROLLER_MASTER_NONE)
        return true;
J
Ján Tomko 已提交
2994
    if ((info->rombar != VIR_TRISTATE_SWITCH_ABSENT) ||
2995 2996 2997 2998 2999
        info->romfile)
        return true;
    if (info->bootIndex)
        return true;
    return false;
3000 3001
}

3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 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
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;
3064 3065 3066 3067 3068

    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DIMM:
        if (memcmp(&a->addr.dimm, &b->addr.dimm, sizeof(a->addr.dimm)))
            return false;
        break;
3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090
    }

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


3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103
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;

3104 3105
    if (VIR_STRDUP(dst->alias, src->alias) < 0 ||
        VIR_STRDUP(dst->romfile, src->romfile) < 0)
3106 3107 3108 3109
        return -1;
    return 0;
}

3110 3111
void virDomainDeviceInfoClear(virDomainDeviceInfoPtr info)
{
3112
    VIR_FREE(info->alias);
3113
    if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB)
3114
        VIR_FREE(info->addr.usb.port);
3115 3116
    memset(&info->addr, 0, sizeof(info->addr));
    info->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE;
3117
    VIR_FREE(info->romfile);
3118 3119 3120
}


3121
static int virDomainDeviceInfoClearAlias(virDomainDefPtr def ATTRIBUTE_UNUSED,
3122
                                         virDomainDeviceDefPtr device ATTRIBUTE_UNUSED,
3123 3124
                                         virDomainDeviceInfoPtr info,
                                         void *opaque ATTRIBUTE_UNUSED)
3125
{
3126 3127 3128 3129 3130
    VIR_FREE(info->alias);
    return 0;
}

static int virDomainDeviceInfoClearPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED,
3131
                                              virDomainDeviceDefPtr device ATTRIBUTE_UNUSED,
3132 3133 3134 3135
                                              virDomainDeviceInfoPtr info,
                                              void *opaque ATTRIBUTE_UNUSED)
{
    if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
3136 3137 3138
        memset(&info->addr, 0, sizeof(info->addr));
        info->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE;
    }
3139
    return 0;
3140 3141
}

3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154
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;
}

3155 3156 3157 3158 3159
static int
virDomainDeviceInfoIterateInternal(virDomainDefPtr def,
                                   virDomainDeviceInfoCallback cb,
                                   bool all,
                                   void *opaque)
3160
{
3161
    size_t i;
3162
    virDomainDeviceDef device;
3163

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

3294 3295 3296 3297 3298 3299 3300
    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;
    }

3301 3302
    /* Coverity is not very happy with this - all dead_error_condition */
#if !STATIC_ANALYSIS
3303
    /* This switch statement is here to trigger compiler warning when adding
E
Eric Blake 已提交
3304
     * a new device type. When you are adding a new field to the switch you
M
Martin Kletzander 已提交
3305
     * also have to add an iteration statement above. Otherwise the switch
3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326
     * 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 已提交
3327
    case VIR_DOMAIN_DEVICE_NVRAM:
3328
    case VIR_DOMAIN_DEVICE_SHMEM:
3329
    case VIR_DOMAIN_DEVICE_TPM:
3330
    case VIR_DOMAIN_DEVICE_PANIC:
3331
    case VIR_DOMAIN_DEVICE_LAST:
3332
    case VIR_DOMAIN_DEVICE_RNG:
3333
    case VIR_DOMAIN_DEVICE_MEMORY:
3334 3335
        break;
    }
3336
#endif
3337

3338
    return 0;
3339 3340 3341
}


3342 3343 3344 3345 3346 3347 3348 3349 3350
int
virDomainDeviceInfoIterate(virDomainDefPtr def,
                           virDomainDeviceInfoCallback cb,
                           void *opaque)
{
    return virDomainDeviceInfoIterateInternal(def, cb, false, opaque);
}


3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364
bool
virDomainDefHasDeviceAddress(virDomainDefPtr def,
                             virDomainDeviceInfoPtr info)
{
    if (virDomainDeviceInfoIterateInternal(def,
                                           virDomainDefHasDeviceAddressIterator,
                                           true,
                                           info) < 0)
        return true;

    return false;
}


3365 3366 3367 3368 3369 3370 3371 3372
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;
3373
    size_t i;
3374 3375 3376 3377 3378

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

    for (i = 0; i < def->ncontrollers; i++) {
        cont = def->controllers[i];
3379
        if ((int) cont->idx > max_idx[cont->type])
3380 3381 3382 3383 3384 3385 3386 3387
            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)))
3388
            goto cleanup;
3389 3390 3391 3392 3393 3394 3395 3396 3397
        nbitmaps++;
    }

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

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

J
Ján Tomko 已提交
3398
        if (virBitmapIsBitSet(bitmaps[cont->type], cont->idx)) {
3399 3400 3401 3402 3403 3404 3405 3406 3407 3408
            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;
3409
 cleanup:
3410 3411 3412 3413 3414
    for (i = 0; i < nbitmaps; i++)
        virBitmapFree(bitmaps[i]);
    return ret;
}

3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436
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;
}
3437

3438
/**
3439 3440
 * virDomainDefMetadataSanitize:
 * @def: Sanitize metadata for this def
3441 3442
 *
 * This function removes metadata elements in @def that share the namespace.
3443 3444
 * The first metadata entry of every duplicate namespace is kept. Additionally
 * elements with no namespace are deleted.
3445 3446
 */
static void
3447
virDomainDefMetadataSanitize(virDomainDefPtr def)
3448 3449 3450
{
    xmlNodePtr child;
    xmlNodePtr next;
3451
    xmlNodePtr dupl;
3452 3453 3454 3455

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

3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467
    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;
        }

3468 3469 3470 3471
        /* 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) {
3472
            dupl = NULL;
3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485

            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);
            }
        }
3486 3487

        child = child->next;
3488 3489 3490 3491
    }
}


3492
static int
3493 3494
virDomainDefPostParseMemory(virDomainDefPtr def,
                            unsigned int parseFlags)
3495
{
3496
    size_t i;
3497 3498
    unsigned long long numaMemory = 0;
    unsigned long long hotplugMemory = 0;
3499

3500 3501 3502 3503 3504
    /* 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);
3505

3506 3507 3508 3509
    if (numaMemory) {
        virDomainDefSetMemoryInitial(def, numaMemory);
    } else {
        /* calculate the sizes of hotplug memory */
3510
        for (i = 0; i < def->nmems; i++)
3511 3512 3513 3514 3515 3516 3517 3518 3519 3520
            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);
3521 3522
    }

3523 3524 3525 3526 3527 3528 3529
    if (virDomainDefGetMemoryInitial(def) == 0) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Memory size must be specified via <memory> or in the "
                         "<numa> configuration"));
        return -1;
    }

3530 3531
    if (def->mem.cur_balloon > virDomainDefGetMemoryActual(def) ||
        def->mem.cur_balloon == 0)
3532
        def->mem.cur_balloon = virDomainDefGetMemoryActual(def);
3533

3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549
    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;
    }

3550 3551 3552 3553 3554 3555
    return 0;
}


static int
virDomainDefPostParseInternal(virDomainDefPtr def,
3556 3557
                              virCapsPtr caps ATTRIBUTE_UNUSED,
                              unsigned int parseFlags)
3558 3559 3560 3561 3562 3563 3564 3565 3566 3567
{
    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;
    }

3568
    if (virDomainDefPostParseMemory(def, parseFlags) < 0)
3569 3570
        return -1;

3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584
    /*
     * 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
     */
3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597

    /* 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;
        }
    }
3598
    if (def->nconsoles > 0 && def->os.type == VIR_DOMAIN_OSTYPE_HVM &&
3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612
        (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) {
3613 3614 3615 3616
            if (VIR_APPEND_ELEMENT(def->serials,
                                   def->nserials,
                                   def->consoles[0]) < 0)
                return -1;
3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633

            /* 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)
3634
                return -1;
3635 3636 3637 3638 3639

            /* 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;
        }
3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660
    } 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;
3661 3662
    }

3663 3664
    if (virDomainDefRejectDuplicateControllers(def) < 0)
        return -1;
3665

3666 3667 3668
    if (virDomainDefRejectDuplicatePanics(def) < 0)
        return -1;

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

3673 3674
        if (timer->name == VIR_DOMAIN_TIMER_NAME_KVMCLOCK ||
            timer->name == VIR_DOMAIN_TIMER_NAME_HYPERVCLOCK) {
3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723
            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;
            }
        }
    }

3724
    /* clean up possibly duplicated metadata entries */
3725
    virDomainDefMetadataSanitize(def);
3726

3727 3728 3729 3730
    return 0;
}


3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 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
/* 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];

3780 3781
        if (hostdev->source.subsys.type != type ||
            hostdev->info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE)
3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 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
            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;
3848
    int ret = -1;
3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866

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

3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877
    /* If failed to find any VIR_DOMAIN_CONTROLLER_TYPE_SCSI or any space
     * on existing VIR_DOMAIN_CONTROLLER_TYPE_SCSI controller(s), then
     * try to add a new controller resulting in placement of this entry
     * as unit=0
     */
    if (ret == -1 &&
        virDomainDefMaybeAddController((virDomainDefPtr) def,
                                           VIR_DOMAIN_CONTROLLER_TYPE_SCSI,
                                           controller, -1) < 0)
        return -1;

3878 3879 3880 3881 3882 3883 3884 3885 3886 3887
    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;
}


3888 3889
static int
virDomainDeviceDefPostParseInternal(virDomainDeviceDefPtr dev,
3890
                                    const virDomainDef *def,
3891
                                    virCapsPtr caps ATTRIBUTE_UNUSED,
3892
                                    virDomainXMLOptionPtr xmlopt)
3893
{
3894 3895
    if (dev->type == VIR_DOMAIN_DEVICE_CHR) {
        virDomainChrDefPtr chr = dev->data.chr;
3896 3897
        const virDomainChrDef **arrPtr;
        size_t i, cnt;
3898

3899
        virDomainChrGetDomainPtrs(def, chr->deviceType, &arrPtr, &cnt);
3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910

        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;

3911 3912 3913
            for (i = 0; i < cnt; i++) {
                if (arrPtr[i]->target.port > maxport)
                    maxport = arrPtr[i]->target.port;
3914 3915 3916 3917 3918
            }

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

3920 3921 3922 3923 3924 3925 3926 3927
    /* 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;
    }

3928 3929 3930 3931
    /* verify disk source */
    if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
        virDomainDiskDefPtr disk = dev->data.disk;

3932 3933
        /* internal snapshots and config files are currently supported
         * only with rbd: */
3934 3935 3936 3937 3938 3939 3940 3941
        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;
            }
3942 3943 3944 3945 3946 3947 3948

            if (disk->src->configFile) {
                virReportError(VIR_ERR_XML_ERROR, "%s",
                               _("<config> element is currently supported "
                                 "only with 'rbd' disks"));
                return -1;
            }
3949
        }
3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971

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

        if (disk->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
3974
            virDomainDiskDefAssignAddress(xmlopt, disk, def) < 0)
3975
            return -1;
3976 3977
    }

3978 3979 3980 3981 3982 3983
    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);
    }

3984 3985 3986 3987
    if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV) {
        virDomainHostdevDefPtr hdev = dev->data.hostdev;

        if (hdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
3988 3989 3990 3991
            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) {
3992 3993 3994
                virReportError(VIR_ERR_XML_ERROR, "%s",
                               _("Cannot assign SCSI host device address"));
                return -1;
3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014
            } 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;
                }
            }
4015 4016
        }
    }
4017 4018 4019 4020
    return 0;
}


4021 4022
static int
virDomainDeviceDefPostParse(virDomainDeviceDefPtr dev,
4023
                            const virDomainDef *def,
4024 4025 4026 4027 4028
                            virCapsPtr caps,
                            virDomainXMLOptionPtr xmlopt)
{
    int ret;

4029
    if (xmlopt->config.devicesPostParseCallback) {
4030 4031 4032 4033 4034 4035
        ret = xmlopt->config.devicesPostParseCallback(dev, def, caps,
                                                      xmlopt->config.priv);
        if (ret < 0)
            return ret;
    }

4036
    if ((ret = virDomainDeviceDefPostParseInternal(dev, def, caps, xmlopt)) < 0)
4037 4038
        return ret;

4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060
    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);
}


4061
int
4062 4063
virDomainDefPostParse(virDomainDefPtr def,
                      virCapsPtr caps,
4064
                      unsigned int parseFlags,
4065 4066 4067 4068 4069 4070 4071 4072 4073 4074
                      virDomainXMLOptionPtr xmlopt)
{
    int ret;
    struct virDomainDefPostParseDeviceIteratorData data = {
        .def = def,
        .caps = caps,
        .xmlopt = xmlopt,
    };

    /* call the domain config callback */
4075
    if (xmlopt->config.domainPostParseCallback) {
4076 4077 4078 4079 4080 4081 4082
        ret = xmlopt->config.domainPostParseCallback(def, caps,
                                                     xmlopt->config.priv);
        if (ret < 0)
            return ret;
    }

    /* iterate the devices */
4083 4084 4085 4086
    if ((ret = virDomainDeviceInfoIterateInternal(def,
                                                  virDomainDefPostParseDeviceIterator,
                                                  true,
                                                  &data)) < 0)
4087 4088
        return ret;

4089

4090
    if ((ret = virDomainDefPostParseInternal(def, caps, parseFlags)) < 0)
4091 4092
        return ret;

4093 4094 4095 4096
    return 0;
}


4097 4098
void virDomainDefClearPCIAddresses(virDomainDefPtr def)
{
4099
    virDomainDeviceInfoIterate(def, virDomainDeviceInfoClearPCIAddress, NULL);
D
Daniel P. Berrange 已提交
4100 4101
}

4102 4103 4104 4105 4106
void virDomainDefClearCCWAddresses(virDomainDefPtr def)
{
    virDomainDeviceInfoIterate(def, virDomainDeviceInfoClearCCWAddress, NULL);
}

D
Daniel P. Berrange 已提交
4107 4108
void virDomainDefClearDeviceAliases(virDomainDefPtr def)
{
4109
    virDomainDeviceInfoIterate(def, virDomainDeviceInfoClearAlias, NULL);
4110 4111 4112
}


4113
/* Generate a string representation of a device address
4114
 * @info address Device address to stringify
4115
 */
E
Eric Blake 已提交
4116 4117 4118
static int ATTRIBUTE_NONNULL(2)
virDomainDeviceInfoFormat(virBufferPtr buf,
                          virDomainDeviceInfoPtr info,
E
Eric Blake 已提交
4119
                          unsigned int flags)
4120
{
4121
    if ((flags & VIR_DOMAIN_DEF_FORMAT_ALLOW_BOOT) && info->bootIndex)
4122
        virBufferAsprintf(buf, "<boot order='%d'/>\n", info->bootIndex);
4123

D
Daniel P. Berrange 已提交
4124
    if (info->alias &&
4125
        !(flags & VIR_DOMAIN_DEF_FORMAT_INACTIVE)) {
4126
        virBufferAsprintf(buf, "<alias name='%s'/>\n", info->alias);
D
Daniel P. Berrange 已提交
4127 4128
    }

4129
    if (info->mastertype == VIR_DOMAIN_CONTROLLER_MASTER_USB) {
4130
        virBufferAsprintf(buf, "<master startport='%d'/>\n",
4131 4132 4133
                          info->master.usb.startport);
    }

4134
    if ((flags & VIR_DOMAIN_DEF_FORMAT_ALLOW_ROM) &&
4135 4136
        (info->rombar || info->romfile)) {

4137
        virBufferAddLit(buf, "<rom");
4138 4139
        if (info->rombar) {

J
Ján Tomko 已提交
4140
            const char *rombar = virTristateSwitchTypeToString(info->rombar);
4141 4142

            if (!rombar) {
4143 4144 4145
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unexpected rom bar value %d"),
                               info->rombar);
4146 4147 4148
                return -1;
            }
            virBufferAsprintf(buf, " bar='%s'", rombar);
4149
        }
4150
        if (info->romfile)
4151
            virBufferEscapeString(buf, " file='%s'", info->romfile);
4152
        virBufferAddLit(buf, "/>\n");
4153 4154
    }

4155 4156
    if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE ||
        info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390)
4157 4158 4159
        return 0;

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

4163
    switch ((virDomainDeviceAddressType) info->type) {
4164
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI:
4165
        virBufferAsprintf(buf, " domain='0x%.4x' bus='0x%.2x' slot='0x%.2x' function='0x%.1x'",
4166 4167 4168 4169
                          info->addr.pci.domain,
                          info->addr.pci.bus,
                          info->addr.pci.slot,
                          info->addr.pci.function);
4170 4171
        if (info->addr.pci.multi) {
           virBufferAsprintf(buf, " multifunction='%s'",
J
Ján Tomko 已提交
4172
                             virTristateSwitchTypeToString(info->addr.pci.multi));
4173
        }
4174 4175
        break;

4176
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE:
4177
        virBufferAsprintf(buf, " controller='%d' bus='%d' target='%d' unit='%d'",
4178 4179
                          info->addr.drive.controller,
                          info->addr.drive.bus,
4180
                          info->addr.drive.target,
4181 4182 4183
                          info->addr.drive.unit);
        break;

4184
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL:
4185
        virBufferAsprintf(buf, " controller='%d' bus='%d' port='%d'",
4186
                          info->addr.vioserial.controller,
4187 4188
                          info->addr.vioserial.bus,
                          info->addr.vioserial.port);
4189 4190
        break;

E
Eric Blake 已提交
4191
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCID:
4192
        virBufferAsprintf(buf, " controller='%d' slot='%d'",
E
Eric Blake 已提交
4193 4194 4195 4196
                          info->addr.ccid.controller,
                          info->addr.ccid.slot);
        break;

M
Marc-André Lureau 已提交
4197
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB:
4198
        virBufferAsprintf(buf, " bus='%d' port='%s'",
M
Marc-André Lureau 已提交
4199 4200 4201 4202
                          info->addr.usb.bus,
                          info->addr.usb.port);
        break;

4203 4204 4205 4206 4207
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO:
        if (info->addr.spaprvio.has_reg)
            virBufferAsprintf(buf, " reg='0x%llx'", info->addr.spaprvio.reg);
        break;

4208 4209 4210 4211 4212 4213 4214
    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;

4215 4216 4217
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO:
        break;

H
Hu Tao 已提交
4218 4219 4220 4221 4222 4223 4224
    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;

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

4231 4232 4233 4234
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390:
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE:
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST:
        break;
4235 4236 4237 4238 4239 4240
    }

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

4241
static int
4242
virDomainDeviceDriveAddressParseXML(xmlNodePtr node,
4243 4244
                                    virDomainDeviceDriveAddressPtr addr)
{
4245
    char *bus, *unit, *controller, *target;
4246 4247 4248 4249 4250 4251
    int ret = -1;

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

    controller = virXMLPropString(node, "controller");
    bus = virXMLPropString(node, "bus");
4252
    target = virXMLPropString(node, "target");
4253 4254 4255
    unit = virXMLPropString(node, "unit");

    if (controller &&
4256
        virStrToLong_uip(controller, NULL, 10, &addr->controller) < 0) {
4257 4258
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Cannot parse <address> 'controller' attribute"));
4259 4260 4261 4262
        goto cleanup;
    }

    if (bus &&
4263
        virStrToLong_uip(bus, NULL, 10, &addr->bus) < 0) {
4264 4265
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Cannot parse <address> 'bus' attribute"));
4266 4267 4268
        goto cleanup;
    }

4269
    if (target &&
4270
        virStrToLong_uip(target, NULL, 10, &addr->target) < 0) {
4271 4272
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Cannot parse <address> 'target' attribute"));
4273 4274 4275
        goto cleanup;
    }

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

    ret = 0;

4285
 cleanup:
4286 4287
    VIR_FREE(controller);
    VIR_FREE(bus);
4288
    VIR_FREE(target);
4289 4290 4291 4292
    VIR_FREE(unit);
    return ret;
}

4293 4294 4295 4296 4297 4298 4299

static int
virDomainDeviceVirtioSerialAddressParseXML(
    xmlNodePtr node,
    virDomainDeviceVirtioSerialAddressPtr addr
)
{
4300
    char *controller, *bus, *port;
4301 4302 4303 4304 4305 4306
    int ret = -1;

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

    controller = virXMLPropString(node, "controller");
    bus = virXMLPropString(node, "bus");
4307
    port = virXMLPropString(node, "port");
4308 4309

    if (controller &&
4310
        virStrToLong_uip(controller, NULL, 10, &addr->controller) < 0) {
4311 4312
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Cannot parse <address> 'controller' attribute"));
4313 4314 4315 4316
        goto cleanup;
    }

    if (bus &&
4317
        virStrToLong_uip(bus, NULL, 10, &addr->bus) < 0) {
4318 4319
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Cannot parse <address> 'bus' attribute"));
4320 4321 4322
        goto cleanup;
    }

4323
    if (port &&
4324
        virStrToLong_uip(port, NULL, 10, &addr->port) < 0) {
4325 4326
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Cannot parse <address> 'port' attribute"));
4327 4328 4329
        goto cleanup;
    }

4330 4331
    ret = 0;

4332
 cleanup:
4333 4334
    VIR_FREE(controller);
    VIR_FREE(bus);
E
Eric Blake 已提交
4335
    VIR_FREE(port);
4336 4337 4338
    return ret;
}

4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355
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 &&
4356
            virStrToLong_uip(cssid, NULL, 0, &addr->cssid) < 0) {
4357 4358 4359 4360 4361
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Cannot parse <address> 'cssid' attribute"));
            goto cleanup;
        }
        if (ssid &&
4362
            virStrToLong_uip(ssid, NULL, 0, &addr->ssid) < 0) {
4363 4364 4365 4366 4367
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Cannot parse <address> 'ssid' attribute"));
            goto cleanup;
        }
        if (devno &&
4368
            virStrToLong_uip(devno, NULL, 0, &addr->devno) < 0) {
4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389
            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;

4390
 cleanup:
4391 4392 4393 4394 4395 4396
    VIR_FREE(cssid);
    VIR_FREE(ssid);
    VIR_FREE(devno);
    return ret;
}

E
Eric Blake 已提交
4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409
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 &&
4410
        virStrToLong_uip(controller, NULL, 10, &addr->controller) < 0) {
4411 4412
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Cannot parse <address> 'controller' attribute"));
E
Eric Blake 已提交
4413 4414 4415 4416
        goto cleanup;
    }

    if (slot &&
4417
        virStrToLong_uip(slot, NULL, 10, &addr->slot) < 0) {
4418 4419
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Cannot parse <address> 'slot' attribute"));
E
Eric Blake 已提交
4420 4421 4422 4423 4424
        goto cleanup;
    }

    ret = 0;

4425
 cleanup:
E
Eric Blake 已提交
4426 4427 4428 4429 4430
    VIR_FREE(controller);
    VIR_FREE(slot);
    return ret;
}

4431 4432 4433 4434
static int
virDomainDeviceUSBAddressParseXML(xmlNodePtr node,
                                  virDomainDeviceUSBAddressPtr addr)
{
4435 4436
    char *port, *bus, *tmp;
    unsigned int p;
4437 4438 4439 4440 4441 4442 4443 4444
    int ret = -1;

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

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

    if (port &&
4445
        ((virStrToLong_uip(port, &tmp, 10, &p) < 0 || (*tmp != '\0' && *tmp != '.')) ||
4446 4447 4448
         (*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'))))) {
4449 4450
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Cannot parse <address> 'port' attribute"));
4451 4452 4453
        goto cleanup;
    }

4454 4455 4456
    addr->port = port;
    port = NULL;

4457
    if (bus &&
4458
        virStrToLong_uip(bus, NULL, 10, &addr->bus) < 0) {
4459 4460
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Cannot parse <address> 'bus' attribute"));
4461 4462 4463 4464 4465
        goto cleanup;
    }

    ret = 0;

4466
 cleanup:
4467 4468 4469 4470 4471
    VIR_FREE(bus);
    VIR_FREE(port);
    return ret;
}

4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483
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) {
4484 4485
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Cannot parse <address> 'reg' attribute"));
4486 4487 4488 4489 4490 4491 4492 4493
            ret = -1;
            goto cleanup;
        }

        addr->has_reg = true;
    }

    ret = 0;
4494
 cleanup:
4495 4496 4497 4498
    VIR_FREE(reg);
    return ret;
}

4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511
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) {
4512 4513
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Cannot parse <master> 'startport' attribute"));
4514 4515 4516 4517 4518
        goto cleanup;
    }

    ret = 0;

4519
 cleanup:
4520 4521 4522 4523
    VIR_FREE(startport);
    return ret;
}

4524 4525 4526
static int
virDomainDeviceBootParseXML(xmlNodePtr node,
                            int *bootIndex,
4527
                            virHashTablePtr bootHash)
4528 4529 4530 4531 4532 4533 4534
{
    char *order;
    int boot;
    int ret = -1;

    order = virXMLPropString(node, "order");
    if (!order) {
4535 4536
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing boot order attribute"));
4537 4538 4539
        goto cleanup;
    } else if (virStrToLong_i(order, NULL, 10, &boot) < 0 ||
               boot <= 0) {
4540 4541 4542
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("incorrect boot order '%s', expecting positive integer"),
                       order);
4543 4544 4545
        goto cleanup;
    }

4546 4547 4548 4549 4550
    if (bootHash) {
        if (virHashLookup(bootHash, order)) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("boot order '%s' used for more than one device"),
                           order);
4551 4552
            goto cleanup;
        }
4553 4554 4555

        if (virHashAddEntry(bootHash, order, (void *) 1) < 0)
            goto cleanup;
4556 4557 4558 4559 4560
    }

    *bootIndex = boot;
    ret = 0;

4561
 cleanup:
4562 4563 4564 4565
    VIR_FREE(order);
    return ret;
}

H
Hu Tao 已提交
4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579
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 &&
4580
        virStrToLong_uip(iobase, NULL, 16, &addr->iobase) < 0) {
H
Hu Tao 已提交
4581 4582 4583 4584 4585 4586
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Cannot parse <address> 'iobase' attribute"));
        goto cleanup;
    }

    if (irq &&
4587
        virStrToLong_uip(irq, NULL, 16, &addr->irq) < 0) {
H
Hu Tao 已提交
4588 4589 4590 4591 4592 4593
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Cannot parse <address> 'irq' attribute"));
        goto cleanup;
    }

    ret = 0;
4594
 cleanup:
H
Hu Tao 已提交
4595 4596 4597 4598 4599
    VIR_FREE(iobase);
    VIR_FREE(irq);
    return ret;
}

4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634

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


4635 4636 4637 4638
/* Parse the XML definition for a device address
 * @param node XML nodeset to parse for device address definition
 */
static int
4639
virDomainDeviceInfoParseXML(xmlNodePtr node,
4640
                            virHashTablePtr bootHash,
4641
                            virDomainDeviceInfoPtr info,
E
Eric Blake 已提交
4642
                            unsigned int flags)
4643 4644 4645
{
    xmlNodePtr cur;
    xmlNodePtr address = NULL;
4646
    xmlNodePtr master = NULL;
D
Daniel P. Berrange 已提交
4647
    xmlNodePtr alias = NULL;
4648 4649
    xmlNodePtr boot = NULL;
    xmlNodePtr rom = NULL;
4650 4651 4652 4653 4654 4655 4656 4657
    char *type = NULL;
    int ret = -1;

    virDomainDeviceInfoClear(info);

    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
D
Daniel P. Berrange 已提交
4658
            if (alias == NULL &&
4659
                !(flags & VIR_DOMAIN_DEF_PARSE_INACTIVE) &&
D
Daniel P. Berrange 已提交
4660 4661 4662 4663
                xmlStrEqual(cur->name, BAD_CAST "alias")) {
                alias = cur;
            } else if (address == NULL &&
                       xmlStrEqual(cur->name, BAD_CAST "address")) {
4664
                address = cur;
4665 4666 4667
            } else if (master == NULL &&
                       xmlStrEqual(cur->name, BAD_CAST "master")) {
                master = cur;
4668
            } else if (boot == NULL &&
4669
                       (flags & VIR_DOMAIN_DEF_PARSE_ALLOW_BOOT) &&
4670 4671 4672
                       xmlStrEqual(cur->name, BAD_CAST "boot")) {
                boot = cur;
            } else if (rom == NULL &&
4673
                       (flags & VIR_DOMAIN_DEF_PARSE_ALLOW_ROM) &&
4674 4675
                       xmlStrEqual(cur->name, BAD_CAST "rom")) {
                rom = cur;
4676 4677 4678 4679 4680
            }
        }
        cur = cur->next;
    }

D
Daniel P. Berrange 已提交
4681 4682 4683
    if (alias)
        info->alias = virXMLPropString(alias, "name");

4684 4685 4686 4687 4688 4689
    if (master) {
        info->mastertype = VIR_DOMAIN_CONTROLLER_MASTER_USB;
        if (virDomainDeviceUSBMasterParseXML(master, &info->master.usb) < 0)
            goto cleanup;
    }

4690
    if (boot) {
4691
        if (virDomainDeviceBootParseXML(boot, &info->bootIndex, bootHash))
4692 4693 4694 4695 4696
            goto cleanup;
    }

    if (rom) {
        char *rombar = virXMLPropString(rom, "bar");
4697
        if (rombar &&
J
Ján Tomko 已提交
4698
            ((info->rombar = virTristateSwitchTypeFromString(rombar)) <= 0)) {
4699 4700
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown rom bar value '%s'"), rombar);
4701 4702 4703 4704
            VIR_FREE(rombar);
            goto cleanup;
        }
        VIR_FREE(rombar);
4705
        info->romfile = virXMLPropString(rom, "file");
4706 4707
    }

4708 4709 4710 4711 4712 4713
    if (!address)
        return 0;

    type = virXMLPropString(address, "type");

    if (type) {
4714
        if ((info->type = virDomainDeviceAddressTypeFromString(type)) <= 0) {
4715
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
4716
                           _("unknown address type '%s'"), type);
4717 4718 4719
            goto cleanup;
        }
    } else {
4720 4721
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("No type specified for device address"));
4722 4723 4724
        goto cleanup;
    }

4725
    switch ((virDomainDeviceAddressType) info->type) {
4726
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI:
4727
        if (virDevicePCIAddressParseXML(address, &info->addr.pci) < 0)
4728 4729 4730
            goto cleanup;
        break;

4731
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE:
4732
        if (virDomainDeviceDriveAddressParseXML(address, &info->addr.drive) < 0)
4733 4734 4735
            goto cleanup;
        break;

4736 4737 4738 4739 4740 4741
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL:
        if (virDomainDeviceVirtioSerialAddressParseXML
                (address, &info->addr.vioserial) < 0)
            goto cleanup;
        break;

E
Eric Blake 已提交
4742 4743 4744 4745 4746
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCID:
        if (virDomainDeviceCcidAddressParseXML(address, &info->addr.ccid) < 0)
            goto cleanup;
        break;

4747 4748 4749 4750 4751
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB:
        if (virDomainDeviceUSBAddressParseXML(address, &info->addr.usb) < 0)
            goto cleanup;
        break;

4752 4753 4754 4755 4756
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO:
        if (virDomainDeviceSpaprVioAddressParseXML(address, &info->addr.spaprvio) < 0)
            goto cleanup;
        break;

4757 4758 4759 4760 4761 4762
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW:
        if (virDomainDeviceCCWAddressParseXML
                (address, &info->addr.ccw) < 0)
            goto cleanup;
        break;

4763 4764 4765
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO:
        break;

H
Hu Tao 已提交
4766 4767 4768 4769 4770
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_ISA:
        if (virDomainDeviceISAAddressParseXML(address, &info->addr.isa) < 0)
            goto cleanup;
        break;

4771 4772 4773
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390:
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("virtio-s390 bus doesn't have an address"));
4774
        goto cleanup;
4775

4776 4777 4778 4779 4780
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DIMM:
        if (virDomainDeviceDimmAddressParseXML(address, &info->addr.dimm) < 0)
            goto cleanup;
        break;

4781 4782 4783
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE:
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST:
        break;
4784 4785 4786 4787
    }

    ret = 0;

4788
 cleanup:
D
Daniel P. Berrange 已提交
4789 4790
    if (ret == -1)
        VIR_FREE(info->alias);
4791 4792 4793 4794
    VIR_FREE(type);
    return ret;
}

4795 4796
static int
virDomainParseLegacyDeviceAddress(char *devaddr,
4797
                                  virDevicePCIAddressPtr pci)
4798 4799 4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811
{
    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;
}
4812

4813
static int
4814
virDomainHostdevSubsysUSBDefParseXML(xmlNodePtr node,
4815 4816 4817 4818
                                     virDomainHostdevDefPtr def)
{

    int ret = -1;
4819
    bool got_product, got_vendor;
4820
    xmlNodePtr cur;
4821
    char *startupPolicy = NULL;
4822
    char *autoAddress;
4823
    virDomainHostdevSubsysUSBPtr usbsrc = &def->source.subsys.u.usb;
4824 4825 4826 4827 4828

    if ((startupPolicy = virXMLPropString(node, "startupPolicy"))) {
        def->startupPolicy =
            virDomainStartupPolicyTypeFromString(startupPolicy);
        if (def->startupPolicy <= 0) {
4829
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
4830 4831 4832 4833 4834 4835 4836
                           _("Unknown startup policy '%s'"),
                           startupPolicy);
            VIR_FREE(startupPolicy);
            goto out;
        }
        VIR_FREE(startupPolicy);
    }
4837

4838 4839
    if ((autoAddress = virXMLPropString(node, "autoAddress"))) {
        if (STREQ(autoAddress, "yes"))
4840
            usbsrc->autoAddress = true;
4841 4842 4843
        VIR_FREE(autoAddress);
    }

4844 4845
    /* Product can validly be 0, so we need some extra help to determine
     * if it is uninitialized*/
4846 4847
    got_product = false;
    got_vendor = false;
4848 4849 4850 4851 4852 4853 4854 4855

    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) {
4856
                    got_vendor = true;
4857
                    if (virStrToLong_ui(vendor, NULL, 0, &usbsrc->vendor) < 0) {
4858 4859
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("cannot parse vendor id %s"), vendor);
4860 4861 4862 4863 4864
                        VIR_FREE(vendor);
                        goto out;
                    }
                    VIR_FREE(vendor);
                } else {
4865 4866
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   "%s", _("usb vendor needs id"));
4867 4868 4869 4870 4871 4872
                    goto out;
                }
            } else if (xmlStrEqual(cur->name, BAD_CAST "product")) {
                char* product = virXMLPropString(cur, "id");

                if (product) {
4873
                    got_product = true;
4874
                    if (virStrToLong_ui(product, NULL, 0,
4875
                                        &usbsrc->product) < 0) {
4876 4877 4878
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("cannot parse product %s"),
                                       product);
4879 4880 4881 4882 4883
                        VIR_FREE(product);
                        goto out;
                    }
                    VIR_FREE(product);
                } else {
4884 4885
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   "%s", _("usb product needs id"));
4886 4887 4888 4889 4890 4891 4892
                    goto out;
                }
            } else if (xmlStrEqual(cur->name, BAD_CAST "address")) {
                char *bus, *device;

                bus = virXMLPropString(cur, "bus");
                if (bus) {
4893
                    if (virStrToLong_ui(bus, NULL, 0, &usbsrc->bus) < 0) {
4894 4895
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("cannot parse bus %s"), bus);
4896 4897 4898 4899 4900
                        VIR_FREE(bus);
                        goto out;
                    }
                    VIR_FREE(bus);
                } else {
4901 4902
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   "%s", _("usb address needs bus id"));
4903 4904 4905 4906 4907
                    goto out;
                }

                device = virXMLPropString(cur, "device");
                if (device) {
4908
                    if (virStrToLong_ui(device, NULL, 0, &usbsrc->device) < 0) {
4909 4910 4911
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("cannot parse device %s"),
                                       device);
4912 4913 4914 4915 4916
                        VIR_FREE(device);
                        goto out;
                    }
                    VIR_FREE(device);
                } else {
4917 4918
                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                   _("usb address needs device id"));
4919 4920 4921
                    goto out;
                }
            } else {
4922 4923 4924
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unknown usb source type '%s'"),
                               cur->name);
4925 4926 4927 4928 4929 4930
                goto out;
            }
        }
        cur = cur->next;
    }

4931
    if (got_vendor && usbsrc->vendor == 0) {
4932 4933
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("vendor cannot be 0."));
4934 4935 4936 4937
        goto out;
    }

    if (!got_vendor && got_product) {
4938 4939
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing vendor"));
4940 4941 4942
        goto out;
    }
    if (got_vendor && !got_product) {
4943 4944
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing product"));
4945 4946 4947 4948
        goto out;
    }

    ret = 0;
4949
 out:
4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961
    return ret;
}

/* The internal XML for host PCI device's original states:
 *
 * <origstates>
 *   <unbind/>
 *   <removeslot/>
 *   <reprobe/>
 * </origstates>
 */
static int
4962
virDomainHostdevSubsysPCIOrigStatesDefParseXML(xmlNodePtr node,
4963 4964 4965 4966 4967 4968 4969 4970
                                               virDomainHostdevOrigStatesPtr def)
{
    xmlNodePtr cur;
    cur = node->children;

    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
            if (xmlStrEqual(cur->name, BAD_CAST "unbind")) {
4971
                def->states.pci.unbind_from_stub = true;
4972
            } else if (xmlStrEqual(cur->name, BAD_CAST "removeslot")) {
4973
                def->states.pci.remove_slot = true;
4974
            } else if (xmlStrEqual(cur->name, BAD_CAST "reprobe")) {
4975
                def->states.pci.reprobe = true;
4976
            } else {
4977 4978 4979
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unsupported element '%s' of 'origstates'"),
                               cur->name);
4980 4981 4982 4983 4984 4985 4986 4987 4988 4989
                return -1;
            }
        }
        cur = cur->next;
    }

    return 0;
}

static int
4990
virDomainHostdevSubsysPCIDefParseXML(xmlNodePtr node,
4991 4992 4993 4994 4995 4996 4997 4998 4999 5000
                                     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")) {
5001
                virDevicePCIAddressPtr addr =
5002
                    &def->source.subsys.u.pci.addr;
5003

5004
                if (virDevicePCIAddressParseXML(cur, addr) < 0)
5005
                    goto out;
5006
            } else if ((flags & VIR_DOMAIN_DEF_PARSE_STATUS) &&
5007 5008 5009 5010 5011
                       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,
5012
                                                      &def->info->addr.pci) < 0) {
5013 5014 5015
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Unable to parse devaddr parameter '%s'"),
                                   devaddr);
5016 5017 5018
                    VIR_FREE(devaddr);
                    goto out;
                }
5019
                def->info->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
5020
            } else if ((flags & VIR_DOMAIN_DEF_PARSE_PCI_ORIG_STATES) &&
5021 5022
                       xmlStrEqual(cur->name, BAD_CAST "origstates")) {
                virDomainHostdevOrigStatesPtr states = &def->origstates;
5023
                if (virDomainHostdevSubsysPCIOrigStatesDefParseXML(cur, states) < 0)
5024 5025
                    goto out;
            } else {
5026 5027 5028
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unknown pci source type '%s'"),
                               cur->name);
5029 5030 5031 5032 5033 5034 5035
                goto out;
            }
        }
        cur = cur->next;
    }

    ret = 0;
5036
 out:
5037 5038 5039
    return ret;
}

5040 5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 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
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 已提交
5113
static int
5114 5115
virDomainHostdevSubsysSCSIHostDefParseXML(xmlNodePtr sourcenode,
                                          virDomainHostdevSubsysSCSIPtr scsisrc)
H
Han Cheng 已提交
5116 5117 5118 5119 5120
{
    int ret = -1;
    bool got_address = false, got_adapter = false;
    xmlNodePtr cur;
    char *bus = NULL, *target = NULL, *unit = NULL;
5121
    virDomainHostdevSubsysSCSIHostPtr scsihostsrc = &scsisrc->u.host;
H
Han Cheng 已提交
5122

5123
    cur = sourcenode->children;
H
Han Cheng 已提交
5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 5142
    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;
                }

5143
                if (virStrToLong_uip(bus, NULL, 0, &scsihostsrc->bus) < 0) {
H
Han Cheng 已提交
5144 5145 5146 5147 5148
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("cannot parse bus '%s'"), bus);
                    goto cleanup;
                }

5149
                if (virStrToLong_uip(target, NULL, 0,
5150
                                    &scsihostsrc->target) < 0) {
H
Han Cheng 已提交
5151 5152 5153 5154 5155
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("cannot parse target '%s'"), target);
                    goto cleanup;
                }

5156
                if (virStrToLong_ullp(unit, NULL, 0, &scsihostsrc->unit) < 0) {
H
Han Cheng 已提交
5157 5158 5159 5160 5161 5162 5163 5164 5165 5166 5167 5168 5169
                    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;
                }
5170
                if (!(scsihostsrc->adapter = virXMLPropString(cur, "name"))) {
H
Han Cheng 已提交
5171 5172 5173 5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194
                    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;
5195
 cleanup:
H
Han Cheng 已提交
5196 5197 5198 5199 5200 5201
    VIR_FREE(bus);
    VIR_FREE(target);
    VIR_FREE(unit);
    return ret;
}

J
John Ferlan 已提交
5202 5203 5204 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228 5229 5230 5231 5232 5233 5234 5235 5236 5237 5238 5239 5240 5241 5242 5243 5244 5245 5246 5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264 5265 5266
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;
}

5267 5268 5269 5270
static int
virDomainHostdevSubsysSCSIDefParseXML(xmlNodePtr sourcenode,
                                      virDomainHostdevSubsysSCSIPtr scsisrc)
{
J
John Ferlan 已提交
5271 5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289 5290 5291 5292
    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;
5293 5294
}

5295

5296
static int
5297 5298 5299 5300 5301
virDomainHostdevDefParseXMLSubsys(xmlNodePtr node,
                                  xmlXPathContextPtr ctxt,
                                  const char *type,
                                  virDomainHostdevDefPtr def,
                                  unsigned int flags)
5302 5303 5304
{
    xmlNodePtr sourcenode;
    char *managed = NULL;
O
Osier Yang 已提交
5305
    char *sgio = NULL;
5306
    char *rawio = NULL;
5307 5308
    char *backendStr = NULL;
    int backend;
5309
    int ret = -1;
5310
    virDomainHostdevSubsysPCIPtr pcisrc = &def->source.subsys.u.pci;
5311
    virDomainHostdevSubsysSCSIPtr scsisrc = &def->source.subsys.u.scsi;
5312 5313 5314 5315 5316 5317

    /* @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 已提交
5318
    if ((managed = virXMLPropString(node, "managed")) != NULL) {
5319
        if (STREQ(managed, "yes"))
5320
            def->managed = true;
5321 5322
    }

O
Osier Yang 已提交
5323
    sgio = virXMLPropString(node, "sgio");
5324
    rawio = virXMLPropString(node, "rawio");
O
Osier Yang 已提交
5325

5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336
    /* @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) {
5337
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
5338 5339
                           _("unknown host device source address type '%s'"),
                           type);
5340 5341 5342
            goto error;
        }
    } else {
5343 5344
        virReportError(VIR_ERR_XML_ERROR,
                       "%s", _("missing source address type"));
5345 5346 5347 5348
        goto error;
    }

    if (!(sourcenode = virXPathNode("./source", ctxt))) {
5349 5350
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Missing <source> element in hostdev device"));
5351 5352
        goto error;
    }
5353 5354 5355 5356 5357 5358 5359 5360 5361

    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 已提交
5362
    if (sgio) {
5363
        if (def->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI) {
O
Osier Yang 已提交
5364 5365 5366 5367 5368
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("sgio is only supported for scsi host device"));
            goto error;
        }

5369
        if ((scsisrc->sgio = virDomainDeviceSGIOTypeFromString(sgio)) <= 0) {
5370
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
O
Osier Yang 已提交
5371 5372 5373 5374 5375
                           _("unknown sgio mode '%s'"), sgio);
            goto error;
        }
    }

5376 5377 5378 5379 5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 5390
    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;
        }
    }

5391 5392
    switch (def->source.subsys.type) {
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
5393
        if (virDomainHostdevSubsysPCIDefParseXML(sourcenode, def, flags) < 0)
5394
            goto error;
5395

5396
        backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT;
5397
        if ((backendStr = virXPathString("string(./driver/@name)", ctxt)) &&
5398
            (((backend = virDomainHostdevSubsysPCIBackendTypeFromString(backendStr)) < 0) ||
5399
             backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT)) {
5400
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
5401 5402 5403 5404
                           _("Unknown PCI device <driver name='%s'/> "
                             "has been specified"), backendStr);
            goto error;
        }
5405
        pcisrc->backend = backend;
5406

5407
        break;
5408

5409
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
5410
        if (virDomainHostdevSubsysUSBDefParseXML(sourcenode, def) < 0)
5411 5412
            goto error;
        break;
H
Han Cheng 已提交
5413 5414

    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
5415
        if (virDomainHostdevSubsysSCSIDefParseXML(sourcenode, scsisrc) < 0)
H
Han Cheng 已提交
5416 5417 5418
            goto error;
        break;

5419
    default:
5420 5421 5422
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("address type='%s' not supported in hostdev interfaces"),
                       virDomainHostdevSubsysTypeToString(def->source.subsys.type));
5423 5424
        goto error;
    }
5425

5426
    ret = 0;
5427
 error:
5428
    VIR_FREE(managed);
O
Osier Yang 已提交
5429
    VIR_FREE(sgio);
5430
    VIR_FREE(rawio);
5431
    VIR_FREE(backendStr);
5432 5433 5434
    return ret;
}

5435 5436 5437 5438
static virDomainNetIpDefPtr
virDomainNetIpParseXML(xmlNodePtr node)
{
    /* Parse the prefix in every case */
5439
    virDomainNetIpDefPtr ip = NULL, ret = NULL;
5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454
    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"));
5455
        goto cleanup;
5456 5457 5458 5459 5460 5461 5462 5463 5464 5465 5466
    }

    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)
5467
        goto cleanup;
5468 5469 5470 5471 5472

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

5477 5478
    ret = ip;
    ip = NULL;
5479

5480
 cleanup:
5481 5482 5483 5484
    VIR_FREE(prefixStr);
    VIR_FREE(familyStr);
    VIR_FREE(address);
    VIR_FREE(ip);
5485
    return ret;
5486 5487
}

5488 5489 5490 5491 5492 5493 5494
static int
virDomainHostdevDefParseXMLCaps(xmlNodePtr node ATTRIBUTE_UNUSED,
                                xmlXPathContextPtr ctxt,
                                const char *type,
                                virDomainHostdevDefPtr def)
{
    xmlNodePtr sourcenode;
5495 5496
    xmlNodePtr *ipnodes = NULL;
    int nipnodes;
5497 5498
    xmlNodePtr *routenodes = NULL;
    int nroutenodes;
5499 5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511
    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) {
5512
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
5513 5514 5515 5516 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545
                           _("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;
5546 5547 5548 5549 5550 5551 5552
    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;
        }
5553 5554 5555 5556 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569 5570 5571 5572

        /* 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;
                }
            }
        }
5573 5574 5575 5576 5577 5578 5579 5580

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

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

5583 5584 5585
                if (!(route = virNetworkRouteDefParseXML(_("Domain hostdev device"),
                                                         routenodes[i],
                                                         ctxt)))
5586 5587
                    goto error;

5588

5589 5590
                if (VIR_APPEND_ELEMENT(def->source.caps.u.net.routes,
                                       def->source.caps.u.net.nroutes, route) < 0) {
5591
                    virNetworkRouteDefFree(route);
5592 5593 5594 5595
                    goto error;
                }
            }
        }
5596
        break;
5597 5598 5599 5600 5601 5602 5603
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("address type='%s' not supported in hostdev interfaces"),
                       virDomainHostdevCapsTypeToString(def->source.caps.type));
        goto error;
    }
    ret = 0;
5604
 error:
5605
    VIR_FREE(ipnodes);
5606
    VIR_FREE(routenodes);
5607 5608 5609
    return ret;
}

5610
int
H
Han Cheng 已提交
5611 5612 5613
virDomainDeviceFindControllerModel(virDomainDefPtr def,
                                   virDomainDeviceInfoPtr info,
                                   int controllerType)
5614 5615
{
    int model = -1;
5616
    size_t i;
5617 5618 5619

    for (i = 0; i < def->ncontrollers; i++) {
        if (def->controllers[i]->type == controllerType &&
H
Han Cheng 已提交
5620
            def->controllers[i]->idx == info->addr.drive.controller)
5621 5622 5623 5624 5625 5626
            model = def->controllers[i]->model;
    }

    return model;
}

5627 5628 5629 5630 5631
virDomainDiskDefPtr
virDomainDiskFindByBusAndDst(virDomainDefPtr def,
                             int bus,
                             char *dst)
{
5632
    size_t i;
5633 5634 5635 5636

    if (!dst)
        return NULL;

5637
    for (i = 0; i < def->ndisks; i++) {
5638 5639 5640 5641 5642 5643 5644 5645 5646
        if (def->disks[i]->bus == bus &&
            STREQ(def->disks[i]->dst, dst)) {
            return def->disks[i];
        }
    }

    return NULL;
}

5647

5648
int
5649
virDomainDiskDefAssignAddress(virDomainXMLOptionPtr xmlopt,
5650 5651
                              virDomainDiskDefPtr def,
                              const virDomainDef *vmdef)
5652 5653
{
    int idx = virDiskNameToIndex(def->dst);
5654 5655 5656 5657
    if (idx < 0) {
        virReportError(VIR_ERR_XML_ERROR,
                       _("Unknown disk name '%s' and no address specified"),
                       def->dst);
5658
        return -1;
5659
    }
5660 5661

    switch (def->bus) {
5662 5663 5664 5665
    case VIR_DOMAIN_DISK_BUS_SCSI: {
        unsigned int controller;
        unsigned int unit;

5666
        def->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE;
5667

5668
        if (xmlopt->config.hasWideSCSIBus) {
5669 5670 5671 5672 5673
            /* 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.
             */
5674 5675
            controller = idx / 15;
            unit = idx % 15;
5676 5677

            /* Skip the SCSI controller at unit 7 */
5678 5679
            if (unit >= 7)
                ++unit;
5680 5681 5682
        } else {
            /* For a narrow SCSI bus we define the default mapping to be
             * 7 units per bus, 1 bus per controller, many controllers */
5683 5684
            controller = idx / 7;
            unit = idx % 7;
5685 5686
        }

5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697
        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;
        }

5698 5699 5700 5701
        def->info.addr.drive.controller = controller;
        def->info.addr.drive.bus = 0;
        def->info.addr.drive.target = 0;
        def->info.addr.drive.unit = unit;
5702
        break;
5703
    }
5704 5705 5706 5707 5708 5709 5710 5711 5712 5713

    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 已提交
5714 5715 5716 5717 5718 5719 5720 5721 5722
    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;

5723 5724 5725 5726 5727 5728 5729 5730 5731 5732 5733 5734 5735
    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;
    }
5736 5737

    return 0;
5738 5739
}

5740 5741
static virSecurityLabelDefPtr
virSecurityLabelDefParseXML(xmlXPathContextPtr ctxt,
5742
                            unsigned int flags)
E
Eric Blake 已提交
5743 5744
{
    char *p;
5745
    virSecurityLabelDefPtr seclabel = NULL;
E
Eric Blake 已提交
5746

5747 5748 5749 5750
    p = virXPathStringLimit("string(./@model)",
                            VIR_SECURITY_MODEL_BUFLEN - 1, ctxt);

    if (!(seclabel = virSecurityLabelDefNew(p)))
5751
        goto error;
5752
    VIR_FREE(p);
E
Eric Blake 已提交
5753

5754 5755 5756
    /* set default value */
    seclabel->type = VIR_DOMAIN_SECLABEL_DYNAMIC;

5757
    p = virXPathStringLimit("string(./@type)",
5758 5759 5760 5761
                            VIR_SECURITY_LABEL_BUFLEN - 1, ctxt);
    if (p) {
        seclabel->type = virDomainSeclabelTypeFromString(p);
        if (seclabel->type <= 0) {
5762
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
5763
                           _("invalid security type '%s'"), p);
E
Eric Blake 已提交
5764 5765
            goto error;
        }
5766
    }
5767

5768 5769 5770 5771 5772
    if (seclabel->type == VIR_DOMAIN_SECLABEL_STATIC ||
        seclabel->type == VIR_DOMAIN_SECLABEL_NONE)
        seclabel->relabel = false;

    VIR_FREE(p);
5773
    p = virXPathStringLimit("string(./@relabel)",
E
Eric Blake 已提交
5774
                            VIR_SECURITY_LABEL_BUFLEN-1, ctxt);
5775
    if (p) {
E
Eric Blake 已提交
5776
        if (STREQ(p, "yes")) {
5777
            seclabel->relabel = true;
E
Eric Blake 已提交
5778
        } else if (STREQ(p, "no")) {
5779
            seclabel->relabel = false;
E
Eric Blake 已提交
5780
        } else {
5781 5782
            virReportError(VIR_ERR_XML_ERROR,
                           _("invalid security relabel value %s"), p);
5783
            goto error;
E
Eric Blake 已提交
5784 5785
        }
    }
5786
    VIR_FREE(p);
E
Eric Blake 已提交
5787

5788 5789 5790 5791 5792 5793 5794 5795 5796 5797 5798 5799
    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;
    }
5800 5801 5802 5803

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

5804
    if (STREQ_NULLABLE(seclabel->model, "none")) {
5805
        if (flags & VIR_DOMAIN_DEF_PARSE_INACTIVE) {
5806
            /* Fix older configurations */
5807 5808
            seclabel->type = VIR_DOMAIN_SECLABEL_NONE;
            seclabel->relabel = false;
5809
        } else {
5810
            if (seclabel->type != VIR_DOMAIN_SECLABEL_NONE) {
5811 5812
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("unsupported type='%s' to model 'none'"),
5813
                               virDomainSeclabelTypeToString(seclabel->type));
5814 5815 5816 5817 5818
                goto error;
            }
            /* combination of relabel='yes' and type='static'
             * is checked a few lines above. */
        }
5819
        return seclabel;
5820
    }
5821

E
Eric Blake 已提交
5822
    /* Only parse label, if using static labels, or
5823
     * if the 'live' VM XML is requested
E
Eric Blake 已提交
5824
     */
5825
    if (seclabel->type == VIR_DOMAIN_SECLABEL_STATIC ||
5826
        (!(flags & VIR_DOMAIN_DEF_PARSE_INACTIVE) &&
5827
         seclabel->type != VIR_DOMAIN_SECLABEL_NONE)) {
5828
        p = virXPathStringLimit("string(./label[1])",
E
Eric Blake 已提交
5829
                                VIR_SECURITY_LABEL_BUFLEN-1, ctxt);
5830
        if (p == NULL) {
5831 5832
            virReportError(VIR_ERR_XML_ERROR,
                           "%s", _("security label is missing"));
5833
            goto error;
E
Eric Blake 已提交
5834 5835
        }

5836
        seclabel->label = p;
5837
        p = NULL;
E
Eric Blake 已提交
5838 5839 5840
    }

    /* Only parse imagelabel, if requested live XML with relabeling */
5841
    if (seclabel->relabel &&
5842
        (!(flags & VIR_DOMAIN_DEF_PARSE_INACTIVE) &&
5843
         seclabel->type != VIR_DOMAIN_SECLABEL_NONE)) {
5844
        p = virXPathStringLimit("string(./imagelabel[1])",
E
Eric Blake 已提交
5845 5846
                                VIR_SECURITY_LABEL_BUFLEN-1, ctxt);
        if (p == NULL) {
5847 5848
            virReportError(VIR_ERR_XML_ERROR,
                           "%s", _("security imagelabel is missing"));
E
Eric Blake 已提交
5849 5850
            goto error;
        }
5851
        seclabel->imagelabel = p;
5852
        p = NULL;
E
Eric Blake 已提交
5853 5854
    }

E
Eric Blake 已提交
5855
    /* Only parse baselabel for dynamic label type */
5856
    if (seclabel->type == VIR_DOMAIN_SECLABEL_DYNAMIC) {
5857
        p = virXPathStringLimit("string(./baselabel[1])",
E
Eric Blake 已提交
5858
                                VIR_SECURITY_LABEL_BUFLEN-1, ctxt);
5859
        seclabel->baselabel = p;
5860
        p = NULL;
E
Eric Blake 已提交
5861 5862
    }

5863
    return seclabel;
E
Eric Blake 已提交
5864

5865
 error:
5866 5867
    VIR_FREE(p);
    virSecurityLabelDefFree(seclabel);
5868
    return NULL;
E
Eric Blake 已提交
5869 5870
}

5871
static int
5872
virSecurityLabelDefsParseXML(virDomainDefPtr def,
5873 5874 5875
                             xmlXPathContextPtr ctxt,
                             virCapsPtr caps,
                             unsigned int flags)
5876
{
5877
    size_t i = 0, j;
5878
    int n;
5879
    xmlNodePtr *list = NULL, saved_node;
5880
    virCapsHostPtr host = &caps->host;
5881

5882 5883 5884 5885
    /* Check args and save context */
    if (def == NULL || ctxt == NULL)
        return 0;
    saved_node = ctxt->node;
5886

5887
    /* Allocate a security labels based on XML */
5888 5889 5890
    if ((n = virXPathNodeSet("./seclabel", ctxt, &list)) < 0)
        goto error;
    if (n == 0)
5891 5892
        return 0;

5893
    if (VIR_ALLOC_N(def->seclabels, n) < 0)
5894
        goto error;
5895

5896 5897
    /* Parse each "seclabel" tag */
    for (i = 0; i < n; i++) {
5898 5899
        virSecurityLabelDefPtr seclabel;

5900
        ctxt->node = list[i];
5901
        if (!(seclabel = virSecurityLabelDefParseXML(ctxt, flags)))
5902
            goto error;
5903 5904 5905 5906

        for (j = 0; j < i; j++) {
            if (STREQ_NULLABLE(seclabel->model, def->seclabels[j]->model)) {
                virReportError(VIR_ERR_XML_DETAIL,
E
Erik Skultety 已提交
5907
                               _("seclabel for model %s is already provided"),
5908 5909 5910 5911 5912 5913 5914
                               seclabel->model);
                virSecurityLabelDefFree(seclabel);
                goto error;
            }
        }

        def->seclabels[i] = seclabel;
5915
    }
5916 5917 5918
    def->nseclabels = n;
    ctxt->node = saved_node;
    VIR_FREE(list);
5919

5920 5921 5922 5923 5924 5925 5926 5927 5928 5929 5930 5931 5932
    /* 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 &&
5933
             (flags & VIR_DOMAIN_DEF_PARSE_INACTIVE))) {
5934 5935 5936
            /* Copy model from host. */
            VIR_DEBUG("Found seclabel without a model, using '%s'",
                      host->secModels[0].model);
5937
            if (VIR_STRDUP(def->seclabels[0]->model, host->secModels[0].model) < 0)
5938
                goto error;
5939 5940

            if (STREQ(def->seclabels[0]->model, "none") &&
5941
                flags & VIR_DOMAIN_DEF_PARSE_INACTIVE) {
5942 5943 5944 5945
                /* Fix older configurations */
                def->seclabels[0]->type = VIR_DOMAIN_SECLABEL_NONE;
                def->seclabels[0]->relabel = false;
            }
5946 5947 5948 5949 5950 5951 5952 5953 5954
        } else {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("missing security model in domain seclabel"));
            goto error;
        }
    }

    /* Checking missing model information */
    if (def->nseclabels > 1) {
5955
        for (; n; n--) {
5956 5957
            if (def->seclabels[n - 1]->model == NULL) {
                virReportError(VIR_ERR_XML_ERROR, "%s",
5958 5959
                               _("missing security model "
                                 "when using multiple labels"));
5960 5961
                goto error;
            }
5962 5963
        }
    }
5964

5965
    return 0;
5966

5967
 error:
5968
    ctxt->node = saved_node;
5969
    for (; i > 0; i--)
5970 5971
        virSecurityLabelDefFree(def->seclabels[i - 1]);
    VIR_FREE(def->seclabels);
5972
    def->nseclabels = 0;
5973 5974 5975
    VIR_FREE(list);
    return -1;
}
5976

5977
/* Parse the <seclabel> from a disk or character device. */
5978
static int
5979 5980
virSecurityDeviceLabelDefParseXML(virSecurityDeviceLabelDefPtr **seclabels_rtn,
                                  size_t *nseclabels_rtn,
5981
                                  virSecurityLabelDefPtr *vmSeclabels,
5982 5983
                                  int nvmSeclabels, xmlXPathContextPtr ctxt,
                                  unsigned int flags)
5984
{
5985
    virSecurityDeviceLabelDefPtr *seclabels = NULL;
5986
    size_t nseclabels = 0;
5987 5988
    int n;
    size_t i, j;
5989 5990
    xmlNodePtr *list = NULL;
    virSecurityLabelDefPtr vmDef = NULL;
5991
    char *model, *relabel, *label, *labelskip;
5992

5993 5994 5995
    if ((n = virXPathNodeSet("./seclabel", ctxt, &list)) < 0)
        goto error;
    if (n == 0)
5996 5997
        return 0;

5998
    if (VIR_ALLOC_N(seclabels, n) < 0)
5999
        goto error;
6000
    nseclabels = n;
6001
    for (i = 0; i < n; i++) {
6002
        if (VIR_ALLOC(seclabels[i]) < 0)
6003
            goto error;
6004 6005
    }

6006 6007 6008
    for (i = 0; i < n; i++) {
        /* get model associated to this override */
        model = virXMLPropString(list[i], "model");
6009 6010
        if (model) {
            /* find the security label that it's being overridden */
6011 6012 6013 6014 6015 6016
            for (j = 0; j < nvmSeclabels; j++) {
                if (STREQ(vmSeclabels[j]->model, model)) {
                    vmDef = vmSeclabels[j];
                    break;
                }
            }
6017 6018 6019 6020 6021 6022 6023 6024 6025

            /* 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;
                }
            }
6026
            seclabels[i]->model = model;
6027 6028 6029
        }

        /* Can't use overrides if top-level doesn't allow relabeling.  */
6030
        if (vmDef && !vmDef->relabel) {
6031 6032 6033 6034 6035 6036 6037 6038 6039
            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")) {
6040
                seclabels[i]->relabel = true;
6041
            } else if (STREQ(relabel, "no")) {
6042
                seclabels[i]->relabel = false;
6043 6044 6045 6046 6047 6048 6049 6050 6051
            } else {
                virReportError(VIR_ERR_XML_ERROR,
                               _("invalid security relabel value %s"),
                               relabel);
                VIR_FREE(relabel);
                goto error;
            }
            VIR_FREE(relabel);
        } else {
6052
            seclabels[i]->relabel = true;
6053 6054
        }

6055 6056 6057
        /* labelskip is only parsed on live images */
        labelskip = virXMLPropString(list[i], "labelskip");
        seclabels[i]->labelskip = false;
6058
        if (labelskip && !(flags & VIR_DOMAIN_DEF_PARSE_INACTIVE))
6059 6060 6061
            seclabels[i]->labelskip = STREQ(labelskip, "yes");
        VIR_FREE(labelskip);

6062 6063 6064
        ctxt->node = list[i];
        label = virXPathStringLimit("string(./label)",
                                    VIR_SECURITY_LABEL_BUFLEN-1, ctxt);
6065
        seclabels[i]->label = label;
6066

6067
        if (label && !seclabels[i]->relabel) {
6068 6069 6070
            virReportError(VIR_ERR_XML_ERROR,
                           _("Cannot specify a label if relabelling is "
                             "turned off. model=%s"),
6071
                             NULLSTR(seclabels[i]->model));
6072 6073 6074 6075
            goto error;
        }
    }
    VIR_FREE(list);
6076 6077 6078 6079

    *nseclabels_rtn = nseclabels;
    *seclabels_rtn = seclabels;

6080
    return 0;
6081

6082
 error:
6083
    for (i = 0; i < nseclabels; i++)
6084 6085
        virSecurityDeviceLabelDefFree(seclabels[i]);
    VIR_FREE(seclabels);
6086 6087
    VIR_FREE(list);
    return -1;
6088 6089 6090
}


6091 6092 6093 6094 6095 6096 6097 6098 6099 6100 6101 6102
/* 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;

6103
    if (VIR_ALLOC(def) < 0)
6104 6105 6106 6107 6108
        return NULL;

    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
E
Eric Blake 已提交
6109
            if (!key && xmlStrEqual(cur->name, BAD_CAST "key")) {
6110
                key = (char *)xmlNodeGetContent(cur);
E
Eric Blake 已提交
6111 6112
            } else if (!lockspace &&
                       xmlStrEqual(cur->name, BAD_CAST "lockspace")) {
6113
                lockspace = (char *)xmlNodeGetContent(cur);
E
Eric Blake 已提交
6114 6115
            } else if (!path &&
                       xmlStrEqual(cur->name, BAD_CAST "target")) {
6116 6117 6118 6119 6120 6121 6122 6123
                path = virXMLPropString(cur, "path");
                offset = virXMLPropString(cur, "offset");
            }
        }
        cur = cur->next;
    }

    if (!key) {
6124 6125
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Missing 'key' element for lease"));
6126 6127 6128
        goto error;
    }
    if (!path) {
6129 6130
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Missing 'target' element for lease"));
6131 6132 6133 6134 6135
        goto error;
    }

    if (offset &&
        virStrToLong_ull(offset, NULL, 10, &def->offset) < 0) {
6136 6137
        virReportError(VIR_ERR_XML_ERROR,
                       _("Malformed lease target offset %s"), offset);
6138 6139 6140 6141 6142 6143 6144 6145
        goto error;
    }

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

6146
 cleanup:
6147 6148 6149 6150 6151 6152 6153 6154 6155 6156 6157 6158 6159
    VIR_FREE(lockspace);
    VIR_FREE(key);
    VIR_FREE(path);
    VIR_FREE(offset);

    return def;

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

6160 6161
static int
virDomainDiskSourcePoolDefParse(xmlNodePtr node,
6162
                                virStorageSourcePoolDefPtr *srcpool)
6163
{
6164
    char *mode = NULL;
6165
    virStorageSourcePoolDefPtr source;
6166 6167
    int ret = -1;

6168 6169 6170 6171 6172 6173 6174
    *srcpool = NULL;

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

    source->pool = virXMLPropString(node, "pool");
    source->volume = virXMLPropString(node, "volume");
6175
    mode = virXMLPropString(node, "mode");
6176 6177

    /* CD-ROM and Floppy allows no source */
6178 6179 6180 6181
    if (!source->pool && !source->volume) {
        ret = 0;
        goto cleanup;
    }
6182

6183
    if (!source->pool || !source->volume) {
6184 6185 6186 6187 6188 6189
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("'pool' and 'volume' must be specified together "
                         "for 'pool' type source"));
        goto cleanup;
    }

6190
    if (mode &&
6191
        (source->mode = virStorageSourcePoolModeTypeFromString(mode)) <= 0) {
6192
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
6193 6194 6195 6196 6197
                       _("unknown source mode '%s' for volume type disk"),
                       mode);
        goto cleanup;
    }

6198 6199
    *srcpool = source;
    source = NULL;
6200 6201
    ret = 0;

6202
 cleanup:
6203
    virStorageSourcePoolDefFree(source);
6204
    VIR_FREE(mode);
6205 6206 6207
    return ret;
}

6208

6209
int
6210
virDomainDiskSourceParse(xmlNodePtr node,
6211
                         xmlXPathContextPtr ctxt,
6212
                         virStorageSourcePtr src)
6213 6214
{
    int ret = -1;
6215
    char *protocol = NULL;
6216 6217 6218
    xmlNodePtr saveNode = ctxt->node;

    ctxt->node = node;
6219

6220
    switch ((virStorageType)src->type) {
E
Eric Blake 已提交
6221
    case VIR_STORAGE_TYPE_FILE:
6222
        src->path = virXMLPropString(node, "file");
6223
        break;
E
Eric Blake 已提交
6224
    case VIR_STORAGE_TYPE_BLOCK:
6225
        src->path = virXMLPropString(node, "dev");
6226
        break;
E
Eric Blake 已提交
6227
    case VIR_STORAGE_TYPE_DIR:
6228
        src->path = virXMLPropString(node, "dir");
6229
        break;
E
Eric Blake 已提交
6230
    case VIR_STORAGE_TYPE_NETWORK:
6231 6232 6233 6234
        if (!(protocol = virXMLPropString(node, "protocol"))) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("missing network source protocol type"));
            goto cleanup;
6235
        }
6236

6237
        if ((src->protocol = virStorageNetProtocolTypeFromString(protocol)) <= 0) {
6238
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
6239 6240
                           _("unknown protocol type '%s'"), protocol);
            goto cleanup;
6241 6242
        }

6243 6244
        if (!(src->path = virXMLPropString(node, "name")) &&
            src->protocol != VIR_STORAGE_NET_PROTOCOL_NBD) {
6245
            virReportError(VIR_ERR_XML_ERROR, "%s",
6246
                           _("missing name for disk source"));
6247
            goto cleanup;
6248
        }
6249

6250 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 6264 6265 6266 6267 6268 6269 6270
        /* 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';
        }

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

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

6277 6278
        if (virDomainStorageHostParse(node, &src->hosts, &src->nhosts) < 0)
            goto cleanup;
6279
        break;
E
Eric Blake 已提交
6280
    case VIR_STORAGE_TYPE_VOLUME:
6281
        if (virDomainDiskSourcePoolDefParse(node, &src->srcpool) < 0)
6282
            goto cleanup;
6283
        break;
6284 6285
    case VIR_STORAGE_TYPE_NONE:
    case VIR_STORAGE_TYPE_LAST:
6286 6287
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected disk type %s"),
6288
                       virStorageTypeToString(src->type));
6289
        goto cleanup;
6290 6291
    }

6292 6293 6294
    /* 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 */
6295 6296
    if (src->path && !*src->path)
        VIR_FREE(src->path);
6297 6298 6299

    ret = 0;

6300
 cleanup:
6301
    VIR_FREE(protocol);
6302
    ctxt->node = saveNode;
6303 6304 6305 6306
    return ret;
}


6307 6308 6309 6310 6311 6312 6313 6314 6315 6316 6317 6318 6319 6320 6321 6322 6323 6324 6325 6326 6327 6328 6329 6330 6331 6332
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);
6333
    if (backingStore->type <= 0) {
6334 6335 6336 6337 6338 6339 6340 6341 6342 6343 6344 6345
        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);
6346
    if (backingStore->format <= 0) {
6347 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357
        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;
    }

6358
    if (virDomainDiskSourceParse(source, ctxt, backingStore) < 0 ||
6359 6360 6361 6362 6363 6364 6365 6366 6367 6368 6369 6370 6371 6372 6373 6374
        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;
}


6375 6376
#define VENDOR_LEN  8
#define PRODUCT_LEN 16
6377

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

6433
    if (!(def = virDomainDiskDefNew(xmlopt)))
6434 6435
        return NULL;

J
J.B. Joret 已提交
6436 6437 6438 6439 6440
    def->geometry.cylinders = 0;
    def->geometry.heads = 0;
    def->geometry.sectors = 0;
    def->geometry.trans = VIR_DOMAIN_DISK_TRANS_DEFAULT;

V
Viktor Mihajlovski 已提交
6441 6442
    def->blockio.logical_block_size = 0;
    def->blockio.physical_block_size = 0;
6443

L
Lei Li 已提交
6444 6445
    ctxt->node = node;

6446 6447
    type = virXMLPropString(node, "type");
    if (type) {
6448
        if ((def->src->type = virStorageTypeFromString(type)) <= 0) {
6449
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
6450
                           _("unknown disk type '%s'"), type);
6451 6452 6453
            goto error;
        }
    } else {
6454
        def->src->type = VIR_STORAGE_TYPE_FILE;
6455 6456
    }

6457 6458
    snapshot = virXMLPropString(node, "snapshot");

6459
    rawio = virXMLPropString(node, "rawio");
O
Osier Yang 已提交
6460
    sgio = virXMLPropString(node, "sgio");
6461

6462 6463 6464
    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
6465
            if (!source && xmlStrEqual(cur->name, BAD_CAST "source")) {
6466 6467
                sourceNode = cur;

6468
                if (virDomainDiskSourceParse(cur, ctxt, def->src) < 0)
6469
                    goto error;
6470 6471

                source = true;
6472

6473 6474
                if (def->src->type == VIR_STORAGE_TYPE_NETWORK) {
                    if (def->src->protocol == VIR_STORAGE_NET_PROTOCOL_ISCSI)
6475
                        expected_secret_usage = VIR_SECRET_USAGE_TYPE_ISCSI;
6476
                    else if (def->src->protocol == VIR_STORAGE_NET_PROTOCOL_RBD)
6477
                        expected_secret_usage = VIR_SECRET_USAGE_TYPE_CEPH;
6478
                }
6479

6480 6481
                startupPolicy = virXMLPropString(cur, "startupPolicy");

E
Eric Blake 已提交
6482 6483
            } else if (!target &&
                       xmlStrEqual(cur->name, BAD_CAST "target")) {
6484 6485
                target = virXMLPropString(cur, "dev");
                bus = virXMLPropString(cur, "bus");
6486
                tray = virXMLPropString(cur, "tray");
6487
                removable = virXMLPropString(cur, "removable");
6488 6489 6490 6491 6492 6493

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

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

E
Eric Blake 已提交
6575 6576 6577 6578 6579 6580 6581 6582 6583 6584 6585 6586 6587 6588 6589
                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 已提交
6590 6591 6592 6593 6594 6595 6596 6597 6598 6599 6600 6601 6602 6603 6604 6605 6606 6607 6608 6609 6610 6611
                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 已提交
6612 6613 6614 6615 6616 6617
                    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 已提交
6618
                    mirrorFormat = virXMLPropString(cur, "format");
6619
                }
6620 6621 6622 6623 6624 6625 6626 6627 6628
                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 已提交
6629 6630 6631 6632 6633 6634 6635 6636 6637
                }
                if (mirrorType) {
                    xmlNodePtr mirrorNode;

                    if (!(mirrorNode = virXPathNode("./mirror/source", ctxt))) {
                        virReportError(VIR_ERR_XML_ERROR, "%s",
                                       _("mirror requires source element"));
                        goto error;
                    }
6638 6639
                    if (virDomainDiskSourceParse(mirrorNode, ctxt,
                                                 def->mirror) < 0)
E
Eric Blake 已提交
6640
                        goto error;
6641
                }
6642 6643
                ready = virXMLPropString(cur, "ready");
                if (ready) {
6644 6645 6646 6647 6648 6649 6650 6651
                    if ((def->mirrorState =
                         virDomainDiskMirrorStateTypeFromString(ready)) < 0) {
                        virReportError(VIR_ERR_XML_ERROR,
                                       _("unknown mirror ready state %s"),
                                       ready);
                        VIR_FREE(ready);
                        goto error;
                    }
6652 6653
                    VIR_FREE(ready);
                }
6654 6655
            } else if (!authdef &&
                       xmlStrEqual(cur->name, BAD_CAST "auth")) {
6656 6657
                if (!(authdef = virStorageAuthDefParse(node->doc, cur)))
                    goto error;
6658 6659
                /* Disk volume types won't have the secrettype filled in until
                 * after virStorageTranslateDiskSourcePool is run
6660
                 */
6661 6662
                if (def->src->type != VIR_STORAGE_TYPE_VOLUME &&
                    (auth_secret_usage =
6663 6664 6665 6666
                     virSecretUsageTypeFromString(authdef->secrettype)) < 0) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("invalid secret type %s"),
                                   authdef->secrettype);
6667 6668
                    goto error;
                }
L
Lei Li 已提交
6669
            } else if (xmlStrEqual(cur->name, BAD_CAST "iotune")) {
6670 6671 6672 6673 6674 6675 6676 6677
                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 已提交
6678 6679 6680
                    def->blkdeviotune.total_bytes_sec = 0;
                }

6681 6682 6683 6684 6685 6686 6687 6688
                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 已提交
6689 6690 6691
                    def->blkdeviotune.read_bytes_sec = 0;
                }

6692 6693 6694 6695 6696 6697 6698 6699
                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 已提交
6700 6701 6702
                    def->blkdeviotune.write_bytes_sec = 0;
                }

6703 6704 6705 6706 6707 6708 6709 6710
                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 已提交
6711 6712 6713
                    def->blkdeviotune.total_iops_sec = 0;
                }

6714 6715 6716 6717 6718 6719 6720 6721
                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 已提交
6722 6723 6724
                    def->blkdeviotune.read_iops_sec = 0;
                }

6725 6726 6727 6728 6729 6730 6731 6732
                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 已提交
6733 6734 6735
                    def->blkdeviotune.write_iops_sec = 0;
                }

6736 6737 6738 6739 6740 6741 6742 6743 6744 6745 6746 6747 6748 6749 6750 6751 6752 6753 6754 6755 6756 6757 6758 6759 6760 6761 6762 6763 6764 6765 6766 6767 6768 6769 6770 6771 6772 6773 6774 6775 6776 6777 6778
                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 已提交
6779 6780 6781 6782
                if ((def->blkdeviotune.total_bytes_sec &&
                     def->blkdeviotune.read_bytes_sec) ||
                    (def->blkdeviotune.total_bytes_sec &&
                     def->blkdeviotune.write_bytes_sec)) {
6783
                    virReportError(VIR_ERR_XML_ERROR, "%s",
6784 6785
                                   _("total and read/write bytes_sec "
                                     "cannot be set at the same time"));
L
Lei Li 已提交
6786 6787 6788 6789 6790 6791 6792
                    goto error;
                }

                if ((def->blkdeviotune.total_iops_sec &&
                     def->blkdeviotune.read_iops_sec) ||
                    (def->blkdeviotune.total_iops_sec &&
                     def->blkdeviotune.write_iops_sec)) {
6793
                    virReportError(VIR_ERR_XML_ERROR, "%s",
6794 6795
                                   _("total and read/write iops_sec "
                                     "cannot be set at the same time"));
L
Lei Li 已提交
6796 6797
                    goto error;
                }
6798 6799 6800 6801 6802 6803 6804 6805 6806 6807 6808 6809 6810 6811 6812 6813 6814 6815 6816 6817 6818

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

6819
            } else if (xmlStrEqual(cur->name, BAD_CAST "readonly")) {
6820
                def->src->readonly = true;
6821
            } else if (xmlStrEqual(cur->name, BAD_CAST "shareable")) {
6822
                def->src->shared = true;
6823
            } else if (xmlStrEqual(cur->name, BAD_CAST "transient")) {
6824
                def->transient = true;
6825
            } else if ((flags & VIR_DOMAIN_DEF_PARSE_STATUS) &&
6826
                       xmlStrEqual(cur->name, BAD_CAST "state")) {
6827
                /* Legacy back-compat. Don't add any more attributes here */
6828
                devaddr = virXMLPropString(cur, "devaddr");
6829 6830
            } else if (encryption == NULL &&
                       xmlStrEqual(cur->name, BAD_CAST "encryption")) {
6831
                encryption = virStorageEncryptionParseNode(node->doc,
6832 6833 6834
                                                           cur);
                if (encryption == NULL)
                    goto error;
E
Eric Blake 已提交
6835 6836
            } else if (!serial &&
                       xmlStrEqual(cur->name, BAD_CAST "serial")) {
6837
                serial = (char *)xmlNodeGetContent(cur);
O
Osier Yang 已提交
6838 6839 6840 6841 6842 6843
            } else if (!wwn &&
                       xmlStrEqual(cur->name, BAD_CAST "wwn")) {
                wwn = (char *)xmlNodeGetContent(cur);

                if (!virValidateWWN(wwn))
                    goto error;
6844 6845 6846 6847 6848 6849 6850 6851 6852 6853 6854 6855 6856 6857 6858 6859 6860 6861 6862
            } 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 已提交
6863
                if (strlen(product) > PRODUCT_LEN) {
6864 6865 6866 6867 6868 6869 6870 6871 6872 6873
                    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;
                }
6874
            } else if (xmlStrEqual(cur->name, BAD_CAST "boot")) {
6875
                /* boot is parsed as part of virDomainDeviceInfoParseXML */
6876 6877 6878 6879 6880
            }
        }
        cur = cur->next;
    }

6881 6882 6883 6884 6885
    /* 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) {
6886 6887
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("invalid secret type '%s'"),
6888
                       virSecretUsageTypeToString(auth_secret_usage));
6889 6890 6891
        goto error;
    }

6892 6893 6894
    device = virXMLPropString(node, "device");
    if (device) {
        if ((def->device = virDomainDiskDeviceTypeFromString(device)) < 0) {
6895
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
6896
                           _("unknown disk device '%s'"), device);
6897 6898 6899 6900 6901 6902 6903
            goto error;
        }
    } else {
        def->device = VIR_DOMAIN_DISK_DEVICE_DISK;
    }

    /* Only CDROM and Floppy devices are allowed missing source path
6904 6905
     * to indicate no media present. LUN is for raw access CD-ROMs
     * that are not attached to a physical device presently */
6906
    if (virStorageSourceIsEmpty(def->src) &&
6907
        (def->device == VIR_DOMAIN_DISK_DEVICE_DISK ||
6908
         (flags & VIR_DOMAIN_DEF_PARSE_DISK_SOURCE))) {
6909 6910
        virReportError(VIR_ERR_NO_SOURCE,
                       target ? "%s" : NULL, target);
6911 6912 6913
        goto error;
    }

6914 6915 6916 6917
    /* If source is present, check for an optional seclabel override.  */
    if (sourceNode) {
        xmlNodePtr saved_node = ctxt->node;
        ctxt->node = sourceNode;
6918 6919
        if (virSecurityDeviceLabelDefParseXML(&def->src->seclabels,
                                              &def->src->nseclabels,
6920
                                              vmSeclabels,
6921
                                              nvmSeclabels,
6922 6923
                                              ctxt,
                                              flags) < 0)
6924 6925 6926 6927
            goto error;
        ctxt->node = saved_node;
    }

6928
    if (!target && !(flags & VIR_DOMAIN_DEF_PARSE_DISK_SOURCE)) {
6929
        if (def->src->srcpool) {
6930 6931
            char *tmp;
            if (virAsprintf(&tmp, "pool = '%s', volume = '%s'",
6932
                def->src->srcpool->pool, def->src->srcpool->volume) < 0)
6933 6934 6935 6936 6937
                goto error;

            virReportError(VIR_ERR_NO_TARGET, "%s", tmp);
            VIR_FREE(tmp);
        } else {
6938
            virReportError(VIR_ERR_NO_TARGET, def->src->path ? "%s" : NULL, def->src->path);
6939
        }
6940 6941 6942
        goto error;
    }

6943
    if (!(flags & VIR_DOMAIN_DEF_PARSE_DISK_SOURCE)) {
6944 6945 6946 6947 6948 6949
        if (def->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY &&
            !STRPREFIX(target, "fd")) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Invalid floppy device name: %s"), target);
            goto error;
        }
6950

6951 6952 6953
        /* Force CDROM to be listed as read only */
        if (def->device == VIR_DOMAIN_DISK_DEVICE_CDROM)
            def->src->readonly = true;
6954

6955 6956 6957 6958 6959 6960 6961 6962 6963 6964 6965
        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;
        }
6966 6967
    }

6968
    if (snapshot) {
E
Eric Blake 已提交
6969
        def->snapshot = virDomainSnapshotLocationTypeFromString(snapshot);
6970
        if (def->snapshot <= 0) {
6971
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
6972 6973
                           _("unknown disk snapshot setting '%s'"),
                           snapshot);
6974 6975
            goto error;
        }
6976
    } else if (def->src->readonly) {
E
Eric Blake 已提交
6977
        def->snapshot = VIR_DOMAIN_SNAPSHOT_LOCATION_NONE;
6978 6979
    }

O
Osier Yang 已提交
6980 6981 6982 6983 6984 6985 6986 6987
    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;
    }

6988
    if (rawio) {
6989
        if ((def->rawio = virTristateBoolTypeFromString(rawio)) <= 0) {
O
Osier Yang 已提交
6990 6991 6992 6993 6994 6995 6996 6997
            virReportError(VIR_ERR_XML_ERROR,
                           _("unknown disk rawio setting '%s'"),
                           rawio);
            goto error;
        }
    }

    if (sgio) {
6998
        if ((def->sgio = virDomainDeviceSGIOTypeFromString(sgio)) <= 0) {
6999
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
O
Osier Yang 已提交
7000
                           _("unknown disk sgio mode '%s'"), sgio);
7001 7002 7003 7004
            goto error;
        }
    }

7005 7006
    if (bus) {
        if ((def->bus = virDomainDiskBusTypeFromString(bus)) < 0) {
7007
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
7008
                           _("unknown disk bus type '%s'"), bus);
7009 7010 7011 7012 7013
            goto error;
        }
    } else {
        if (def->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
            def->bus = VIR_DOMAIN_DISK_BUS_FDC;
7014
        } else if (!(flags & VIR_DOMAIN_DEF_PARSE_DISK_SOURCE)) {
7015 7016 7017 7018 7019 7020 7021 7022
            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;
7023 7024
            else if (STRPREFIX(target, "ubd"))
                def->bus = VIR_DOMAIN_DISK_BUS_UML;
7025 7026 7027 7028 7029
            else
                def->bus = VIR_DOMAIN_DISK_BUS_IDE;
        }
    }

7030 7031
    if (tray) {
        if ((def->tray_status = virDomainDiskTrayTypeFromString(tray)) < 0) {
7032
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
7033
                           _("unknown disk tray status '%s'"), tray);
7034 7035 7036 7037 7038
            goto error;
        }

        if (def->device != VIR_DOMAIN_DISK_DEVICE_FLOPPY &&
            def->device != VIR_DOMAIN_DISK_DEVICE_CDROM) {
7039 7040
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("tray is only valid for cdrom and floppy"));
7041 7042 7043 7044 7045 7046 7047 7048
            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;
    }

7049
    if (removable) {
J
Ján Tomko 已提交
7050
        if ((def->removable = virTristateSwitchTypeFromString(removable)) < 0) {
7051
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
7052 7053 7054 7055 7056 7057 7058 7059 7060 7061
                           _("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 {
7062
        if (def->bus == VIR_DOMAIN_DISK_BUS_USB)
J
Ján Tomko 已提交
7063
            def->removable = VIR_TRISTATE_SWITCH_ABSENT;
7064 7065
    }

7066 7067
    if (def->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY &&
        def->bus != VIR_DOMAIN_DISK_BUS_FDC) {
7068 7069
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Invalid bus type '%s' for floppy disk"), bus);
7070 7071 7072 7073
        goto error;
    }
    if (def->device != VIR_DOMAIN_DISK_DEVICE_FLOPPY &&
        def->bus == VIR_DOMAIN_DISK_BUS_FDC) {
7074 7075
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Invalid bus type '%s' for disk"), bus);
7076 7077 7078
        goto error;
    }

7079 7080
    if (cachetag &&
        (def->cachemode = virDomainDiskCacheTypeFromString(cachetag)) < 0) {
7081
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
7082
                       _("unknown disk cache mode '%s'"), cachetag);
7083 7084 7085
        goto error;
    }

7086
    if (error_policy &&
7087
        (def->error_policy = virDomainDiskErrorPolicyTypeFromString(error_policy)) <= 0) {
7088
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
7089
                       _("unknown disk error policy '%s'"), error_policy);
7090 7091 7092
        goto error;
    }

7093 7094 7095 7096
    if (rerror_policy &&
        (((def->rerror_policy
           = virDomainDiskErrorPolicyTypeFromString(rerror_policy)) <= 0) ||
         (def->rerror_policy == VIR_DOMAIN_DISK_ERROR_POLICY_ENOSPACE))) {
7097
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
7098 7099
                       _("unknown disk read error policy '%s'"),
                       rerror_policy);
7100 7101 7102
        goto error;
    }

M
Matthias Dahl 已提交
7103 7104 7105
    if (iotag) {
        if ((def->iomode = virDomainDiskIoTypeFromString(iotag)) < 0 ||
            def->iomode == VIR_DOMAIN_DISK_IO_DEFAULT) {
7106
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
7107
                           _("unknown disk io mode '%s'"), iotag);
M
Matthias Dahl 已提交
7108 7109 7110 7111
            goto error;
        }
    }

7112
    if (ioeventfd) {
7113 7114
        int val;

7115
        if (def->bus != VIR_DOMAIN_DISK_BUS_VIRTIO) {
7116
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
7117 7118
                           _("disk ioeventfd mode supported "
                             "only for virtio bus"));
7119 7120 7121
            goto error;
        }

J
Ján Tomko 已提交
7122
        if ((val = virTristateSwitchTypeFromString(ioeventfd)) <= 0) {
7123 7124 7125
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown disk ioeventfd mode '%s'"),
                           ioeventfd);
7126 7127
            goto error;
        }
7128
        def->ioeventfd = val;
7129 7130
    }

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

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

O
Osier Yang 已提交
7149 7150
    if (copy_on_read) {
        int cor;
J
Ján Tomko 已提交
7151
        if ((cor = virTristateSwitchTypeFromString(copy_on_read)) <= 0) {
7152 7153 7154
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown disk copy_on_read mode '%s'"),
                           copy_on_read);
O
Osier Yang 已提交
7155 7156 7157 7158 7159
            goto error;
        }
        def->copy_on_read = cor;
    }

O
Osier Yang 已提交
7160 7161 7162 7163 7164 7165 7166 7167
    if (discard) {
        if ((def->discard = virDomainDiskDiscardTypeFromString(discard)) <= 0) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown disk discard mode '%s'"), discard);
            goto error;
        }
    }

7168
    if (driverIOThread) {
7169 7170
        if (virStrToLong_uip(driverIOThread, NULL, 10, &def->iothread) < 0 ||
            def->iothread == 0) {
7171 7172 7173 7174 7175 7176 7177
            virReportError(VIR_ERR_XML_ERROR,
                           _("Invalid iothread attribute in disk driver "
                             "element: %s"), driverIOThread);
            goto error;
        }
    }

7178
    if (devaddr) {
7179 7180
        if (virDomainParseLegacyDeviceAddress(devaddr,
                                              &def->info.addr.pci) < 0) {
7181 7182 7183
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unable to parse devaddr parameter '%s'"),
                           devaddr);
7184 7185 7186 7187
            goto error;
        }
        def->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
    } else {
7188
        if (virDomainDeviceInfoParseXML(node, bootHash, &def->info,
7189
                                        flags | VIR_DOMAIN_DEF_PARSE_ALLOW_BOOT) < 0)
7190
            goto error;
7191 7192
    }

7193
    if (startupPolicy) {
7194
        int val;
7195

7196
        if ((val = virDomainStartupPolicyTypeFromString(startupPolicy)) <= 0) {
7197 7198 7199
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown startupPolicy value '%s'"),
                           startupPolicy);
7200 7201 7202
            goto error;
        }

7203
        if (def->src->type == VIR_STORAGE_TYPE_NETWORK) {
7204 7205 7206
            virReportError(VIR_ERR_XML_ERROR,
                           _("Setting disk %s is not allowed for "
                             "disk of network type"),
7207
                           startupPolicy);
7208 7209
            goto error;
        }
7210 7211 7212 7213 7214 7215 7216 7217 7218

        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;
        }
7219
        def->startupPolicy = val;
7220 7221
    }

7222 7223
    def->dst = target;
    target = NULL;
7224 7225
    def->src->auth = authdef;
    authdef = NULL;
7226
    def->src->driverName = driverName;
7227
    driverName = NULL;
7228
    def->src->encryption = encryption;
7229
    encryption = NULL;
7230 7231
    def->domain_name = domain_name;
    domain_name = NULL;
7232 7233
    def->serial = serial;
    serial = NULL;
O
Osier Yang 已提交
7234 7235
    def->wwn = wwn;
    wwn = NULL;
7236 7237 7238 7239
    def->vendor = vendor;
    vendor = NULL;
    def->product = product;
    product = NULL;
7240

7241
    if (driverType) {
7242 7243
        def->src->format = virStorageFileFormatTypeFromString(driverType);
        if (def->src->format <= 0) {
7244 7245 7246 7247 7248 7249
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown driver format value '%s'"),
                           driverType);
            goto error;
        }
    }
7250

7251
    if (!(flags & VIR_DOMAIN_DEF_PARSE_DISK_SOURCE)) {
7252 7253 7254
        if (virDomainDiskBackingStoreParse(ctxt, def->src) < 0)
            goto error;
    }
7255

7256
 cleanup:
7257 7258
    VIR_FREE(bus);
    VIR_FREE(type);
7259
    VIR_FREE(snapshot);
7260
    VIR_FREE(rawio);
O
Osier Yang 已提交
7261
    VIR_FREE(sgio);
7262
    VIR_FREE(target);
7263
    VIR_FREE(tray);
7264
    VIR_FREE(removable);
J
J.B. Joret 已提交
7265
    VIR_FREE(trans);
7266
    VIR_FREE(device);
7267
    virStorageAuthDefFree(authdef);
7268 7269
    VIR_FREE(driverType);
    VIR_FREE(driverName);
7270
    VIR_FREE(cachetag);
7271
    VIR_FREE(error_policy);
7272
    VIR_FREE(rerror_policy);
M
Matthias Dahl 已提交
7273
    VIR_FREE(iotag);
7274
    VIR_FREE(ioeventfd);
7275
    VIR_FREE(event_idx);
O
Osier Yang 已提交
7276
    VIR_FREE(copy_on_read);
O
Osier Yang 已提交
7277
    VIR_FREE(discard);
7278
    VIR_FREE(driverIOThread);
7279
    VIR_FREE(devaddr);
7280
    VIR_FREE(serial);
7281
    virStorageEncryptionFree(encryption);
7282
    VIR_FREE(startupPolicy);
7283 7284
    VIR_FREE(logical_block_size);
    VIR_FREE(physical_block_size);
O
Osier Yang 已提交
7285
    VIR_FREE(wwn);
7286 7287
    VIR_FREE(vendor);
    VIR_FREE(product);
E
Eric Blake 已提交
7288 7289
    VIR_FREE(mirrorType);
    VIR_FREE(mirrorFormat);
7290
    VIR_FREE(domain_name);
7291

L
Lei Li 已提交
7292
    ctxt->node = save_ctxt;
7293 7294
    return def;

7295
 error:
7296 7297 7298 7299 7300
    virDomainDiskDefFree(def);
    def = NULL;
    goto cleanup;
}

7301 7302 7303 7304 7305 7306 7307 7308 7309 7310 7311 7312 7313 7314 7315 7316 7317 7318 7319 7320 7321 7322
/**
 * 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.
 */
7323 7324
static int
virDomainParseScaledValue(const char *xpath,
7325
                          const char *units_xpath,
7326 7327 7328 7329 7330 7331 7332 7333
                          xmlXPathContextPtr ctxt,
                          unsigned long long *val,
                          unsigned long long scale,
                          unsigned long long max,
                          bool required)
{
    char *xpath_full = NULL;
    char *unit = NULL;
7334
    char *bytes_str = NULL;
7335 7336 7337 7338 7339 7340
    int ret = -1;
    unsigned long long bytes;

    *val = 0;
    if (virAsprintf(&xpath_full, "string(%s)", xpath) < 0)
        goto cleanup;
7341 7342 7343 7344 7345 7346

    bytes_str = virXPathString(xpath_full, ctxt);
    if (!bytes_str) {
        if (!required) {
            ret = 0;
        } else {
7347
            virReportError(VIR_ERR_XML_ERROR,
7348
                           _("missing element or attribute '%s'"),
7349
                           xpath);
7350
        }
7351 7352 7353 7354
        goto cleanup;
    }
    VIR_FREE(xpath_full);

7355 7356
    if (virStrToLong_ullp(bytes_str, NULL, 10, &bytes) < 0) {
        virReportError(VIR_ERR_XML_ERROR,
7357
                       _("Invalid value '%s' for element or attribute '%s'"),
7358 7359 7360 7361
                       bytes_str, xpath);
        goto cleanup;
    }

7362 7363 7364 7365
    if ((units_xpath &&
         virAsprintf(&xpath_full, "string(%s)", units_xpath) < 0) ||
        (!units_xpath &&
         virAsprintf(&xpath_full, "string(%s/@unit)", xpath) < 0))
7366 7367 7368 7369 7370 7371 7372 7373
        goto cleanup;
    unit = virXPathString(xpath_full, ctxt);

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

    *val = bytes;
    ret = 1;
7374
 cleanup:
7375
    VIR_FREE(bytes_str);
7376 7377 7378 7379 7380 7381
    VIR_FREE(xpath_full);
    VIR_FREE(unit);
    return ret;
}


7382 7383 7384 7385 7386 7387 7388 7389
/**
 * 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
7390
 *
7391 7392 7393 7394 7395 7396 7397 7398 7399 7400 7401 7402 7403
 * 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.
 */
7404
int
7405 7406 7407 7408 7409 7410
virDomainParseMemory(const char *xpath,
                     const char *units_xpath,
                     xmlXPathContextPtr ctxt,
                     unsigned long long *mem,
                     bool required,
                     bool capped)
7411 7412 7413 7414
{
    int ret = -1;
    unsigned long long bytes, max;

7415
    max = virMemoryMaxValue(capped);
7416

7417 7418
    ret = virDomainParseScaledValue(xpath, units_xpath, ctxt,
                                    &bytes, 1024, max, required);
7419 7420 7421 7422 7423
    if (ret < 0)
        goto cleanup;

    /* Yes, we really do use kibibytes for our internal sizing.  */
    *mem = VIR_DIV_UP(bytes, 1024);
7424 7425 7426 7427 7428 7429 7430

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

7431 7432 7433 7434 7435 7436
    ret = 0;
 cleanup:
    return ret;
}


7437 7438 7439 7440 7441 7442 7443 7444 7445 7446 7447 7448 7449 7450 7451 7452 7453 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
/**
 * 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;
}


7481 7482 7483 7484 7485 7486 7487
bool
virDomainDefHasMemoryHotplug(const virDomainDef *def)
{
    return def->mem.memory_slots > 0 || def->mem.max_memory > 0;
}


7488 7489 7490 7491 7492 7493 7494 7495 7496
/**
 * 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
7497
virDomainDefGetMemoryInitial(const virDomainDef *def)
7498
{
7499
    return def->mem.initial_memory;
7500 7501 7502 7503
}


/**
7504
 * virDomainDefSetMemoryTotal:
7505 7506 7507
 * @def: domain definition
 * @size: size to set
 *
7508 7509
 * Sets the total memory size in @def. This function should be used only by
 * hypervisors that don't support memory hotplug.
7510 7511
 */
void
7512 7513
virDomainDefSetMemoryTotal(virDomainDefPtr def,
                           unsigned long long size)
7514
{
7515
    def->mem.total_memory = size;
7516 7517 7518 7519 7520 7521 7522 7523 7524 7525 7526 7527 7528 7529 7530 7531
    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;
7532 7533 7534 7535 7536 7537 7538 7539 7540 7541 7542 7543 7544 7545
}


/**
 * 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)
{
7546 7547 7548
    unsigned long long ret;
    size_t i;

7549 7550 7551 7552
    ret = def->mem.initial_memory;

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

    return ret;
7555 7556 7557
}


7558
static int
7559
virDomainControllerModelTypeFromString(const virDomainControllerDef *def,
7560 7561 7562 7563
                                       const char *model)
{
    if (def->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI)
        return virDomainControllerModelSCSITypeFromString(model);
7564 7565
    else if (def->type == VIR_DOMAIN_CONTROLLER_TYPE_USB)
        return virDomainControllerModelUSBTypeFromString(model);
J
Ján Tomko 已提交
7566 7567
    else if (def->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI)
        return virDomainControllerModelPCITypeFromString(model);
7568 7569 7570 7571

    return -1;
}

7572 7573 7574 7575
/* Parse the XML definition for a controller
 * @param node XML nodeset to parse for controller definition
 */
static virDomainControllerDefPtr
7576
virDomainControllerDefParseXML(xmlNodePtr node,
7577
                               xmlXPathContextPtr ctxt,
E
Eric Blake 已提交
7578
                               unsigned int flags)
7579
{
7580 7581
    virDomainControllerDefPtr def = NULL;
    int type = 0;
7582
    xmlNodePtr cur = NULL;
7583
    char *typeStr = NULL;
7584
    char *idx = NULL;
7585
    char *model = NULL;
7586
    char *queues = NULL;
7587 7588
    char *cmd_per_lun = NULL;
    char *max_sectors = NULL;
7589 7590
    bool processedModel = false;
    char *modelName = NULL;
7591 7592
    bool processedTarget = false;
    char *chassisNr = NULL;
7593 7594
    char *chassis = NULL;
    char *port = NULL;
7595
    char *ioeventfd = NULL;
7596
    xmlNodePtr saved = ctxt->node;
7597
    int rc;
7598 7599

    ctxt->node = node;
7600

7601 7602 7603
    typeStr = virXMLPropString(node, "type");
    if (typeStr) {
        if ((type = virDomainControllerTypeFromString(typeStr)) < 0) {
7604
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
7605
                           _("Unknown controller type '%s'"), typeStr);
7606 7607 7608 7609
            goto error;
        }
    }

7610 7611 7612
    if (!(def = virDomainControllerDefNew(type)))
        goto error;

7613 7614
    idx = virXMLPropString(node, "index");
    if (idx) {
7615 7616
        if (virStrToLong_ui(idx, NULL, 10, &def->idx) < 0 ||
            def->idx > INT_MAX) {
7617 7618
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Cannot parse controller index %s"), idx);
7619 7620 7621 7622
            goto error;
        }
    }

7623 7624
    model = virXMLPropString(node, "model");
    if (model) {
7625
        if ((def->model = virDomainControllerModelTypeFromString(def, model)) < 0) {
7626
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
7627
                           _("Unknown model type '%s'"), model);
7628 7629 7630 7631
            goto error;
        }
    }

7632 7633 7634
    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
7635
            if (xmlStrEqual(cur->name, BAD_CAST "driver")) {
7636
                queues = virXMLPropString(cur, "queues");
7637 7638
                cmd_per_lun = virXMLPropString(cur, "cmd_per_lun");
                max_sectors = virXMLPropString(cur, "max_sectors");
7639
                ioeventfd = virXMLPropString(cur, "ioeventfd");
7640 7641 7642 7643 7644 7645 7646 7647 7648
            } 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;
7649 7650 7651 7652 7653 7654 7655 7656
            } 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");
7657 7658
                chassis = virXMLPropString(cur, "chassis");
                port = virXMLPropString(cur, "port");
7659
                processedTarget = true;
7660
            }
7661
        }
7662 7663 7664 7665 7666 7667 7668
        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;
7669 7670
    }

7671 7672 7673 7674 7675 7676 7677 7678 7679
    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);
7680
        goto error;
7681 7682
    }

7683 7684 7685
    if (ioeventfd &&
        (def->ioeventfd = virTristateSwitchTypeFromString(ioeventfd)) < 0) {
        virReportError(VIR_ERR_XML_ERROR,
7686
                       _("Malformed 'ioeventfd' value %s'"), ioeventfd);
7687 7688 7689
        goto error;
    }

7690 7691 7692 7693
    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) {
7694
        goto error;
7695
    }
7696

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

7770 7771 7772 7773
            if (rc == 1)
                def->opts.pciopts.pcihole64 = true;
            def->opts.pciopts.pcihole64size = VIR_DIV_UP(bytes, 1024);
        }
J
Ján Tomko 已提交
7774
        }
7775 7776 7777 7778 7779 7780 7781 7782
        if (modelName &&
            (def->opts.pciopts.modelName
             = virDomainControllerPCIModelNameTypeFromString(modelName)) <= 0) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unknown PCI controller model name '%s'"),
                           modelName);
            goto error;
        }
7783 7784 7785 7786 7787 7788 7789 7790 7791 7792 7793 7794 7795 7796 7797 7798 7799
        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;
            }
        }
7800 7801 7802 7803 7804 7805 7806 7807 7808 7809 7810 7811 7812 7813 7814 7815 7816 7817 7818 7819 7820 7821 7822 7823 7824 7825 7826 7827 7828 7829 7830 7831 7832 7833
        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;
            }
        }
7834
        break;
7835 7836 7837 7838 7839

    default:
        break;
    }

7840
    if (def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
7841
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO &&
7842
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW &&
7843
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390 &&
7844
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO &&
7845
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
7846 7847
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Controllers must use the 'pci' address type"));
7848 7849 7850
        goto error;
    }

7851
 cleanup:
7852
    ctxt->node = saved;
7853
    VIR_FREE(typeStr);
7854
    VIR_FREE(idx);
7855
    VIR_FREE(model);
7856
    VIR_FREE(queues);
7857 7858
    VIR_FREE(cmd_per_lun);
    VIR_FREE(max_sectors);
7859
    VIR_FREE(modelName);
7860
    VIR_FREE(chassisNr);
7861 7862
    VIR_FREE(chassis);
    VIR_FREE(port);
7863
    VIR_FREE(ioeventfd);
7864 7865 7866 7867 7868 7869 7870 7871 7872

    return def;

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

7873

7874 7875 7876 7877 7878 7879 7880 7881
void
virDomainNetGenerateMAC(virDomainXMLOptionPtr xmlopt,
                        virMacAddrPtr mac)
{
    virMacAddrGenerate(xmlopt->config.macPrefix, mac);
}


7882 7883 7884 7885
/* Parse the XML definition for a disk
 * @param node XML nodeset to parse for disk definition
 */
static virDomainFSDefPtr
7886
virDomainFSDefParseXML(xmlNodePtr node,
7887
                       xmlXPathContextPtr ctxt,
7888 7889
                       unsigned int flags)
{
7890
    virDomainFSDefPtr def;
7891
    xmlNodePtr cur, save_node = ctxt->node;
7892
    char *type = NULL;
7893
    char *fsdriver = NULL;
7894 7895
    char *source = NULL;
    char *target = NULL;
7896
    char *format = NULL;
7897
    char *accessmode = NULL;
7898
    char *wrpolicy = NULL;
7899
    char *usage = NULL;
7900
    char *units = NULL;
7901

7902 7903
    ctxt->node = node;

7904
    if (VIR_ALLOC(def) < 0)
7905 7906 7907 7908 7909
        return NULL;

    type = virXMLPropString(node, "type");
    if (type) {
        if ((def->type = virDomainFSTypeFromString(type)) < 0) {
7910
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
7911
                           _("unknown filesystem type '%s'"), type);
7912 7913 7914 7915 7916 7917
            goto error;
        }
    } else {
        def->type = VIR_DOMAIN_FS_TYPE_MOUNT;
    }

7918 7919 7920
    accessmode = virXMLPropString(node, "accessmode");
    if (accessmode) {
        if ((def->accessmode = virDomainFSAccessModeTypeFromString(accessmode)) < 0) {
7921
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
7922
                           _("unknown accessmode '%s'"), accessmode);
7923 7924 7925 7926 7927 7928
            goto error;
        }
    } else {
        def->accessmode = VIR_DOMAIN_FS_ACCESSMODE_PASSTHROUGH;
    }

7929 7930 7931
    if (virDomainParseScaledValue("./space_hard_limit[1]",
                                  NULL, ctxt, &def->space_hard_limit,
                                  1, ULLONG_MAX, false) < 0)
7932 7933
        goto error;

7934 7935 7936
    if (virDomainParseScaledValue("./space_soft_limit[1]",
                                  NULL, ctxt, &def->space_soft_limit,
                                  1, ULLONG_MAX, false) < 0)
7937 7938
        goto error;

7939 7940 7941
    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
E
Eric Blake 已提交
7942 7943
            if (!source &&
                xmlStrEqual(cur->name, BAD_CAST "source")) {
7944

7945
                if (def->type == VIR_DOMAIN_FS_TYPE_MOUNT ||
7946
                    def->type == VIR_DOMAIN_FS_TYPE_BIND) {
7947
                    source = virXMLPropString(cur, "dir");
7948
                } else if (def->type == VIR_DOMAIN_FS_TYPE_FILE) {
7949
                    source = virXMLPropString(cur, "file");
7950
                } else if (def->type == VIR_DOMAIN_FS_TYPE_BLOCK) {
7951
                    source = virXMLPropString(cur, "dev");
7952
                } else if (def->type == VIR_DOMAIN_FS_TYPE_TEMPLATE) {
7953
                    source = virXMLPropString(cur, "name");
7954
                } else if (def->type == VIR_DOMAIN_FS_TYPE_RAM) {
7955
                    usage = virXMLPropString(cur, "usage");
7956
                    units = virXMLPropString(cur, "units");
7957
                }
E
Eric Blake 已提交
7958 7959
            } else if (!target &&
                       xmlStrEqual(cur->name, BAD_CAST "target")) {
7960 7961
                target = virXMLPropString(cur, "dir");
            } else if (xmlStrEqual(cur->name, BAD_CAST "readonly")) {
7962
                def->readonly = true;
7963 7964 7965 7966 7967 7968 7969
            } 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");
7970 7971 7972 7973 7974
            }
        }
        cur = cur->next;
    }

7975
    if (fsdriver) {
7976
        if ((def->fsdriver = virDomainFSDriverTypeFromString(fsdriver)) <= 0) {
7977
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
7978
                           _("unknown fs driver type '%s'"), fsdriver);
7979 7980 7981 7982
            goto error;
        }
    }

7983 7984 7985 7986 7987 7988 7989 7990
    if (format) {
        if ((def->format = virStorageFileFormatTypeFromString(format)) <= 0) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown driver format value '%s'"), format);
            goto error;
        }
    }

7991 7992
    if (wrpolicy) {
        if ((def->wrpolicy = virDomainFSWrpolicyTypeFromString(wrpolicy)) <= 0) {
7993 7994
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown filesystem write policy '%s'"), wrpolicy);
7995 7996 7997 7998 7999 8000
            goto error;
        }
    } else {
        def->wrpolicy = VIR_DOMAIN_FS_WRPOLICY_DEFAULT;
    }

8001 8002
    if (source == NULL &&
        def->type != VIR_DOMAIN_FS_TYPE_RAM) {
8003 8004
        virReportError(VIR_ERR_NO_SOURCE,
                       target ? "%s" : NULL, target);
8005 8006 8007 8008
        goto error;
    }

    if (target == NULL) {
8009 8010
        virReportError(VIR_ERR_NO_TARGET,
                       source ? "%s" : NULL, source);
8011 8012 8013
        goto error;
    }

8014 8015
    if (def->type == VIR_DOMAIN_FS_TYPE_RAM) {
        if (!usage) {
8016 8017
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("missing 'usage' attribute for RAM filesystem"));
8018 8019 8020
            goto error;
        }
        if (virStrToLong_ull(usage, NULL, 10, &def->usage) < 0) {
8021 8022 8023
            virReportError(VIR_ERR_XML_ERROR,
                           _("cannot parse usage '%s' for RAM filesystem"),
                           usage);
8024 8025
            goto error;
        }
8026
        if (virScaleInteger(&def->usage, units,
8027
                            1024, ULLONG_MAX) < 0)
8028 8029 8030
            goto error;
    }

8031 8032 8033 8034 8035
    def->src = source;
    source = NULL;
    def->dst = target;
    target = NULL;

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

8039
 cleanup:
8040
    ctxt->node = save_node;
8041
    VIR_FREE(type);
8042
    VIR_FREE(fsdriver);
8043 8044
    VIR_FREE(target);
    VIR_FREE(source);
8045
    VIR_FREE(accessmode);
8046
    VIR_FREE(wrpolicy);
8047
    VIR_FREE(usage);
8048
    VIR_FREE(units);
8049
    VIR_FREE(format);
8050 8051 8052 8053 8054 8055 8056 8057 8058

    return def;

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

8059 8060 8061
static int
virDomainActualNetDefParseXML(xmlNodePtr node,
                              xmlXPathContextPtr ctxt,
8062 8063 8064
                              virDomainNetDefPtr parent,
                              virDomainActualNetDefPtr *def,
                              unsigned int flags)
8065 8066 8067 8068
{
    virDomainActualNetDefPtr actual = NULL;
    int ret = -1;
    xmlNodePtr save_ctxt = ctxt->node;
8069
    xmlNodePtr bandwidth_node = NULL;
8070
    xmlNodePtr vlanNode;
8071
    xmlNodePtr virtPortNode;
8072 8073
    char *type = NULL;
    char *mode = NULL;
8074
    char *addrtype = NULL;
8075
    char *trustGuestRxFilters = NULL;
8076
    char *macTableManager = NULL;
8077

8078
    if (VIR_ALLOC(actual) < 0)
8079 8080 8081 8082 8083 8084
        return -1;

    ctxt->node = node;

    type = virXMLPropString(node, "type");
    if (!type) {
8085 8086
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("missing type attribute in interface's <actual> element"));
8087 8088 8089
        goto error;
    }
    if ((actual->type = virDomainNetTypeFromString(type)) < 0) {
8090
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
8091
                       _("unknown type '%s' in interface's <actual> element"), type);
8092 8093 8094
        goto error;
    }
    if (actual->type != VIR_DOMAIN_NET_TYPE_BRIDGE &&
8095
        actual->type != VIR_DOMAIN_NET_TYPE_DIRECT &&
8096
        actual->type != VIR_DOMAIN_NET_TYPE_HOSTDEV &&
8097
        actual->type != VIR_DOMAIN_NET_TYPE_NETWORK) {
8098 8099 8100
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unsupported type '%s' in interface's <actual> element"),
                       type);
8101 8102 8103
        goto error;
    }

8104 8105 8106 8107 8108 8109 8110 8111 8112 8113
    trustGuestRxFilters = virXMLPropString(node, "trustGuestRxFilters");
    if (trustGuestRxFilters &&
        ((actual->trustGuestRxFilters
          = virTristateBoolTypeFromString(trustGuestRxFilters)) <= 0)) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("unknown trustGuestRxFilters value '%s'"),
                       trustGuestRxFilters);
        goto error;
    }

8114 8115 8116 8117 8118
    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) {
8119 8120 8121
            /* the virtualport in <actual> should always already
             * have an instanceid/interfaceid if its required,
             * so don't let the parser generate one */
8122
            if (!(actual->virtPortProfile
8123 8124 8125
                  = virNetDevVPortProfileParse(virtPortNode,
                                               VIR_VPORT_XML_REQUIRE_ALL_ATTRIBUTES |
                                               VIR_VPORT_XML_REQUIRE_TYPE))) {
8126 8127 8128 8129 8130 8131
                goto error;
            }
        } else {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("<virtualport> element unsupported for type='%s'"
                             " in interface's <actual> element"), type);
A
Ansis Atteka 已提交
8132
            goto error;
8133 8134
        }
    }
8135

8136
    if (actual->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
8137 8138 8139 8140 8141
        actual->data.direct.linkdev = virXPathString("string(./source[1]/@dev)", ctxt);

        mode = virXPathString("string(./source[1]/@mode)", ctxt);
        if (mode) {
            int m;
8142
            if ((m = virNetDevMacVLanModeTypeFromString(mode)) < 0) {
8143
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
J
Ján Tomko 已提交
8144
                               _("Unknown mode '%s' in interface <actual> element"),
8145
                               mode);
8146 8147 8148 8149
                goto error;
            }
            actual->data.direct.mode = m;
        }
8150 8151 8152 8153 8154 8155 8156 8157 8158 8159 8160 8161
    } 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 已提交
8162
        if (!addrtype && virXPathNode("./source/vendor", ctxt) &&
8163
            VIR_STRDUP(addrtype, "usb") < 0)
8164
            goto error;
8165 8166 8167
        hostdev->mode = VIR_DOMAIN_HOSTDEV_MODE_SUBSYS;
        if (virDomainHostdevDefParseXMLSubsys(node, ctxt, addrtype,
                                              hostdev, flags) < 0) {
8168 8169
            goto error;
        }
8170 8171 8172 8173 8174 8175 8176 8177 8178 8179 8180
    } 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);
8181 8182 8183
    }
    if (actual->type == VIR_DOMAIN_NET_TYPE_BRIDGE ||
        actual->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
8184
        char *brname = virXPathString("string(./source/@bridge)", ctxt);
8185 8186

        if (!brname && actual->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
8187 8188 8189 8190 8191 8192
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Missing <source> element with bridge name in "
                             "interface's <actual> element"));
            goto error;
        }
        actual->data.bridge.brname = brname;
8193 8194 8195 8196 8197 8198 8199 8200 8201 8202
        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;
        }
8203 8204
    }

8205 8206
    bandwidth_node = virXPathNode("./bandwidth", ctxt);
    if (bandwidth_node &&
8207 8208 8209
        virNetDevBandwidthParse(&actual->bandwidth,
                                bandwidth_node,
                                actual->type) < 0)
8210 8211
        goto error;

8212 8213 8214 8215
    vlanNode = virXPathNode("./vlan", ctxt);
    if (vlanNode && virNetDevVlanParse(vlanNode, ctxt, &actual->vlan) < 0)
       goto error;

8216 8217 8218
    *def = actual;
    actual = NULL;
    ret = 0;
8219
 error:
8220 8221
    VIR_FREE(type);
    VIR_FREE(mode);
8222
    VIR_FREE(addrtype);
8223
    VIR_FREE(trustGuestRxFilters);
8224
    VIR_FREE(macTableManager);
8225 8226 8227 8228 8229
    virDomainActualNetDefFree(actual);

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

E
Eric Blake 已提交
8231
#define NET_MODEL_CHARS \
8232
    "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-"
E
Eric Blake 已提交
8233

8234 8235 8236 8237 8238 8239 8240 8241 8242 8243 8244 8245 8246 8247 8248 8249 8250 8251 8252 8253 8254 8255 8256 8257 8258

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

8259 8260 8261 8262
/* Parse the XML definition for a network interface
 * @param node XML nodeset to parse for net definition
 * @return 0 on success, -1 on failure
 */
8263
static virDomainNetDefPtr
8264
virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt,
8265
                        xmlNodePtr node,
8266
                        xmlXPathContextPtr ctxt,
8267
                        virHashTablePtr bootHash,
E
Eric Blake 已提交
8268
                        unsigned int flags)
8269
{
8270
    virDomainNetDefPtr def;
8271
    virDomainHostdevDefPtr hostdev;
8272 8273 8274 8275
    xmlNodePtr cur;
    char *macaddr = NULL;
    char *type = NULL;
    char *network = NULL;
8276
    char *portgroup = NULL;
8277 8278 8279
    char *bridge = NULL;
    char *dev = NULL;
    char *ifname = NULL;
8280 8281
    char *ifname_guest = NULL;
    char *ifname_guest_actual = NULL;
8282 8283 8284
    char *script = NULL;
    char *address = NULL;
    char *port = NULL;
8285 8286
    char *localaddr = NULL;
    char *localport = NULL;
8287
    char *model = NULL;
8288
    char *backend = NULL;
8289
    char *txmode = NULL;
8290
    char *ioeventfd = NULL;
8291
    char *event_idx = NULL;
8292
    char *queues = NULL;
8293
    char *str = NULL;
8294
    char *filter = NULL;
D
Daniel Veillard 已提交
8295
    char *internal = NULL;
8296
    char *devaddr = NULL;
8297
    char *mode = NULL;
8298
    char *linkstate = NULL;
8299
    char *addrtype = NULL;
8300
    char *domain_name = NULL;
M
Michele Paolino 已提交
8301 8302 8303
    char *vhostuser_mode = NULL;
    char *vhostuser_path = NULL;
    char *vhostuser_type = NULL;
8304
    char *trustGuestRxFilters = NULL;
8305
    char *vhost_path = NULL;
8306
    virNWFilterHashTablePtr filterparams = NULL;
8307
    virDomainActualNetDefPtr actual = NULL;
8308
    xmlNodePtr oldnode = ctxt->node;
8309
    int ret, val;
8310 8311 8312
    size_t i;
    size_t nips = 0;
    virDomainNetIpDefPtr *ips = NULL;
8313
    size_t nroutes = 0;
8314
    virNetworkRouteDefPtr *routes = NULL;
8315

8316
    if (VIR_ALLOC(def) < 0)
8317 8318
        return NULL;

8319 8320
    ctxt->node = node;

8321 8322
    type = virXMLPropString(node, "type");
    if (type != NULL) {
S
Stefan Berger 已提交
8323
        if ((int)(def->type = virDomainNetTypeFromString(type)) < 0) {
8324
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
8325
                           _("unknown interface type '%s'"), type);
8326 8327 8328 8329 8330 8331
            goto error;
        }
    } else {
        def->type = VIR_DOMAIN_NET_TYPE_USER;
    }

8332 8333 8334 8335 8336 8337 8338 8339 8340 8341
    trustGuestRxFilters = virXMLPropString(node, "trustGuestRxFilters");
    if (trustGuestRxFilters &&
        ((def->trustGuestRxFilters
          = virTristateBoolTypeFromString(trustGuestRxFilters)) <= 0)) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("unknown trustGuestRxFilters value '%s'"),
                       trustGuestRxFilters);
        goto error;
    }

8342 8343 8344
    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
E
Eric Blake 已提交
8345
            if (!macaddr && xmlStrEqual(cur->name, BAD_CAST "mac")) {
8346
                macaddr = virXMLPropString(cur, "address");
E
Eric Blake 已提交
8347 8348 8349
            } else if (!network &&
                       def->type == VIR_DOMAIN_NET_TYPE_NETWORK &&
                       xmlStrEqual(cur->name, BAD_CAST "source")) {
8350
                network = virXMLPropString(cur, "network");
8351
                portgroup = virXMLPropString(cur, "portgroup");
E
Eric Blake 已提交
8352 8353 8354
            } else if (!internal &&
                       def->type == VIR_DOMAIN_NET_TYPE_INTERNAL &&
                       xmlStrEqual(cur->name, BAD_CAST "source")) {
D
Daniel Veillard 已提交
8355
                internal = virXMLPropString(cur, "name");
G
Guannan Ren 已提交
8356
            } else if (!bridge &&
E
Eric Blake 已提交
8357 8358
                       def->type == VIR_DOMAIN_NET_TYPE_BRIDGE &&
                       xmlStrEqual(cur->name, BAD_CAST "source")) {
8359
                bridge = virXMLPropString(cur, "bridge");
E
Eric Blake 已提交
8360
            } else if (!dev &&
8361 8362
                       (def->type == VIR_DOMAIN_NET_TYPE_ETHERNET ||
                        def->type == VIR_DOMAIN_NET_TYPE_DIRECT) &&
8363
                       xmlStrEqual(cur->name, BAD_CAST "source")) {
8364 8365
                dev  = virXMLPropString(cur, "dev");
                mode = virXMLPropString(cur, "mode");
M
Michele Paolino 已提交
8366 8367 8368 8369 8370 8371
            } 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");
8372 8373
            } else if (!def->virtPortProfile
                       && xmlStrEqual(cur->name, BAD_CAST "virtualport")) {
8374
                if (def->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
8375
                    if (!(def->virtPortProfile
8376 8377 8378 8379 8380 8381 8382 8383 8384 8385 8386 8387
                          = 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))) {
8388 8389 8390 8391 8392 8393
                        goto error;
                    }
                } else {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("<virtualport> element unsupported for"
                                     " <interface type='%s'>"), type);
8394
                    goto error;
8395
                }
G
Guannan Ren 已提交
8396
            } else if (!address &&
E
Eric Blake 已提交
8397 8398
                       (def->type == VIR_DOMAIN_NET_TYPE_SERVER ||
                        def->type == VIR_DOMAIN_NET_TYPE_CLIENT ||
8399 8400
                        def->type == VIR_DOMAIN_NET_TYPE_MCAST ||
                        def->type == VIR_DOMAIN_NET_TYPE_UDP) &&
E
Eric Blake 已提交
8401
                       xmlStrEqual(cur->name, BAD_CAST "source")) {
8402 8403
                address = virXMLPropString(cur, "address");
                port = virXMLPropString(cur, "port");
8404 8405 8406 8407 8408 8409 8410
                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;
                }
8411 8412 8413 8414 8415 8416 8417 8418
            } 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;
8419
            } else if (xmlStrEqual(cur->name, BAD_CAST "route")) {
8420 8421 8422
                virNetworkRouteDefPtr route = NULL;
                if (!(route = virNetworkRouteDefParseXML(_("Domain interface"),
                                                         cur, ctxt)))
8423 8424
                    goto error;

8425 8426
                if (VIR_APPEND_ELEMENT(routes, nroutes, route) < 0) {
                    virNetworkRouteDefFree(route);
8427
                    goto error;
8428
                }
E
Eric Blake 已提交
8429
            } else if (!ifname &&
8430 8431
                       xmlStrEqual(cur->name, BAD_CAST "target")) {
                ifname = virXMLPropString(cur, "dev");
E
Eric Blake 已提交
8432
                if (ifname &&
8433
                    (flags & VIR_DOMAIN_DEF_PARSE_INACTIVE) &&
E
Eric Blake 已提交
8434
                    STRPREFIX(ifname, VIR_NET_GENERATED_PREFIX)) {
8435 8436 8437
                    /* An auto-generated target name, blank it out */
                    VIR_FREE(ifname);
                }
8438 8439 8440 8441
            } 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 已提交
8442
            } else if (!linkstate &&
8443 8444
                       xmlStrEqual(cur->name, BAD_CAST "link")) {
                linkstate = virXMLPropString(cur, "state");
E
Eric Blake 已提交
8445
            } else if (!script &&
8446 8447
                       xmlStrEqual(cur->name, BAD_CAST "script")) {
                script = virXMLPropString(cur, "path");
8448 8449 8450
            } else if (!domain_name &&
                       xmlStrEqual(cur->name, BAD_CAST "backenddomain")) {
                domain_name = virXMLPropString(cur, "name");
8451
            } else if (xmlStrEqual(cur->name, BAD_CAST "model")) {
8452
                model = virXMLPropString(cur, "type");
8453
            } else if (xmlStrEqual(cur->name, BAD_CAST "driver")) {
8454
                backend = virXMLPropString(cur, "name");
8455
                txmode = virXMLPropString(cur, "txmode");
8456
                ioeventfd = virXMLPropString(cur, "ioeventfd");
8457
                event_idx = virXMLPropString(cur, "event_idx");
8458
                queues = virXMLPropString(cur, "queues");
8459
            } else if (xmlStrEqual(cur->name, BAD_CAST "filterref")) {
8460 8461 8462 8463 8464 8465
                if (filter) {
                    virReportError(VIR_ERR_XML_ERROR, "%s",
                                   _("Invalid specification of multiple <filterref>s "
                                     "in a single <interface>"));
                    goto error;
                }
8466
                filter = virXMLPropString(cur, "filter");
8467
                virNWFilterHashTableFree(filterparams);
8468
                filterparams = virNWFilterParseParamAttributes(cur);
8469
            } else if ((flags & VIR_DOMAIN_DEF_PARSE_STATUS) &&
8470
                       xmlStrEqual(cur->name, BAD_CAST "state")) {
8471
                /* Legacy back-compat. Don't add any more attributes here */
8472
                devaddr = virXMLPropString(cur, "devaddr");
8473
            } else if (xmlStrEqual(cur->name, BAD_CAST "boot")) {
8474
                /* boot is parsed as part of virDomainDeviceInfoParseXML */
E
Eric Blake 已提交
8475
            } else if (!actual &&
8476
                       (flags & VIR_DOMAIN_DEF_PARSE_ACTUAL_NET) &&
E
Eric Blake 已提交
8477
                       def->type == VIR_DOMAIN_NET_TYPE_NETWORK &&
8478
                       xmlStrEqual(cur->name, BAD_CAST "actual")) {
8479 8480
                if (virDomainActualNetDefParseXML(cur, ctxt, def,
                                                  &actual, flags) < 0) {
8481
                    goto error;
8482
                }
8483
            } else if (xmlStrEqual(cur->name, BAD_CAST "bandwidth")) {
8484 8485 8486
                if (virNetDevBandwidthParse(&def->bandwidth,
                                            cur,
                                            def->type) < 0)
8487
                    goto error;
8488 8489 8490
            } else if (xmlStrEqual(cur->name, BAD_CAST "vlan")) {
                if (virNetDevVlanParse(cur, ctxt, &def->vlan) < 0)
                    goto error;
8491
            } else if (xmlStrEqual(cur->name, BAD_CAST "backend")) {
8492 8493 8494 8495 8496 8497
                char *tmp = NULL;

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

8498 8499
                if (!vhost_path && (tmp = virXMLPropString(cur, "vhost")))
                    vhost_path = virFileSanitizePath(tmp);
8500
                VIR_FREE(tmp);
8501 8502 8503 8504 8505 8506
            }
        }
        cur = cur->next;
    }

    if (macaddr) {
8507
        if (virMacAddrParse((const char *)macaddr, &def->mac) < 0) {
8508 8509 8510
            virReportError(VIR_ERR_XML_ERROR,
                           _("unable to parse mac address '%s'"),
                           (const char *)macaddr);
8511 8512
            goto error;
        }
8513
        if (virMacAddrIsMulticast(&def->mac)) {
8514 8515 8516
            virReportError(VIR_ERR_XML_ERROR,
                           _("expected unicast mac address, found multicast '%s'"),
                           (const char *)macaddr);
8517 8518
            goto error;
        }
8519
    } else {
8520
        virDomainNetGenerateMAC(xmlopt, &def->mac);
8521 8522
    }

8523
    if (devaddr) {
8524 8525
        if (virDomainParseLegacyDeviceAddress(devaddr,
                                              &def->info.addr.pci) < 0) {
8526 8527 8528
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unable to parse devaddr parameter '%s'"),
                           devaddr);
8529 8530 8531 8532
            goto error;
        }
        def->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
    } else {
8533
        if (virDomainDeviceInfoParseXML(node, bootHash, &def->info,
8534 8535
                                        flags | VIR_DOMAIN_DEF_PARSE_ALLOW_BOOT
                                        | VIR_DOMAIN_DEF_PARSE_ALLOW_ROM) < 0)
8536 8537 8538 8539 8540 8541
            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 &&
8542
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO &&
8543
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW &&
8544
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390 &&
8545
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO &&
8546
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
8547 8548
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Network interfaces must use 'pci' address type"));
8549 8550 8551
        goto error;
    }

8552 8553 8554
    switch (def->type) {
    case VIR_DOMAIN_NET_TYPE_NETWORK:
        if (network == NULL) {
8555 8556 8557
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("No <source> 'network' attribute "
                             "specified with <interface type='network'/>"));
8558 8559 8560 8561
            goto error;
        }
        def->data.network.name = network;
        network = NULL;
8562 8563 8564 8565
        def->data.network.portgroup = portgroup;
        portgroup = NULL;
        def->data.network.actual = actual;
        actual = NULL;
8566 8567
        break;

M
Michele Paolino 已提交
8568 8569 8570 8571 8572 8573 8574 8575 8576 8577 8578 8579 8580 8581 8582 8583 8584 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
    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;

8614
        if (STREQ(vhostuser_mode, "server")) {
M
Michele Paolino 已提交
8615
            def->data.vhostuser->data.nix.listen = true;
8616
        } else if (STREQ(vhostuser_mode, "client")) {
M
Michele Paolino 已提交
8617
            def->data.vhostuser->data.nix.listen = false;
8618
        } else {
M
Michele Paolino 已提交
8619 8620 8621 8622 8623 8624 8625 8626
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("Wrong <source> 'mode' attribute "
                             "specified with <interface "
                             "type='vhostuser'/>"));
            goto error;
        }
        break;

8627 8628 8629 8630 8631 8632 8633 8634 8635
    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) {
8636 8637 8638
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("No <source> 'bridge' attribute "
                             "specified with <interface type='bridge'/>"));
8639 8640 8641 8642 8643 8644 8645 8646 8647
            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:
8648
    case VIR_DOMAIN_NET_TYPE_UDP:
8649
        if (port == NULL) {
8650 8651 8652
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("No <source> 'port' attribute "
                             "specified with socket interface"));
8653 8654 8655
            goto error;
        }
        if (virStrToLong_i(port, NULL, 10, &def->data.socket.port) < 0) {
8656 8657 8658
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Cannot parse <source> 'port' attribute "
                             "with socket interface"));
8659 8660 8661 8662 8663
            goto error;
        }

        if (address == NULL) {
            if (def->type == VIR_DOMAIN_NET_TYPE_CLIENT ||
8664 8665
                def->type == VIR_DOMAIN_NET_TYPE_MCAST ||
                def->type == VIR_DOMAIN_NET_TYPE_UDP) {
8666 8667 8668
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("No <source> 'address' attribute "
                                 "specified with socket interface"));
8669 8670 8671 8672 8673 8674
                goto error;
            }
        } else {
            def->data.socket.address = address;
            address = NULL;
        }
8675 8676 8677 8678 8679 8680 8681 8682 8683 8684 8685 8686 8687 8688 8689 8690 8691 8692 8693 8694 8695 8696 8697 8698 8699 8700

        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;
        }
8701 8702
        break;

D
Daniel Veillard 已提交
8703 8704
    case VIR_DOMAIN_NET_TYPE_INTERNAL:
        if (internal == NULL) {
8705 8706 8707
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("No <source> 'name' attribute specified "
                             "with <interface type='internal'/>"));
D
Daniel Veillard 已提交
8708 8709 8710 8711 8712
            goto error;
        }
        def->data.internal.name = internal;
        internal = NULL;
        break;
8713 8714 8715

    case VIR_DOMAIN_NET_TYPE_DIRECT:
        if (dev == NULL) {
8716 8717 8718
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("No <source> 'dev' attribute specified "
                             "with <interface type='direct'/>"));
8719 8720 8721 8722
            goto error;
        }

        if (mode != NULL) {
8723
            if ((val = virNetDevMacVLanModeTypeFromString(mode)) < 0) {
8724
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
J
Ján Tomko 已提交
8725
                               _("Unknown mode has been specified"));
8726 8727
                goto error;
            }
8728
            def->data.direct.mode = val;
E
Eric Blake 已提交
8729
        } else {
8730
            def->data.direct.mode = VIR_NETDEV_MACVLAN_MODE_VEPA;
E
Eric Blake 已提交
8731
        }
8732 8733 8734 8735

        def->data.direct.linkdev = dev;
        dev = NULL;

8736
        if (flags & VIR_DOMAIN_DEF_PARSE_INACTIVE)
8737
            VIR_FREE(ifname);
8738

8739
        break;
S
Stefan Berger 已提交
8740

8741 8742 8743 8744 8745 8746 8747 8748 8749 8750 8751
    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 已提交
8752
        if (!addrtype && virXPathNode("./source/vendor", ctxt) &&
8753
            VIR_STRDUP(addrtype, "usb") < 0)
8754
            goto error;
8755 8756 8757
        hostdev->mode = VIR_DOMAIN_HOSTDEV_MODE_SUBSYS;
        if (virDomainHostdevDefParseXMLSubsys(node, ctxt, addrtype,
                                              hostdev, flags) < 0) {
8758 8759 8760 8761
            goto error;
        }
        break;

S
Stefan Berger 已提交
8762 8763 8764
    case VIR_DOMAIN_NET_TYPE_USER:
    case VIR_DOMAIN_NET_TYPE_LAST:
        break;
8765 8766
    }

8767 8768 8769 8770
    for (i = 0; i < nips; i++) {
        if (VIR_APPEND_ELEMENT(def->ips, def->nips, ips[i]) < 0)
            goto error;
    }
8771 8772
    def->nroutes = nroutes;
    def->routes = routes;
8773

8774 8775 8776 8777
    if (script != NULL) {
        def->script = script;
        script = NULL;
    }
8778 8779 8780 8781
    if (domain_name != NULL) {
        def->domain_name = domain_name;
        domain_name = NULL;
    }
8782 8783 8784 8785
    if (ifname != NULL) {
        def->ifname = ifname;
        ifname = NULL;
    }
8786 8787 8788 8789 8790 8791 8792 8793
    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;
    }
8794 8795 8796 8797 8798

    /* 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 已提交
8799
     * QEMU PPC64 supports spapr-vlan
8800 8801
     */
    if (model != NULL) {
E
Eric Blake 已提交
8802
        if (strspn(model, NET_MODEL_CHARS) < strlen(model)) {
8803 8804
            virReportError(VIR_ERR_INVALID_ARG, "%s",
                           _("Model name contains invalid characters"));
E
Eric Blake 已提交
8805
            goto error;
8806 8807 8808 8809 8810
        }
        def->model = model;
        model = NULL;
    }

8811 8812
    if (def->type != VIR_DOMAIN_NET_TYPE_HOSTDEV &&
        STREQ_NULLABLE(def->model, "virtio")) {
8813
        if (backend != NULL) {
8814 8815
            if ((val = virDomainNetBackendTypeFromString(backend)) < 0 ||
                val == VIR_DOMAIN_NET_BACKEND_TYPE_DEFAULT) {
8816
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
8817 8818 8819
                               _("Unknown interface <driver name='%s'> "
                                 "has been specified"),
                               backend);
8820 8821
                goto error;
            }
8822
            def->driver.virtio.name = val;
8823
        }
8824
        if (txmode != NULL) {
8825 8826
            if ((val = virDomainNetVirtioTxModeTypeFromString(txmode)) < 0 ||
                val == VIR_DOMAIN_NET_VIRTIO_TX_MODE_DEFAULT) {
8827
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
8828 8829 8830
                               _("Unknown interface <driver txmode='%s'> "
                                 "has been specified"),
                               txmode);
8831 8832
                goto error;
            }
8833
            def->driver.virtio.txmode = val;
8834
        }
8835
        if (ioeventfd) {
J
Ján Tomko 已提交
8836
            if ((val = virTristateSwitchTypeFromString(ioeventfd)) <= 0) {
8837 8838 8839
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("unknown interface ioeventfd mode '%s'"),
                               ioeventfd);
8840 8841
                goto error;
            }
8842
            def->driver.virtio.ioeventfd = val;
8843
        }
8844
        if (event_idx) {
8845
            if ((val = virTristateSwitchTypeFromString(event_idx)) <= 0) {
8846 8847 8848
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("unknown interface event_idx mode '%s'"),
                               event_idx);
8849 8850
                goto error;
            }
8851
            def->driver.virtio.event_idx = val;
8852
        }
8853 8854
        if (queues) {
            unsigned int q;
8855
            if (virStrToLong_uip(queues, NULL, 10, &q) < 0) {
8856 8857 8858 8859 8860
                virReportError(VIR_ERR_XML_DETAIL,
                               _("'queues' attribute must be positive number: %s"),
                               queues);
                goto error;
            }
8861 8862
            if (q > 1)
                def->driver.virtio.queues = q;
8863
        }
8864 8865 8866 8867 8868 8869 8870 8871 8872 8873 8874 8875 8876 8877 8878 8879 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
        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);
8924 8925 8926 8927 8928 8929 8930 8931 8932 8933
        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);
8934 8935 8936 8937 8938 8939 8940 8941 8942 8943 8944 8945 8946 8947 8948 8949 8950 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
        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;
        }
8983 8984
        def->backend.vhost = vhost_path;
        vhost_path = NULL;
8985
    }
8986

8987 8988 8989
    def->linkstate = VIR_DOMAIN_NET_INTERFACE_LINK_STATE_DEFAULT;
    if (linkstate != NULL) {
        if ((def->linkstate = virDomainNetInterfaceLinkStateTypeFromString(linkstate)) <= 0) {
8990 8991 8992
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown interface link state '%s'"),
                           linkstate);
8993 8994 8995 8996
            goto error;
        }
    }

8997 8998 8999 9000 9001 9002 9003 9004 9005 9006 9007 9008 9009 9010 9011
    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;
        }
    }

9012 9013 9014 9015
    ret = virXPathULong("string(./tune/sndbuf)", ctxt, &def->tune.sndbuf);
    if (ret >= 0) {
        def->tune.sndbuf_specified = true;
    } else if (ret == -2) {
9016 9017
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("sndbuf must be a positive integer"));
9018 9019 9020
        goto error;
    }

9021
 cleanup:
9022
    ctxt->node = oldnode;
9023 9024
    VIR_FREE(macaddr);
    VIR_FREE(network);
9025
    VIR_FREE(portgroup);
9026 9027
    VIR_FREE(address);
    VIR_FREE(port);
M
Michele Paolino 已提交
9028 9029 9030
    VIR_FREE(vhostuser_type);
    VIR_FREE(vhostuser_path);
    VIR_FREE(vhostuser_mode);
9031
    VIR_FREE(ifname);
9032 9033
    VIR_FREE(ifname_guest);
    VIR_FREE(ifname_guest_actual);
9034
    VIR_FREE(dev);
9035
    virDomainActualNetDefFree(actual);
9036 9037 9038
    VIR_FREE(script);
    VIR_FREE(bridge);
    VIR_FREE(model);
9039
    VIR_FREE(backend);
9040
    VIR_FREE(txmode);
9041
    VIR_FREE(ioeventfd);
9042
    VIR_FREE(event_idx);
9043
    VIR_FREE(queues);
9044
    VIR_FREE(str);
9045
    VIR_FREE(filter);
9046
    VIR_FREE(type);
D
Daniel Veillard 已提交
9047
    VIR_FREE(internal);
9048
    VIR_FREE(devaddr);
S
Stefan Berger 已提交
9049
    VIR_FREE(mode);
9050
    VIR_FREE(linkstate);
9051
    VIR_FREE(addrtype);
9052
    VIR_FREE(domain_name);
9053
    VIR_FREE(trustGuestRxFilters);
9054
    VIR_FREE(ips);
9055
    VIR_FREE(vhost_path);
9056 9057
    VIR_FREE(localaddr);
    VIR_FREE(localport);
9058
    virNWFilterHashTableFree(filterparams);
9059 9060 9061

    return def;

9062
 error:
9063 9064 9065 9066 9067
    virDomainNetDefFree(def);
    def = NULL;
    goto cleanup;
}

9068
static int
9069 9070
virDomainChrDefaultTargetType(int devtype)
{
9071
    switch ((virDomainChrDeviceType) devtype) {
9072
    case VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL:
9073 9074 9075
        virReportError(VIR_ERR_XML_ERROR,
                       _("target type must be specified for %s device"),
                       virDomainChrDeviceTypeToString(devtype));
9076
        return -1;
9077 9078

    case VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE:
9079
        return VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_NONE;
9080

9081
    case VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL:
9082
        return VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_ISA;
G
Guannan Ren 已提交
9083

9084
    case VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL:
9085
    case VIR_DOMAIN_CHR_DEVICE_TYPE_LAST:
9086 9087 9088 9089
        /* No target type yet*/
        break;
    }

9090
    return 0;
9091 9092 9093
}

static int
9094
virDomainChrTargetTypeFromString(virDomainChrDefPtr def,
9095
                                 int devtype,
9096 9097 9098 9099
                                 const char *targetType)
{
    int ret = -1;

9100 9101
    if (!targetType)
        return virDomainChrDefaultTargetType(devtype);
9102

9103
    switch ((virDomainChrDeviceType) devtype) {
9104
    case VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL:
9105
        ret = virDomainChrChannelTargetTypeFromString(targetType);
9106 9107
        break;

9108
    case VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE:
9109
        ret = virDomainChrConsoleTargetTypeFromString(targetType);
C
Cole Robinson 已提交
9110
        break;
9111

9112
    case VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL:
9113
        ret = virDomainChrSerialTargetTypeFromString(targetType);
G
Guannan Ren 已提交
9114 9115
        break;

9116
    case VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL:
9117
    case VIR_DOMAIN_CHR_DEVICE_TYPE_LAST:
9118
        /* No target type yet*/
9119
        ret = 0;
9120 9121 9122
        break;
    }

G
Guannan Ren 已提交
9123 9124
    def->targetTypeAttr = true;

9125 9126 9127 9128
    return ret;
}

static int
9129
virDomainChrDefParseTargetXML(virDomainChrDefPtr def,
9130 9131
                              xmlNodePtr cur,
                              unsigned int flags)
9132 9133 9134
{
    int ret = -1;
    unsigned int port;
9135 9136 9137
    char *targetType = virXMLPropString(cur, "type");
    char *addrStr = NULL;
    char *portStr = NULL;
9138
    char *stateStr = NULL;
9139 9140

    if ((def->targetType =
9141 9142
         virDomainChrTargetTypeFromString(def, def->deviceType,
                                          targetType)) < 0) {
9143
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
9144 9145
                       _("unknown target type '%s' specified for character device"),
                       targetType);
9146 9147 9148 9149 9150 9151 9152 9153 9154 9155
        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");

9156
            if (VIR_ALLOC(def->target.addr) < 0)
9157 9158
                goto error;

9159
            if (addrStr == NULL) {
9160 9161 9162
                virReportError(VIR_ERR_XML_ERROR, "%s",
                               _("guestfwd channel does not "
                                 "define a target address"));
9163 9164 9165
                goto error;
            }

9166
            if (virSocketAddrParse(def->target.addr, addrStr, AF_UNSPEC) < 0)
9167 9168
                goto error;

9169
            if (def->target.addr->data.stor.ss_family != AF_INET) {
9170 9171 9172
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               "%s", _("guestfwd channel only supports "
                                       "IPv4 addresses"));
9173 9174 9175 9176
                goto error;
            }

            if (portStr == NULL) {
9177 9178 9179
                virReportError(VIR_ERR_XML_ERROR, "%s",
                               _("guestfwd channel does "
                                 "not define a target port"));
9180 9181 9182 9183
                goto error;
            }

            if (virStrToLong_ui(portStr, NULL, 10, &port) < 0) {
9184 9185 9186
                virReportError(VIR_ERR_XML_ERROR,
                               _("Invalid port number: %s"),
                               portStr);
9187 9188 9189
                goto error;
            }

9190
            virSocketAddrSetPort(def->target.addr, port);
9191 9192 9193 9194
            break;

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

9196
            if (!(flags & VIR_DOMAIN_DEF_PARSE_INACTIVE) &&
9197 9198 9199 9200 9201 9202 9203 9204 9205 9206 9207 9208
                (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;
            }
9209 9210 9211 9212 9213 9214 9215
            break;
        }
        break;

    default:
        portStr = virXMLPropString(cur, "port");
        if (portStr == NULL) {
9216 9217
            /* Set to negative value to indicate we should set it later */
            def->target.port = -1;
9218 9219 9220 9221
            break;
        }

        if (virStrToLong_ui(portStr, NULL, 10, &port) < 0) {
9222 9223 9224
            virReportError(VIR_ERR_XML_ERROR,
                           _("Invalid port number: %s"),
                           portStr);
9225 9226
            goto error;
        }
9227
        def->target.port = port;
9228 9229 9230 9231 9232
        break;
    }


    ret = 0;
9233
 error:
9234 9235 9236
    VIR_FREE(targetType);
    VIR_FREE(addrStr);
    VIR_FREE(portStr);
9237
    VIR_FREE(stateStr);
9238 9239 9240 9241

    return ret;
}

9242 9243 9244
#define SERIAL_CHANNEL_NAME_CHARS \
    "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-."

9245 9246 9247 9248 9249 9250 9251
/* 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,
9252 9253 9254 9255 9256
                              xmlNodePtr cur, unsigned int flags,
                              virDomainChrDefPtr chr_def,
                              xmlXPathContextPtr ctxt,
                              virSecurityLabelDefPtr* vmSeclabels,
                              int nvmSeclabels)
9257
{
9258 9259 9260 9261 9262 9263 9264
    char *bindHost = NULL;
    char *bindService = NULL;
    char *connectHost = NULL;
    char *connectService = NULL;
    char *path = NULL;
    char *mode = NULL;
    char *protocol = NULL;
9265
    char *channel = NULL;
9266 9267
    char *master = NULL;
    char *slave = NULL;
9268
    int remaining = 0;
9269 9270 9271 9272

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

9276
                switch ((virDomainChrType) def->type) {
9277 9278 9279 9280 9281
                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:
9282
                    /* PTY path is only parsed from live xml.  */
9283
                    if (!path  &&
9284
                        (def->type != VIR_DOMAIN_CHR_TYPE_PTY ||
9285
                         !(flags & VIR_DOMAIN_DEF_PARSE_INACTIVE)))
9286 9287 9288 9289 9290 9291
                        path = virXMLPropString(cur, "path");

                    break;

                case VIR_DOMAIN_CHR_TYPE_UDP:
                case VIR_DOMAIN_CHR_TYPE_TCP:
9292 9293
                    if (!mode || STREQ(mode, "connect")) {
                        if (!connectHost)
9294
                            connectHost = virXMLPropString(cur, "host");
9295
                        if (!connectService)
9296
                            connectService = virXMLPropString(cur, "service");
9297 9298
                    } else if (STREQ(mode, "bind")) {
                        if (!bindHost)
9299
                            bindHost = virXMLPropString(cur, "host");
9300
                        if (!bindService)
9301
                            bindService = virXMLPropString(cur, "service");
9302
                    } else {
9303
                        virReportError(VIR_ERR_INTERNAL_ERROR,
9304
                                       _("Unknown source mode '%s'"), mode);
9305
                        goto error;
9306 9307
                    }

9308
                    if (def->type == VIR_DOMAIN_CHR_TYPE_UDP)
9309
                        VIR_FREE(mode);
9310 9311
                    break;

9312 9313 9314 9315 9316
                case VIR_DOMAIN_CHR_TYPE_SPICEPORT:
                    if (!channel)
                        channel = virXMLPropString(cur, "channel");
                    break;

9317 9318 9319 9320 9321 9322 9323
                case VIR_DOMAIN_CHR_TYPE_NMDM:
                    if (!master)
                        master = virXMLPropString(cur, "master");
                    if (!slave)
                        slave = virXMLPropString(cur, "slave");
                    break;

9324 9325 9326 9327 9328 9329
                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;
9330
                }
9331 9332 9333 9334 9335 9336 9337 9338 9339

                /* 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,
9340 9341
                                                          ctxt,
                                                          flags) < 0) {
9342 9343 9344 9345 9346
                        ctxt->node = saved_node;
                        goto error;
                    }
                    ctxt->node = saved_node;
                }
9347
            } else if (xmlStrEqual(cur->name, BAD_CAST "protocol")) {
9348
                if (!protocol)
9349
                    protocol = virXMLPropString(cur, "type");
9350 9351
            } else {
                remaining++;
9352 9353 9354 9355 9356
            }
        }
        cur = cur->next;
    }

9357
    switch ((virDomainChrType) def->type) {
9358
    case VIR_DOMAIN_CHR_TYPE_NULL:
9359
    case VIR_DOMAIN_CHR_TYPE_VC:
9360 9361
    case VIR_DOMAIN_CHR_TYPE_STDIO:
    case VIR_DOMAIN_CHR_TYPE_SPICEVMC:
9362
    case VIR_DOMAIN_CHR_TYPE_LAST:
9363 9364 9365 9366 9367 9368
        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:
9369
        if (!path &&
9370
            def->type != VIR_DOMAIN_CHR_TYPE_PTY) {
9371 9372
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Missing source path attribute for char device"));
9373 9374 9375 9376 9377 9378 9379
            goto error;
        }

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

9380 9381 9382 9383 9384 9385 9386 9387 9388 9389 9390 9391 9392 9393 9394 9395 9396 9397 9398
    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;

9399
    case VIR_DOMAIN_CHR_TYPE_TCP:
9400 9401
        if (!mode || STREQ(mode, "connect")) {
            if (!connectHost) {
9402 9403
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Missing source host attribute for char device"));
9404 9405
                goto error;
            }
9406 9407

            if (!connectService) {
9408 9409
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Missing source service attribute for char device"));
9410 9411 9412 9413 9414 9415 9416
                goto error;
            }

            def->data.tcp.host = connectHost;
            connectHost = NULL;
            def->data.tcp.service = connectService;
            connectService = NULL;
9417
            def->data.tcp.listen = false;
9418
        } else {
9419
            if (!bindHost) {
9420 9421
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Missing source host attribute for char device"));
9422 9423
                goto error;
            }
9424 9425

            if (!bindService) {
9426 9427
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Missing source service attribute for char device"));
9428 9429 9430 9431 9432 9433 9434
                goto error;
            }

            def->data.tcp.host = bindHost;
            bindHost = NULL;
            def->data.tcp.service = bindService;
            bindService = NULL;
9435
            def->data.tcp.listen = true;
9436
        }
9437

9438
        if (!protocol)
9439
            def->data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_RAW;
9440 9441
        else if ((def->data.tcp.protocol =
                  virDomainChrTcpProtocolTypeFromString(protocol)) < 0) {
9442
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
9443
                           _("Unknown protocol '%s'"), protocol);
9444 9445 9446
            goto error;
        }

9447 9448 9449
        break;

    case VIR_DOMAIN_CHR_TYPE_UDP:
9450
        if (!connectService) {
9451 9452
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Missing source service attribute for char device"));
9453 9454 9455 9456 9457 9458 9459 9460 9461 9462 9463 9464 9465 9466 9467
            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:
9468 9469
        /* path can be auto generated */
        if (!path &&
9470 9471
            (!chr_def ||
             chr_def->targetType != VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO)) {
9472 9473
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Missing source path attribute for char device"));
9474 9475 9476
            goto error;
        }

9477
        def->data.nix.listen = mode != NULL && STRNEQ(mode, "connect");
9478 9479 9480 9481

        def->data.nix.path = path;
        path = NULL;
        break;
9482 9483 9484 9485 9486 9487 9488 9489 9490 9491 9492 9493 9494 9495 9496

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

9499
 cleanup:
9500 9501 9502 9503 9504 9505 9506
    VIR_FREE(mode);
    VIR_FREE(protocol);
    VIR_FREE(bindHost);
    VIR_FREE(bindService);
    VIR_FREE(connectHost);
    VIR_FREE(connectService);
    VIR_FREE(path);
9507
    VIR_FREE(channel);
9508

9509 9510
    return remaining;

9511
 error:
9512 9513 9514 9515 9516
    virDomainChrSourceDefClear(def);
    remaining = -1;
    goto cleanup;
}

M
Michal Novotny 已提交
9517 9518 9519 9520
/* Create a new character device definition and set
 * default port.
 */
virDomainChrDefPtr
9521 9522
virDomainChrDefNew(void)
{
M
Michal Novotny 已提交
9523 9524
    virDomainChrDefPtr def = NULL;

9525
    if (VIR_ALLOC(def) < 0)
M
Michal Novotny 已提交
9526 9527 9528 9529 9530 9531
        return NULL;

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

9532 9533 9534 9535 9536 9537 9538 9539 9540 9541 9542 9543 9544 9545 9546 9547 9548 9549 9550 9551 9552 9553 9554 9555 9556 9557 9558 9559 9560 9561 9562 9563 9564 9565 9566 9567 9568
/* 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>
 *
9569 9570 9571 9572 9573
 * <serial type="nmdm">
 *   <source master="/dev/nmdm0A" slave="/dev/nmdm0B"/>
 *   <target port="1">
 * </serial>
 *
9574 9575
 */
static virDomainChrDefPtr
9576
virDomainChrDefParseXML(xmlXPathContextPtr ctxt,
9577
                        xmlNodePtr node,
9578 9579
                        virSecurityLabelDefPtr* vmSeclabels,
                        int nvmSeclabels,
E
Eric Blake 已提交
9580 9581
                        unsigned int flags)
{
9582 9583 9584 9585
    xmlNodePtr cur;
    char *type = NULL;
    const char *nodeName;
    virDomainChrDefPtr def;
9586
    bool seenTarget = false;
9587

M
Michal Novotny 已提交
9588
    if (!(def = virDomainChrDefNew()))
9589 9590 9591 9592 9593 9594
        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) {
9595
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
9596 9597
                       _("unknown type presented to host for character device: %s"),
                       type);
9598 9599 9600 9601 9602
        goto error;
    }

    nodeName = (const char *) node->name;
    if ((def->deviceType = virDomainChrDeviceTypeFromString(nodeName)) < 0) {
9603
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
9604 9605
                       _("unknown character device type: %s"),
                       nodeName);
9606
        goto error;
9607 9608 9609
    }

    cur = node->children;
9610 9611 9612 9613
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
            if (xmlStrEqual(cur->name, BAD_CAST "target")) {
                seenTarget = true;
9614
                if (virDomainChrDefParseTargetXML(def, cur, flags) < 0)
9615
                    goto error;
9616 9617
            }
        }
9618
        cur = cur->next;
9619 9620
    }

9621
    if (!seenTarget &&
9622
        ((def->targetType = virDomainChrDefaultTargetType(def->deviceType)) < 0))
9623
        goto error;
9624

9625 9626 9627 9628
    if (virDomainChrSourceDefParseXML(&def->source, node->children, flags, def,
                                      ctxt, vmSeclabels, nvmSeclabels) < 0)
        goto error;

E
Eric Blake 已提交
9629 9630
    if (def->source.type == VIR_DOMAIN_CHR_TYPE_SPICEVMC) {
        if (def->targetType != VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO) {
9631 9632 9633
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("spicevmc device type only supports "
                             "virtio"));
E
Eric Blake 已提交
9634 9635 9636 9637
            goto error;
        } else {
            def->source.data.spicevmc = VIR_DOMAIN_CHR_SPICEVMC_VDAGENT;
        }
9638 9639
    }

9640 9641 9642 9643
    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) {
9644
        goto error;
9645 9646
    }

9647

G
Guannan Ren 已提交
9648 9649 9650 9651 9652 9653 9654 9655 9656
    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;
    }

9657
 cleanup:
9658 9659
    VIR_FREE(type);

9660 9661
    return def;

9662
 error:
9663 9664 9665 9666 9667
    virDomainChrDefFree(def);
    def = NULL;
    goto cleanup;
}

E
Eric Blake 已提交
9668 9669
static virDomainSmartcardDefPtr
virDomainSmartcardDefParseXML(xmlNodePtr node,
E
Eric Blake 已提交
9670
                              unsigned int flags)
E
Eric Blake 已提交
9671 9672 9673 9674 9675
{
    xmlNodePtr cur;
    char *mode = NULL;
    char *type = NULL;
    virDomainSmartcardDefPtr def;
9676
    size_t i;
E
Eric Blake 已提交
9677

9678
    if (VIR_ALLOC(def) < 0)
E
Eric Blake 已提交
9679 9680 9681 9682
        return NULL;

    mode = virXMLPropString(node, "mode");
    if (mode == NULL) {
9683 9684
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("missing smartcard device mode"));
E
Eric Blake 已提交
9685 9686 9687
        goto error;
    }
    if ((def->type = virDomainSmartcardTypeFromString(mode)) < 0) {
9688
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
9689 9690
                       _("unknown smartcard device mode: %s"),
                       mode);
E
Eric Blake 已提交
9691 9692 9693 9694 9695 9696 9697 9698 9699 9700 9701 9702 9703 9704
        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) {
9705 9706 9707
                    virReportError(VIR_ERR_XML_ERROR, "%s",
                                   _("host-certificates mode needs "
                                     "exactly three certificates"));
E
Eric Blake 已提交
9708 9709 9710 9711 9712 9713 9714 9715 9716 9717 9718 9719 9720 9721 9722 9723 9724
                    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 != '/') {
9725 9726 9727
                    virReportError(VIR_ERR_XML_ERROR,
                                   _("expecting absolute path: %s"),
                                   def->data.cert.database);
E
Eric Blake 已提交
9728 9729 9730 9731 9732 9733
                    goto error;
                }
            }
            cur = cur->next;
        }
        if (i < 3) {
9734 9735 9736
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("host-certificates mode needs "
                             "exactly three certificates"));
E
Eric Blake 已提交
9737 9738 9739 9740 9741 9742 9743
            goto error;
        }
        break;

    case VIR_DOMAIN_SMARTCARD_TYPE_PASSTHROUGH:
        type = virXMLPropString(node, "type");
        if (type == NULL) {
9744 9745 9746
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("passthrough mode requires a character "
                             "device type attribute"));
E
Eric Blake 已提交
9747 9748 9749
            goto error;
        }
        if ((def->data.passthru.type = virDomainChrTypeFromString(type)) < 0) {
9750
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
9751 9752
                           _("unknown type presented to host for "
                             "character device: %s"), type);
E
Eric Blake 已提交
9753 9754 9755 9756
            goto error;
        }

        cur = node->children;
9757 9758
        if (virDomainChrSourceDefParseXML(&def->data.passthru, cur, flags,
                                          NULL, NULL, NULL, 0) < 0)
E
Eric Blake 已提交
9759
            goto error;
9760 9761

        if (def->data.passthru.type == VIR_DOMAIN_CHR_TYPE_SPICEVMC) {
E
Eric Blake 已提交
9762 9763
            def->data.passthru.data.spicevmc
                = VIR_DOMAIN_CHR_SPICEVMC_SMARTCARD;
9764
        }
E
Eric Blake 已提交
9765

E
Eric Blake 已提交
9766 9767 9768
        break;

    default:
9769 9770
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("unknown smartcard mode"));
E
Eric Blake 已提交
9771 9772 9773
        goto error;
    }

9774
    if (virDomainDeviceInfoParseXML(node, NULL, &def->info, flags) < 0)
E
Eric Blake 已提交
9775 9776 9777
        goto error;
    if (def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCID) {
9778 9779
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Controllers must use the 'ccid' address type"));
E
Eric Blake 已提交
9780 9781 9782
        goto error;
    }

9783
 cleanup:
E
Eric Blake 已提交
9784 9785 9786 9787 9788
    VIR_FREE(mode);
    VIR_FREE(type);

    return def;

9789
 error:
E
Eric Blake 已提交
9790 9791 9792 9793 9794
    virDomainSmartcardDefFree(def);
    def = NULL;
    goto cleanup;
}

9795 9796 9797 9798 9799 9800 9801 9802 9803 9804 9805 9806
/* 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
9807
virDomainTPMDefParseXML(xmlNodePtr node,
9808 9809 9810 9811 9812 9813 9814 9815 9816 9817 9818 9819
                        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;

9820
    if (VIR_ALLOC(def) < 0)
9821 9822 9823 9824 9825
        return NULL;

    model = virXMLPropString(node, "model");
    if (model != NULL &&
        (int)(def->model = virDomainTPMModelTypeFromString(model)) < 0) {
9826
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
9827 9828 9829 9830 9831 9832 9833 9834 9835 9836 9837 9838 9839 9840 9841 9842 9843
                       _("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;
    }

9844 9845 9846 9847 9848 9849
    if (nbackends == 0) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("missing TPM device backend"));
        goto error;
    }

9850 9851 9852 9853 9854 9855 9856
    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) {
9857
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
9858 9859 9860 9861 9862 9863 9864 9865
                       _("Unknown TPM backend type '%s'"),
                       backend);
        goto error;
    }

    switch (def->type) {
    case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH:
        path = virXPathString("string(./backend/device/@path)", ctxt);
9866
        if (!path && VIR_STRDUP(path, VIR_DOMAIN_TPM_DEFAULT_DEVICE) < 0)
9867 9868 9869 9870 9871 9872 9873 9874 9875 9876 9877 9878
            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;

9879
 cleanup:
9880 9881 9882 9883 9884 9885 9886 9887
    VIR_FREE(type);
    VIR_FREE(path);
    VIR_FREE(model);
    VIR_FREE(backend);
    VIR_FREE(backends);
    ctxt->node = save;
    return def;

9888
 error:
9889 9890 9891 9892 9893
    virDomainTPMDefFree(def);
    def = NULL;
    goto cleanup;
}

9894 9895 9896 9897
static virDomainPanicDefPtr
virDomainPanicDefParseXML(xmlNodePtr node)
{
    virDomainPanicDefPtr panic;
9898
    char *model = NULL;
9899 9900 9901 9902 9903 9904 9905

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

    if (virDomainDeviceInfoParseXML(node, NULL, &panic->info, 0) < 0)
        goto error;

9906 9907 9908 9909 9910 9911 9912 9913 9914 9915
    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);
9916
    return panic;
9917

9918 9919
 error:
    virDomainPanicDefFree(panic);
9920 9921
    panic = NULL;
    goto cleanup;
9922 9923
}

9924
/* Parse the XML definition for an input device */
9925
static virDomainInputDefPtr
L
Li Zhang 已提交
9926
virDomainInputDefParseXML(const virDomainDef *dom,
9927
                          xmlNodePtr node,
9928
                          xmlXPathContextPtr ctxt,
E
Eric Blake 已提交
9929 9930
                          unsigned int flags)
{
9931
    xmlNodePtr save = ctxt->node;
9932
    virDomainInputDefPtr def;
9933
    char *evdev = NULL;
9934 9935 9936
    char *type = NULL;
    char *bus = NULL;

9937
    if (VIR_ALLOC(def) < 0)
9938 9939
        return NULL;

9940 9941
    ctxt->node = node;

9942 9943 9944 9945
    type = virXMLPropString(node, "type");
    bus = virXMLPropString(node, "bus");

    if (!type) {
9946 9947
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing input device type"));
9948 9949 9950 9951
        goto error;
    }

    if ((def->type = virDomainInputTypeFromString(type)) < 0) {
9952
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
9953
                       _("unknown input device type '%s'"), type);
9954 9955 9956 9957 9958
        goto error;
    }

    if (bus) {
        if ((def->bus = virDomainInputBusTypeFromString(bus)) < 0) {
9959
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
9960
                           _("unknown input bus type '%s'"), bus);
9961 9962 9963
            goto error;
        }

9964
        if (dom->os.type == VIR_DOMAIN_OSTYPE_HVM) {
L
Li Zhang 已提交
9965 9966 9967
            if (def->bus == VIR_DOMAIN_INPUT_BUS_PS2 &&
                def->type != VIR_DOMAIN_INPUT_TYPE_MOUSE &&
                def->type != VIR_DOMAIN_INPUT_TYPE_KBD) {
9968 9969 9970
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("ps2 bus does not support %s input device"),
                               type);
9971 9972 9973
                goto error;
            }
            if (def->bus == VIR_DOMAIN_INPUT_BUS_XEN) {
9974 9975 9976
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unsupported input bus %s"),
                               bus);
9977 9978
                goto error;
            }
9979
        } else if (dom->os.type == VIR_DOMAIN_OSTYPE_XEN) {
9980
            if (def->bus != VIR_DOMAIN_INPUT_BUS_XEN) {
9981 9982 9983
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unsupported input bus %s"),
                               bus);
9984
                goto error;
9985
            }
L
Li Zhang 已提交
9986 9987
            if (def->type != VIR_DOMAIN_INPUT_TYPE_MOUSE &&
                def->type != VIR_DOMAIN_INPUT_TYPE_KBD) {
9988 9989 9990
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("xen bus does not support %s input device"),
                               type);
9991 9992
                goto error;
            }
9993
        } else {
9994 9995
            if (dom->virtType == VIR_DOMAIN_VIRT_VZ ||
                dom->virtType == VIR_DOMAIN_VIRT_PARALLELS) {
9996 9997 9998 9999 10000 10001 10002 10003 10004 10005 10006 10007 10008 10009 10010 10011 10012 10013 10014 10015 10016 10017
                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;
            }
10018 10019
        }
    } else {
10020
        if (dom->os.type == VIR_DOMAIN_OSTYPE_HVM) {
L
Li Zhang 已提交
10021
            if ((def->type == VIR_DOMAIN_INPUT_TYPE_MOUSE ||
10022 10023
                def->type == VIR_DOMAIN_INPUT_TYPE_KBD) &&
                (ARCH_IS_X86(dom->os.arch) || dom->os.arch == VIR_ARCH_NONE)) {
10024
                def->bus = VIR_DOMAIN_INPUT_BUS_PS2;
10025
            } else {
10026
                def->bus = VIR_DOMAIN_INPUT_BUS_USB;
10027
            }
10028
        } else if (dom->os.type == VIR_DOMAIN_OSTYPE_XEN) {
10029
            def->bus = VIR_DOMAIN_INPUT_BUS_XEN;
10030
        } else {
10031 10032
            if ((dom->virtType == VIR_DOMAIN_VIRT_VZ ||
                 dom->virtType == VIR_DOMAIN_VIRT_PARALLELS))
10033
                def->bus = VIR_DOMAIN_INPUT_BUS_PARALLELS;
10034 10035 10036
        }
    }

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

10040 10041 10042
    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) {
10043 10044
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Invalid address for a USB device"));
10045 10046 10047
        goto error;
    }

10048 10049 10050 10051 10052 10053 10054 10055
    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;
    }

10056
 cleanup:
10057
    VIR_FREE(evdev);
10058 10059 10060
    VIR_FREE(type);
    VIR_FREE(bus);

10061
    ctxt->node = save;
10062 10063
    return def;

10064
 error:
10065 10066 10067 10068 10069 10070
    virDomainInputDefFree(def);
    def = NULL;
    goto cleanup;
}


E
Eric Blake 已提交
10071
/* Parse the XML definition for a hub device */
M
Marc-André Lureau 已提交
10072 10073 10074 10075 10076 10077
static virDomainHubDefPtr
virDomainHubDefParseXML(xmlNodePtr node, unsigned int flags)
{
    virDomainHubDefPtr def;
    char *type = NULL;

10078
    if (VIR_ALLOC(def) < 0)
M
Marc-André Lureau 已提交
10079 10080 10081 10082 10083
        return NULL;

    type = virXMLPropString(node, "type");

    if (!type) {
10084 10085
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing hub device type"));
M
Marc-André Lureau 已提交
10086 10087 10088 10089
        goto error;
    }

    if ((def->type = virDomainHubTypeFromString(type)) < 0) {
10090
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
10091
                       _("unknown hub device type '%s'"), type);
M
Marc-André Lureau 已提交
10092 10093 10094
        goto error;
    }

10095
    if (virDomainDeviceInfoParseXML(node, NULL, &def->info, flags) < 0)
M
Marc-André Lureau 已提交
10096 10097
        goto error;

10098
 cleanup:
M
Marc-André Lureau 已提交
10099 10100 10101 10102
    VIR_FREE(type);

    return def;

10103
 error:
M
Marc-André Lureau 已提交
10104 10105 10106 10107 10108 10109
    virDomainHubDefFree(def);
    def = NULL;
    goto cleanup;
}


10110 10111
/* Parse the XML definition for a clock timer */
static virDomainTimerDefPtr
10112
virDomainTimerDefParseXML(xmlNodePtr node,
E
Eric Blake 已提交
10113
                          xmlXPathContextPtr ctxt)
10114 10115 10116 10117
{
    char *name = NULL;
    char *present = NULL;
    char *tickpolicy = NULL;
10118
    char *track = NULL;
10119 10120 10121 10122
    char *mode = NULL;

    virDomainTimerDefPtr def;
    xmlNodePtr oldnode = ctxt->node;
10123 10124
    xmlNodePtr catchup;
    int ret;
10125

10126
    if (VIR_ALLOC(def) < 0)
10127 10128 10129 10130 10131 10132
        return NULL;

    ctxt->node = node;

    name = virXMLPropString(node, "name");
    if (name == NULL) {
10133 10134
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing timer name"));
10135 10136 10137
        goto error;
    }
    if ((def->name = virDomainTimerNameTypeFromString(name)) < 0) {
10138
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
10139
                       _("unknown timer name '%s'"), name);
10140 10141 10142 10143 10144 10145 10146 10147 10148 10149
        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 {
10150 10151
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown timer present value '%s'"), present);
10152 10153 10154 10155 10156 10157 10158 10159
            goto error;
        }
    }

    def->tickpolicy = -1;
    tickpolicy = virXMLPropString(node, "tickpolicy");
    if (tickpolicy != NULL) {
        if ((def->tickpolicy = virDomainTimerTickpolicyTypeFromString(tickpolicy)) < 0) {
10160
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
10161
                           _("unknown timer tickpolicy '%s'"), tickpolicy);
10162 10163 10164 10165
            goto error;
        }
    }

10166 10167 10168 10169
    def->track = -1;
    track = virXMLPropString(node, "track");
    if (track != NULL) {
        if ((def->track = virDomainTimerTrackTypeFromString(track)) < 0) {
10170
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
10171
                           _("unknown timer track '%s'"), track);
10172 10173 10174 10175
            goto error;
        }
    }

10176
    ret = virXPathULong("string(./frequency)", ctxt, &def->frequency);
10177 10178
    if (ret == -1) {
        def->frequency = 0;
10179
    } else if (ret < 0) {
10180 10181
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("invalid timer frequency"));
10182 10183 10184 10185 10186 10187 10188
        goto error;
    }

    def->mode = -1;
    mode = virXMLPropString(node, "mode");
    if (mode != NULL) {
        if ((def->mode = virDomainTimerModeTypeFromString(mode)) < 0) {
10189
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
10190
                           _("unknown timer mode '%s'"), mode);
10191 10192 10193 10194
            goto error;
        }
    }

10195
    catchup = virXPathNode("./catchup", ctxt);
10196 10197 10198 10199 10200 10201
    if (catchup != NULL) {
        ret = virXPathULong("string(./catchup/@threshold)", ctxt,
                            &def->catchup.threshold);
        if (ret == -1) {
            def->catchup.threshold = 0;
        } else if (ret < 0) {
10202 10203
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("invalid catchup threshold"));
10204 10205 10206 10207 10208 10209 10210
            goto error;
        }

        ret = virXPathULong("string(./catchup/@slew)", ctxt, &def->catchup.slew);
        if (ret == -1) {
            def->catchup.slew = 0;
        } else if (ret < 0) {
10211 10212
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("invalid catchup slew"));
10213 10214 10215 10216 10217 10218 10219
            goto error;
        }

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

10226
 cleanup:
10227 10228 10229
    VIR_FREE(name);
    VIR_FREE(present);
    VIR_FREE(tickpolicy);
10230
    VIR_FREE(track);
10231 10232 10233 10234 10235
    VIR_FREE(mode);
    ctxt->node = oldnode;

    return def;

10236
 error:
10237 10238 10239 10240
    VIR_FREE(def);
    goto cleanup;
}

10241 10242

static int
10243 10244 10245
virDomainGraphicsAuthDefParseXML(xmlNodePtr node,
                                 virDomainGraphicsAuthDefPtr def,
                                 int type)
10246 10247
{
    char *validTo = NULL;
10248
    char *connected = virXMLPropString(node, "connected");
10249 10250 10251 10252 10253 10254 10255 10256 10257 10258 10259 10260 10261 10262 10263 10264 10265 10266 10267 10268 10269 10270 10271 10272

    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') {
10273 10274 10275
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot parse password validity time '%s', expect YYYY-MM-DDTHH:MM:SS"),
                           validTo);
10276 10277 10278 10279 10280 10281 10282 10283 10284 10285
            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);
10286
        def->expires = true;
10287 10288
    }

10289 10290 10291
    if (connected) {
        int action = virDomainGraphicsAuthConnectedTypeFromString(connected);
        if (action <= 0) {
10292 10293 10294
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown connected value %s"),
                           connected);
10295 10296 10297 10298 10299 10300 10301 10302
            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) {
10303 10304
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("VNC supports connected='keep' only"));
10305 10306 10307 10308 10309 10310
            return -1;
        }

        def->connected = action;
    }

10311 10312 10313
    return 0;
}

10314 10315 10316 10317 10318 10319 10320 10321 10322
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");
10323 10324
    char *fromConfig = virXMLPropString(node, "fromConfig");
    int tmp;
10325 10326

    if (!type) {
10327 10328
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("graphics listen type must be specified"));
10329 10330 10331 10332
        goto error;
    }

    if ((def->type = virDomainGraphicsListenTypeFromString(type)) < 0) {
10333
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
10334
                       _("unknown graphics listen type '%s'"), type);
10335 10336 10337 10338 10339 10340 10341
        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 已提交
10342 10343
        (def->type == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS ||
         (def->type == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NETWORK &&
10344
          !(flags & VIR_DOMAIN_DEF_PARSE_INACTIVE)))) {
10345 10346 10347 10348 10349 10350 10351
        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
10352
             * type='network' */
10353 10354
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("network attribute not allowed when listen type is not network"));
10355 10356 10357 10358 10359 10360
            goto error;
        }
        def->network = network;
        network = NULL;
    }

10361
    if (fromConfig &&
10362
        flags & VIR_DOMAIN_DEF_PARSE_STATUS) {
10363 10364 10365 10366 10367 10368 10369 10370 10371
        if (virStrToLong_i(fromConfig, NULL, 10, &tmp) < 0) {
            virReportError(VIR_ERR_XML_ERROR,
                           _("Invalid fromConfig value: %s"),
                           fromConfig);
            goto error;
        }
        def->fromConfig = tmp != 0;
    }

10372
    ret = 0;
10373
 error:
10374 10375 10376 10377 10378
    if (ret < 0)
        virDomainGraphicsListenDefClear(def);
    VIR_FREE(type);
    VIR_FREE(address);
    VIR_FREE(network);
10379
    VIR_FREE(fromConfig);
10380 10381 10382
    return ret;
}

10383

10384 10385
/* Parse the XML definition for a graphics device */
static virDomainGraphicsDefPtr
10386 10387 10388
virDomainGraphicsDefParseXML(xmlNodePtr node,
                             xmlXPathContextPtr ctxt,
                             unsigned int flags)
E
Eric Blake 已提交
10389
{
10390 10391
    virDomainGraphicsDefPtr def;
    char *type = NULL;
10392 10393 10394 10395
    int nListens;
    xmlNodePtr *listenNodes = NULL;
    char *listenAddr = NULL;
    xmlNodePtr save = ctxt->node;
10396

10397
    if (VIR_ALLOC(def) < 0)
10398 10399
        return NULL;

10400 10401
    ctxt->node = node;

10402 10403 10404
    type = virXMLPropString(node, "type");

    if (!type) {
10405 10406
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing graphics device type"));
10407 10408 10409 10410
        goto error;
    }

    if ((def->type = virDomainGraphicsTypeFromString(type)) < 0) {
10411
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
10412
                       _("unknown graphics device type '%s'"), type);
10413 10414 10415
        goto error;
    }

E
Eric Blake 已提交
10416 10417 10418
    if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC ||
        def->type == VIR_DOMAIN_GRAPHICS_TYPE_RDP ||
        def->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) {
10419 10420 10421 10422 10423 10424 10425

        /* parse the <listen> subelements for graphics types that support it */
        nListens = virXPathNodeSet("./listen", ctxt, &listenNodes);
        if (nListens < 0)
            goto error;

        if (nListens > 0) {
10426
            size_t i;
10427

10428
            if (VIR_ALLOC_N(def->listens, nListens) < 0)
10429 10430
                goto error;

10431 10432 10433
            for (i = 0; i < nListens; i++) {
                int ret = virDomainGraphicsListenDefParseXML(&def->listens[i],
                                                             listenNodes[i],
10434 10435 10436 10437 10438 10439 10440 10441 10442 10443 10444 10445 10446 10447 10448 10449 10450 10451 10452 10453 10454 10455 10456 10457 10458 10459 10460 10461 10462
                                                             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;
10463
                size_t i;
10464

10465 10466
                for (i = 0; i < nListens; i++) {
                    if (virDomainGraphicsListenGetType(def, i)
10467
                        == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS) {
10468
                        found = virDomainGraphicsListenGetAddress(def, i);
10469
                        if (STREQ_NULLABLE(found, listenAddr))
10470 10471 10472 10473
                            matched = true;
                        break;
                    }
                }
10474
                if (found && !matched) {
10475 10476 10477
                    virReportError(VIR_ERR_XML_ERROR,
                                   _("graphics listen attribute %s must match address "
                                     "attribute of first listen element (found %s)"),
10478
                                   listenAddr, found);
10479
                    goto error;
10480 10481 10482 10483
                } else if (!found) {
                    /* quietly ignore listen address if none of the listens
                     * are of type address */
                    VIR_FREE(listenAddr);
10484 10485 10486 10487 10488
                }
            }
        }
    }

10489 10490
    if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
        char *port = virXMLPropString(node, "port");
M
Martin Kletzander 已提交
10491
        char *websocket = virXMLPropString(node, "websocket");
10492
        char *sharePolicy = virXMLPropString(node, "sharePolicy");
10493 10494 10495 10496
        char *autoport;

        if (port) {
            if (virStrToLong_i(port, NULL, 10, &def->data.vnc.port) < 0) {
10497 10498
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("cannot parse vnc port %s"), port);
10499 10500 10501 10502 10503 10504
                VIR_FREE(port);
                goto error;
            }
            VIR_FREE(port);
            /* Legacy compat syntax, used -1 for auto-port */
            if (def->data.vnc.port == -1) {
10505
                if (flags & VIR_DOMAIN_DEF_PARSE_INACTIVE)
10506
                    def->data.vnc.port = 0;
10507
                def->data.vnc.autoport = true;
10508 10509 10510
            }
        } else {
            def->data.vnc.port = 0;
10511
            def->data.vnc.autoport = true;
10512 10513 10514 10515
        }

        if ((autoport = virXMLPropString(node, "autoport")) != NULL) {
            if (STREQ(autoport, "yes")) {
10516
                if (flags & VIR_DOMAIN_DEF_PARSE_INACTIVE)
10517
                    def->data.vnc.port = 0;
10518
                def->data.vnc.autoport = true;
10519 10520 10521 10522
            }
            VIR_FREE(autoport);
        }

M
Martin Kletzander 已提交
10523 10524 10525 10526 10527 10528 10529 10530 10531 10532 10533 10534
        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);
        }

10535 10536 10537 10538 10539 10540 10541 10542 10543 10544 10545 10546 10547 10548 10549
        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);
        }

10550
        def->data.vnc.socket = virXMLPropString(node, "socket");
10551
        def->data.vnc.keymap = virXMLPropString(node, "keymap");
10552

10553 10554
        if (virDomainGraphicsAuthDefParseXML(node, &def->data.vnc.auth,
                                             def->type) < 0)
10555
            goto error;
10556
    } else if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) {
10557 10558 10559 10560
        char *fullscreen = virXMLPropString(node, "fullscreen");

        if (fullscreen != NULL) {
            if (STREQ(fullscreen, "yes")) {
10561
                def->data.sdl.fullscreen = true;
10562
            } else if (STREQ(fullscreen, "no")) {
10563
                def->data.sdl.fullscreen = false;
10564
            } else {
10565 10566
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unknown fullscreen value '%s'"), fullscreen);
10567 10568 10569 10570
                VIR_FREE(fullscreen);
                goto error;
            }
            VIR_FREE(fullscreen);
E
Eric Blake 已提交
10571
        } else {
10572
            def->data.sdl.fullscreen = false;
E
Eric Blake 已提交
10573
        }
10574 10575
        def->data.sdl.xauth = virXMLPropString(node, "xauth");
        def->data.sdl.display = virXMLPropString(node, "display");
10576 10577 10578 10579 10580 10581 10582 10583
    } 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) {
10584 10585
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("cannot parse rdp port %s"), port);
10586 10587 10588
                VIR_FREE(port);
                goto error;
            }
M
Michal Privoznik 已提交
10589 10590
            /* Legacy compat syntax, used -1 for auto-port */
            if (def->data.rdp.port == -1)
10591
                def->data.rdp.autoport = true;
M
Michal Privoznik 已提交
10592

10593 10594 10595
            VIR_FREE(port);
        } else {
            def->data.rdp.port = 0;
10596
            def->data.rdp.autoport = true;
10597 10598 10599
        }

        if ((autoport = virXMLPropString(node, "autoport")) != NULL) {
M
Michal Privoznik 已提交
10600
            if (STREQ(autoport, "yes"))
10601
                def->data.rdp.autoport = true;
M
Michal Privoznik 已提交
10602

10603 10604 10605
            VIR_FREE(autoport);
        }

10606
        if (def->data.rdp.autoport && (flags & VIR_DOMAIN_DEF_PARSE_INACTIVE))
M
Michal Privoznik 已提交
10607 10608
            def->data.rdp.port = 0;

10609
        if ((replaceUser = virXMLPropString(node, "replaceUser")) != NULL) {
10610
            if (STREQ(replaceUser, "yes"))
10611
                def->data.rdp.replaceUser = true;
10612 10613 10614 10615
            VIR_FREE(replaceUser);
        }

        if ((multiUser = virXMLPropString(node, "multiUser")) != NULL) {
10616
            if (STREQ(multiUser, "yes"))
10617
                def->data.rdp.multiUser = true;
10618 10619 10620 10621 10622 10623 10624 10625
            VIR_FREE(multiUser);
        }

    } else if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP) {
        char *fullscreen = virXMLPropString(node, "fullscreen");

        if (fullscreen != NULL) {
            if (STREQ(fullscreen, "yes")) {
10626
                def->data.desktop.fullscreen = true;
10627
            } else if (STREQ(fullscreen, "no")) {
10628
                def->data.desktop.fullscreen = false;
10629
            } else {
10630 10631
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unknown fullscreen value '%s'"), fullscreen);
10632 10633 10634 10635
                VIR_FREE(fullscreen);
                goto error;
            }
            VIR_FREE(fullscreen);
E
Eric Blake 已提交
10636
        } else {
10637
            def->data.desktop.fullscreen = false;
E
Eric Blake 已提交
10638
        }
10639 10640

        def->data.desktop.display = virXMLPropString(node, "display");
10641
    } else if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) {
10642
        xmlNodePtr cur;
10643 10644 10645
        char *port = virXMLPropString(node, "port");
        char *tlsPort;
        char *autoport;
10646 10647
        char *defaultMode;
        int defaultModeVal;
10648 10649 10650

        if (port) {
            if (virStrToLong_i(port, NULL, 10, &def->data.spice.port) < 0) {
10651 10652
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("cannot parse spice port %s"), port);
10653 10654 10655 10656 10657
                VIR_FREE(port);
                goto error;
            }
            VIR_FREE(port);
        } else {
10658
            def->data.spice.port = 0;
10659 10660 10661 10662 10663
        }

        tlsPort = virXMLPropString(node, "tlsPort");
        if (tlsPort) {
            if (virStrToLong_i(tlsPort, NULL, 10, &def->data.spice.tlsPort) < 0) {
10664 10665
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("cannot parse spice tlsPort %s"), tlsPort);
10666 10667 10668 10669 10670 10671 10672 10673 10674
                VIR_FREE(tlsPort);
                goto error;
            }
            VIR_FREE(tlsPort);
        } else {
            def->data.spice.tlsPort = 0;
        }

        if ((autoport = virXMLPropString(node, "autoport")) != NULL) {
M
Michal Privoznik 已提交
10675
            if (STREQ(autoport, "yes"))
10676
                def->data.spice.autoport = true;
10677 10678 10679
            VIR_FREE(autoport);
        }

10680 10681 10682 10683
        def->data.spice.defaultMode = VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_ANY;

        if ((defaultMode = virXMLPropString(node, "defaultMode")) != NULL) {
            if ((defaultModeVal = virDomainGraphicsSpiceChannelModeTypeFromString(defaultMode)) < 0) {
10684
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
10685 10686
                               _("unknown default spice channel mode %s"),
                               defaultMode);
10687 10688 10689 10690 10691 10692 10693
                VIR_FREE(defaultMode);
                goto error;
            }
            def->data.spice.defaultMode = defaultModeVal;
            VIR_FREE(defaultMode);
        }

M
Michal Privoznik 已提交
10694 10695
        if (def->data.spice.port == -1 && def->data.spice.tlsPort == -1) {
            /* Legacy compat syntax, used -1 for auto-port */
10696
            def->data.spice.autoport = true;
M
Michal Privoznik 已提交
10697 10698
        }

10699
        if (def->data.spice.autoport && (flags & VIR_DOMAIN_DEF_PARSE_INACTIVE)) {
M
Michal Privoznik 已提交
10700 10701 10702 10703
            def->data.spice.port = 0;
            def->data.spice.tlsPort = 0;
        }

10704
        def->data.spice.keymap = virXMLPropString(node, "keymap");
10705

10706 10707
        if (virDomainGraphicsAuthDefParseXML(node, &def->data.spice.auth,
                                             def->type) < 0)
10708
            goto error;
10709 10710 10711 10712 10713

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

                    if (!name || !mode) {
10720 10721
                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                       _("spice channel missing name/mode"));
E
Eric Blake 已提交
10722 10723
                        VIR_FREE(name);
                        VIR_FREE(mode);
10724 10725 10726 10727
                        goto error;
                    }

                    if ((nameval = virDomainGraphicsSpiceChannelNameTypeFromString(name)) < 0) {
10728
                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
10729 10730
                                       _("unknown spice channel name %s"),
                                       name);
E
Eric Blake 已提交
10731 10732
                        VIR_FREE(name);
                        VIR_FREE(mode);
10733 10734 10735
                        goto error;
                    }
                    if ((modeval = virDomainGraphicsSpiceChannelModeTypeFromString(mode)) < 0) {
10736
                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
10737 10738
                                       _("unknown spice channel mode %s"),
                                       mode);
E
Eric Blake 已提交
10739 10740
                        VIR_FREE(name);
                        VIR_FREE(mode);
10741 10742
                        goto error;
                    }
E
Eric Blake 已提交
10743 10744
                    VIR_FREE(name);
                    VIR_FREE(mode);
10745 10746

                    def->data.spice.channels[nameval] = modeval;
10747
                } else if (xmlStrEqual(cur->name, BAD_CAST "image")) {
10748
                    char *compression = virXMLPropString(cur, "compression");
10749 10750 10751
                    int compressionVal;

                    if (!compression) {
10752 10753
                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                       _("spice image missing compression"));
10754 10755 10756 10757 10758
                        goto error;
                    }

                    if ((compressionVal =
                         virDomainGraphicsSpiceImageCompressionTypeFromString(compression)) <= 0) {
10759 10760 10761
                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                       _("unknown spice image compression %s"),
                                       compression);
10762 10763 10764 10765 10766 10767 10768
                        VIR_FREE(compression);
                        goto error;
                    }
                    VIR_FREE(compression);

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

                    if (!compression) {
10773 10774
                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                       _("spice jpeg missing compression"));
10775 10776 10777 10778 10779
                        goto error;
                    }

                    if ((compressionVal =
                         virDomainGraphicsSpiceJpegCompressionTypeFromString(compression)) <= 0) {
10780 10781 10782
                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                       _("unknown spice jpeg compression %s"),
                                       compression);
10783 10784 10785 10786 10787 10788 10789
                        VIR_FREE(compression);
                        goto error;
                    }
                    VIR_FREE(compression);

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

                    if (!compression) {
10794 10795
                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                       _("spice zlib missing compression"));
10796 10797 10798 10799 10800
                        goto error;
                    }

                    if ((compressionVal =
                         virDomainGraphicsSpiceZlibCompressionTypeFromString(compression)) <= 0) {
10801 10802 10803
                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                       _("unknown spice zlib compression %s"),
                                       compression);
10804 10805 10806
                        VIR_FREE(compression);
                        goto error;
                    }
10807
                    VIR_FREE(compression);
10808 10809 10810

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

                    if (!compression) {
10815 10816
                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                       _("spice playback missing compression"));
10817 10818 10819 10820
                        goto error;
                    }

                    if ((compressionVal =
J
Ján Tomko 已提交
10821
                         virTristateSwitchTypeFromString(compression)) <= 0) {
10822
                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
10823
                                       _("unknown spice playback compression"));
10824 10825 10826 10827 10828 10829 10830
                        VIR_FREE(compression);
                        goto error;

                    }
                    VIR_FREE(compression);

                    def->data.spice.playback = compressionVal;
10831
                } else if (xmlStrEqual(cur->name, BAD_CAST "streaming")) {
10832
                    char *mode = virXMLPropString(cur, "mode");
10833 10834 10835
                    int modeVal;

                    if (!mode) {
10836 10837
                        virReportError(VIR_ERR_XML_ERROR, "%s",
                                       _("spice streaming missing mode"));
10838 10839 10840 10841
                        goto error;
                    }
                    if ((modeVal =
                         virDomainGraphicsSpiceStreamingModeTypeFromString(mode)) <= 0) {
10842
                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
10843
                                       _("unknown spice streaming mode"));
10844 10845 10846 10847 10848 10849 10850
                        VIR_FREE(mode);
                        goto error;

                    }
                    VIR_FREE(mode);

                    def->data.spice.streaming = modeVal;
10851
                } else if (xmlStrEqual(cur->name, BAD_CAST "clipboard")) {
10852
                    char *copypaste = virXMLPropString(cur, "copypaste");
10853 10854 10855
                    int copypasteVal;

                    if (!copypaste) {
10856 10857
                        virReportError(VIR_ERR_XML_ERROR, "%s",
                                       _("spice clipboard missing copypaste"));
10858 10859 10860 10861
                        goto error;
                    }

                    if ((copypasteVal =
J
Ján Tomko 已提交
10862
                         virTristateBoolTypeFromString(copypaste)) <= 0) {
10863
                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
10864
                                       _("unknown copypaste value '%s'"), copypaste);
10865 10866 10867 10868 10869 10870
                        VIR_FREE(copypaste);
                        goto error;
                    }
                    VIR_FREE(copypaste);

                    def->data.spice.copypaste = copypasteVal;
10871 10872 10873 10874 10875 10876 10877 10878 10879 10880 10881
                } 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 已提交
10882
                         virTristateBoolTypeFromString(enable)) <= 0) {
10883 10884 10885 10886 10887 10888 10889 10890
                        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 已提交
10891
                } else if (xmlStrEqual(cur->name, BAD_CAST "mouse")) {
10892
                    char *mode = virXMLPropString(cur, "mode");
P
Peng Zhou 已提交
10893 10894 10895
                    int modeVal;

                    if (!mode) {
10896 10897
                        virReportError(VIR_ERR_XML_ERROR, "%s",
                                       _("spice mouse missing mode"));
P
Peng Zhou 已提交
10898 10899 10900 10901
                        goto error;
                    }

                    if ((modeVal = virDomainGraphicsSpiceMouseModeTypeFromString(mode)) <= 0) {
10902
                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
10903 10904
                                       _("unknown mouse mode value '%s'"),
                                       mode);
P
Peng Zhou 已提交
10905 10906 10907 10908 10909 10910
                        VIR_FREE(mode);
                        goto error;
                    }
                    VIR_FREE(mode);

                    def->data.spice.mousemode = modeVal;
10911 10912 10913 10914
                }
            }
            cur = cur->next;
        }
10915 10916
    }

10917
 cleanup:
10918
    VIR_FREE(type);
10919 10920
    VIR_FREE(listenNodes);
    VIR_FREE(listenAddr);
10921

10922
    ctxt->node = save;
10923 10924
    return def;

10925
 error:
10926 10927 10928 10929 10930 10931
    virDomainGraphicsDefFree(def);
    def = NULL;
    goto cleanup;
}


10932
static virDomainSoundCodecDefPtr
10933
virDomainSoundCodecDefParseXML(xmlNodePtr node)
10934 10935 10936 10937
{
    char *type;
    virDomainSoundCodecDefPtr def;

10938
    if (VIR_ALLOC(def) < 0)
10939 10940 10941 10942
        return NULL;

    type = virXMLPropString(node, "type");
    if ((def->type = virDomainSoundCodecTypeFromString(type)) < 0) {
10943
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
10944
                       _("unknown codec type '%s'"), type);
10945 10946 10947
        goto error;
    }

10948
 cleanup:
10949 10950 10951 10952
    VIR_FREE(type);

    return def;

10953
 error:
10954 10955 10956 10957 10958 10959
    virDomainSoundCodecDefFree(def);
    def = NULL;
    goto cleanup;
}


10960
static virDomainSoundDefPtr
10961
virDomainSoundDefParseXML(xmlNodePtr node,
10962
                          xmlXPathContextPtr ctxt,
E
Eric Blake 已提交
10963
                          unsigned int flags)
10964
{
10965 10966
    char *model;
    virDomainSoundDefPtr def;
10967
    xmlNodePtr save = ctxt->node;
10968

10969
    if (VIR_ALLOC(def) < 0)
10970 10971
        return NULL;

10972 10973
    ctxt->node = node;

10974 10975
    model = virXMLPropString(node, "model");
    if ((def->model = virDomainSoundModelTypeFromString(model)) < 0) {
10976
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
10977
                       _("unknown sound model '%s'"), model);
10978 10979 10980
        goto error;
    }

10981 10982
    if (def->model == VIR_DOMAIN_SOUND_MODEL_ICH6 ||
        def->model == VIR_DOMAIN_SOUND_MODEL_ICH9) {
10983 10984 10985 10986 10987 10988 10989 10990 10991
        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) {
10992
            size_t i;
10993 10994 10995 10996 10997 10998

            if (VIR_ALLOC_N(def->codecs, ncodecs) < 0) {
                VIR_FREE(codecNodes);
                goto error;
            }

10999 11000
            for (i = 0; i < ncodecs; i++) {
                virDomainSoundCodecDefPtr codec = virDomainSoundCodecDefParseXML(codecNodes[i]);
11001 11002
                if (codec == NULL) {
                    VIR_FREE(codecNodes);
11003
                    goto error;
11004
                }
11005 11006 11007 11008 11009 11010 11011 11012

                codec->cad = def->ncodecs; /* that will do for now */
                def->codecs[def->ncodecs++] = codec;
            }
            VIR_FREE(codecNodes);
        }
    }

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

11016
 cleanup:
11017 11018
    VIR_FREE(model);

11019
    ctxt->node = save;
11020 11021
    return def;

11022
 error:
11023 11024 11025 11026 11027
    virDomainSoundDefFree(def);
    def = NULL;
    goto cleanup;
}

11028

R
Richard Jones 已提交
11029
static virDomainWatchdogDefPtr
11030
virDomainWatchdogDefParseXML(xmlNodePtr node,
E
Eric Blake 已提交
11031
                             unsigned int flags)
11032
{
R
Richard Jones 已提交
11033 11034 11035 11036 11037

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

11038
    if (VIR_ALLOC(def) < 0)
R
Richard Jones 已提交
11039 11040
        return NULL;

11041
    model = virXMLPropString(node, "model");
R
Richard Jones 已提交
11042
    if (model == NULL) {
11043 11044
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("watchdog must contain model name"));
R
Richard Jones 已提交
11045 11046
        goto error;
    }
11047
    def->model = virDomainWatchdogModelTypeFromString(model);
R
Richard Jones 已提交
11048
    if (def->model < 0) {
11049
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
11050
                       _("unknown watchdog model '%s'"), model);
R
Richard Jones 已提交
11051 11052 11053
        goto error;
    }

11054
    action = virXMLPropString(node, "action");
11055
    if (action == NULL) {
R
Richard Jones 已提交
11056
        def->action = VIR_DOMAIN_WATCHDOG_ACTION_RESET;
11057
    } else {
11058
        def->action = virDomainWatchdogActionTypeFromString(action);
R
Richard Jones 已提交
11059
        if (def->action < 0) {
11060
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
11061
                           _("unknown watchdog action '%s'"), action);
R
Richard Jones 已提交
11062 11063 11064 11065
            goto error;
        }
    }

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

11069
 cleanup:
11070 11071
    VIR_FREE(action);
    VIR_FREE(model);
R
Richard Jones 已提交
11072 11073 11074

    return def;

11075
 error:
11076
    virDomainWatchdogDefFree(def);
R
Richard Jones 已提交
11077 11078 11079 11080 11081
    def = NULL;
    goto cleanup;
}


11082
static virDomainRNGDefPtr
11083
virDomainRNGDefParseXML(xmlNodePtr node,
11084 11085 11086
                        xmlXPathContextPtr ctxt,
                        unsigned int flags)
{
11087 11088 11089
    char *model = NULL;
    char *backend = NULL;
    char *type = NULL;
11090 11091 11092 11093 11094
    virDomainRNGDefPtr def;
    xmlNodePtr save = ctxt->node;
    xmlNodePtr *backends = NULL;
    int nbackends;

11095
    if (VIR_ALLOC(def) < 0)
11096 11097 11098 11099 11100 11101 11102 11103
        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) {
11104
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("unknown RNG model '%s'"), model);
11105 11106 11107 11108 11109
        goto error;
    }

    ctxt->node = node;

11110 11111 11112 11113 11114 11115 11116 11117 11118 11119 11120 11121 11122
    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;
    }

11123 11124 11125 11126 11127 11128 11129 11130 11131 11132 11133 11134 11135 11136 11137 11138
    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) {
11139
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
11140 11141 11142 11143
                       _("unknown RNG backend model '%s'"), backend);
        goto error;
    }

11144
    switch ((virDomainRNGBackend) def->backend) {
11145 11146
    case VIR_DOMAIN_RNG_BACKEND_RANDOM:
        def->source.file = virXPathString("string(./backend)", ctxt);
11147 11148
        if (def->source.file &&
            STRNEQ(def->source.file, "/dev/random") &&
11149 11150 11151 11152 11153 11154
            STRNEQ(def->source.file, "/dev/hwrng")) {
            virReportError(VIR_ERR_XML_ERROR,
                           _("file '%s' is not a supported random source"),
                           def->source.file);
            goto error;
        }
11155 11156 11157 11158 11159 11160 11161 11162 11163
        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;
        }

11164
        if (VIR_ALLOC(def->source.chardev) < 0)
11165 11166 11167 11168
            goto error;

        def->source.chardev->type = virDomainChrTypeFromString(type);
        if (def->source.chardev->type < 0) {
11169
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
11170 11171 11172 11173 11174 11175 11176 11177 11178 11179 11180 11181 11182 11183 11184 11185 11186 11187
                           _("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;

11188
 cleanup:
11189 11190 11191 11192 11193 11194 11195
    VIR_FREE(model);
    VIR_FREE(backend);
    VIR_FREE(type);
    VIR_FREE(backends);
    ctxt->node = save;
    return def;

11196
 error:
11197 11198 11199 11200 11201 11202
    virDomainRNGDefFree(def);
    def = NULL;
    goto cleanup;
}


11203
static virDomainMemballoonDefPtr
11204
virDomainMemballoonDefParseXML(xmlNodePtr node,
11205
                               xmlXPathContextPtr ctxt,
E
Eric Blake 已提交
11206
                               unsigned int flags)
11207 11208 11209
{
    char *model;
    virDomainMemballoonDefPtr def;
11210
    xmlNodePtr save = ctxt->node;
11211
    unsigned int period = 0;
11212

11213
    if (VIR_ALLOC(def) < 0)
11214 11215 11216
        return NULL;

    model = virXMLPropString(node, "model");
11217
    if (model == NULL) {
11218
        virReportError(VIR_ERR_XML_ERROR, "%s",
11219
                       _("balloon memory must contain model name"));
11220 11221
        goto error;
    }
11222

11223
    if ((def->model = virDomainMemballoonModelTypeFromString(model)) < 0) {
11224
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
11225
                       _("unknown memory balloon model '%s'"), model);
11226 11227 11228
        goto error;
    }

11229
    ctxt->node = node;
11230
    if (virXPathUInt("string(./stats/@period)", ctxt, &period) < -1) {
11231 11232 11233 11234 11235
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("invalid statistics collection period"));
        goto error;
    }

11236 11237 11238 11239
    def->period = period;
    if (def->period < 0)
        def->period = 0;

11240 11241 11242
    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)
11243 11244
        goto error;

11245
 cleanup:
11246 11247
    VIR_FREE(model);

11248
    ctxt->node = save;
11249 11250
    return def;

11251
 error:
11252 11253 11254 11255 11256
    virDomainMemballoonDefFree(def);
    def = NULL;
    goto cleanup;
}

L
Li Zhang 已提交
11257
static virDomainNVRAMDefPtr
11258
virDomainNVRAMDefParseXML(xmlNodePtr node,
L
Li Zhang 已提交
11259 11260 11261 11262
                          unsigned int flags)
{
   virDomainNVRAMDefPtr def;

11263
    if (VIR_ALLOC(def) < 0)
L
Li Zhang 已提交
11264 11265 11266 11267 11268 11269 11270
        return NULL;

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

    return def;

11271
 error:
L
Li Zhang 已提交
11272 11273 11274 11275
    virDomainNVRAMDefFree(def);
    return NULL;
}

11276 11277 11278 11279 11280 11281 11282 11283 11284 11285 11286 11287 11288 11289 11290 11291 11292 11293 11294 11295 11296 11297 11298 11299
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;
    }

11300 11301
    if (virDomainParseScaledValue("./size[1]", NULL, ctxt,
                                  &def->size, 1, ULLONG_MAX, false) < 0)
11302 11303
        goto cleanup;

11304
    if ((server = virXPathNode("./server[1]", ctxt))) {
11305 11306
        def->server.enabled = true;

11307 11308
        def->server.chr.type = VIR_DOMAIN_CHR_TYPE_UNIX;
        def->server.chr.data.nix.listen = false;
11309
        if ((tmp = virXMLPropString(server, "path")))
11310
            def->server.chr.data.nix.path = virFileSanitizePath(tmp);
11311 11312 11313
        VIR_FREE(tmp);
    }

11314
    if ((msi = virXPathNode("./msi[1]", ctxt))) {
11315 11316 11317 11318 11319 11320 11321 11322 11323 11324 11325
        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);

11326 11327 11328 11329 11330 11331 11332 11333 11334 11335
        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;
11336 11337 11338 11339 11340 11341 11342 11343 11344 11345 11346 11347 11348 11349 11350 11351 11352 11353 11354 11355 11356 11357 11358 11359
        }
        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;
}

11360 11361 11362 11363 11364 11365 11366 11367 11368 11369 11370 11371 11372 11373 11374 11375 11376 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
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;
}

11419 11420 11421
static int
virSysinfoSystemParseXML(xmlNodePtr node,
                         xmlXPathContextPtr ctxt,
M
Michal Privoznik 已提交
11422
                         virSysinfoSystemDefPtr *sysdef,
11423 11424 11425 11426 11427 11428 11429 11430 11431 11432 11433 11434 11435 11436 11437 11438 11439 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
                         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 已提交
11485
    *sysdef = def;
11486 11487 11488 11489 11490 11491 11492 11493
    def = NULL;
    ret = 0;
 cleanup:
    virSysinfoSystemDefFree(def);
    VIR_FREE(tmpUUID);
    return ret;
}

11494 11495 11496 11497 11498 11499 11500 11501 11502 11503 11504 11505 11506 11507 11508 11509 11510 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
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;
}

11549
static virSysinfoDefPtr
11550
virSysinfoParseXML(xmlNodePtr node,
11551 11552 11553
                  xmlXPathContextPtr ctxt,
                  unsigned char *domUUID,
                  bool uuid_generated)
11554 11555
{
    virSysinfoDefPtr def;
11556
    xmlNodePtr oldnode, tmpnode;
11557 11558 11559
    char *type;

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

11565
    if (VIR_ALLOC(def) < 0)
11566
        return NULL;
11567 11568 11569

    type = virXMLPropString(node, "type");
    if (type == NULL) {
11570 11571
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("sysinfo must contain a type attribute"));
11572 11573
        goto error;
    }
11574
    if ((def->type = virSysinfoTypeFromString(type)) < 0) {
11575
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
11576
                       _("unknown sysinfo type '%s'"), type);
11577 11578 11579 11580
        goto error;
    }

    /* Extract BIOS related metadata */
11581 11582 11583 11584 11585
    if ((tmpnode = virXPathNode("./bios[1]", ctxt)) != NULL) {
        oldnode = ctxt->node;
        ctxt->node = tmpnode;
        if (virSysinfoBIOSParseXML(tmpnode, ctxt, &def->bios) < 0) {
            ctxt->node = oldnode;
11586 11587
            goto error;
        }
11588
        ctxt->node = oldnode;
11589
    }
11590 11591

    /* Extract system related metadata */
11592 11593 11594 11595 11596 11597
    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;
11598 11599
            goto error;
        }
11600
        ctxt->node = oldnode;
11601
    }
11602

11603 11604 11605 11606
    /* Extract system base board metadata */
    if (virSysinfoBaseBoardParseXML(ctxt, &def->baseBoard, &def->nbaseBoard) < 0)
        goto error;

11607
 cleanup:
11608
    VIR_FREE(type);
11609
    return def;
11610

11611
 error:
11612 11613 11614 11615
    virSysinfoDefFree(def);
    def = NULL;
    goto cleanup;
}
11616

11617
unsigned int
11618
virDomainVideoDefaultRAM(const virDomainDef *def,
11619
                         const virDomainVideoType type)
11620
{
11621 11622 11623 11624
    /* Defer setting default vram to the Xen drivers */
    if (def->virtType == VIR_DOMAIN_VIRT_XEN)
        return 0;

11625 11626 11627 11628 11629 11630
    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 已提交
11631 11632
        else if (def->virtType == VIR_DOMAIN_VIRT_VMWARE)
            return 4 * 1024;
11633
        else
11634
            return 16 * 1024;
11635 11636 11637 11638 11639 11640
        break;

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

11641
    case VIR_DOMAIN_VIDEO_TYPE_QXL:
11642
        /* QEMU use 64M as the minimal video memory for qxl device */
11643 11644
        return 64 * 1024;

11645 11646 11647 11648 11649 11650 11651
    default:
        return 0;
    }
}


int
11652
virDomainVideoDefaultType(const virDomainDef *def)
11653 11654 11655 11656 11657 11658 11659
{
    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:
11660 11661
        if (def->os.type == VIR_DOMAIN_OSTYPE_XEN ||
            def->os.type == VIR_DOMAIN_OSTYPE_LINUX)
11662
            return VIR_DOMAIN_VIDEO_TYPE_XEN;
11663
        else if ARCH_IS_PPC64(def->os.arch)
11664
            return VIR_DOMAIN_VIDEO_TYPE_VGA;
11665 11666 11667 11668 11669 11670
        else
            return VIR_DOMAIN_VIDEO_TYPE_CIRRUS;

    case VIR_DOMAIN_VIRT_VBOX:
        return VIR_DOMAIN_VIDEO_TYPE_VBOX;

M
Matthias Bolte 已提交
11671 11672 11673
    case VIR_DOMAIN_VIRT_VMWARE:
        return VIR_DOMAIN_VIDEO_TYPE_VMVGA;

11674
    case VIR_DOMAIN_VIRT_VZ:
11675
    case VIR_DOMAIN_VIRT_PARALLELS:
11676
        if (def->os.type == VIR_DOMAIN_OSTYPE_HVM)
11677
            return VIR_DOMAIN_VIDEO_TYPE_VGA;
11678 11679
        else
            return VIR_DOMAIN_VIDEO_TYPE_PARALLELS;
11680 11681 11682 11683 11684
    default:
        return -1;
    }
}

11685
static virDomainVideoAccelDefPtr
11686 11687
virDomainVideoAccelDefParseXML(xmlNodePtr node)
{
11688 11689
    xmlNodePtr cur;
    virDomainVideoAccelDefPtr def;
11690
    char *accel2d = NULL;
11691 11692
    char *accel3d = NULL;
    int val;
11693 11694 11695 11696

    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
11697
            if (!accel3d && !accel2d &&
11698
                xmlStrEqual(cur->name, BAD_CAST "acceleration")) {
11699 11700
                accel3d = virXMLPropString(cur, "accel3d");
                accel2d = virXMLPropString(cur, "accel2d");
11701 11702 11703 11704 11705
            }
        }
        cur = cur->next;
    }

11706
    if (!accel3d && !accel2d)
11707
        return NULL;
11708

11709
    if (VIR_ALLOC(def) < 0)
11710
        goto cleanup;
11711

11712
    if (accel3d) {
11713 11714 11715 11716 11717 11718
        if ((val = virTristateBoolTypeFromString(accel3d)) <= 0) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown accel3d value '%s'"), accel3d);
            goto cleanup;
        }
        def->accel3d = val;
11719 11720
    }

11721
    if (accel2d) {
11722 11723 11724 11725 11726 11727
        if ((val = virTristateBoolTypeFromString(accel2d)) <= 0) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown accel2d value '%s'"), accel2d);
            goto cleanup;
        }
        def->accel2d = val;
11728 11729
    }

11730 11731 11732
 cleanup:
    VIR_FREE(accel2d);
    VIR_FREE(accel3d);
11733 11734 11735
    return def;
}

11736
static virDomainVideoDefPtr
11737 11738
virDomainVideoDefParseXML(xmlNodePtr node,
                          const virDomainDef *dom,
E
Eric Blake 已提交
11739 11740
                          unsigned int flags)
{
11741 11742 11743 11744 11745
    virDomainVideoDefPtr def;
    xmlNodePtr cur;
    char *type = NULL;
    char *heads = NULL;
    char *vram = NULL;
11746
    char *ram = NULL;
11747
    char *vgamem = NULL;
11748
    char *primary = NULL;
11749

11750
    if (VIR_ALLOC(def) < 0)
11751 11752 11753 11754 11755
        return NULL;

    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
11756
            if (!type && !vram && !ram && !heads &&
11757 11758
                xmlStrEqual(cur->name, BAD_CAST "model")) {
                type = virXMLPropString(cur, "type");
11759
                ram = virXMLPropString(cur, "ram");
11760
                vram = virXMLPropString(cur, "vram");
11761
                vgamem = virXMLPropString(cur, "vgamem");
11762
                heads = virXMLPropString(cur, "heads");
11763

11764
                if ((primary = virXMLPropString(cur, "primary")) != NULL) {
11765 11766
                    if (STREQ(primary, "yes"))
                        def->primary = 1;
11767 11768
                    VIR_FREE(primary);
                }
11769

11770
                def->accel = virDomainVideoAccelDefParseXML(cur);
11771 11772 11773 11774 11775 11776 11777
            }
        }
        cur = cur->next;
    }

    if (type) {
        if ((def->type = virDomainVideoTypeFromString(type)) < 0) {
11778
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
11779
                           _("unknown video model '%s'"), type);
11780 11781 11782 11783
            goto error;
        }
    } else {
        if ((def->type = virDomainVideoDefaultType(dom)) < 0) {
11784 11785
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("missing video model and cannot determine default"));
11786 11787 11788 11789
            goto error;
        }
    }

11790 11791 11792 11793 11794 11795
    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;
        }
11796
        if (virStrToLong_uip(ram, NULL, 10, &def->ram) < 0) {
11797 11798 11799 11800 11801 11802 11803 11804
            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);
    }

11805
    if (vram) {
11806
        if (virStrToLong_uip(vram, NULL, 10, &def->vram) < 0) {
11807
            virReportError(VIR_ERR_XML_ERROR,
11808
                           _("cannot parse video vram '%s'"), vram);
11809 11810 11811 11812 11813 11814
            goto error;
        }
    } else {
        def->vram = virDomainVideoDefaultRAM(dom, def->type);
    }

11815 11816 11817 11818 11819 11820
    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;
        }
11821
        if (virStrToLong_uip(vgamem, NULL, 10, &def->vgamem) < 0) {
11822 11823 11824 11825 11826 11827
            virReportError(VIR_ERR_XML_ERROR,
                           _("cannot parse video vgamem '%s'"), vgamem);
            goto error;
        }
    }

11828
    if (heads) {
11829
        if (virStrToLong_uip(heads, NULL, 10, &def->heads) < 0) {
11830 11831
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot parse video heads '%s'"), heads);
11832 11833 11834 11835 11836 11837
            goto error;
        }
    } else {
        def->heads = 1;
    }

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

11841
    VIR_FREE(type);
11842
    VIR_FREE(ram);
11843
    VIR_FREE(vram);
11844
    VIR_FREE(vgamem);
11845 11846 11847 11848
    VIR_FREE(heads);

    return def;

11849
 error:
11850 11851
    virDomainVideoDefFree(def);
    VIR_FREE(type);
11852
    VIR_FREE(ram);
11853
    VIR_FREE(vram);
11854
    VIR_FREE(vgamem);
11855 11856 11857 11858
    VIR_FREE(heads);
    return NULL;
}

11859
static virDomainHostdevDefPtr
11860
virDomainHostdevDefParseXML(xmlNodePtr node,
11861
                            xmlXPathContextPtr ctxt,
11862
                            virHashTablePtr bootHash,
E
Eric Blake 已提交
11863
                            unsigned int flags)
11864
{
11865
    virDomainHostdevDefPtr def;
11866 11867 11868
    xmlNodePtr save = ctxt->node;
    char *mode = virXMLPropString(node, "mode");
    char *type = virXMLPropString(node, "type");
11869

11870
    ctxt->node = node;
11871

11872
    if (!(def = virDomainHostdevDefAlloc()))
11873 11874
        goto error;

11875 11876
    if (mode) {
        if ((def->mode = virDomainHostdevModeTypeFromString(mode)) < 0) {
11877
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
11878 11879 11880 11881 11882 11883 11884 11885 11886 11887 11888 11889 11890
                           _("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;
11891 11892 11893 11894 11895
    case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
        /* parse managed/mode/type, and the <source> element */
        if (virDomainHostdevDefParseXMLCaps(node, ctxt, type, def) < 0)
            goto error;
        break;
11896 11897 11898
    default:
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unexpected hostdev mode %d"), def->mode);
11899
        goto error;
11900
    }
11901

11902
    if (def->info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
11903
        if (virDomainDeviceInfoParseXML(node, bootHash, def->info,
11904 11905
                                        flags  | VIR_DOMAIN_DEF_PARSE_ALLOW_BOOT
                                        | VIR_DOMAIN_DEF_PARSE_ALLOW_ROM) < 0)
11906 11907 11908 11909 11910 11911
            goto error;
    }

    if (def->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
        switch (def->source.subsys.type) {
        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
11912 11913
            if (def->info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
                def->info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
11914 11915
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("PCI host devices must use 'pci' address type"));
11916 11917 11918
                goto error;
            }
            break;
H
Han Cheng 已提交
11919
        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
11920 11921
            if (def->info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
                def->info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
H
Han Cheng 已提交
11922
                virReportError(VIR_ERR_XML_ERROR, "%s",
11923 11924
                               _("SCSI host device must use 'drive' "
                                 "address type"));
H
Han Cheng 已提交
11925 11926
                goto error;
            }
O
Osier Yang 已提交
11927 11928
            if (virXPathBoolean("boolean(./readonly)", ctxt))
                def->readonly = true;
11929 11930
            if (virXPathBoolean("boolean(./shareable)", ctxt))
                def->shareable = true;
H
Han Cheng 已提交
11931
            break;
11932 11933 11934
        }
    }

11935
 cleanup:
11936 11937
    VIR_FREE(type);
    VIR_FREE(mode);
11938
    ctxt->node = save;
11939 11940
    return def;

11941
 error:
11942 11943 11944 11945 11946
    virDomainHostdevDefFree(def);
    def = NULL;
    goto cleanup;
}

11947

11948
static virDomainRedirdevDefPtr
11949
virDomainRedirdevDefParseXML(xmlNodePtr node,
11950
                             virHashTablePtr bootHash,
11951 11952 11953 11954 11955
                             unsigned int flags)
{
    xmlNodePtr cur;
    virDomainRedirdevDefPtr def;
    char *bus, *type = NULL;
11956
    int remaining;
11957

11958
    if (VIR_ALLOC(def) < 0)
11959 11960 11961 11962 11963
        return NULL;

    bus = virXMLPropString(node, "bus");
    if (bus) {
        if ((def->bus = virDomainRedirdevBusTypeFromString(bus)) < 0) {
11964
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
11965
                           _("unknown redirdev bus '%s'"), bus);
11966 11967 11968 11969 11970 11971 11972 11973 11974
            goto error;
        }
    } else {
        def->bus = VIR_DOMAIN_REDIRDEV_BUS_USB;
    }

    type = virXMLPropString(node, "type");
    if (type) {
        if ((def->source.chr.type = virDomainChrTypeFromString(type)) < 0) {
11975
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
11976
                           _("unknown redirdev character device type '%s'"), type);
11977 11978 11979
            goto error;
        }
    } else {
11980 11981
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing type in redirdev"));
11982 11983 11984 11985
        goto error;
    }

    cur = node->children;
11986 11987 11988 11989 11990 11991 11992
    /* 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;
11993

11994
    if (def->source.chr.type == VIR_DOMAIN_CHR_TYPE_SPICEVMC)
11995 11996
        def->source.chr.data.spicevmc = VIR_DOMAIN_CHR_SPICEVMC_USBREDIR;

11997
    if (virDomainDeviceInfoParseXML(node, bootHash, &def->info,
11998
                                    flags | VIR_DOMAIN_DEF_PARSE_ALLOW_BOOT) < 0)
11999 12000 12001 12002 12003
        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) {
12004 12005
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Invalid address for a USB device"));
12006 12007 12008 12009
        goto error;
    }


12010
 cleanup:
12011 12012 12013 12014
    VIR_FREE(bus);
    VIR_FREE(type);
    return def;

12015
 error:
12016 12017 12018 12019 12020
    virDomainRedirdevDefFree(def);
    def = NULL;
    goto cleanup;
}

12021
/*
J
Ján Tomko 已提交
12022
 * This is the helper function to convert USB device version from a
12023 12024 12025
 * 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 已提交
12026 12027
 * e.g. USB version 2.0 is reported as 0x0200,
 *      USB version 4.07 as 0x0407
12028 12029
 */
static int
12030 12031
virDomainRedirFilterUSBVersionHelper(const char *version,
                                     virDomainRedirFilterUSBDevDefPtr def)
12032
{
J
Ján Tomko 已提交
12033 12034
    unsigned int major, minor;
    char *s = NULL;
12035

J
Ján Tomko 已提交
12036 12037 12038 12039
    if ((virStrToLong_ui(version, &s, 10, &major)) < 0 ||
        *s++ != '.' ||
        (virStrToLong_ui(s, NULL, 10, &minor)) < 0)
        goto error;
12040

J
Ján Tomko 已提交
12041 12042
    if (major >= 100 || minor >= 100)
        goto error;
12043

J
Ján Tomko 已提交
12044 12045 12046
    /* Treat JJ.M as JJ.M0, not JJ.0M */
    if (strlen(s) == 1)
        minor *= 10;
12047

J
Ján Tomko 已提交
12048 12049
    def->version = (major / 10) << 12 | (major % 10) << 8 |
                   (minor / 10) << 4 | (minor % 10) << 0;
12050

J
Ján Tomko 已提交
12051
    return 0;
12052

J
Ján Tomko 已提交
12053 12054 12055 12056
 error:
    virReportError(VIR_ERR_XML_ERROR,
                   _("Cannot parse USB device version %s"), version);
    return -1;
12057 12058
}

12059 12060
static virDomainRedirFilterUSBDevDefPtr
virDomainRedirFilterUSBDevDefParseXML(xmlNodePtr node)
12061 12062 12063 12064
{
    char *class;
    char *vendor = NULL, *product = NULL;
    char *version = NULL, *allow = NULL;
12065
    virDomainRedirFilterUSBDevDefPtr def;
12066

12067
    if (VIR_ALLOC(def) < 0)
12068 12069 12070 12071 12072 12073 12074 12075 12076 12077 12078 12079 12080 12081 12082 12083 12084 12085 12086 12087 12088 12089 12090 12091 12092 12093 12094 12095 12096 12097 12098 12099 12100 12101 12102 12103 12104 12105 12106 12107 12108 12109 12110 12111 12112
        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;
12113
        else if ((virDomainRedirFilterUSBVersionHelper(version, def)) < 0)
12114 12115 12116 12117 12118 12119 12120
            goto error;
    } else {
        def->version = -1;
    }

    allow = virXMLPropString(node, "allow");
    if (allow) {
12121
        if (STREQ(allow, "yes")) {
12122
            def->allow = true;
12123
        } else if (STREQ(allow, "no")) {
12124
            def->allow = false;
12125
        } else {
12126 12127 12128 12129 12130 12131 12132 12133 12134 12135
            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;
    }

12136
 cleanup:
12137 12138 12139 12140 12141 12142 12143
    VIR_FREE(class);
    VIR_FREE(vendor);
    VIR_FREE(product);
    VIR_FREE(version);
    VIR_FREE(allow);
    return def;

12144
 error:
12145 12146 12147 12148 12149 12150
    VIR_FREE(def);
    def = NULL;
    goto cleanup;
}

static virDomainRedirFilterDefPtr
12151
virDomainRedirFilterDefParseXML(xmlNodePtr node,
12152 12153 12154 12155 12156 12157 12158 12159 12160
                                xmlXPathContextPtr ctxt)
{
    int n;
    size_t i;
    xmlNodePtr *nodes = NULL;
    xmlNodePtr save = ctxt->node;
    virDomainRedirFilterDefPtr def = NULL;

    if (VIR_ALLOC(def) < 0)
12161
        goto error;
12162 12163

    ctxt->node = node;
12164
    if ((n = virXPathNodeSet("./usbdev", ctxt, &nodes)) < 0)
12165 12166 12167
        goto error;

    if (n && VIR_ALLOC_N(def->usbdevs, n) < 0)
12168
        goto error;
12169 12170

    for (i = 0; i < n; i++) {
12171 12172
        virDomainRedirFilterUSBDevDefPtr usbdev =
            virDomainRedirFilterUSBDevDefParseXML(nodes[i]);
12173 12174 12175 12176 12177 12178 12179 12180 12181 12182

        if (!usbdev)
            goto error;
        def->usbdevs[def->nusbdevs++] = usbdev;
    }
    VIR_FREE(nodes);

    ctxt->node = save;
    return def;

12183
 error:
12184 12185 12186 12187 12188
    VIR_FREE(nodes);
    virDomainRedirFilterDefFree(def);
    return NULL;
}

12189 12190 12191 12192 12193 12194 12195
static int
virDomainEventActionParseXML(xmlXPathContextPtr ctxt,
                             const char *name,
                             const char *xpath,
                             int *val,
                             int defaultVal,
                             virEventActionFromStringFunc convFunc)
12196
{
12197
    char *tmp = virXPathString(xpath, ctxt);
12198 12199 12200
    if (tmp == NULL) {
        *val = defaultVal;
    } else {
12201
        *val = convFunc(tmp);
12202
        if (*val < 0) {
12203
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
12204
                           _("unknown %s action: %s"), name, tmp);
12205 12206 12207 12208 12209 12210 12211 12212
            VIR_FREE(tmp);
            return -1;
        }
        VIR_FREE(tmp);
    }
    return 0;
}

12213 12214 12215 12216 12217 12218 12219 12220
static int
virDomainPMStateParseXML(xmlXPathContextPtr ctxt,
                         const char *xpath,
                         int *val)
{
    int ret = -1;
    char *tmp = virXPathString(xpath, ctxt);
    if (tmp) {
J
Ján Tomko 已提交
12221
        *val = virTristateBoolTypeFromString(tmp);
12222 12223 12224 12225 12226 12227 12228 12229 12230 12231 12232 12233 12234
        if (*val < 0) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown PM state value %s"), tmp);
            goto cleanup;
        }
    }

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

12235 12236 12237 12238 12239 12240 12241 12242 12243 12244 12245 12246 12247 12248 12249 12250 12251 12252 12253

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;
12254 12255 12256 12257 12258 12259

        if (virBitmapIsAllClear(def->sourceNodes)) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Invalid value of 'nodemask': %s"), nodemask);
            goto cleanup;
        }
12260 12261 12262 12263 12264 12265 12266 12267 12268 12269 12270 12271 12272 12273 12274 12275 12276 12277 12278
    }

    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;
12279
    int rv;
12280

12281 12282 12283 12284 12285
    /* 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)) {
12286
        virReportError(VIR_ERR_XML_ERROR, "%s",
12287
                       _("invalid value of memory device node"));
12288 12289 12290 12291 12292 12293 12294 12295 12296 12297 12298 12299 12300 12301 12302 12303 12304 12305 12306 12307 12308 12309 12310 12311 12312 12313 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
        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;

12349
    ctxt->node = save;
12350 12351 12352 12353 12354 12355 12356 12357 12358 12359
    return def;

 error:
    VIR_FREE(tmp);
    virDomainMemoryDefFree(def);
    ctxt->node = save;
    return NULL;
}


12360
virDomainDeviceDefPtr
12361
virDomainDeviceDefParse(const char *xmlStr,
12362
                        const virDomainDef *def,
12363 12364
                        virCapsPtr caps,
                        virDomainXMLOptionPtr xmlopt,
12365
                        unsigned int flags)
12366 12367 12368
{
    xmlDocPtr xml;
    xmlNodePtr node;
12369
    xmlXPathContextPtr ctxt = NULL;
12370 12371
    virDomainDeviceDefPtr dev = NULL;

12372
    if (!(xml = virXMLParseStringCtxt(xmlStr, _("(device_definition)"), &ctxt)))
12373
        goto error;
12374

12375
    node = ctxt->node;
12376

12377
    if (VIR_ALLOC(dev) < 0)
12378 12379
        goto error;

12380 12381 12382 12383 12384 12385 12386 12387 12388
    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 {
12389
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
12390 12391 12392 12393 12394 12395 12396 12397
                           _("unknown device type '%s'"),
                           node->name);
            goto error;
        }
    }

    switch ((virDomainDeviceType) dev->type) {
    case VIR_DOMAIN_DEVICE_DISK:
12398
        if (!(dev->data.disk = virDomainDiskDefParseXML(xmlopt, node, ctxt,
12399 12400
                                                        NULL, def->seclabels,
                                                        def->nseclabels,
12401
                                                        flags)))
12402
            goto error;
12403 12404
        break;
    case VIR_DOMAIN_DEVICE_LEASE:
12405 12406
        if (!(dev->data.lease = virDomainLeaseDefParseXML(node)))
            goto error;
12407 12408
        break;
    case VIR_DOMAIN_DEVICE_FS:
12409
        if (!(dev->data.fs = virDomainFSDefParseXML(node, ctxt, flags)))
12410
            goto error;
12411 12412
        break;
    case VIR_DOMAIN_DEVICE_NET:
12413
        if (!(dev->data.net = virDomainNetDefParseXML(xmlopt, node, ctxt,
12414
                                                      NULL, flags)))
12415
            goto error;
12416 12417
        break;
    case VIR_DOMAIN_DEVICE_INPUT:
12418 12419
        if (!(dev->data.input = virDomainInputDefParseXML(def, node,
                                                          ctxt, flags)))
12420
            goto error;
12421 12422
        break;
    case VIR_DOMAIN_DEVICE_SOUND:
12423
        if (!(dev->data.sound = virDomainSoundDefParseXML(node, ctxt, flags)))
12424
            goto error;
12425 12426
        break;
    case VIR_DOMAIN_DEVICE_WATCHDOG:
12427
        if (!(dev->data.watchdog = virDomainWatchdogDefParseXML(node, flags)))
R
Richard Jones 已提交
12428
            goto error;
12429 12430
        break;
    case VIR_DOMAIN_DEVICE_VIDEO:
12431
        if (!(dev->data.video = virDomainVideoDefParseXML(node, def, flags)))
12432
            goto error;
12433 12434
        break;
    case VIR_DOMAIN_DEVICE_HOSTDEV:
12435
        if (!(dev->data.hostdev = virDomainHostdevDefParseXML(node, ctxt,
12436
                                                              NULL, flags)))
12437
            goto error;
12438 12439
        break;
    case VIR_DOMAIN_DEVICE_CONTROLLER:
12440 12441
        if (!(dev->data.controller = virDomainControllerDefParseXML(node, ctxt,
                                                                    flags)))
12442
            goto error;
12443 12444
        break;
    case VIR_DOMAIN_DEVICE_GRAPHICS:
12445
        if (!(dev->data.graphics = virDomainGraphicsDefParseXML(node, ctxt, flags)))
12446
            goto error;
12447 12448
        break;
    case VIR_DOMAIN_DEVICE_HUB:
M
Marc-André Lureau 已提交
12449 12450
        if (!(dev->data.hub = virDomainHubDefParseXML(node, flags)))
            goto error;
12451 12452
        break;
    case VIR_DOMAIN_DEVICE_REDIRDEV:
12453
        if (!(dev->data.redirdev = virDomainRedirdevDefParseXML(node, NULL, flags)))
12454
            goto error;
12455 12456
        break;
    case VIR_DOMAIN_DEVICE_RNG:
12457 12458
        if (!(dev->data.rng = virDomainRNGDefParseXML(node, ctxt, flags)))
            goto error;
12459 12460
        break;
    case VIR_DOMAIN_DEVICE_CHR:
12461 12462 12463 12464 12465 12466
        if (!(dev->data.chr = virDomainChrDefParseXML(ctxt,
                                                      node,
                                                      def->seclabels,
                                                      def->nseclabels,
                                                      flags)))
            goto error;
12467 12468
        break;
    case VIR_DOMAIN_DEVICE_SMARTCARD:
12469 12470
        if (!(dev->data.smartcard = virDomainSmartcardDefParseXML(node, flags)))
            goto error;
12471 12472
        break;
    case VIR_DOMAIN_DEVICE_MEMBALLOON:
12473 12474 12475
        if (!(dev->data.memballoon = virDomainMemballoonDefParseXML(node,
                                                                    ctxt,
                                                                    flags)))
12476
            goto error;
12477 12478
        break;
    case VIR_DOMAIN_DEVICE_NVRAM:
12479 12480
        if (!(dev->data.nvram = virDomainNVRAMDefParseXML(node, flags)))
            goto error;
12481
        break;
12482 12483 12484 12485
    case VIR_DOMAIN_DEVICE_SHMEM:
        if (!(dev->data.shmem = virDomainShmemDefParseXML(node, ctxt, flags)))
            goto error;
        break;
12486 12487 12488 12489
    case VIR_DOMAIN_DEVICE_TPM:
        if (!(dev->data.tpm = virDomainTPMDefParseXML(node, ctxt, flags)))
            goto error;
        break;
12490 12491 12492 12493
    case VIR_DOMAIN_DEVICE_PANIC:
        if (!(dev->data.panic = virDomainPanicDefParseXML(node)))
            goto error;
        break;
12494 12495 12496 12497
    case VIR_DOMAIN_DEVICE_MEMORY:
        if (!(dev->data.memory = virDomainMemoryDefParseXML(node, ctxt, flags)))
            goto error;
        break;
12498 12499 12500
    case VIR_DOMAIN_DEVICE_NONE:
    case VIR_DOMAIN_DEVICE_LAST:
        break;
12501 12502
    }

12503
    /* callback to fill driver specific device aspects */
12504
    if (virDomainDeviceDefPostParse(dev, def, caps, xmlopt) < 0)
12505 12506
        goto error;

12507
 cleanup:
12508
    xmlFreeDoc(xml);
12509
    xmlXPathFreeContext(ctxt);
12510 12511
    return dev;

12512
 error:
12513
    VIR_FREE(dev);
12514
    goto cleanup;
12515
}
M
Matthias Bolte 已提交
12516 12517


12518 12519 12520 12521 12522 12523 12524 12525 12526 12527 12528 12529 12530 12531 12532 12533 12534 12535 12536 12537 12538 12539 12540
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;
    }

12541
    flags |= VIR_DOMAIN_DEF_PARSE_DISK_SOURCE;
12542 12543 12544 12545 12546 12547 12548 12549 12550 12551 12552 12553 12554 12555 12556 12557 12558
    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;
}


12559 12560 12561 12562 12563 12564 12565 12566 12567 12568 12569 12570 12571
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 已提交
12572 12573 12574
    case VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL:
        type = virDomainChrSerialTargetTypeToString(targetType);
        break;
12575 12576 12577 12578 12579 12580 12581
    default:
        break;
    }

    return type;
}

L
Laine Stump 已提交
12582 12583 12584
int
virDomainHostdevInsert(virDomainDefPtr def, virDomainHostdevDefPtr hostdev)
{
12585 12586

    return VIR_APPEND_ELEMENT(def->hostdevs, def->nhostdevs, hostdev);
L
Laine Stump 已提交
12587 12588
}

12589
virDomainHostdevDefPtr
L
Laine Stump 已提交
12590 12591
virDomainHostdevRemove(virDomainDefPtr def, size_t i)
{
12592 12593
    virDomainHostdevDefPtr hostdev = def->hostdevs[i];

12594
    VIR_DELETE_ELEMENT(def->hostdevs, i, def->nhostdevs);
12595
    return hostdev;
L
Laine Stump 已提交
12596 12597
}

12598 12599

static int
12600 12601
virDomainHostdevMatchSubsysUSB(virDomainHostdevDefPtr first,
                               virDomainHostdevDefPtr second)
12602
{
12603 12604 12605 12606
    virDomainHostdevSubsysUSBPtr first_usbsrc = &first->source.subsys.u.usb;
    virDomainHostdevSubsysUSBPtr second_usbsrc = &second->source.subsys.u.usb;

    if (first_usbsrc->bus && first_usbsrc->device) {
12607
        /* specified by bus location on host */
12608 12609
        if (first_usbsrc->bus == second_usbsrc->bus &&
            first_usbsrc->device == second_usbsrc->device)
12610 12611 12612
            return 1;
    } else {
        /* specified by product & vendor id */
12613 12614
        if (first_usbsrc->product == second_usbsrc->product &&
            first_usbsrc->vendor == second_usbsrc->vendor)
12615 12616 12617 12618 12619 12620
            return 1;
    }
    return 0;
}

static int
12621 12622
virDomainHostdevMatchSubsysPCI(virDomainHostdevDefPtr first,
                               virDomainHostdevDefPtr second)
12623
{
12624 12625 12626 12627 12628 12629 12630
    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)
12631 12632 12633 12634
        return 1;
    return 0;
}

H
Han Cheng 已提交
12635
static int
12636 12637 12638 12639 12640 12641 12642 12643 12644 12645 12646 12647
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 已提交
12648 12649 12650
        return 1;
    return 0;
}
12651

12652 12653 12654 12655 12656 12657 12658 12659 12660 12661 12662 12663 12664 12665 12666 12667
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;
}

12668 12669 12670 12671 12672 12673 12674 12675 12676 12677 12678 12679
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 已提交
12680
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
12681 12682 12683
        if (a->source.subsys.u.scsi.protocol !=
            b->source.subsys.u.scsi.protocol)
            return 0;
12684 12685 12686 12687 12688
        if (a->source.subsys.u.scsi.protocol ==
            VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_ISCSI)
            return virDomainHostdevMatchSubsysSCSIiSCSI(a, b);
        else
            return virDomainHostdevMatchSubsysSCSIHost(a, b);
12689 12690 12691 12692 12693
    }
    return 0;
}


12694 12695 12696 12697 12698 12699 12700 12701 12702 12703 12704 12705 12706 12707 12708 12709 12710
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);
}

12711 12712 12713 12714 12715 12716 12717 12718
static int
virDomainHostdevMatchCapsNet(virDomainHostdevDefPtr a,
                              virDomainHostdevDefPtr b)
{
    return STREQ_NULLABLE(a->source.caps.u.net.iface,
                          b->source.caps.u.net.iface);
}

12719 12720 12721 12722 12723 12724 12725 12726 12727 12728 12729 12730 12731

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);
12732 12733
    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_NET:
        return virDomainHostdevMatchCapsNet(a, b);
12734 12735 12736 12737 12738
    }
    return 0;
}


12739 12740 12741 12742 12743 12744 12745 12746 12747 12748
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);
12749 12750
    case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
        return virDomainHostdevMatchCaps(a, b);
12751 12752 12753 12754
    }
    return 0;
}

L
Laine Stump 已提交
12755 12756 12757 12758 12759 12760 12761 12762 12763 12764 12765
/* 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;
12766
    size_t i;
L
Laine Stump 已提交
12767 12768 12769 12770 12771

    if (!found)
        found = &local_found;
    *found = NULL;

12772
    for (i = 0; i < def->nhostdevs; i++) {
12773 12774
        if (virDomainHostdevMatch(match, def->hostdevs[i])) {
            *found = def->hostdevs[i];
L
Laine Stump 已提交
12775 12776 12777 12778 12779 12780
            break;
        }
    }
    return *found ? i : -1;
}

12781 12782 12783 12784 12785 12786 12787 12788 12789 12790 12791 12792 12793 12794 12795 12796 12797 12798 12799 12800 12801 12802
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;
}

12803 12804 12805 12806 12807 12808 12809 12810 12811 12812 12813 12814
/* 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++) {
12815
            if (STREQ(def->disks[i]->dst, def->disks[j]->dst)) {
12816 12817 12818 12819 12820 12821 12822 12823 12824 12825 12826 12827 12828
                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;
}

12829 12830 12831 12832 12833 12834 12835 12836 12837 12838 12839 12840 12841 12842 12843 12844 12845 12846 12847 12848 12849 12850 12851 12852 12853 12854 12855 12856 12857 12858 12859 12860
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;
}

12861 12862 12863 12864 12865 12866 12867 12868 12869 12870 12871
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];
}

12872 12873 12874
int
virDomainDiskIndexByName(virDomainDefPtr def, const char *name,
                         bool allow_ambiguous)
12875 12876
{
    virDomainDiskDefPtr vdisk;
12877
    size_t i;
12878
    int candidate = -1;
12879

12880 12881 12882 12883
    /* 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.  */
12884 12885
    for (i = 0; i < def->ndisks; i++) {
        vdisk = def->disks[i];
12886 12887 12888
        if (*name != '/') {
            if (STREQ(vdisk->dst, name))
                return i;
12889
        } else if (STREQ_NULLABLE(virDomainDiskGetSource(vdisk), name)) {
12890 12891 12892 12893 12894 12895
            if (allow_ambiguous)
                return i;
            if (candidate >= 0)
                return -1;
            candidate = i;
        }
12896
    }
12897 12898 12899 12900 12901 12902 12903 12904 12905
    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)
{
12906
    int idx = virDomainDiskIndexByName(def, name, true);
12907

12908
    return idx < 0 ? NULL : virDomainDiskGetSource(def->disks[idx]);
12909 12910
}

12911 12912 12913 12914 12915 12916 12917 12918 12919
virDomainDiskDefPtr
virDomainDiskByName(virDomainDefPtr def,
                    const char *name,
                    bool allow_ambiguous)
{
    int idx = virDomainDiskIndexByName(def, name, allow_ambiguous);
    return idx < 0 ? NULL : def->disks[idx];
}

12920 12921
int virDomainDiskInsert(virDomainDefPtr def,
                        virDomainDiskDefPtr disk)
12922 12923
{

12924 12925 12926 12927 12928 12929
    if (VIR_REALLOC_N(def->disks, def->ndisks+1) < 0)
        return -1;

    virDomainDiskInsertPreAlloced(def, disk);

    return 0;
12930 12931
}

12932 12933 12934
void virDomainDiskInsertPreAlloced(virDomainDefPtr def,
                                   virDomainDiskDefPtr disk)
{
12935
    int idx;
12936 12937 12938 12939 12940 12941 12942 12943
    /* 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
     */
12944
    for (idx = (def->ndisks - 1); idx >= 0; idx--) {
12945 12946
        /* If bus matches and current disk is after
         * new disk, then new disk should go here */
12947 12948
        if (def->disks[idx]->bus == disk->bus &&
            (virDiskNameToIndex(def->disks[idx]->dst) >
12949
             virDiskNameToIndex(disk->dst))) {
12950 12951
            insertAt = idx;
        } else if (def->disks[idx]->bus == disk->bus &&
12952 12953 12954 12955
                   insertAt == -1) {
            /* Last disk with match bus is before the
             * new disk, then put new disk just after
             */
12956
            insertAt = idx + 1;
12957 12958 12959
        }
    }

12960 12961 12962
    /* VIR_INSERT_ELEMENT_INPLACE will never return an error here. */
    ignore_value(VIR_INSERT_ELEMENT_INPLACE(def->disks, insertAt,
                                            def->ndisks, disk));
12963 12964 12965
}


12966 12967
virDomainDiskDefPtr
virDomainDiskRemove(virDomainDefPtr def, size_t i)
12968
{
12969
    virDomainDiskDefPtr disk = def->disks[i];
12970

12971
    VIR_DELETE_ELEMENT(def->disks, i, def->ndisks);
12972
    return disk;
12973 12974
}

12975 12976
virDomainDiskDefPtr
virDomainDiskRemoveByName(virDomainDefPtr def, const char *name)
12977
{
12978 12979
    int idx = virDomainDiskIndexByName(def, name, false);
    if (idx < 0)
12980
        return NULL;
12981
    return virDomainDiskRemove(def, idx);
12982 12983
}

12984 12985
int virDomainNetInsert(virDomainDefPtr def, virDomainNetDefPtr net)
{
12986 12987 12988 12989 12990 12991 12992 12993 12994 12995
    /* 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);
12996
        return -1;
12997
    }
12998 12999 13000
    return 0;
}

13001 13002 13003 13004
/* virDomainNetFindIdx: search according to mac address and guest side
 *                      PCI address (if specified)
 *
 * Return: index of match if unique match found
13005
 *         -1 otherwise and an error is logged
13006 13007 13008
 */
int
virDomainNetFindIdx(virDomainDefPtr def, virDomainNetDefPtr net)
13009
{
13010 13011
    size_t i;
    int matchidx = -1;
13012
    char mac[VIR_MAC_STRING_BUFLEN];
13013 13014
    bool PCIAddrSpecified = virDomainDeviceAddressIsValid(&net->info,
                                                          VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI);
13015

13016 13017
    for (i = 0; i < def->nnets; i++) {
        if (virMacAddrCmp(&def->nets[i]->mac, &net->mac))
13018 13019 13020 13021 13022 13023 13024 13025 13026
            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.
             */
13027 13028 13029 13030
            virReportError(VIR_ERR_OPERATION_FAILED,
                           _("multiple devices matching mac address %s found"),
                           virMacAddrFormat(&net->mac, mac));
            return -1;
13031 13032
        }
        if (PCIAddrSpecified) {
13033
            if (virDevicePCIAddressEqual(&def->nets[i]->info.addr.pci,
13034 13035 13036 13037
                                         &net->info.addr.pci)) {
                /* exit early if the pci address was specified and
                 * it matches, as this guarantees no duplicates.
                 */
13038
                matchidx = i;
13039 13040 13041 13042
                break;
            }
        } else {
            /* no PCI address given, so there may be multiple matches */
13043
            matchidx = i;
13044 13045
        }
    }
13046
    if (matchidx < 0) {
13047 13048 13049 13050 13051 13052 13053 13054 13055 13056 13057 13058 13059 13060
        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));
        }
13061
    }
13062
    return matchidx;
13063 13064
}

13065 13066 13067 13068 13069 13070 13071 13072 13073 13074 13075 13076 13077 13078 13079 13080 13081 13082 13083 13084 13085
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;
}
13086

13087 13088 13089 13090
void
virDomainNetRemoveHostdev(virDomainDefPtr def,
                          virDomainNetDefPtr net)
{
13091 13092 13093 13094 13095 13096
    /* 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;
13097

13098
    if (hostdev) {
13099 13100 13101
        for (i = 0; i < def->nhostdevs; i++) {
            if (def->hostdevs[i] == hostdev) {
                virDomainHostdevRemove(def, i);
13102 13103 13104 13105
                break;
            }
        }
    }
13106 13107 13108 13109 13110 13111 13112 13113 13114
}


virDomainNetDefPtr
virDomainNetRemove(virDomainDefPtr def, size_t i)
{
    virDomainNetDefPtr net = def->nets[i];

    virDomainNetRemoveHostdev(def, net);
13115
    VIR_DELETE_ELEMENT(def->nets, i, def->nnets);
13116
    return net;
13117 13118
}

13119 13120 13121 13122 13123 13124 13125 13126 13127 13128 13129 13130 13131 13132 13133
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)
{
13134
    int idx;
13135 13136
    /* Tenatively plan to insert controller at the end. */
    int insertAt = -1;
13137
    virDomainControllerDefPtr current = NULL;
13138 13139 13140 13141 13142 13143

    /* 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
     */
13144
    for (idx = (def->ncontrollers - 1); idx >= 0; idx--) {
13145 13146 13147 13148 13149 13150 13151
        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;
13152 13153 13154 13155 13156 13157 13158 13159
            } 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;
13160 13161 13162 13163 13164 13165
            } else if (insertAt == -1) {
                /* Last controller with match bus is before the
                 * new controller, then put new controller just after
                 */
                insertAt = idx + 1;
            }
13166 13167 13168
        }
    }

13169 13170 13171
    /* VIR_INSERT_ELEMENT_INPLACE will never return an error here. */
    ignore_value(VIR_INSERT_ELEMENT_INPLACE(def->controllers, insertAt,
                                            def->ncontrollers, controller));
13172 13173
}

13174 13175 13176 13177
int
virDomainControllerFind(virDomainDefPtr def,
                        int type, int idx)
{
13178
    size_t i;
13179

13180
    for (i = 0; i < def->ncontrollers; i++) {
13181 13182 13183 13184 13185 13186 13187 13188 13189
        if ((def->controllers[i]->type == type) &&
            (def->controllers[i]->idx == idx)) {
            return i;
        }
    }

    return -1;
}

13190 13191 13192 13193 13194 13195 13196 13197 13198 13199 13200 13201 13202 13203 13204 13205 13206 13207 13208 13209 13210 13211 13212 13213 13214 13215 13216 13217 13218 13219 13220 13221 13222 13223

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


13224 13225 13226 13227 13228 13229 13230 13231 13232 13233 13234 13235 13236 13237
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;
}

13238 13239 13240 13241 13242 13243 13244 13245 13246 13247 13248 13249 13250 13251 13252 13253 13254
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;
}

13255 13256 13257 13258 13259
virDomainControllerDefPtr
virDomainControllerRemove(virDomainDefPtr def, size_t i)
{
    virDomainControllerDefPtr controller = def->controllers[i];

13260
    VIR_DELETE_ELEMENT(def->controllers, i, def->ncontrollers);
13261 13262
    return controller;
}
13263

13264 13265 13266 13267
int virDomainLeaseIndex(virDomainDefPtr def,
                        virDomainLeaseDefPtr lease)
{
    virDomainLeaseDefPtr vlease;
13268
    size_t i;
13269 13270 13271

    for (i = 0; i < def->nleases; i++) {
        vlease = def->leases[i];
L
Luyao Huang 已提交
13272 13273 13274 13275
        /* Either both must have lockspaces present which match.. */
        if (vlease->lockspace && lease->lockspace) {
            if (STRNEQ(vlease->lockspace, lease->lockspace))
                continue;
13276
        /* ...or neither must have a lockspace present */
L
Luyao Huang 已提交
13277
        } else if (vlease->lockspace || lease->lockspace) {
13278
            continue;
L
Luyao Huang 已提交
13279 13280
        }

13281 13282 13283 13284 13285 13286 13287 13288 13289
        if (STREQ(vlease->key, lease->key))
            return i;
    }
    return -1;
}


int virDomainLeaseInsertPreAlloc(virDomainDefPtr def)
{
13290
    return VIR_EXPAND_N(def->leases, def->nleases, 1);
13291 13292 13293 13294 13295 13296 13297 13298 13299 13300 13301 13302 13303 13304 13305 13306 13307 13308 13309 13310 13311 13312 13313
}

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


13314 13315
virDomainLeaseDefPtr
virDomainLeaseRemoveAt(virDomainDefPtr def, size_t i)
13316
{
13317 13318 13319

    virDomainLeaseDefPtr lease = def->leases[i];

13320
    VIR_DELETE_ELEMENT(def->leases, i, def->nleases);
13321
    return lease;
13322 13323 13324
}


13325 13326 13327
virDomainLeaseDefPtr
virDomainLeaseRemove(virDomainDefPtr def,
                     virDomainLeaseDefPtr lease)
13328
{
13329 13330
    int idx = virDomainLeaseIndex(def, lease);
    if (idx < 0)
13331
        return NULL;
13332
    return virDomainLeaseRemoveAt(def, idx);
13333 13334
}

13335
bool
13336 13337 13338 13339 13340 13341 13342 13343 13344 13345
virDomainChrEquals(virDomainChrDefPtr src,
                   virDomainChrDefPtr tgt)
{
    if (!src || !tgt)
        return src == tgt;

    if (src->deviceType != tgt->deviceType ||
        !virDomainChrSourceDefIsEqual(&src->source, &tgt->source))
        return false;

13346
    switch ((virDomainChrDeviceType) src->deviceType) {
13347 13348 13349
    case VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL:
        if (src->targetType != tgt->targetType)
            return false;
13350
        switch ((virDomainChrChannelTargetType) src->targetType) {
13351 13352 13353 13354 13355 13356 13357 13358 13359 13360 13361 13362 13363 13364 13365 13366 13367 13368 13369 13370 13371 13372 13373 13374 13375 13376 13377 13378 13379 13380 13381 13382 13383 13384 13385
        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)
{
13386 13387 13388
    virDomainChrDefPtr chr;
    const virDomainChrDef **arrPtr;
    size_t i, cnt;
13389

13390
    virDomainChrGetDomainPtrs(def, target->deviceType, &arrPtr, &cnt);
13391

13392 13393 13394
    for (i = 0; i < cnt; i++) {
        /* Cast away const */
        chr = (virDomainChrDefPtr) arrPtr[i];
13395 13396 13397 13398 13399 13400
        if (virDomainChrEquals(chr, target))
            return chr;
    }
    return NULL;
}

13401 13402 13403 13404 13405

/* Return the address within vmdef to be modified when working with a
 * chrdefptr of the given type.  */
static void
virDomainChrGetDomainPtrsInternal(virDomainDefPtr vmdef,
13406
                                  virDomainChrDeviceType type,
13407 13408
                                  virDomainChrDefPtr ***arrPtr,
                                  size_t **cntPtr)
13409
{
13410
    switch (type) {
13411 13412 13413 13414 13415 13416 13417 13418 13419 13420 13421 13422 13423 13424 13425 13426 13427 13428 13429 13430 13431
    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:
13432 13433
        *arrPtr = NULL;
        *cntPtr = NULL;
13434 13435 13436 13437
        break;
    }
}

13438

13439 13440 13441 13442
/* Return the array within vmdef that can contain a chrdefptr of the
 * given type.  */
void
virDomainChrGetDomainPtrs(const virDomainDef *vmdef,
13443
                          virDomainChrDeviceType type,
13444 13445 13446
                          const virDomainChrDef ***arrPtr,
                          size_t *cntPtr)
{
13447 13448
    virDomainChrDef ***arrVar = NULL;
    size_t *cntVar = NULL;
13449 13450 13451 13452 13453 13454 13455 13456 13457 13458 13459 13460 13461

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

13462

13463
int
13464 13465 13466 13467 13468 13469 13470 13471 13472 13473 13474 13475 13476 13477
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)
13478
{
13479 13480
    virDomainChrDefPtr **arrPtr = NULL;
    size_t *cntPtr = NULL;
13481

13482
    virDomainChrGetDomainPtrsInternal(vmdef, chr->deviceType, &arrPtr, &cntPtr);
13483

13484
    ignore_value(VIR_APPEND_ELEMENT_INPLACE(*arrPtr, *cntPtr, chr));
13485 13486 13487 13488 13489 13490
}

virDomainChrDefPtr
virDomainChrRemove(virDomainDefPtr vmdef,
                   virDomainChrDefPtr chr)
{
13491 13492
    virDomainChrDefPtr ret, **arrPtr = NULL;
    size_t i, *cntPtr = NULL;
13493

13494
    virDomainChrGetDomainPtrsInternal(vmdef, chr->deviceType, &arrPtr, &cntPtr);
13495 13496 13497 13498 13499 13500 13501 13502 13503 13504 13505 13506 13507 13508

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

13510 13511 13512 13513 13514 13515 13516 13517 13518 13519 13520 13521 13522 13523 13524 13525 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

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


13580 13581 13582 13583 13584 13585 13586 13587 13588 13589 13590 13591 13592 13593 13594 13595 13596 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
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);
13676 13677 13678 13679 13680

    /* fix up balloon size */
    if (def->mem.cur_balloon > virDomainDefGetMemoryActual(def))
        def->mem.cur_balloon = virDomainDefGetMemoryActual(def);

13681 13682 13683 13684
    return ret;
}


13685 13686 13687 13688
char *
virDomainDefGetDefaultEmulator(virDomainDefPtr def,
                               virCapsPtr caps)
{
13689
    char *retemu;
13690
    virCapsDomainDataPtr capsdata;
13691

13692 13693 13694
    if (!(capsdata = virCapabilitiesDomainDataLookup(caps, def->os.type,
            def->os.arch, def->virtType, NULL, NULL)))
        return NULL;
13695

13696 13697
    if (VIR_STRDUP(retemu, capsdata->emulator) < 0) {
        VIR_FREE(capsdata);
13698 13699
        return NULL;
    }
13700
    VIR_FREE(capsdata);
13701 13702 13703
    return retemu;
}

13704 13705
static int
virDomainDefParseBootXML(xmlXPathContextPtr ctxt,
13706
                         virDomainDefPtr def)
13707 13708
{
    xmlNodePtr *nodes = NULL;
13709 13710
    size_t i;
    int n;
M
Martin Kletzander 已提交
13711
    char *tmp = NULL;
13712
    int ret = -1;
M
Michal Privoznik 已提交
13713
    unsigned long deviceBoot, serialPorts;
13714 13715

    if (virXPathULong("count(./devices/disk[boot]"
13716
                      "|./devices/interface[boot]"
13717 13718
                      "|./devices/hostdev[boot]"
                      "|./devices/redirdev[boot])", ctxt, &deviceBoot) < 0) {
13719 13720
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("cannot count boot devices"));
13721 13722
        goto cleanup;
    }
13723 13724

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

13728
    if (n > 0 && deviceBoot) {
13729 13730 13731
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("per-device boot elements cannot be used"
                         " together with os/boot elements"));
13732 13733 13734
        goto cleanup;
    }

13735
    for (i = 0; i < n && i < VIR_DOMAIN_BOOT_LAST; i++) {
13736 13737 13738
        int val;
        char *dev = virXMLPropString(nodes[i], "dev");
        if (!dev) {
13739 13740
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("missing boot device"));
13741 13742 13743
            goto cleanup;
        }
        if ((val = virDomainBootTypeFromString(dev)) < 0) {
13744
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
13745 13746
                           _("unknown boot device '%s'"),
                           dev);
13747 13748 13749 13750 13751 13752
            VIR_FREE(dev);
            goto cleanup;
        }
        VIR_FREE(dev);
        def->os.bootDevs[def->os.nBootDevs++] = val;
    }
13753
    if (def->os.nBootDevs == 0 && !deviceBoot) {
13754 13755 13756 13757
        def->os.nBootDevs = 1;
        def->os.bootDevs[0] = VIR_DOMAIN_BOOT_DISK;
    }

M
Martin Kletzander 已提交
13758 13759
    tmp = virXPathString("string(./os/bootmenu[1]/@enable)", ctxt);
    if (tmp) {
J
Ján Tomko 已提交
13760
        def->os.bootmenu = virTristateBoolTypeFromString(tmp);
13761 13762 13763 13764 13765
        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 已提交
13766
                     tmp);
J
Ján Tomko 已提交
13767
            def->os.bootmenu = VIR_TRISTATE_BOOL_NO;
13768
        }
M
Martin Kletzander 已提交
13769
        VIR_FREE(tmp);
13770 13771
    }

13772 13773 13774 13775 13776 13777 13778 13779 13780 13781 13782 13783 13784
    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 已提交
13785 13786 13787
    tmp = virXPathString("string(./os/bios[1]/@useserial)", ctxt);
    if (tmp) {
        if (STREQ(tmp, "yes")) {
M
Michal Privoznik 已提交
13788 13789
            if (virXPathULong("count(./devices/serial)",
                              ctxt, &serialPorts) < 0) {
13790 13791 13792
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                               _("need at least one serial port "
                                 "for useserial"));
M
Michal Privoznik 已提交
13793 13794
                goto cleanup;
            }
J
Ján Tomko 已提交
13795
            def->os.bios.useserial = VIR_TRISTATE_BOOL_YES;
M
Michal Privoznik 已提交
13796
        } else {
J
Ján Tomko 已提交
13797
            def->os.bios.useserial = VIR_TRISTATE_BOOL_NO;
M
Michal Privoznik 已提交
13798
        }
M
Martin Kletzander 已提交
13799
        VIR_FREE(tmp);
M
Michal Privoznik 已提交
13800 13801
    }

13802 13803 13804 13805 13806 13807 13808 13809 13810 13811 13812 13813 13814 13815
    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;
    }

13816 13817
    ret = 0;

13818
 cleanup:
13819
    VIR_FREE(tmp);
13820 13821 13822 13823
    VIR_FREE(nodes);
    return ret;
}

13824

G
Gao feng 已提交
13825 13826
static int virDomainIdMapEntrySort(const void *a, const void *b)
{
13827 13828
    const virDomainIdMapEntry *entrya = a;
    const virDomainIdMapEntry *entryb = b;
G
Gao feng 已提交
13829 13830 13831 13832 13833 13834 13835 13836 13837

    if (entrya->start > entryb->start)
        return 1;
    else if (entrya->start < entryb->start)
        return -1;
    else
        return 0;
}

13838 13839 13840 13841 13842 13843 13844 13845 13846
/* 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,
13847
                          xmlNodePtr *node,
13848 13849 13850 13851 13852 13853
                          size_t num)
{
    size_t i;
    virDomainIdMapEntryPtr idmap = NULL;
    xmlNodePtr save_ctxt = ctxt->node;

13854
    if (VIR_ALLOC_N(idmap, num) < 0)
13855 13856 13857 13858 13859 13860 13861
        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) {
13862 13863
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("invalid idmap start/target/count settings"));
13864 13865 13866 13867 13868
            VIR_FREE(idmap);
            goto cleanup;
        }
    }

G
Gao feng 已提交
13869 13870 13871 13872 13873 13874 13875 13876 13877 13878 13879
    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;
    }

13880
 cleanup:
13881 13882 13883 13884
    ctxt->node = save_ctxt;
    return idmap;
}

13885 13886 13887 13888 13889 13890 13891 13892 13893 13894 13895 13896 13897 13898 13899 13900 13901 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
/* 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 已提交
13929
    iothrid = NULL;
13930 13931 13932 13933
    goto cleanup;
}


13934 13935 13936 13937 13938 13939 13940 13941 13942 13943 13944 13945 13946 13947 13948 13949 13950 13951 13952
/* 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;
}

13953
/* Parse the XML definition for a vcpupin
13954 13955 13956 13957
 *
 * vcpupin has the form of
 *   <vcpupin vcpu='0' cpuset='0'/>
 */
13958
static virDomainPinDefPtr
13959
virDomainVcpuPinDefParseXML(xmlNodePtr node,
13960
                            xmlXPathContextPtr ctxt)
13961
{
13962
    virDomainPinDefPtr def;
13963
    xmlNodePtr oldnode = ctxt->node;
13964
    unsigned int vcpuid;
13965 13966
    char *tmp = NULL;

13967
    if (VIR_ALLOC(def) < 0)
13968 13969 13970 13971
        return NULL;

    ctxt->node = node;

13972 13973 13974
    if (!(tmp = virXPathString("string(./@vcpu)", ctxt))) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("missing vcpu id in vcpupin"));
13975 13976
        goto error;
    }
13977

13978 13979 13980
    if (virStrToLong_uip(tmp, NULL, 10, &vcpuid) < 0) {
        virReportError(VIR_ERR_XML_ERROR,
                       _("invalid setting for vcpu '%s'"), tmp);
13981 13982
        goto error;
    }
13983
    VIR_FREE(tmp);
13984 13985 13986 13987

    def->id = vcpuid;

    if (!(tmp = virXMLPropString(node, "cpuset"))) {
13988
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
13989
                           _("missing cpuset for vcpupin"));
13990

13991
        goto error;
13992
    }
13993

13994 13995 13996 13997 13998 13999 14000 14001 14002 14003 14004 14005 14006 14007 14008 14009 14010 14011
    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'/>
 */
14012
static int
14013 14014
virDomainIOThreadPinDefParseXML(xmlNodePtr node,
                                xmlXPathContextPtr ctxt,
14015
                                virDomainDefPtr def)
14016
{
14017 14018
    int ret = -1;
    virDomainIOThreadIDDefPtr iothrid;
14019
    virBitmapPtr cpumask = NULL;
14020 14021 14022 14023 14024 14025
    xmlNodePtr oldnode = ctxt->node;
    unsigned int iothreadid;
    char *tmp = NULL;

    ctxt->node = node;

14026 14027 14028
    if (!(tmp = virXPathString("string(./@iothread)", ctxt))) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("missing iothread id in iothreadpin"));
14029
        goto cleanup;
14030
    }
14031

14032 14033 14034
    if (virStrToLong_uip(tmp, NULL, 10, &iothreadid) < 0) {
        virReportError(VIR_ERR_XML_ERROR,
                       _("invalid setting for iothread '%s'"), tmp);
14035
        goto cleanup;
14036 14037
    }
    VIR_FREE(tmp);
14038

14039 14040 14041
    if (iothreadid == 0) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("zero is an invalid iothread id value"));
14042
        goto cleanup;
14043
    }
14044

14045 14046 14047 14048
    if (!(iothrid = virDomainIOThreadIDFind(def, iothreadid))) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Cannot find 'iothread' : %u"),
                       iothreadid);
J
John Ferlan 已提交
14049
        goto cleanup;
14050 14051
    }

14052
    if (!(tmp = virXMLPropString(node, "cpuset"))) {
14053 14054
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("missing cpuset for iothreadpin"));
14055
        goto cleanup;
14056 14057
    }

14058 14059
    if (virBitmapParse(tmp, 0, &cpumask, VIR_DOMAIN_CPUMASK_LEN) < 0)
        goto cleanup;
14060

14061
    if (virBitmapIsAllClear(cpumask)) {
14062 14063 14064
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Invalid value of 'cpuset': %s"),
                       tmp);
14065
        goto cleanup;
14066 14067
    }

14068 14069 14070 14071 14072 14073 14074 14075 14076 14077 14078
    if (iothrid->cpumask) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("duplicate iothreadpin for same iothread '%u'"),
                       iothreadid);
        goto cleanup;
    }

    iothrid->cpumask = cpumask;
    cpumask = NULL;
    ret = 0;

14079
 cleanup:
14080
    VIR_FREE(tmp);
14081
    virBitmapFree(cpumask);
14082
    ctxt->node = oldnode;
14083
    return ret;
14084 14085
}

14086

14087 14088 14089 14090
/* Parse the XML definition for emulatorpin.
 * emulatorpin has the form of
 *   <emulatorpin cpuset='0'/>
 */
14091
static virBitmapPtr
14092 14093
virDomainEmulatorPinDefParseXML(xmlNodePtr node)
{
14094
    virBitmapPtr def = NULL;
14095 14096 14097 14098 14099
    char *tmp = NULL;

    if (!(tmp = virXMLPropString(node, "cpuset"))) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("missing cpuset for emulatorpin"));
14100
        return NULL;
14101 14102
    }

14103
    ignore_value(virBitmapParse(tmp, 0, &def, VIR_DOMAIN_CPUMASK_LEN));
14104 14105 14106 14107 14108 14109

    VIR_FREE(tmp);
    return def;
}


14110
int
14111 14112 14113 14114
virDomainDefMaybeAddController(virDomainDefPtr def,
                               int type,
                               int idx,
                               int model)
14115
{
14116
    size_t i;
14117 14118
    virDomainControllerDefPtr cont;

14119
    for (i = 0; i < def->ncontrollers; i++) {
14120 14121
        if (def->controllers[i]->type == type &&
            def->controllers[i]->idx == idx)
14122
            return 0;
14123 14124
    }

14125
    if (!(cont = virDomainControllerDefNew(type)))
14126 14127 14128
        return -1;

    cont->idx = idx;
14129
    cont->model = model;
14130

14131
    if (VIR_APPEND_ELEMENT(def->controllers, def->ncontrollers, cont) < 0) {
14132 14133 14134 14135
        VIR_FREE(cont);
        return -1;
    }

14136
    return 1;
14137 14138
}

E
Eric Blake 已提交
14139

14140 14141 14142 14143 14144 14145 14146 14147 14148 14149 14150 14151 14152 14153 14154 14155 14156 14157 14158 14159 14160 14161 14162 14163 14164 14165 14166 14167 14168
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;
}


14169 14170 14171 14172 14173 14174 14175 14176 14177 14178 14179
static int
virDomainHugepagesParseXML(xmlNodePtr node,
                           xmlXPathContextPtr ctxt,
                           virDomainHugePagePtr hugepage)
{
    int ret = -1;
    xmlNodePtr oldnode = ctxt->node;
    char *unit = NULL, *nodeset = NULL;

    ctxt->node = node;

14180 14181
    if (virDomainParseMemory("./@size", "./@unit", ctxt,
                             &hugepage->size, true, false) < 0)
14182 14183
        goto cleanup;

14184
    if (!hugepage->size) {
14185 14186 14187 14188 14189 14190 14191 14192 14193
        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;
14194 14195 14196 14197 14198 14199

        if (virBitmapIsAllClear(hugepage->nodemask)) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Invalid value of 'nodeset': %s"), nodeset);
            goto cleanup;
        }
14200 14201 14202 14203 14204 14205 14206 14207 14208 14209 14210
    }

    ret = 0;
 cleanup:
    VIR_FREE(unit);
    VIR_FREE(nodeset);
    ctxt->node = oldnode;
    return ret;
}


14211 14212 14213 14214 14215 14216 14217 14218 14219
static virDomainResourceDefPtr
virDomainResourceDefParse(xmlNodePtr node,
                          xmlXPathContextPtr ctxt)
{
    virDomainResourceDefPtr def = NULL;
    xmlNodePtr tmp = ctxt->node;

    ctxt->node = node;

14220
    if (VIR_ALLOC(def) < 0)
14221 14222 14223 14224 14225 14226 14227 14228 14229 14230 14231 14232
        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;

14233
 error:
14234 14235 14236 14237 14238
    ctxt->node = tmp;
    virDomainResourceDefFree(def);
    return NULL;
}

14239 14240 14241 14242
static int
virDomainDefMaybeAddHostdevSCSIcontroller(virDomainDefPtr def)
{
    /* Look for any hostdev scsi dev */
14243
    size_t i;
14244 14245 14246 14247 14248 14249 14250 14251 14252 14253 14254 14255
    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;
        }
    }

14256 14257 14258
    if (maxController == -1)
        return 0;

14259 14260 14261 14262 14263 14264 14265
    for (i = 0; i <= maxController; i++) {
        if (virDomainDefMaybeAddController(def, VIR_DOMAIN_CONTROLLER_TYPE_SCSI, i, -1) < 0)
            return -1;
    }

    return 0;
}
14266

14267 14268 14269 14270 14271 14272 14273 14274 14275 14276 14277 14278 14279 14280 14281 14282 14283 14284 14285 14286 14287 14288 14289 14290 14291 14292 14293 14294 14295 14296 14297 14298 14299 14300 14301 14302
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;
}

14303 14304 14305 14306 14307 14308 14309 14310
static int
virDomainThreadSchedParse(xmlNodePtr node,
                          unsigned int minid,
                          unsigned int maxid,
                          const char *name,
                          virDomainThreadSchedParamPtr sp)
{
    char *tmp = NULL;
14311
    int pol = 0;
14312 14313 14314 14315 14316 14317 14318 14319 14320

    tmp = virXMLPropString(node, name);
    if (!tmp) {
        virReportError(VIR_ERR_XML_ERROR,
                       _("Missing attribute '%s' in element '%sched'"),
                       name, name);
        goto error;
    }

14321 14322 14323 14324
    if (virBitmapParse(tmp, 0, &sp->ids, VIR_DOMAIN_CPUMASK_LEN) < 0)
        goto error;

    if (virBitmapIsAllClear(sp->ids) ||
14325 14326 14327
        virBitmapNextSetBit(sp->ids, -1) < minid ||
        virBitmapLastSetBit(sp->ids) > maxid) {

14328
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
14329 14330 14331 14332 14333 14334
                       _("Invalid value of '%s': %s"),
                       name, tmp);
        goto error;
    }
    VIR_FREE(tmp);

14335 14336 14337 14338 14339 14340 14341 14342 14343 14344 14345 14346 14347 14348 14349 14350 14351 14352 14353 14354 14355
    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"));
14356 14357
            goto error;
        }
14358 14359 14360 14361
        if (virStrToLong_i(tmp, NULL, 10, &sp->priority) < 0) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("Invalid value for element priority"));
            goto error;
14362
        }
14363
        VIR_FREE(tmp);
14364 14365 14366 14367 14368 14369 14370 14371
    }

    return 0;

 error:
    VIR_FREE(tmp);
    return -1;
}
14372

14373 14374 14375 14376 14377 14378 14379 14380 14381 14382 14383 14384 14385 14386 14387 14388 14389 14390 14391 14392 14393 14394 14395 14396 14397 14398 14399 14400 14401 14402 14403 14404 14405 14406 14407 14408 14409 14410 14411 14412 14413 14414 14415 14416 14417 14418 14419 14420 14421 14422 14423 14424 14425 14426 14427 14428 14429 14430 14431 14432 14433 14434 14435 14436 14437 14438 14439 14440 14441 14442 14443 14444 14445 14446 14447

static int
virDomainVcpuParse(virDomainDefPtr def,
                   xmlXPathContextPtr ctxt)
{
    int n;
    char *tmp = NULL;
    int ret = -1;

    if ((n = virXPathUInt("string(./vcpu[1])", ctxt, &def->maxvcpus)) < 0) {
        if (n == -2) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("maximum vcpus count must be an integer"));
            goto cleanup;
        }

        def->maxvcpus = 1;
    }

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

        def->vcpus = def->maxvcpus;
    }

    if (def->maxvcpus < def->vcpus) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("maxvcpus must not be less than current vcpus "
                         "(%u < %u)"), def->maxvcpus, def->vcpus);
        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;
}

14448
static virDomainDefPtr
14449
virDomainDefParseXML(xmlDocPtr xml,
14450 14451
                     xmlNodePtr root,
                     xmlXPathContextPtr ctxt,
14452 14453
                     virCapsPtr caps,
                     virDomainXMLOptionPtr xmlopt,
14454
                     unsigned int flags)
14455 14456 14457
{
    xmlNodePtr *nodes = NULL, node = NULL;
    char *tmp = NULL;
14458
    size_t i, j;
J
John Ferlan 已提交
14459
    int n, virtType;
14460
    long id = -1;
14461
    virDomainDefPtr def;
14462
    bool uuid_generated = false;
14463
    virHashTablePtr bootHash = NULL;
14464 14465
    bool usb_none = false;
    bool usb_other = false;
14466
    bool usb_master = false;
14467
    bool primaryVideo = false;
14468

14469 14470
    if (flags & VIR_DOMAIN_DEF_PARSE_VALIDATE) {
        char *schema = virFileFindResource("domain.rng",
14471
                                           abs_topsrcdir "/docs/schemas",
14472 14473 14474 14475 14476 14477 14478 14479 14480 14481
                                           PKGDATADIR "/schemas");
        if (!schema)
            return NULL;
        if (virXMLValidateAgainstSchema(schema, xml) < 0) {
            VIR_FREE(schema);
            return NULL;
        }
        VIR_FREE(schema);
    }

14482
    if (!(def = virDomainDefNew()))
14483
        return NULL;
14484

14485
    if (!(flags & VIR_DOMAIN_DEF_PARSE_INACTIVE))
E
Eric Blake 已提交
14486
        if (virXPathLong("string(./@id)", ctxt, &id) < 0)
14487 14488
            id = -1;
    def->id = (int)id;
14489

14490
    /* Find out what type of virtualization to use */
14491
    if (!(tmp = virXPathString("string(./@type)", ctxt))) {
14492 14493
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing domain type attribute"));
14494 14495 14496
        goto error;
    }

J
John Ferlan 已提交
14497
    if ((virtType = virDomainVirtTypeFromString(tmp)) < 0) {
14498
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
14499
                       _("invalid domain type %s"), tmp);
14500 14501
        goto error;
    }
J
John Ferlan 已提交
14502
    def->virtType = virtType;
14503 14504
    VIR_FREE(tmp);

14505 14506 14507 14508 14509 14510 14511 14512 14513 14514 14515 14516 14517 14518 14519 14520 14521 14522 14523 14524 14525 14526 14527 14528 14529 14530 14531 14532 14533 14534 14535 14536 14537 14538 14539 14540 14541 14542 14543 14544 14545 14546 14547 14548
    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)) {
14549 14550 14551 14552 14553 14554 14555 14556
        /* 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;
14557

14558
        if (!(capsdata = virCapabilitiesDomainDataLookup(caps, def->os.type,
14559
                def->os.arch, use_virttype ? def->virtType : VIR_DOMAIN_VIRT_NONE,
14560 14561
                NULL, NULL)))
            goto error;
14562

14563 14564 14565 14566 14567 14568
        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;
14569
        }
14570
        VIR_FREE(capsdata);
14571 14572
    }

14573
    /* Extract domain name */
14574
    if (!(def->name = virXPathString("string(./name[1])", ctxt))) {
14575
        virReportError(VIR_ERR_NO_NAME, NULL);
14576 14577 14578
        goto error;
    }

14579 14580 14581
    /* 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. */
14582
    tmp = virXPathString("string(./uuid[1])", ctxt);
14583
    if (!tmp) {
14584
        if (virUUIDGenerate(def->uuid)) {
14585 14586
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("Failed to generate UUID"));
14587 14588
            goto error;
        }
14589
        uuid_generated = true;
14590 14591
    } else {
        if (virUUIDParse(tmp, def->uuid) < 0) {
14592 14593
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("malformed uuid element"));
14594 14595 14596 14597 14598
            goto error;
        }
        VIR_FREE(tmp);
    }

14599 14600 14601
    /* Extract short description of domain (title) */
    def->title = virXPathString("string(./title[1])", ctxt);
    if (def->title && strchr(def->title, '\n')) {
14602 14603
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Domain title can't contain newlines"));
14604 14605 14606
        goto error;
    }

14607
    /* Extract documentation if present */
14608
    def->description = virXPathString("string(./description[1])", ctxt);
14609

E
Eric Blake 已提交
14610 14611
    /* analysis of security label, done early even though we format it
     * late, so devices can refer to this for defaults */
14612
    if (virSecurityLabelDefsParseXML(def, ctxt, caps, flags) == -1)
E
Eric Blake 已提交
14613 14614
        goto error;

14615
    /* Extract domain memory */
14616
    if (virDomainParseMemory("./memory[1]", NULL, ctxt,
14617
                             &def->mem.total_memory, false, true) < 0)
14618 14619
        goto error;

14620
    if (virDomainParseMemory("./currentMemory[1]", NULL, ctxt,
14621
                             &def->mem.cur_balloon, false, true) < 0)
E
Eric Blake 已提交
14622
        goto error;
14623

14624 14625 14626 14627 14628 14629 14630 14631 14632 14633
    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;
    }

14634
    /* and info about it */
14635
    if ((tmp = virXPathString("string(./memory[1]/@dumpCore)", ctxt)) &&
J
Ján Tomko 已提交
14636
        (def->mem.dump_core = virTristateSwitchTypeFromString(tmp)) <= 0) {
14637
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
14638 14639
                       _("Invalid memory core dump attribute value '%s'"), tmp);
        goto error;
14640
    }
14641
    VIR_FREE(tmp);
14642

14643 14644 14645 14646 14647 14648 14649 14650 14651 14652 14653 14654 14655 14656 14657 14658 14659 14660 14661 14662 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
    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;
        }
    }
14691

14692 14693 14694
    if ((node = virXPathNode("./memoryBacking/nosharepages", ctxt)))
        def->mem.nosharepages = true;

14695 14696 14697
    if (virXPathBoolean("boolean(./memoryBacking/locked)", ctxt))
        def->mem.locked = true;

14698 14699 14700 14701 14702
    /* Extract blkio cgroup tunables */
    if (virXPathUInt("string(./blkiotune/weight)", ctxt,
                     &def->blkio.weight) < 0)
        def->blkio.weight = 0;

14703
    if ((n = virXPathNodeSet("./blkiotune/device", ctxt, &nodes)) < 0) {
14704 14705
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("cannot extract blkiotune nodes"));
14706 14707 14708
        goto error;
    }
    if (n && VIR_ALLOC_N(def->blkio.devices, n) < 0)
14709
        goto error;
14710 14711

    for (i = 0; i < n; i++) {
14712 14713
        if (virDomainBlkioDeviceParseXML(nodes[i],
                                         &def->blkio.devices[i]) < 0)
14714 14715
            goto error;
        def->blkio.ndevices++;
14716 14717 14718
        for (j = 0; j < i; j++) {
            if (STREQ(def->blkio.devices[j].path,
                      def->blkio.devices[i].path)) {
14719
                virReportError(VIR_ERR_XML_ERROR,
14720
                               _("duplicate blkio device path '%s'"),
14721
                               def->blkio.devices[i].path);
14722 14723 14724
                goto error;
            }
        }
14725 14726 14727
    }
    VIR_FREE(nodes);

14728
    /* Extract other memory tunables */
14729 14730
    if (virDomainParseMemoryLimit("./memtune/hard_limit[1]", NULL, ctxt,
                                  &def->mem.hard_limit) < 0)
E
Eric Blake 已提交
14731
        goto error;
14732

14733 14734
    if (virDomainParseMemoryLimit("./memtune/soft_limit[1]", NULL, ctxt,
                                  &def->mem.soft_limit) < 0)
E
Eric Blake 已提交
14735
        goto error;
14736

14737
    if (virDomainParseMemory("./memtune/min_guarantee[1]", NULL, ctxt,
14738
                             &def->mem.min_guarantee, false, false) < 0)
E
Eric Blake 已提交
14739
        goto error;
14740

14741 14742
    if (virDomainParseMemoryLimit("./memtune/swap_hard_limit[1]", NULL, ctxt,
                                  &def->mem.swap_hard_limit) < 0)
E
Eric Blake 已提交
14743
        goto error;
14744

14745
    if (virDomainVcpuParse(def, ctxt) < 0)
14746
        goto error;
14747

14748 14749 14750 14751 14752 14753 14754 14755 14756
    /* 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);

14757 14758 14759 14760 14761 14762 14763 14764 14765 14766 14767 14768 14769 14770 14771 14772 14773 14774 14775 14776 14777 14778 14779 14780 14781 14782
    /* 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);

14783 14784
    if (virDomainIOThreadIDDefArrayInit(def) < 0)
        goto error;
14785

14786
    /* Extract cpu tunables. */
14787 14788
    if ((n = virXPathULong("string(./cputune/shares[1])", ctxt,
                           &def->cputune.shares)) < -1) {
14789 14790 14791
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("can't parse cputune shares value"));
        goto error;
14792 14793
    } else if (n == 0) {
        def->cputune.sharesSpecified = true;
14794
    }
14795

14796
    if (virXPathULongLong("string(./cputune/period[1])", ctxt,
14797 14798 14799 14800 14801
                          &def->cputune.period) < -1) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("can't parse cputune period value"));
        goto error;
    }
14802

14803 14804 14805 14806 14807 14808 14809 14810
    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;
    }

14811
    if (virXPathLongLong("string(./cputune/quota[1])", ctxt,
14812 14813 14814 14815 14816
                         &def->cputune.quota) < -1) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("can't parse cputune quota value"));
        goto error;
    }
14817

14818 14819
    if (def->cputune.quota > 0 &&
        (def->cputune.quota < 1000 ||
E
Eric Blake 已提交
14820
         def->cputune.quota > 18446744073709551LL)) {
14821 14822 14823 14824 14825 14826
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Value of cputune quota must be in range "
                         "[1000, 18446744073709551]"));
        goto error;
    }

14827
    if (virXPathULongLong("string(./cputune/emulator_period[1])", ctxt,
14828 14829 14830 14831 14832
                          &def->cputune.emulator_period) < -1) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("can't parse cputune emulator period value"));
        goto error;
    }
14833

14834 14835 14836 14837 14838 14839 14840 14841 14842
    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;
    }

14843
    if (virXPathLongLong("string(./cputune/emulator_quota[1])", ctxt,
14844 14845 14846
                         &def->cputune.emulator_quota) < -1) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("can't parse cputune emulator quota value"));
14847 14848 14849
        goto error;
    }

14850 14851
    if (def->cputune.emulator_quota > 0 &&
        (def->cputune.emulator_quota < 1000 ||
E
Eric Blake 已提交
14852
         def->cputune.emulator_quota > 18446744073709551LL)) {
14853 14854 14855 14856 14857 14858
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Value of cputune emulator_quota must be in range "
                         "[1000, 18446744073709551]"));
        goto error;
    }

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

14862
    if (n && VIR_ALLOC_N(def->cputune.vcpupin, n) < 0)
14863
        goto error;
14864

14865
    for (i = 0; i < n; i++) {
14866 14867
        virDomainPinDefPtr vcpupin;
        if (!(vcpupin = virDomainVcpuPinDefParseXML(nodes[i], ctxt)))
14868 14869
            goto error;

14870 14871 14872
        if (virDomainPinIsDuplicate(def->cputune.vcpupin,
                                    def->cputune.nvcpupin,
                                    vcpupin->id)) {
14873 14874
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("duplicate vcpupin for same vcpu"));
14875
            virDomainPinDefFree(vcpupin);
14876 14877 14878
            goto error;
        }

14879
        if (vcpupin->id >= def->vcpus) {
14880 14881 14882 14883 14884
            /* 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.
             */
14885
            VIR_WARN("Ignore vcpupin for missing vcpus");
14886
            virDomainPinDefFree(vcpupin);
14887
        } else {
14888
            def->cputune.vcpupin[def->cputune.nvcpupin++] = vcpupin;
14889
        }
14890 14891 14892
    }
    VIR_FREE(nodes);

14893 14894 14895 14896
    /* Initialize the pinning policy for vcpus which doesn't has
     * the policy specified explicitly as def->cpuset.
     */
    if (def->cpumask) {
14897
        if (VIR_REALLOC_N(def->cputune.vcpupin, def->vcpus) < 0)
14898
            goto error;
14899 14900

        for (i = 0; i < def->vcpus; i++) {
14901 14902 14903
            if (virDomainPinIsDuplicate(def->cputune.vcpupin,
                                        def->cputune.nvcpupin,
                                        i))
14904
                continue;
14905

14906
            virDomainPinDefPtr vcpupin = NULL;
14907

14908
            if (VIR_ALLOC(vcpupin) < 0)
14909 14910
                goto error;

14911 14912
            if (!(vcpupin->cpumask = virBitmapNew(VIR_DOMAIN_CPUMASK_LEN))) {
                VIR_FREE(vcpupin);
14913
                goto error;
14914
            }
14915
            virBitmapCopy(vcpupin->cpumask, def->cpumask);
14916
            vcpupin->id = i;
14917
            def->cputune.vcpupin[def->cputune.nvcpupin++] = vcpupin;
14918 14919 14920
        }
    }

T
Tang Chen 已提交
14921 14922 14923 14924 14925 14926 14927
    if ((n = virXPathNodeSet("./cputune/emulatorpin", ctxt, &nodes)) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("cannot extract emulatorpin nodes"));
        goto error;
    }

    if (n) {
14928 14929 14930 14931 14932 14933
        if (n > 1) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("only one emulatorpin is supported"));
            VIR_FREE(nodes);
            goto error;
        }
T
Tang Chen 已提交
14934

14935
        if (!(def->cputune.emulatorpin = virDomainEmulatorPinDefParseXML(nodes[0])))
14936
            goto error;
T
Tang Chen 已提交
14937 14938 14939
    }
    VIR_FREE(nodes);

14940 14941 14942 14943 14944 14945 14946

    if ((n = virXPathNodeSet("./cputune/iothreadpin", ctxt, &nodes)) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("cannot extract iothreadpin nodes"));
        goto error;
    }

14947
    for (i = 0; i < n; i++) {
14948
        if (virDomainIOThreadPinDefParseXML(nodes[i], ctxt, def) < 0)
14949
            goto error;
14950 14951 14952
    }
    VIR_FREE(nodes);

14953 14954 14955 14956 14957 14958 14959 14960 14961 14962 14963 14964 14965 14966 14967 14968 14969 14970 14971 14972 14973 14974 14975 14976 14977 14978 14979 14980 14981 14982 14983 14984 14985 14986 14987 14988
    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) {
14989
        if (n > def->niothreadids) {
14990 14991 14992 14993 14994 14995 14996 14997 14998 14999
            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++) {
15000 15001
            ssize_t pos = -1;

15002
            if (virDomainThreadSchedParse(nodes[i],
15003
                                          1, UINT_MAX,
15004 15005 15006 15007
                                          "iothreads",
                                          &def->cputune.iothreadsched[i]) < 0)
                goto error;

15008 15009 15010 15011 15012 15013 15014 15015 15016 15017
            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;
                }
            }

15018 15019 15020 15021 15022 15023 15024 15025 15026 15027 15028 15029
            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);
15030

M
Martin Kletzander 已提交
15031 15032 15033 15034 15035 15036 15037 15038 15039 15040 15041 15042 15043 15044 15045 15046 15047 15048
    /* 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;
        }

15049 15050
    }

15051
    if (virDomainNumaDefCPUParseXML(def->numa, ctxt) < 0)
15052 15053
        goto error;

15054
    if (virDomainNumaGetCPUCountTotal(def->numa) > def->maxvcpus) {
15055 15056 15057 15058
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Number of CPUs in <numa> exceeds the"
                         " <vcpu> count"));
        goto error;
M
Martin Kletzander 已提交
15059 15060
    }

15061 15062 15063 15064 15065 15066
    if (virDomainNumaGetMaxCPUID(def->numa) >= def->maxvcpus) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("CPU IDs in <numa> exceed the <vcpu> count"));
        goto error;
    }

15067
    if (virDomainNumatuneParseXML(def->numa,
15068 15069 15070
                                  def->placement_mode ==
                                  VIR_DOMAIN_CPU_PLACEMENT_MODE_STATIC,
                                  ctxt) < 0)
15071 15072
        goto error;

15073
    if (virDomainNumatuneHasPlacementAuto(def->numa) &&
15074
        !def->cpumask && !def->cputune.vcpupin &&
15075 15076
        !def->cputune.emulatorpin &&
        !virDomainIOThreadIDArrayHasPin(def))
15077 15078
        def->placement_mode = VIR_DOMAIN_CPU_PLACEMENT_MODE_AUTO;

15079 15080 15081 15082 15083 15084 15085 15086 15087 15088 15089 15090 15091 15092 15093 15094 15095
    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);

15096
    if ((n = virXPathNodeSet("./features/*", ctxt, &nodes)) < 0)
15097
        goto error;
15098

15099
    for (i = 0; i < n; i++) {
15100 15101
        int val = virDomainFeatureTypeFromString((const char *)nodes[i]->name);
        if (val < 0) {
15102
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
15103
                           _("unexpected feature '%s'"), nodes[i]->name);
15104 15105
            goto error;
        }
15106

15107
        switch ((virDomainFeature) val) {
15108 15109
        case VIR_DOMAIN_FEATURE_APIC:
            if ((tmp = virXPathString("string(./features/apic/@eoi)", ctxt))) {
15110
                int eoi;
J
Ján Tomko 已提交
15111
                if ((eoi = virTristateSwitchTypeFromString(tmp)) <= 0) {
15112
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
15113
                                   _("unknown value for attribute eoi: '%s'"),
15114 15115
                                   tmp);
                    goto error;
15116
                }
15117 15118
                def->apic_eoi = eoi;
                VIR_FREE(tmp);
15119
            }
15120 15121 15122 15123 15124 15125 15126
            /* 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:
15127
        case VIR_DOMAIN_FEATURE_KVM:
J
Ján Tomko 已提交
15128
            def->features[val] = VIR_TRISTATE_SWITCH_ON;
15129 15130
            break;

15131 15132 15133 15134 15135 15136 15137 15138 15139 15140 15141 15142
        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 已提交
15143
                def->features[val] = VIR_TRISTATE_SWITCH_ABSENT;
15144 15145 15146
            }
            ctxt->node = node;
            break;
15147 15148

        case VIR_DOMAIN_FEATURE_PMU:
15149
        case VIR_DOMAIN_FEATURE_PVSPINLOCK:
15150
        case VIR_DOMAIN_FEATURE_VMPORT:
15151 15152 15153
            node = ctxt->node;
            ctxt->node = nodes[i];
            if ((tmp = virXPathString("string(./@state)", ctxt))) {
J
Ján Tomko 已提交
15154
                if ((def->features[val] = virTristateSwitchTypeFromString(tmp)) == -1) {
15155
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
Y
Yuri Chornoivan 已提交
15156
                                   _("unknown state attribute '%s' of feature '%s'"),
15157 15158 15159
                                   tmp, virDomainFeatureTypeToString(val));
                    goto error;
                }
15160
                VIR_FREE(tmp);
15161
            } else {
J
Ján Tomko 已提交
15162
                def->features[val] = VIR_TRISTATE_SWITCH_ON;
15163 15164 15165 15166
            }
            ctxt->node = node;
            break;

M
Michal Privoznik 已提交
15167 15168 15169 15170 15171 15172 15173 15174 15175 15176 15177 15178 15179 15180 15181 15182
        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;

15183
        /* coverity[dead_error_begin] */
15184 15185
        case VIR_DOMAIN_FEATURE_LAST:
            break;
15186 15187
        }
    }
15188
    VIR_FREE(nodes);
15189

J
Ján Tomko 已提交
15190
    if (def->features[VIR_DOMAIN_FEATURE_HYPERV] == VIR_TRISTATE_SWITCH_ON) {
15191 15192 15193 15194 15195 15196 15197 15198 15199
        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) {
15200
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
15201 15202 15203 15204 15205 15206 15207
                               _("unsupported HyperV Enlightenment feature: %s"),
                               nodes[i]->name);
                goto error;
            }

            ctxt->node = nodes[i];

15208
            switch ((virDomainHyperv) feature) {
15209
                case VIR_DOMAIN_HYPERV_RELAXED:
15210
                case VIR_DOMAIN_HYPERV_VAPIC:
15211 15212 15213 15214 15215 15216 15217 15218
                    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 已提交
15219
                    if ((value = virTristateSwitchTypeFromString(tmp)) < 0) {
15220
                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
15221 15222 15223 15224 15225 15226
                                       _("invalid value of state argument "
                                         "for HyperV Enlightenment feature '%s'"),
                                       nodes[i]->name);
                        goto error;
                    }

15227
                    VIR_FREE(tmp);
15228 15229 15230
                    def->hyperv_features[feature] = value;
                    break;

15231 15232 15233 15234 15235 15236 15237 15238 15239
                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 已提交
15240
                    if ((value = virTristateSwitchTypeFromString(tmp)) < 0) {
15241
                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
15242 15243 15244 15245 15246 15247 15248
                                       _("invalid value of state argument "
                                         "for HyperV Enlightenment feature '%s'"),
                                       nodes[i]->name);
                        goto error;
                    }

                    VIR_FREE(tmp);
J
Ján Tomko 已提交
15249
                    if (value == VIR_TRISTATE_SWITCH_ON) {
15250 15251 15252 15253 15254 15255
                        if (virXPathUInt("string(./@retries)", ctxt,
                                     &def->hyperv_spinlocks) < 0) {
                            virReportError(VIR_ERR_XML_ERROR, "%s",
                                           _("invalid HyperV spinlock retry count"));
                            goto error;
                        }
15256

15257 15258 15259 15260 15261 15262
                        if (def->hyperv_spinlocks < 0xFFF) {
                            virReportError(VIR_ERR_XML_ERROR, "%s",
                                           _("HyperV spinlock retry count must be "
                                             "at least 4095"));
                            goto error;
                        }
15263 15264 15265 15266
                    }
                    def->hyperv_features[feature] = value;
                    break;

15267
                /* coverity[dead_error_begin] */
15268 15269 15270 15271 15272 15273 15274 15275
                case VIR_DOMAIN_HYPERV_LAST:
                    break;
            }
        }
        VIR_FREE(nodes);
        ctxt->node = node;
    }

15276 15277 15278 15279 15280 15281 15282 15283 15284 15285 15286 15287 15288 15289 15290 15291 15292 15293 15294 15295 15296 15297 15298 15299 15300 15301 15302 15303 15304 15305 15306 15307 15308 15309 15310 15311 15312 15313 15314 15315
    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;

15316
                /* coverity[dead_error_begin] */
15317 15318 15319 15320 15321 15322 15323 15324
                case VIR_DOMAIN_KVM_LAST:
                    break;
            }
        }
        VIR_FREE(nodes);
        ctxt->node = node;
    }

15325 15326 15327 15328 15329 15330 15331 15332 15333 15334 15335 15336 15337 15338 15339 15340
    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 已提交
15341
                if ((def->caps_features[val] = virTristateSwitchTypeFromString(tmp)) == -1) {
15342 15343 15344 15345 15346 15347 15348
                    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 已提交
15349
                def->caps_features[val] = VIR_TRISTATE_SWITCH_ON;
15350 15351 15352 15353 15354 15355
            }
            ctxt->node = node;
        }
    }
    VIR_FREE(nodes);

15356 15357 15358 15359 15360
    if (virDomainEventActionParseXML(ctxt, "on_reboot",
                                     "string(./on_reboot[1])",
                                     &def->onReboot,
                                     VIR_DOMAIN_LIFECYCLE_RESTART,
                                     virDomainLifecycleTypeFromString) < 0)
15361 15362
        goto error;

15363 15364 15365 15366 15367
    if (virDomainEventActionParseXML(ctxt, "on_poweroff",
                                     "string(./on_poweroff[1])",
                                     &def->onPoweroff,
                                     VIR_DOMAIN_LIFECYCLE_DESTROY,
                                     virDomainLifecycleTypeFromString) < 0)
15368 15369
        goto error;

15370 15371 15372 15373 15374
    if (virDomainEventActionParseXML(ctxt, "on_crash",
                                     "string(./on_crash[1])",
                                     &def->onCrash,
                                     VIR_DOMAIN_LIFECYCLE_CRASH_DESTROY,
                                     virDomainLifecycleCrashTypeFromString) < 0)
15375 15376
        goto error;

15377 15378 15379 15380 15381 15382 15383
    if (virDomainEventActionParseXML(ctxt, "on_lockfailure",
                                     "string(./on_lockfailure[1])",
                                     &def->onLockFailure,
                                     VIR_DOMAIN_LOCK_FAILURE_DEFAULT,
                                     virDomainLockFailureTypeFromString) < 0)
        goto error;

15384 15385 15386 15387 15388 15389 15390 15391 15392 15393
    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;

15394 15395
    if ((tmp = virXPathString("string(./clock/@offset)", ctxt)) &&
        (def->clock.offset = virDomainClockOffsetTypeFromString(tmp)) < 0) {
15396
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
15397 15398
                       _("unknown clock offset '%s'"), tmp);
        goto error;
15399
    }
15400 15401
    VIR_FREE(tmp);

15402
    switch (def->clock.offset) {
15403 15404 15405 15406 15407 15408 15409
    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 {
15410 15411
                if (virStrToLong_ll(tmp, NULL, 10,
                                    &def->clock.data.variable.adjustment) < 0) {
15412 15413 15414
                    virReportError(VIR_ERR_XML_ERROR,
                                   _("unknown clock adjustment '%s'"),
                                   tmp);
15415 15416 15417 15418 15419 15420 15421 15422 15423 15424 15425 15426 15427 15428 15429 15430 15431 15432
                    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;

15433 15434
    case VIR_DOMAIN_CLOCK_OFFSET_VARIABLE:
        if (virXPathLongLong("number(./clock/@adjustment)", ctxt,
15435 15436
                             &def->clock.data.variable.adjustment) < 0)
            def->clock.data.variable.adjustment = 0;
15437 15438 15439
        if (virXPathLongLong("number(./clock/@adjustment0)", ctxt,
                             &def->clock.data.variable.adjustment0) < 0)
            def->clock.data.variable.adjustment0 = 0;
15440 15441 15442
        tmp = virXPathString("string(./clock/@basis)", ctxt);
        if (tmp) {
            if ((def->clock.data.variable.basis = virDomainClockBasisTypeFromString(tmp)) < 0) {
15443
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
15444
                               _("unknown clock basis '%s'"), tmp);
15445 15446 15447 15448 15449 15450
                goto error;
            }
            VIR_FREE(tmp);
        } else {
            def->clock.data.variable.basis = VIR_DOMAIN_CLOCK_BASIS_UTC;
        }
15451 15452 15453 15454 15455
        break;

    case VIR_DOMAIN_CLOCK_OFFSET_TIMEZONE:
        def->clock.data.timezone = virXPathString("string(./clock/@timezone)", ctxt);
        if (!def->clock.data.timezone) {
15456 15457
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("missing 'timezone' attribute for clock with offset='timezone'"));
15458 15459
            goto error;
        }
15460 15461
        break;
    }
15462

15463
    if ((n = virXPathNodeSet("./clock/timer", ctxt, &nodes)) < 0)
15464
        goto error;
15465

15466
    if (n && VIR_ALLOC_N(def->clock.timers, n) < 0)
15467
        goto error;
15468

15469
    for (i = 0; i < n; i++) {
15470
        virDomainTimerDefPtr timer = virDomainTimerDefParseXML(nodes[i],
E
Eric Blake 已提交
15471
                                                               ctxt);
15472 15473 15474 15475 15476 15477 15478
        if (!timer)
            goto error;

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

15479

15480 15481 15482 15483 15484 15485 15486 15487 15488
    /*
     * 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)
     */

15489
    if (def->os.type == VIR_DOMAIN_OSTYPE_EXE) {
15490
        def->os.init = virXPathString("string(./os/init[1])", ctxt);
15491
        def->os.cmdline = virXPathString("string(./os/cmdline[1])", ctxt);
15492

15493
        if ((n = virXPathNodeSet("./os/initarg", ctxt, &nodes)) < 0)
15494 15495 15496
            goto error;

        if (VIR_ALLOC_N(def->os.initargv, n+1) < 0)
15497
            goto error;
15498
        for (i = 0; i < n; i++) {
15499 15500
            if (!nodes[i]->children ||
                !nodes[i]->children->content) {
15501 15502
                virReportError(VIR_ERR_XML_ERROR, "%s",
                               _("No data supplied for <initarg> element"));
15503 15504
                goto error;
            }
15505 15506 15507
            if (VIR_STRDUP(def->os.initargv[i],
                           (const char*) nodes[i]->children->content) < 0)
                goto error;
15508 15509 15510
        }
        def->os.initargv[n] = NULL;
        VIR_FREE(nodes);
15511 15512
    }

15513 15514 15515
    if (def->os.type == VIR_DOMAIN_OSTYPE_XEN ||
        def->os.type == VIR_DOMAIN_OSTYPE_HVM ||
        def->os.type == VIR_DOMAIN_OSTYPE_UML) {
15516 15517
        xmlNodePtr loader_node;

15518 15519 15520
        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);
15521
        def->os.dtb = virXPathString("string(./os/dtb[1])", ctxt);
15522
        def->os.root = virXPathString("string(./os/root[1])", ctxt);
15523 15524 15525 15526 15527 15528 15529 15530
        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);
15531
            def->os.loader->templt = virXPathString("string(./os/nvram[1]/@template)", ctxt);
15532
        }
15533
    }
15534

15535
    if (def->os.type == VIR_DOMAIN_OSTYPE_HVM) {
15536 15537 15538
        if (virDomainDefParseBootXML(ctxt, def) < 0)
            goto error;
        if (!(bootHash = virHashCreate(5, NULL)))
15539
            goto error;
15540 15541 15542 15543
    }


    /* analysis of the disk devices */
15544
    if ((n = virXPathNodeSet("./devices/disk", ctxt, &nodes)) < 0)
15545
        goto error;
15546

15547
    if (n && VIR_ALLOC_N(def->disks, n) < 0)
15548
        goto error;
15549

15550
    for (i = 0; i < n; i++) {
15551
        virDomainDiskDefPtr disk = virDomainDiskDefParseXML(xmlopt,
15552
                                                            nodes[i],
L
Lei Li 已提交
15553
                                                            ctxt,
15554
                                                            bootHash,
15555 15556
                                                            def->seclabels,
                                                            def->nseclabels,
15557
                                                            flags);
15558 15559 15560
        if (!disk)
            goto error;

15561
        virDomainDiskInsertPreAlloced(def, disk);
15562 15563 15564
    }
    VIR_FREE(nodes);

15565
    /* analysis of the controller devices */
15566
    if ((n = virXPathNodeSet("./devices/controller", ctxt, &nodes)) < 0)
15567
        goto error;
15568

15569
    if (n && VIR_ALLOC_N(def->controllers, n) < 0)
15570
        goto error;
15571

15572
    for (i = 0; i < n; i++) {
15573
        virDomainControllerDefPtr controller = virDomainControllerDefParseXML(nodes[i],
15574
                                                                              ctxt,
15575 15576 15577 15578
                                                                              flags);
        if (!controller)
            goto error;

15579 15580 15581 15582
        /* 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) {
15583
                    virDomainControllerDefFree(controller);
15584 15585 15586 15587 15588 15589 15590 15591
                    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) {
15592
                    virDomainControllerDefFree(controller);
15593 15594 15595 15596 15597 15598 15599
                    virReportError(VIR_ERR_XML_DETAIL, "%s",
                                   _("Can't add another USB controller: "
                                     "USB is disabled for this domain"));
                    goto error;
                }
                usb_other = true;
            }
15600 15601 15602

            if (controller->info.mastertype == VIR_DOMAIN_CONTROLLER_MASTER_NONE)
                usb_master = true;
15603 15604
        }

15605
        virDomainControllerInsertPreAlloced(def, controller);
15606 15607 15608
    }
    VIR_FREE(nodes);

15609 15610 15611 15612 15613 15614
    if (usb_other && !usb_master) {
        virReportError(VIR_ERR_XML_DETAIL, "%s",
                       _("No master USB controller specified"));
        goto error;
    }

15615 15616
    /* analysis of the resource leases */
    if ((n = virXPathNodeSet("./devices/lease", ctxt, &nodes)) < 0) {
15617 15618
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("cannot extract device leases"));
15619 15620 15621
        goto error;
    }
    if (n && VIR_ALLOC_N(def->leases, n) < 0)
15622
        goto error;
15623
    for (i = 0; i < n; i++) {
15624 15625 15626 15627 15628 15629 15630 15631
        virDomainLeaseDefPtr lease = virDomainLeaseDefParseXML(nodes[i]);
        if (!lease)
            goto error;

        def->leases[def->nleases++] = lease;
    }
    VIR_FREE(nodes);

15632
    /* analysis of the filesystems */
15633
    if ((n = virXPathNodeSet("./devices/filesystem", ctxt, &nodes)) < 0)
15634
        goto error;
15635
    if (n && VIR_ALLOC_N(def->fss, n) < 0)
15636
        goto error;
15637
    for (i = 0; i < n; i++) {
15638
        virDomainFSDefPtr fs = virDomainFSDefParseXML(nodes[i], ctxt,
15639
                                                      flags);
15640 15641 15642
        if (!fs)
            goto error;

15643
        def->fss[def->nfss++] = fs;
15644 15645 15646
    }
    VIR_FREE(nodes);

15647
    /* analysis of the network devices */
15648
    if ((n = virXPathNodeSet("./devices/interface", ctxt, &nodes)) < 0)
15649
        goto error;
15650
    if (n && VIR_ALLOC_N(def->nets, n) < 0)
15651
        goto error;
15652
    for (i = 0; i < n; i++) {
15653
        virDomainNetDefPtr net = virDomainNetDefParseXML(xmlopt,
15654
                                                         nodes[i],
15655
                                                         ctxt,
15656
                                                         bootHash,
15657
                                                         flags);
15658 15659 15660
        if (!net)
            goto error;

15661
        def->nets[def->nnets++] = net;
15662

15663 15664 15665 15666 15667 15668
        /* <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) {
15669
            goto error;
15670
        }
15671 15672 15673 15674
    }
    VIR_FREE(nodes);


E
Eric Blake 已提交
15675
    /* analysis of the smartcard devices */
15676
    if ((n = virXPathNodeSet("./devices/smartcard", ctxt, &nodes)) < 0)
E
Eric Blake 已提交
15677 15678
        goto error;
    if (n && VIR_ALLOC_N(def->smartcards, n) < 0)
15679
        goto error;
E
Eric Blake 已提交
15680

15681
    for (i = 0; i < n; i++) {
E
Eric Blake 已提交
15682 15683 15684 15685 15686 15687 15688 15689 15690 15691
        virDomainSmartcardDefPtr card = virDomainSmartcardDefParseXML(nodes[i],
                                                                      flags);
        if (!card)
            goto error;

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


15692
    /* analysis of the character devices */
15693
    if ((n = virXPathNodeSet("./devices/parallel", ctxt, &nodes)) < 0)
15694
        goto error;
15695
    if (n && VIR_ALLOC_N(def->parallels, n) < 0)
15696
        goto error;
15697

15698
    for (i = 0; i < n; i++) {
15699
        virDomainChrDefPtr chr = virDomainChrDefParseXML(ctxt,
15700
                                                         nodes[i],
15701 15702
                                                         def->seclabels,
                                                         def->nseclabels,
15703
                                                         flags);
15704 15705 15706
        if (!chr)
            goto error;

15707 15708
        if (chr->target.port == -1) {
            int maxport = -1;
15709
            for (j = 0; j < i; j++) {
15710 15711 15712 15713 15714
                if (def->parallels[j]->target.port > maxport)
                    maxport = def->parallels[j]->target.port;
            }
            chr->target.port = maxport + 1;
        }
15715
        def->parallels[def->nparallels++] = chr;
15716 15717 15718
    }
    VIR_FREE(nodes);

15719
    if ((n = virXPathNodeSet("./devices/serial", ctxt, &nodes)) < 0)
15720
        goto error;
15721

15722
    if (n && VIR_ALLOC_N(def->serials, n) < 0)
15723
        goto error;
15724

15725
    for (i = 0; i < n; i++) {
15726
        virDomainChrDefPtr chr = virDomainChrDefParseXML(ctxt,
15727
                                                         nodes[i],
15728 15729
                                                         def->seclabels,
                                                         def->nseclabels,
15730
                                                         flags);
15731 15732 15733
        if (!chr)
            goto error;

15734 15735
        if (chr->target.port == -1) {
            int maxport = -1;
15736
            for (j = 0; j < i; j++) {
15737 15738 15739 15740 15741
                if (def->serials[j]->target.port > maxport)
                    maxport = def->serials[j]->target.port;
            }
            chr->target.port = maxport + 1;
        }
15742
        def->serials[def->nserials++] = chr;
15743 15744 15745
    }
    VIR_FREE(nodes);

15746
    if ((n = virXPathNodeSet("./devices/console", ctxt, &nodes)) < 0) {
15747 15748
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("cannot extract console devices"));
15749 15750 15751
        goto error;
    }
    if (n && VIR_ALLOC_N(def->consoles, n) < 0)
15752
        goto error;
15753

15754
    for (i = 0; i < n; i++) {
15755
        virDomainChrDefPtr chr = virDomainChrDefParseXML(ctxt,
15756
                                                         nodes[i],
15757 15758
                                                         def->seclabels,
                                                         def->nseclabels,
15759
                                                         flags);
15760 15761
        if (!chr)
            goto error;
15762

15763 15764
        chr->target.port = i;
        def->consoles[def->nconsoles++] = chr;
15765
    }
15766
    VIR_FREE(nodes);
15767

15768
    if ((n = virXPathNodeSet("./devices/channel", ctxt, &nodes)) < 0)
15769 15770
        goto error;
    if (n && VIR_ALLOC_N(def->channels, n) < 0)
15771
        goto error;
15772

15773
    for (i = 0; i < n; i++) {
15774
        virDomainChrDefPtr chr = virDomainChrDefParseXML(ctxt,
15775
                                                         nodes[i],
15776 15777
                                                         def->seclabels,
                                                         def->nseclabels,
15778 15779 15780 15781 15782 15783 15784 15785
                                                         flags);
        if (!chr)
            goto error;

        def->channels[def->nchannels++] = chr;
    }
    VIR_FREE(nodes);

15786 15787

    /* analysis of the input devices */
15788
    if ((n = virXPathNodeSet("./devices/input", ctxt, &nodes)) < 0)
15789
        goto error;
15790
    if (n && VIR_ALLOC_N(def->inputs, n) < 0)
15791
        goto error;
15792

15793
    for (i = 0; i < n; i++) {
L
Li Zhang 已提交
15794
        virDomainInputDefPtr input = virDomainInputDefParseXML(def,
15795
                                                               nodes[i],
15796
                                                               ctxt,
15797
                                                               flags);
15798 15799 15800
        if (!input)
            goto error;

15801 15802
        /* Check if USB bus is required */
        if (input->bus == VIR_DOMAIN_INPUT_BUS_USB && usb_none) {
15803
            virDomainInputDefFree(input);
15804 15805 15806 15807 15808
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("Can't add USB input device. "
                             "USB bus is disabled"));
            goto error;
        }
15809 15810 15811 15812

        /* 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 ? */
15813
        if ((def->os.type == VIR_DOMAIN_OSTYPE_HVM &&
15814
             input->bus == VIR_DOMAIN_INPUT_BUS_PS2 &&
L
Li Zhang 已提交
15815 15816
             (input->type == VIR_DOMAIN_INPUT_TYPE_MOUSE ||
              input->type == VIR_DOMAIN_INPUT_TYPE_KBD)) ||
15817
            (def->os.type == VIR_DOMAIN_OSTYPE_XEN &&
15818
             input->bus == VIR_DOMAIN_INPUT_BUS_XEN &&
15819 15820
             (input->type == VIR_DOMAIN_INPUT_TYPE_MOUSE ||
              input->type == VIR_DOMAIN_INPUT_TYPE_KBD)) ||
15821
            (def->os.type == VIR_DOMAIN_OSTYPE_EXE &&
15822 15823
             (def->virtType == VIR_DOMAIN_VIRT_VZ ||
              def->virtType == VIR_DOMAIN_VIRT_PARALLELS)  &&
15824
             input->bus == VIR_DOMAIN_INPUT_BUS_PARALLELS &&
L
Li Zhang 已提交
15825 15826
             (input->type == VIR_DOMAIN_INPUT_TYPE_MOUSE ||
              input->type == VIR_DOMAIN_INPUT_TYPE_KBD))) {
15827 15828 15829 15830
            virDomainInputDefFree(input);
            continue;
        }

15831
        def->inputs[def->ninputs++] = input;
15832 15833 15834
    }
    VIR_FREE(nodes);

15835
    /* analysis of the graphics devices */
15836
    if ((n = virXPathNodeSet("./devices/graphics", ctxt, &nodes)) < 0)
15837
        goto error;
15838
    if (n && VIR_ALLOC_N(def->graphics, n) < 0)
15839
        goto error;
15840
    for (i = 0; i < n; i++) {
15841
        virDomainGraphicsDefPtr graphics = virDomainGraphicsDefParseXML(nodes[i],
15842
                                                                        ctxt,
15843
                                                                        flags);
15844 15845 15846
        if (!graphics)
            goto error;

15847
        def->graphics[def->ngraphics++] = graphics;
15848 15849 15850 15851
    }
    VIR_FREE(nodes);

    /* If graphics are enabled, there's an implicit PS2 mouse */
15852 15853
    if (def->ngraphics > 0 &&
        (ARCH_IS_X86(def->os.arch) || def->os.arch == VIR_ARCH_NONE)) {
15854
        int input_bus = VIR_DOMAIN_INPUT_BUS_XEN;
15855

15856
        if (def->os.type == VIR_DOMAIN_OSTYPE_HVM)
15857
            input_bus = VIR_DOMAIN_INPUT_BUS_PS2;
15858
        if (def->os.type == VIR_DOMAIN_OSTYPE_EXE &&
15859 15860
            (def->virtType == VIR_DOMAIN_VIRT_VZ ||
             def->virtType == VIR_DOMAIN_VIRT_PARALLELS))
15861
            input_bus = VIR_DOMAIN_INPUT_BUS_PARALLELS;
15862

15863 15864 15865
        if (virDomainDefMaybeAddInput(def,
                                      VIR_DOMAIN_INPUT_TYPE_MOUSE,
                                      input_bus) < 0)
15866
            goto error;
15867

L
Li Zhang 已提交
15868 15869 15870 15871 15872
        if (virDomainDefMaybeAddInput(def,
                                      VIR_DOMAIN_INPUT_TYPE_KBD,
                                      input_bus) < 0)
            goto error;
    }
15873 15874

    /* analysis of the sound devices */
15875
    if ((n = virXPathNodeSet("./devices/sound", ctxt, &nodes)) < 0)
15876
        goto error;
15877
    if (n && VIR_ALLOC_N(def->sounds, n) < 0)
15878
        goto error;
15879
    for (i = 0; i < n; i++) {
15880
        virDomainSoundDefPtr sound = virDomainSoundDefParseXML(nodes[i],
15881
                                                               ctxt,
15882
                                                               flags);
15883 15884 15885
        if (!sound)
            goto error;

15886
        def->sounds[def->nsounds++] = sound;
15887 15888 15889
    }
    VIR_FREE(nodes);

15890
    /* analysis of the video devices */
15891
    if ((n = virXPathNodeSet("./devices/video", ctxt, &nodes)) < 0)
15892 15893
        goto error;
    if (n && VIR_ALLOC_N(def->videos, n) < 0)
15894
        goto error;
15895
    for (i = 0; i < n; i++) {
15896
        j = def->nvideos;
15897
        virDomainVideoDefPtr video = virDomainVideoDefParseXML(nodes[j],
15898 15899 15900 15901
                                                               def,
                                                               flags);
        if (!video)
            goto error;
15902 15903 15904

        if (video->primary) {
            if (primaryVideo) {
15905
                virDomainVideoDefFree(video);
15906 15907 15908 15909 15910
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                               _("Only one primary video device is supported"));
                goto error;
            }

15911
            j = 0;
15912 15913
            primaryVideo = true;
        }
15914
        if (VIR_INSERT_ELEMENT_INPLACE(def->videos,
15915
                                       j,
15916 15917
                                       def->nvideos,
                                       video) < 0) {
15918
            virDomainVideoDefFree(video);
15919
            goto error;
15920
        }
15921 15922 15923
    }
    VIR_FREE(nodes);

15924
    /* For backwards compatibility, if no <video> tag is set but there
15925 15926 15927 15928
     * is a <graphics> tag, then we add a single video tag */
    if (def->ngraphics && !def->nvideos) {
        virDomainVideoDefPtr video;
        if (VIR_ALLOC(video) < 0)
15929
            goto error;
15930 15931
        video->type = virDomainVideoDefaultType(def);
        if (video->type < 0) {
15932 15933
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("cannot determine default video type"));
15934 15935 15936 15937 15938 15939 15940
            VIR_FREE(video);
            goto error;
        }
        video->vram = virDomainVideoDefaultRAM(def, video->type);
        video->heads = 1;
        if (VIR_ALLOC_N(def->videos, 1) < 0) {
            virDomainVideoDefFree(video);
15941
            goto error;
15942 15943 15944 15945
        }
        def->videos[def->nvideos++] = video;
    }

15946
    /* analysis of the host devices */
15947
    if ((n = virXPathNodeSet("./devices/hostdev", ctxt, &nodes)) < 0)
15948
        goto error;
15949
    if (n && VIR_REALLOC_N(def->hostdevs, def->nhostdevs + n) < 0)
15950
        goto error;
15951
    for (i = 0; i < n; i++) {
15952 15953
        virDomainHostdevDefPtr hostdev;

15954
        hostdev = virDomainHostdevDefParseXML(nodes[i], ctxt, bootHash, flags);
15955 15956 15957
        if (!hostdev)
            goto error;

15958 15959 15960 15961 15962
        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"));
15963
            virDomainHostdevDefFree(hostdev);
15964 15965 15966
            goto error;
        }

15967
        def->hostdevs[def->nhostdevs++] = hostdev;
15968 15969 15970
    }
    VIR_FREE(nodes);

R
Richard Jones 已提交
15971 15972
    /* analysis of the watchdog devices */
    def->watchdog = NULL;
15973
    if ((n = virXPathNodeSet("./devices/watchdog", ctxt, &nodes)) < 0)
R
Richard Jones 已提交
15974 15975
        goto error;
    if (n > 1) {
15976 15977
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("only a single watchdog device is supported"));
R
Richard Jones 已提交
15978 15979 15980 15981
        goto error;
    }
    if (n > 0) {
        virDomainWatchdogDefPtr watchdog =
15982
            virDomainWatchdogDefParseXML(nodes[0], flags);
R
Richard Jones 已提交
15983 15984 15985 15986 15987 15988 15989
        if (!watchdog)
            goto error;

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

15990 15991
    /* analysis of the memballoon devices */
    def->memballoon = NULL;
15992
    if ((n = virXPathNodeSet("./devices/memballoon", ctxt, &nodes)) < 0)
15993 15994
        goto error;
    if (n > 1) {
15995 15996
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("only a single memory balloon device is supported"));
15997 15998 15999 16000
        goto error;
    }
    if (n > 0) {
        virDomainMemballoonDefPtr memballoon =
16001
            virDomainMemballoonDefParseXML(nodes[0], ctxt, flags);
16002 16003 16004 16005 16006 16007 16008
        if (!memballoon)
            goto error;

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

16009
    /* Parse the RNG devices */
16010 16011
    if ((n = virXPathNodeSet("./devices/rng", ctxt, &nodes)) < 0)
        goto error;
16012
    if (n && VIR_ALLOC_N(def->rngs, n) < 0)
16013
        goto error;
16014 16015 16016 16017 16018
    for (i = 0; i < n; i++) {
        virDomainRNGDefPtr rng = virDomainRNGDefParseXML(nodes[i],
                                                         ctxt,
                                                         flags);
        if (!rng)
16019
            goto error;
16020 16021

        def->rngs[def->nrngs++] = rng;
16022
    }
16023 16024 16025 16026 16027 16028 16029 16030 16031 16032 16033 16034 16035 16036 16037 16038 16039
    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);
16040

16041
    if ((n = virXPathNodeSet("./devices/nvram", ctxt, &nodes)) < 0)
L
Li Zhang 已提交
16042 16043 16044 16045 16046 16047 16048 16049 16050 16051 16052 16053 16054 16055 16056
        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 已提交
16057
    /* analysis of the hub devices */
16058
    if ((n = virXPathNodeSet("./devices/hub", ctxt, &nodes)) < 0)
M
Marc-André Lureau 已提交
16059 16060
        goto error;
    if (n && VIR_ALLOC_N(def->hubs, n) < 0)
16061
        goto error;
16062
    for (i = 0; i < n; i++) {
M
Marc-André Lureau 已提交
16063 16064 16065 16066
        virDomainHubDefPtr hub = virDomainHubDefParseXML(nodes[i], flags);
        if (!hub)
            goto error;

16067
        if (hub->type == VIR_DOMAIN_HUB_TYPE_USB && usb_none) {
16068
            virDomainHubDefFree(hub);
16069 16070 16071 16072 16073 16074
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("Can't add USB hub: "
                             "USB is disabled for this domain"));
            goto error;
        }

M
Marc-André Lureau 已提交
16075 16076 16077 16078
        def->hubs[def->nhubs++] = hub;
    }
    VIR_FREE(nodes);

16079
    /* analysis of the redirected devices */
16080
    if ((n = virXPathNodeSet("./devices/redirdev", ctxt, &nodes)) < 0)
16081 16082
        goto error;
    if (n && VIR_ALLOC_N(def->redirdevs, n) < 0)
16083
        goto error;
16084
    for (i = 0; i < n; i++) {
16085
        virDomainRedirdevDefPtr redirdev = virDomainRedirdevDefParseXML(nodes[i],
16086
                                                                        bootHash,
16087 16088 16089 16090
                                                                        flags);
        if (!redirdev)
            goto error;

16091 16092 16093 16094
        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"));
16095
            virDomainRedirdevDefFree(redirdev);
16096 16097 16098
            goto error;
        }

16099 16100 16101 16102
        def->redirdevs[def->nredirdevs++] = redirdev;
    }
    VIR_FREE(nodes);

16103
    /* analysis of the redirection filter rules */
16104
    if ((n = virXPathNodeSet("./devices/redirfilter", ctxt, &nodes)) < 0)
16105 16106 16107 16108 16109 16110 16111 16112 16113 16114 16115 16116 16117 16118 16119 16120 16121
        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 已提交
16122
    /* analysis of the panic devices */
16123
    if ((n = virXPathNodeSet("./devices/panic", ctxt, &nodes)) < 0)
H
Hu Tao 已提交
16124
        goto error;
D
Dmitry Andreev 已提交
16125
    if (n && VIR_ALLOC_N(def->panics, n) < 0)
H
Hu Tao 已提交
16126
        goto error;
D
Dmitry Andreev 已提交
16127
    for (i = 0; i < n; i++) {
H
Hu Tao 已提交
16128
        virDomainPanicDefPtr panic =
D
Dmitry Andreev 已提交
16129
            virDomainPanicDefParseXML(nodes[i]);
H
Hu Tao 已提交
16130 16131 16132
        if (!panic)
            goto error;

D
Dmitry Andreev 已提交
16133
        def->panics[def->npanics++] = panic;
H
Hu Tao 已提交
16134
    }
D
Dmitry Andreev 已提交
16135
    VIR_FREE(nodes);
H
Hu Tao 已提交
16136

16137
    /* analysis of the shmem devices */
16138
    if ((n = virXPathNodeSet("./devices/shmem", ctxt, &nodes)) < 0)
16139 16140 16141 16142 16143 16144 16145 16146 16147 16148 16149 16150 16151 16152 16153 16154
        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 已提交
16155

16156 16157 16158 16159 16160 16161 16162 16163 16164 16165 16166 16167 16168 16169 16170 16171 16172
    /* 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);

16173 16174 16175 16176 16177 16178 16179 16180 16181 16182 16183 16184 16185 16186 16187 16188 16189 16190 16191 16192 16193 16194 16195 16196 16197 16198 16199 16200 16201 16202 16203 16204
    /* 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;
    }

16205 16206 16207
    if ((node = virXPathNode("./sysinfo[1]", ctxt)) != NULL) {
        xmlNodePtr oldnode = ctxt->node;
        ctxt->node = node;
16208 16209
        def->sysinfo = virSysinfoParseXML(node, ctxt,
                                          def->uuid, uuid_generated);
16210 16211 16212 16213 16214
        ctxt->node = oldnode;

        if (def->sysinfo == NULL)
            goto error;
    }
16215 16216

    if ((tmp = virXPathString("string(./os/smbios/@mode)", ctxt))) {
16217 16218 16219
        int mode;

        if ((mode = virDomainSmbiosModeTypeFromString(tmp)) < 0) {
16220
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
16221
                           _("unknown smbios mode '%s'"), tmp);
16222 16223 16224 16225 16226
            goto error;
        }
        def->os.smbios_mode = mode;
        VIR_FREE(tmp);
    }
16227

16228 16229 16230
    if (virDomainKeyWrapDefParseXML(def, ctxt) < 0)
        goto error;

16231
    /* Extract custom metadata */
16232
    if ((node = virXPathNode("./metadata[1]", ctxt)) != NULL)
16233 16234
        def->metadata = xmlCopyNode(node, 1);

16235 16236 16237
    /* we have to make a copy of all of the callback pointers here since
     * we won't have the virCaps structure available during free
     */
16238
    def->ns = xmlopt->ns;
16239

16240 16241 16242
    if (def->ns.parse &&
        (def->ns.parse)(xml, root, ctxt, &def->namespaceData) < 0)
        goto error;
16243

16244
    /* callback to fill driver specific domain aspects */
16245
    if (virDomainDefPostParse(def, caps, flags, xmlopt) < 0)
16246 16247
        goto error;

16248 16249 16250 16251
    /* Auto-add any implied controllers which aren't present */
    if (virDomainDefAddImplicitControllers(def) < 0)
        goto error;

16252
    virHashFree(bootHash);
16253

16254 16255
    return def;

16256
 error:
16257 16258
    VIR_FREE(tmp);
    VIR_FREE(nodes);
16259
    virHashFree(bootHash);
16260 16261 16262 16263
    virDomainDefFree(def);
    return NULL;
}

16264

16265
static virDomainObjPtr
16266
virDomainObjParseXML(xmlDocPtr xml,
16267
                     xmlXPathContextPtr ctxt,
16268 16269
                     virCapsPtr caps,
                     virDomainXMLOptionPtr xmlopt,
16270
                     unsigned int flags)
16271 16272 16273 16274 16275 16276
{
    char *tmp = NULL;
    long val;
    xmlNodePtr config;
    xmlNodePtr oldnode;
    virDomainObjPtr obj;
16277
    xmlNodePtr *nodes = NULL;
16278 16279
    size_t i;
    int n;
J
Jiri Denemark 已提交
16280 16281
    int state;
    int reason = 0;
16282

16283
    if (!(obj = virDomainObjNew(xmlopt)))
16284 16285
        return NULL;

16286
    if (!(config = virXPathNode("./domain", ctxt))) {
16287 16288
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("no domain config"));
16289 16290 16291 16292 16293
        goto error;
    }

    oldnode = ctxt->node;
    ctxt->node = config;
16294
    obj->def = virDomainDefParseXML(xml, config, ctxt, caps, xmlopt, flags);
16295 16296 16297 16298
    ctxt->node = oldnode;
    if (!obj->def)
        goto error;

16299
    if (!(tmp = virXPathString("string(./@state)", ctxt))) {
16300 16301
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing domain state"));
16302 16303
        goto error;
    }
J
Jiri Denemark 已提交
16304
    if ((state = virDomainStateTypeFromString(tmp)) < 0) {
16305
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
16306
                       _("invalid domain state '%s'"), tmp);
16307 16308 16309 16310 16311
        VIR_FREE(tmp);
        goto error;
    }
    VIR_FREE(tmp);

J
Jiri Denemark 已提交
16312 16313
    if ((tmp = virXPathString("string(./@reason)", ctxt))) {
        if ((reason = virDomainStateReasonFromString(state, tmp)) < 0) {
16314
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
16315
                           _("invalid domain state reason '%s'"), tmp);
J
Jiri Denemark 已提交
16316 16317 16318 16319 16320 16321 16322 16323
            VIR_FREE(tmp);
            goto error;
        }
        VIR_FREE(tmp);
    }

    virDomainObjSetState(obj, state, reason);

E
Eric Blake 已提交
16324
    if (virXPathLong("string(./@pid)", ctxt, &val) < 0) {
16325 16326
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("invalid pid"));
16327 16328 16329 16330
        goto error;
    }
    obj->pid = (pid_t)val;

16331
    if ((n = virXPathNodeSet("./taint", ctxt, &nodes)) < 0)
16332
        goto error;
16333
    for (i = 0; i < n; i++) {
16334 16335 16336 16337
        char *str = virXMLPropString(nodes[i], "flag");
        if (str) {
            int flag = virDomainTaintTypeFromString(str);
            if (flag < 0) {
16338
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
16339
                               _("Unknown taint flag %s"), str);
16340
                VIR_FREE(str);
16341 16342
                goto error;
            }
16343
            VIR_FREE(str);
16344 16345 16346 16347 16348
            virDomainObjTaint(obj, flag);
        }
    }
    VIR_FREE(nodes);

16349
    if (xmlopt->privateData.parse &&
16350
        xmlopt->privateData.parse(ctxt, obj, &xmlopt->config) < 0)
16351
        goto error;
16352

16353 16354
    return obj;

16355
 error:
16356
    virObjectUnref(obj);
16357
    VIR_FREE(nodes);
16358 16359 16360 16361
    return NULL;
}


J
Jiri Denemark 已提交
16362 16363 16364 16365
static virDomainDefPtr
virDomainDefParse(const char *xmlStr,
                  const char *filename,
                  virCapsPtr caps,
16366
                  virDomainXMLOptionPtr xmlopt,
E
Eric Blake 已提交
16367
                  unsigned int flags)
16368
{
J
Jiri Denemark 已提交
16369 16370
    xmlDocPtr xml;
    virDomainDefPtr def = NULL;
16371
    int keepBlanksDefault = xmlKeepBlanksDefault(0);
J
Jiri Denemark 已提交
16372

16373
    if ((xml = virXMLParse(filename, xmlStr, _("(domain_definition)")))) {
16374
        def = virDomainDefParseNode(xml, xmlDocGetRootElement(xml), caps,
16375
                                    xmlopt, flags);
J
Jiri Denemark 已提交
16376
        xmlFreeDoc(xml);
16377
    }
J
Jiri Denemark 已提交
16378

16379
    xmlKeepBlanksDefault(keepBlanksDefault);
J
Jiri Denemark 已提交
16380
    return def;
16381
}
16382

16383
virDomainDefPtr
16384 16385
virDomainDefParseString(const char *xmlStr,
                        virCapsPtr caps,
16386
                        virDomainXMLOptionPtr xmlopt,
16387
                        unsigned int flags)
16388
{
16389
    return virDomainDefParse(xmlStr, NULL, caps, xmlopt, flags);
16390 16391
}

16392
virDomainDefPtr
16393 16394
virDomainDefParseFile(const char *filename,
                      virCapsPtr caps,
16395
                      virDomainXMLOptionPtr xmlopt,
16396
                      unsigned int flags)
16397
{
16398
    return virDomainDefParse(NULL, filename, caps, xmlopt, flags);
16399 16400 16401
}


16402
virDomainDefPtr
16403
virDomainDefParseNode(xmlDocPtr xml,
16404
                      xmlNodePtr root,
16405 16406
                      virCapsPtr caps,
                      virDomainXMLOptionPtr xmlopt,
16407
                      unsigned int flags)
16408 16409 16410 16411 16412
{
    xmlXPathContextPtr ctxt = NULL;
    virDomainDefPtr def = NULL;

    if (!xmlStrEqual(root->name, BAD_CAST "domain")) {
16413 16414 16415 16416
        virReportError(VIR_ERR_XML_ERROR,
                       _("unexpected root element <%s>, "
                         "expecting <domain>"),
                       root->name);
16417 16418 16419 16420 16421
        goto cleanup;
    }

    ctxt = xmlXPathNewContext(xml);
    if (ctxt == NULL) {
16422
        virReportOOMError();
16423 16424 16425 16426
        goto cleanup;
    }

    ctxt->node = root;
16427
    def = virDomainDefParseXML(xml, root, ctxt, caps, xmlopt, flags);
16428

16429
 cleanup:
16430 16431 16432
    xmlXPathFreeContext(ctxt);
    return def;
}
16433 16434


16435
virDomainObjPtr
16436
virDomainObjParseNode(xmlDocPtr xml,
L
Laine Stump 已提交
16437
                      xmlNodePtr root,
16438 16439
                      virCapsPtr caps,
                      virDomainXMLOptionPtr xmlopt,
L
Laine Stump 已提交
16440
                      unsigned int flags)
16441 16442 16443 16444 16445
{
    xmlXPathContextPtr ctxt = NULL;
    virDomainObjPtr obj = NULL;

    if (!xmlStrEqual(root->name, BAD_CAST "domstatus")) {
16446 16447 16448 16449
        virReportError(VIR_ERR_XML_ERROR,
                       _("unexpected root element <%s>, "
                         "expecting <domstatus>"),
                       root->name);
16450 16451 16452
        goto cleanup;
    }

16453
    if (!(ctxt = xmlXPathNewContext(xml))) {
16454
        virReportOOMError();
16455 16456 16457 16458
        goto cleanup;
    }

    ctxt->node = root;
16459
    obj = virDomainObjParseXML(xml, ctxt, caps, xmlopt, flags);
16460

16461
 cleanup:
16462 16463 16464 16465
    xmlXPathFreeContext(ctxt);
    return obj;
}

H
Hu Tao 已提交
16466

16467
virDomainObjPtr
16468 16469
virDomainObjParseFile(const char *filename,
                      virCapsPtr caps,
16470
                      virDomainXMLOptionPtr xmlopt,
16471
                      unsigned int flags)
H
Hu Tao 已提交
16472 16473 16474
{
    xmlDocPtr xml;
    virDomainObjPtr obj = NULL;
16475
    int keepBlanksDefault = xmlKeepBlanksDefault(0);
H
Hu Tao 已提交
16476 16477

    if ((xml = virXMLParseFile(filename))) {
16478
        obj = virDomainObjParseNode(xml, xmlDocGetRootElement(xml),
16479
                                    caps, xmlopt, flags);
H
Hu Tao 已提交
16480 16481 16482
        xmlFreeDoc(xml);
    }

16483
    xmlKeepBlanksDefault(keepBlanksDefault);
H
Hu Tao 已提交
16484 16485 16486 16487
    return obj;
}


16488 16489 16490
static bool
virDomainTimerDefCheckABIStability(virDomainTimerDefPtr src,
                                   virDomainTimerDefPtr dst)
16491 16492
{
    if (src->name != dst->name) {
16493 16494 16495 16496
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target timer %s does not match source %s"),
                       virDomainTimerNameTypeToString(dst->name),
                       virDomainTimerNameTypeToString(src->name));
16497
        return false;
16498 16499 16500
    }

    if (src->present != dst->present) {
16501 16502 16503
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target timer presence %d does not match source %d"),
                       dst->present, src->present);
16504
        return false;
16505 16506 16507 16508
    }

    if (src->name == VIR_DOMAIN_TIMER_NAME_TSC) {
        if (src->frequency != dst->frequency) {
16509 16510 16511
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Target TSC frequency %lu does not match source %lu"),
                           dst->frequency, src->frequency);
16512
            return false;
16513 16514 16515
        }

        if (src->mode != dst->mode) {
16516 16517 16518 16519
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Target TSC mode %s does not match source %s"),
                           virDomainTimerModeTypeToString(dst->mode),
                           virDomainTimerModeTypeToString(src->mode));
16520
            return false;
16521 16522 16523
        }
    }

16524
    return true;
16525 16526 16527
}


16528 16529 16530
static bool
virDomainDeviceInfoCheckABIStability(virDomainDeviceInfoPtr src,
                                     virDomainDeviceInfoPtr dst)
16531 16532
{
    if (src->type != dst->type) {
16533 16534 16535 16536
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target device address type %s does not match source %s"),
                       virDomainDeviceAddressTypeToString(dst->type),
                       virDomainDeviceAddressTypeToString(src->type));
16537
        return false;
16538 16539
    }

16540
    switch ((virDomainDeviceAddressType) src->type) {
16541 16542 16543 16544 16545
    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) {
16546
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
16547 16548
                           _("Target device PCI address %04x:%02x:%02x.%02x "
                             "does not match source %04x:%02x:%02x.%02x"),
16549 16550 16551 16552
                           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);
16553
            return false;
16554 16555 16556 16557 16558 16559 16560
        }
        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) {
16561
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
16562 16563
                           _("Target device drive address %d:%d:%d "
                             "does not match source %d:%d:%d"),
16564 16565 16566 16567
                           dst->addr.drive.controller, dst->addr.drive.bus,
                           dst->addr.drive.unit,
                           src->addr.drive.controller, src->addr.drive.bus,
                           src->addr.drive.unit);
16568
            return false;
16569 16570 16571 16572 16573 16574 16575
        }
        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) {
16576
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
16577 16578
                           _("Target device virtio serial address %d:%d:%d "
                             "does not match source %d:%d:%d"),
16579 16580 16581 16582
                           dst->addr.vioserial.controller, dst->addr.vioserial.bus,
                           dst->addr.vioserial.port,
                           src->addr.vioserial.controller, src->addr.vioserial.bus,
                           src->addr.vioserial.port);
16583
            return false;
16584 16585 16586 16587 16588 16589
        }
        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) {
16590
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
16591 16592
                           _("Target device ccid address %d:%d "
                             "does not match source %d:%d"),
16593 16594 16595 16596
                           dst->addr.ccid.controller,
                           dst->addr.ccid.slot,
                           src->addr.ccid.controller,
                           src->addr.ccid.slot);
16597
            return false;
16598 16599
        }
        break;
H
Hu Tao 已提交
16600 16601 16602 16603 16604 16605 16606 16607 16608 16609 16610 16611 16612 16613

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

16615 16616 16617 16618 16619 16620 16621 16622 16623 16624 16625 16626 16627 16628 16629 16630 16631 16632 16633 16634
    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;

16635 16636 16637 16638 16639 16640 16641 16642
    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;
16643 16644
    }

16645
    return true;
16646 16647 16648
}


16649 16650 16651
static bool
virDomainDiskDefCheckABIStability(virDomainDiskDefPtr src,
                                  virDomainDiskDefPtr dst)
16652 16653
{
    if (src->device != dst->device) {
16654 16655 16656 16657
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target disk device %s does not match source %s"),
                       virDomainDiskDeviceTypeToString(dst->device),
                       virDomainDiskDeviceTypeToString(src->device));
16658
        return false;
16659 16660 16661
    }

    if (src->bus != dst->bus) {
16662 16663 16664 16665
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target disk bus %s does not match source %s"),
                       virDomainDiskBusTypeToString(dst->bus),
                       virDomainDiskBusTypeToString(src->bus));
16666
        return false;
16667 16668 16669
    }

    if (STRNEQ(src->dst, dst->dst)) {
16670 16671 16672
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target disk %s does not match source %s"),
                       dst->dst, src->dst);
16673
        return false;
16674 16675 16676
    }

    if (STRNEQ_NULLABLE(src->serial, dst->serial)) {
16677 16678 16679
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target disk serial %s does not match source %s"),
                       NULLSTR(dst->serial), NULLSTR(src->serial));
16680
        return false;
16681 16682
    }

16683 16684 16685 16686 16687 16688 16689 16690
    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;

    }

16691 16692
    if (src->src->readonly != dst->src->readonly ||
        src->src->shared != dst->src->shared) {
16693 16694
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Target disk access mode does not match source"));
16695
        return false;
16696 16697 16698
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
16699
        return false;
16700

16701
    return true;
16702 16703 16704
}


16705 16706 16707
static bool
virDomainControllerDefCheckABIStability(virDomainControllerDefPtr src,
                                        virDomainControllerDefPtr dst)
16708 16709
{
    if (src->type != dst->type) {
16710 16711 16712 16713
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target controller type %s does not match source %s"),
                       virDomainControllerTypeToString(dst->type),
                       virDomainControllerTypeToString(src->type));
16714
        return false;
16715 16716 16717
    }

    if (src->idx != dst->idx) {
16718 16719 16720
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target controller index %d does not match source %d"),
                       dst->idx, src->idx);
16721
        return false;
16722 16723 16724
    }

    if (src->model != dst->model) {
16725 16726 16727
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target controller model %d does not match source %d"),
                       dst->model, src->model);
16728
        return false;
16729 16730 16731 16732
    }

    if (src->type == VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL) {
        if (src->opts.vioserial.ports != dst->opts.vioserial.ports) {
16733 16734 16735
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Target controller ports %d does not match source %d"),
                           dst->opts.vioserial.ports, src->opts.vioserial.ports);
16736
            return false;
16737 16738 16739
        }

        if (src->opts.vioserial.vectors != dst->opts.vioserial.vectors) {
16740 16741 16742
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Target controller vectors %d does not match source %d"),
                           dst->opts.vioserial.vectors, src->opts.vioserial.vectors);
16743
            return false;
16744 16745 16746 16747
        }
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
16748
        return false;
16749

16750
    return true;
16751 16752 16753
}


16754 16755 16756
static bool
virDomainFsDefCheckABIStability(virDomainFSDefPtr src,
                                virDomainFSDefPtr dst)
16757 16758
{
    if (STRNEQ(src->dst, dst->dst)) {
16759 16760 16761
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target filesystem guest target %s does not match source %s"),
                       dst->dst, src->dst);
16762
        return false;
16763 16764 16765
    }

    if (src->readonly != dst->readonly) {
16766 16767
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Target filesystem access mode does not match source"));
16768
        return false;
16769 16770 16771
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
16772
        return false;
16773

16774
    return true;
16775 16776 16777
}


16778 16779 16780
static bool
virDomainNetDefCheckABIStability(virDomainNetDefPtr src,
                                 virDomainNetDefPtr dst)
16781
{
16782 16783 16784
    char srcmac[VIR_MAC_STRING_BUFLEN];
    char dstmac[VIR_MAC_STRING_BUFLEN];

16785
    if (virMacAddrCmp(&src->mac, &dst->mac) != 0) {
16786
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
16787 16788 16789 16790
                       _("Target network card mac %s"
                         " does not match source %s"),
                       virMacAddrFormat(&dst->mac, dstmac),
                       virMacAddrFormat(&src->mac, srcmac));
16791
        return false;
16792 16793 16794
    }

    if (STRNEQ_NULLABLE(src->model, dst->model)) {
16795 16796 16797
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target network card model %s does not match source %s"),
                       NULLSTR(dst->model), NULLSTR(src->model));
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
virDomainInputDefCheckABIStability(virDomainInputDefPtr src,
                                   virDomainInputDefPtr dst)
16811 16812
{
    if (src->type != dst->type) {
16813 16814 16815 16816
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target input device type %s does not match source %s"),
                       virDomainInputTypeToString(dst->type),
                       virDomainInputTypeToString(src->type));
16817
        return false;
16818 16819 16820
    }

    if (src->bus != dst->bus) {
16821 16822 16823 16824
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target input device bus %s does not match source %s"),
                       virDomainInputBusTypeToString(dst->bus),
                       virDomainInputBusTypeToString(src->bus));
16825
        return false;
16826 16827 16828
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
16829
        return false;
16830

16831
    return true;
16832 16833 16834
}


16835 16836 16837
static bool
virDomainSoundDefCheckABIStability(virDomainSoundDefPtr src,
                                   virDomainSoundDefPtr dst)
16838 16839
{
    if (src->model != dst->model) {
16840 16841 16842 16843
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target sound card model %s does not match source %s"),
                       virDomainSoundModelTypeToString(dst->model),
                       virDomainSoundModelTypeToString(src->model));
16844
        return false;
16845 16846 16847
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
16848
        return false;
16849

16850
    return true;
16851 16852 16853
}


16854 16855 16856
static bool
virDomainVideoDefCheckABIStability(virDomainVideoDefPtr src,
                                   virDomainVideoDefPtr dst)
16857 16858
{
    if (src->type != dst->type) {
16859 16860 16861 16862
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target video card model %s does not match source %s"),
                       virDomainVideoTypeToString(dst->type),
                       virDomainVideoTypeToString(src->type));
16863
        return false;
16864 16865
    }

16866 16867 16868 16869 16870 16871 16872
    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;
    }

16873
    if (src->vram != dst->vram) {
16874 16875 16876
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target video card vram %u does not match source %u"),
                       dst->vram, src->vram);
16877
        return false;
16878 16879
    }

16880 16881 16882 16883 16884 16885 16886
    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;
    }

16887
    if (src->heads != dst->heads) {
16888 16889 16890
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target video card heads %u does not match source %u"),
                       dst->heads, src->heads);
16891
        return false;
16892 16893 16894 16895
    }

    if ((src->accel && !dst->accel) ||
        (!src->accel && dst->accel)) {
16896 16897
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Target video card acceleration does not match source"));
16898
        return false;
16899 16900 16901
    }

    if (src->accel) {
16902
        if (src->accel->accel2d != dst->accel->accel2d) {
16903 16904
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Target video card 2d accel %u does not match source %u"),
16905
                           dst->accel->accel2d, src->accel->accel2d);
16906
            return false;
16907 16908
        }

16909
        if (src->accel->accel3d != dst->accel->accel3d) {
16910 16911
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Target video card 3d accel %u does not match source %u"),
16912
                           dst->accel->accel3d, src->accel->accel3d);
16913
            return false;
16914 16915 16916 16917
        }
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
16918
        return false;
16919

16920
    return true;
16921 16922 16923
}


16924 16925 16926
static bool
virDomainHostdevDefCheckABIStability(virDomainHostdevDefPtr src,
                                     virDomainHostdevDefPtr dst)
16927 16928
{
    if (src->mode != dst->mode) {
16929 16930 16931 16932
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target host device mode %s does not match source %s"),
                       virDomainHostdevModeTypeToString(dst->mode),
                       virDomainHostdevModeTypeToString(src->mode));
16933
        return false;
16934 16935
    }

16936 16937 16938 16939 16940 16941 16942
    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;
16943 16944
    }

16945
    if (!virDomainDeviceInfoCheckABIStability(src->info, dst->info))
16946
        return false;
16947

16948
    return true;
16949 16950 16951
}


16952 16953 16954
static bool
virDomainSmartcardDefCheckABIStability(virDomainSmartcardDefPtr src,
                                       virDomainSmartcardDefPtr dst)
16955 16956
{
    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
16957
        return false;
16958

16959
    return true;
16960 16961 16962
}


16963 16964 16965
static bool
virDomainSerialDefCheckABIStability(virDomainChrDefPtr src,
                                    virDomainChrDefPtr dst)
16966
{
16967 16968 16969 16970 16971 16972 16973 16974
    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;
    }

16975
    if (src->target.port != dst->target.port) {
16976 16977 16978
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target serial port %d does not match source %d"),
                       dst->target.port, src->target.port);
16979
        return false;
16980 16981 16982
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
16983
        return false;
16984

16985
    return true;
16986 16987 16988
}


16989 16990 16991
static bool
virDomainParallelDefCheckABIStability(virDomainChrDefPtr src,
                                      virDomainChrDefPtr dst)
16992 16993
{
    if (src->target.port != dst->target.port) {
16994
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
16995
                       _("Target parallel port %d does not match source %d"),
16996
                       dst->target.port, src->target.port);
16997
        return false;
16998 16999 17000
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
17001
        return false;
17002

17003
    return true;
17004 17005 17006
}


17007 17008 17009
static bool
virDomainChannelDefCheckABIStability(virDomainChrDefPtr src,
                                     virDomainChrDefPtr dst)
17010 17011
{
    if (src->targetType != dst->targetType) {
17012 17013 17014 17015
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target channel type %s does not match source %s"),
                       virDomainChrChannelTargetTypeToString(dst->targetType),
                       virDomainChrChannelTargetTypeToString(src->targetType));
17016
        return false;
17017 17018 17019 17020
    }

    switch (src->targetType) {
    case VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO:
17021
        if (STRNEQ_NULLABLE(src->target.name, dst->target.name)) {
17022 17023 17024
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Target channel name %s does not match source %s"),
                           NULLSTR(dst->target.name), NULLSTR(src->target.name));
17025
            return false;
17026
        }
17027 17028 17029 17030 17031 17032 17033
        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"));
17034
            return false;
17035
        }
17036 17037
        break;
    case VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_GUESTFWD:
E
Eric Blake 已提交
17038 17039
        if (memcmp(src->target.addr, dst->target.addr,
                   sizeof(*src->target.addr)) != 0) {
17040 17041
            char *saddr = virSocketAddrFormatFull(src->target.addr, true, ":");
            char *daddr = virSocketAddrFormatFull(dst->target.addr, true, ":");
17042 17043 17044
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Target channel addr %s does not match source %s"),
                           NULLSTR(daddr), NULLSTR(saddr));
17045 17046
            VIR_FREE(saddr);
            VIR_FREE(daddr);
17047
            return false;
17048 17049 17050 17051 17052
        }
        break;
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
17053
        return false;
17054

17055
    return true;
17056 17057 17058
}


17059 17060 17061
static bool
virDomainConsoleDefCheckABIStability(virDomainChrDefPtr src,
                                     virDomainChrDefPtr dst)
17062 17063
{
    if (src->targetType != dst->targetType) {
17064 17065 17066 17067
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target console type %s does not match source %s"),
                       virDomainChrConsoleTargetTypeToString(dst->targetType),
                       virDomainChrConsoleTargetTypeToString(src->targetType));
17068
        return false;
17069 17070 17071
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
17072
        return false;
17073

17074
    return true;
17075 17076 17077
}


17078 17079 17080
static bool
virDomainWatchdogDefCheckABIStability(virDomainWatchdogDefPtr src,
                                      virDomainWatchdogDefPtr dst)
17081 17082
{
    if (src->model != dst->model) {
17083 17084 17085 17086
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target watchdog model %s does not match source %s"),
                       virDomainWatchdogModelTypeToString(dst->model),
                       virDomainWatchdogModelTypeToString(src->model));
17087
        return false;
17088 17089 17090
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
17091
        return false;
17092

17093
    return true;
17094 17095 17096
}


17097 17098 17099
static bool
virDomainMemballoonDefCheckABIStability(virDomainMemballoonDefPtr src,
                                        virDomainMemballoonDefPtr dst)
17100 17101
{
    if (src->model != dst->model) {
17102 17103 17104 17105
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target balloon model %s does not match source %s"),
                       virDomainMemballoonModelTypeToString(dst->model),
                       virDomainMemballoonModelTypeToString(src->model));
17106
        return false;
17107 17108 17109
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
17110
        return false;
17111

17112
    return true;
17113 17114 17115
}


17116 17117 17118 17119 17120 17121 17122 17123 17124 17125 17126 17127 17128 17129 17130 17131 17132 17133 17134
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;
}


17135 17136 17137
static bool
virDomainHubDefCheckABIStability(virDomainHubDefPtr src,
                                 virDomainHubDefPtr dst)
M
Marc-André Lureau 已提交
17138 17139
{
    if (src->type != dst->type) {
17140 17141 17142 17143
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target hub device type %s does not match source %s"),
                       virDomainHubTypeToString(dst->type),
                       virDomainHubTypeToString(src->type));
17144
        return false;
M
Marc-André Lureau 已提交
17145 17146 17147
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
17148
        return false;
M
Marc-André Lureau 已提交
17149

17150
    return true;
M
Marc-André Lureau 已提交
17151 17152
}

17153 17154 17155 17156 17157 17158 17159 17160 17161 17162 17163 17164 17165 17166

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

17167
    switch ((virDomainRedirdevBus) src->bus) {
17168 17169 17170 17171 17172 17173 17174 17175 17176 17177 17178 17179 17180 17181 17182 17183 17184 17185 17186 17187 17188
    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;
}


17189 17190 17191 17192
static bool
virDomainRedirFilterDefCheckABIStability(virDomainRedirFilterDefPtr src,
                                         virDomainRedirFilterDefPtr dst)
{
17193
    size_t i;
17194 17195 17196 17197 17198 17199

    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);
17200
        return false;
17201 17202 17203
    }

    for (i = 0; i < src->nusbdevs; i++) {
17204 17205 17206
        virDomainRedirFilterUSBDevDefPtr srcUSBDev = src->usbdevs[i];
        virDomainRedirFilterUSBDevDefPtr dstUSBDev = dst->usbdevs[i];
        if (srcUSBDev->usbClass != dstUSBDev->usbClass) {
17207 17208
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           "%s", _("Target USB Class code does not match source"));
17209
            return false;
17210 17211
        }

17212
        if (srcUSBDev->vendor != dstUSBDev->vendor) {
17213 17214
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           "%s", _("Target USB vendor ID does not match source"));
17215
            return false;
17216 17217
        }

17218
        if (srcUSBDev->product != dstUSBDev->product) {
17219 17220
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           "%s", _("Target USB product ID does not match source"));
17221
            return false;
17222 17223
        }

17224
        if (srcUSBDev->version != dstUSBDev->version) {
17225 17226
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           "%s", _("Target USB version does not match source"));
17227
            return false;
17228 17229
        }

17230
        if (srcUSBDev->allow != dstUSBDev->allow) {
17231 17232
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Target USB allow '%s' does not match source '%s'"),
17233 17234
                             dstUSBDev->allow ? "yes" : "no",
                             srcUSBDev->allow ? "yes" : "no");
17235
            return false;
17236 17237 17238
        }
    }

17239
    return true;
17240
}
M
Marc-André Lureau 已提交
17241

17242 17243 17244 17245 17246 17247 17248

static bool
virDomainDefFeaturesCheckABIStability(virDomainDefPtr src,
                                      virDomainDefPtr dst)
{
    size_t i;

17249 17250 17251 17252 17253 17254
    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 已提交
17255 17256
                           virTristateSwitchTypeToString(src->features[i]),
                           virTristateSwitchTypeToString(dst->features[i]));
17257 17258
            return false;
        }
17259 17260 17261 17262 17263 17264 17265
    }

    /* 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 已提交
17266 17267
                       virTristateSwitchTypeToString(src->apic_eoi),
                       virTristateSwitchTypeToString(dst->apic_eoi));
17268 17269 17270
        return false;
    }

M
Michal Privoznik 已提交
17271 17272 17273 17274 17275 17276 17277 17278
    /* 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;
    }

17279
    /* hyperv */
J
Ján Tomko 已提交
17280
    if (src->features[VIR_DOMAIN_FEATURE_HYPERV] == VIR_TRISTATE_SWITCH_ON) {
17281
        for (i = 0; i < VIR_DOMAIN_HYPERV_LAST; i++) {
17282
            switch ((virDomainHyperv) i) {
17283 17284 17285 17286 17287 17288 17289 17290
            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 已提交
17291 17292
                                   virTristateSwitchTypeToString(src->hyperv_features[i]),
                                   virTristateSwitchTypeToString(dst->hyperv_features[i]));
17293 17294 17295 17296 17297 17298 17299 17300 17301 17302 17303 17304 17305 17306 17307 17308 17309
                    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;

17310
            /* coverity[dead_error_begin] */
17311 17312 17313 17314 17315 17316
            case VIR_DOMAIN_HYPERV_LAST:
                break;
            }
        }
    }

17317 17318 17319 17320 17321 17322 17323 17324 17325 17326 17327 17328 17329 17330 17331 17332 17333
    /* 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;

17334
            /* coverity[dead_error_begin] */
17335 17336 17337 17338 17339 17340
            case VIR_DOMAIN_KVM_LAST:
                break;
            }
        }
    }

17341 17342 17343
    return true;
}

H
Hu Tao 已提交
17344
static bool
17345 17346
virDomainPanicDefCheckABIStability(virDomainPanicDefPtr src,
                                   virDomainPanicDefPtr dst)
H
Hu Tao 已提交
17347
{
17348 17349 17350 17351 17352 17353 17354 17355
    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 已提交
17356 17357 17358
    return virDomainDeviceInfoCheckABIStability(&src->info, &dst->info);
}

17359

17360 17361 17362 17363 17364 17365 17366 17367 17368 17369 17370 17371 17372 17373 17374 17375 17376 17377 17378 17379 17380 17381 17382 17383 17384 17385 17386 17387 17388 17389 17390 17391 17392 17393 17394 17395 17396 17397
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);
}


17398 17399 17400 17401 17402 17403 17404 17405 17406 17407 17408 17409 17410 17411 17412 17413 17414 17415 17416
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);
}

17417 17418 17419 17420 17421 17422 17423 17424 17425 17426 17427 17428 17429 17430 17431
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,
17432 17433
                       _("Target memory device targetNode '%d' "
                         "doesn't match source targetNode '%d'"),
17434 17435 17436 17437 17438 17439 17440 17441 17442 17443 17444 17445 17446 17447 17448 17449
                       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);
}


17450 17451 17452 17453
/* 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
 */
17454 17455 17456
bool
virDomainDefCheckABIStability(virDomainDefPtr src,
                              virDomainDefPtr dst)
17457
{
17458
    size_t i;
17459 17460 17461
    virErrorPtr err;
    char *strSrc;
    char *strDst;
17462 17463

    if (src->virtType != dst->virtType) {
17464 17465 17466 17467
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target domain virt type %s does not match source %s"),
                       virDomainVirtTypeToString(dst->virtType),
                       virDomainVirtTypeToString(src->virtType));
17468
        goto error;
17469 17470 17471 17472 17473 17474 17475
    }

    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);
17476 17477 17478
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target domain uuid %s does not match source %s"),
                       uuiddst, uuidsrc);
17479
        goto error;
17480 17481
    }

17482 17483 17484 17485
    /* 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
     */
17486
    if (STRNEQ_NULLABLE(src->name, dst->name)) {
17487 17488 17489
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target domain name '%s' does not match source '%s'"),
                       dst->name, src->name);
17490
        goto error;
17491 17492
    }

17493
    if (virDomainDefGetMemoryInitial(src) != virDomainDefGetMemoryInitial(dst)) {
17494 17495
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target domain max memory %lld does not match source %lld"),
17496 17497
                       virDomainDefGetMemoryInitial(dst),
                       virDomainDefGetMemoryInitial(src));
17498
        goto error;
17499 17500
    }
    if (src->mem.cur_balloon != dst->mem.cur_balloon) {
17501 17502 17503
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target domain current memory %lld does not match source %lld"),
                       dst->mem.cur_balloon, src->mem.cur_balloon);
17504
        goto error;
17505 17506
    }

17507 17508 17509
    if (!virDomainNumaCheckABIStability(src->numa, dst->numa))
        goto error;

17510 17511
    if (src->mem.memory_slots != dst->mem.memory_slots) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
17512
                       _("Target domain memory slots count '%u' doesn't match source '%u'"),
17513 17514 17515 17516 17517 17518 17519 17520 17521 17522
                       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;
    }

17523
    if (src->vcpus != dst->vcpus) {
17524
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
17525
                       _("Target domain vCPU count %d does not match source %d"),
17526
                       dst->vcpus, src->vcpus);
17527
        goto error;
17528 17529
    }
    if (src->maxvcpus != dst->maxvcpus) {
17530
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
17531
                       _("Target domain vCPU max %d does not match source %d"),
17532
                       dst->maxvcpus, src->maxvcpus);
17533
        goto error;
17534 17535
    }

17536 17537 17538 17539 17540 17541 17542 17543
    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;
    }

17544
    if (src->os.type != dst->os.type) {
17545 17546
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target domain OS type %s does not match source %s"),
17547 17548
                       virDomainOSTypeToString(dst->os.type),
                       virDomainOSTypeToString(src->os.type));
17549
        goto error;
17550
    }
17551
    if (src->os.arch != dst->os.arch) {
17552 17553
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target domain architecture %s does not match source %s"),
17554 17555
                       virArchToString(dst->os.arch),
                       virArchToString(src->os.arch));
17556
        goto error;
17557
    }
17558
    if (STRNEQ_NULLABLE(src->os.machine, dst->os.machine)) {
17559
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
17560 17561
                    _("Target domain machine type %s does not match source %s"),
                    dst->os.machine, src->os.machine);
17562
        goto error;
17563 17564 17565
    }

    if (src->os.smbios_mode != dst->os.smbios_mode) {
17566 17567 17568 17569
        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));
17570
        goto error;
17571 17572
    }

17573
    if (!virDomainDefFeaturesCheckABIStability(src, dst))
17574
        goto error;
17575 17576

    if (src->clock.ntimers != dst->clock.ntimers) {
17577 17578
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Target domain timers do not match source"));
17579
        goto error;
17580 17581
    }

17582
    for (i = 0; i < src->clock.ntimers; i++) {
17583 17584
        if (!virDomainTimerDefCheckABIStability(src->clock.timers[i],
                                                dst->clock.timers[i]))
17585
            goto error;
17586 17587 17588
    }

    if (!virCPUDefIsEqual(src->cpu, dst->cpu))
17589
        goto error;
17590 17591

    if (!virSysinfoIsEqual(src->sysinfo, dst->sysinfo))
17592
        goto error;
17593 17594

    if (src->ndisks != dst->ndisks) {
17595
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
17596
                       _("Target domain disk count %zu does not match source %zu"),
17597
                       dst->ndisks, src->ndisks);
17598
        goto error;
17599 17600
    }

17601
    for (i = 0; i < src->ndisks; i++)
17602
        if (!virDomainDiskDefCheckABIStability(src->disks[i], dst->disks[i]))
17603
            goto error;
17604 17605

    if (src->ncontrollers != dst->ncontrollers) {
17606
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
17607
                       _("Target domain controller count %zu "
17608
                         "does not match source %zu"),
17609
                       dst->ncontrollers, src->ncontrollers);
17610
        goto error;
17611 17612
    }

17613
    for (i = 0; i < src->ncontrollers; i++)
17614 17615
        if (!virDomainControllerDefCheckABIStability(src->controllers[i],
                                                     dst->controllers[i]))
17616
            goto error;
17617 17618

    if (src->nfss != dst->nfss) {
17619
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
17620 17621
                       _("Target domain filesystem count %zu "
                         "does not match source %zu"),
17622
                       dst->nfss, src->nfss);
17623
        goto error;
17624 17625
    }

17626
    for (i = 0; i < src->nfss; i++)
17627
        if (!virDomainFsDefCheckABIStability(src->fss[i], dst->fss[i]))
17628
            goto error;
17629 17630

    if (src->nnets != dst->nnets) {
17631
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
17632 17633
                       _("Target domain net card count %zu "
                         "does not match source %zu"),
17634
                       dst->nnets, src->nnets);
17635
        goto error;
17636 17637
    }

17638
    for (i = 0; i < src->nnets; i++)
17639
        if (!virDomainNetDefCheckABIStability(src->nets[i], dst->nets[i]))
17640
            goto error;
17641 17642

    if (src->ninputs != dst->ninputs) {
17643
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
17644 17645
                       _("Target domain input device count %zu "
                         "does not match source %zu"),
17646
                       dst->ninputs, src->ninputs);
17647
        goto error;
17648 17649
    }

17650
    for (i = 0; i < src->ninputs; i++)
17651
        if (!virDomainInputDefCheckABIStability(src->inputs[i], dst->inputs[i]))
17652
            goto error;
17653 17654

    if (src->nsounds != dst->nsounds) {
17655
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
17656 17657
                       _("Target domain sound card count %zu "
                         "does not match source %zu"),
17658
                       dst->nsounds, src->nsounds);
17659
        goto error;
17660 17661
    }

17662
    for (i = 0; i < src->nsounds; i++)
17663
        if (!virDomainSoundDefCheckABIStability(src->sounds[i], dst->sounds[i]))
17664
            goto error;
17665 17666

    if (src->nvideos != dst->nvideos) {
17667
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
17668 17669
                       _("Target domain video card count %zu "
                         "does not match source %zu"),
17670
                       dst->nvideos, src->nvideos);
17671
        goto error;
17672 17673
    }

17674
    for (i = 0; i < src->nvideos; i++)
17675
        if (!virDomainVideoDefCheckABIStability(src->videos[i], dst->videos[i]))
17676
            goto error;
17677 17678

    if (src->nhostdevs != dst->nhostdevs) {
17679
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
17680 17681
                       _("Target domain host device count %zu "
                         "does not match source %zu"),
17682
                       dst->nhostdevs, src->nhostdevs);
17683
        goto error;
17684 17685
    }

17686
    for (i = 0; i < src->nhostdevs; i++)
17687 17688
        if (!virDomainHostdevDefCheckABIStability(src->hostdevs[i],
                                                  dst->hostdevs[i]))
17689
            goto error;
17690 17691

    if (src->nsmartcards != dst->nsmartcards) {
17692
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
17693 17694
                       _("Target domain smartcard count %zu "
                         "does not match source %zu"),
17695
                       dst->nsmartcards, src->nsmartcards);
17696
        goto error;
17697 17698
    }

17699
    for (i = 0; i < src->nsmartcards; i++)
17700 17701
        if (!virDomainSmartcardDefCheckABIStability(src->smartcards[i],
                                                    dst->smartcards[i]))
17702
            goto error;
17703 17704

    if (src->nserials != dst->nserials) {
17705
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
17706 17707
                       _("Target domain serial port count %zu "
                         "does not match source %zu"),
17708
                       dst->nserials, src->nserials);
17709
        goto error;
17710 17711
    }

17712
    for (i = 0; i < src->nserials; i++)
17713 17714
        if (!virDomainSerialDefCheckABIStability(src->serials[i],
                                                 dst->serials[i]))
17715
            goto error;
17716 17717

    if (src->nparallels != dst->nparallels) {
17718
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
17719 17720
                       _("Target domain parallel port count %zu "
                         "does not match source %zu"),
17721
                       dst->nparallels, src->nparallels);
17722
        goto error;
17723 17724
    }

17725
    for (i = 0; i < src->nparallels; i++)
17726 17727
        if (!virDomainParallelDefCheckABIStability(src->parallels[i],
                                                   dst->parallels[i]))
17728
            goto error;
17729 17730

    if (src->nchannels != dst->nchannels) {
17731
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
17732 17733
                       _("Target domain channel count %zu "
                         "does not match source %zu"),
17734
                       dst->nchannels, src->nchannels);
17735
        goto error;
17736 17737
    }

17738
    for (i = 0; i < src->nchannels; i++)
17739 17740
        if (!virDomainChannelDefCheckABIStability(src->channels[i],
                                                  dst->channels[i]))
17741
            goto error;
17742

17743
    if (src->nconsoles != dst->nconsoles) {
17744
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
17745 17746
                       _("Target domain console count %zu "
                         "does not match source %zu"),
17747
                       dst->nconsoles, src->nconsoles);
17748
        goto error;
17749 17750
    }

17751
    for (i = 0; i < src->nconsoles; i++)
17752 17753
        if (!virDomainConsoleDefCheckABIStability(src->consoles[i],
                                                  dst->consoles[i]))
17754
            goto error;
17755

M
Marc-André Lureau 已提交
17756
    if (src->nhubs != dst->nhubs) {
17757
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
17758 17759
                       _("Target domain hub device count %zu "
                         "does not match source %zu"),
17760
                       dst->nhubs, src->nhubs);
17761
        goto error;
M
Marc-André Lureau 已提交
17762 17763
    }

17764
    for (i = 0; i < src->nhubs; i++)
M
Marc-André Lureau 已提交
17765
        if (!virDomainHubDefCheckABIStability(src->hubs[i], dst->hubs[i]))
17766
            goto error;
M
Marc-André Lureau 已提交
17767

17768 17769 17770 17771
    if (src->nredirdevs != dst->nredirdevs) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target domain redirected devices count %zu "
                         "does not match source %zu"),
17772
                       dst->nredirdevs, src->nredirdevs);
17773 17774 17775 17776 17777 17778 17779 17780 17781
        goto error;
    }

    for (i = 0; i < src->nredirdevs; i++) {
        if (!virDomainRedirdevDefCheckABIStability(src->redirdevs[i],
                                                   dst->redirdevs[i]))
            goto error;
    }

17782 17783 17784
    if ((!src->redirfilter && dst->redirfilter) ||
        (src->redirfilter && !dst->redirfilter)) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
17785 17786
                       _("Target domain USB redirection filter count %d "
                         "does not match source %d"),
17787
                       dst->redirfilter ? 1 : 0, src->redirfilter ? 1 : 0);
17788
        goto error;
17789 17790 17791
    }

    if (src->redirfilter &&
17792 17793
        !virDomainRedirFilterDefCheckABIStability(src->redirfilter,
                                                  dst->redirfilter))
17794
        goto error;
17795 17796 17797

    if ((!src->watchdog && dst->watchdog) ||
        (src->watchdog && !dst->watchdog)) {
17798
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
17799 17800
                       _("Target domain watchdog count %d "
                         "does not match source %d"),
17801
                       dst->watchdog ? 1 : 0, src->watchdog ? 1 : 0);
17802
        goto error;
17803 17804 17805 17806
    }

    if (src->watchdog &&
        !virDomainWatchdogDefCheckABIStability(src->watchdog, dst->watchdog))
17807
        goto error;
17808 17809 17810

    if ((!src->memballoon && dst->memballoon) ||
        (src->memballoon && !dst->memballoon)) {
17811
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
17812 17813
                       _("Target domain memory balloon count %d "
                         "does not match source %d"),
17814
                       dst->memballoon ? 1 : 0, src->memballoon ? 1 : 0);
17815
        goto error;
17816 17817 17818
    }

    if (src->memballoon &&
17819 17820
        !virDomainMemballoonDefCheckABIStability(src->memballoon,
                                                 dst->memballoon))
17821
        goto error;
17822

17823 17824 17825 17826
    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);
17827
        goto error;
17828 17829 17830 17831 17832
    }

    for (i = 0; i < src->nrngs; i++)
        if (!virDomainRNGDefCheckABIStability(src->rngs[i], dst->rngs[i]))
            goto error;
17833

D
Dmitry Andreev 已提交
17834 17835 17836 17837
    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);
17838
        goto error;
D
Dmitry Andreev 已提交
17839 17840 17841 17842 17843 17844
    }

    for (i = 0; i < src->npanics; i++) {
        if (!virDomainPanicDefCheckABIStability(src->panics[i], dst->panics[i]))
            goto error;
    }
H
Hu Tao 已提交
17845

17846 17847 17848 17849 17850 17851 17852 17853 17854 17855 17856 17857
    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;
    }

17858 17859 17860 17861 17862 17863 17864 17865 17866 17867
    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;
    }

17868 17869 17870 17871 17872 17873 17874 17875 17876 17877 17878 17879
    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;
    }

17880 17881 17882 17883 17884 17885 17886 17887 17888 17889 17890 17891 17892 17893 17894 17895 17896 17897 17898 17899 17900 17901 17902 17903 17904 17905 17906 17907
    /* 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:
17908
    case VIR_DOMAIN_DEVICE_TPM:
17909
    case VIR_DOMAIN_DEVICE_PANIC:
17910
    case VIR_DOMAIN_DEVICE_SHMEM:
17911
    case VIR_DOMAIN_DEVICE_MEMORY:
17912 17913 17914 17915
        break;
    }
#endif

17916
    return true;
17917

17918
 error:
17919 17920 17921 17922 17923 17924 17925 17926 17927 17928 17929 17930 17931 17932
    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;
17933 17934 17935
}


17936 17937 17938 17939
static int
virDomainDefAddDiskControllersForType(virDomainDefPtr def,
                                      int controllerType,
                                      int diskBus)
17940
{
17941
    size_t i;
17942 17943
    int maxController = -1;

17944
    for (i = 0; i < def->ndisks; i++) {
17945 17946 17947 17948 17949 17950 17951 17952 17953 17954
        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;
    }

17955 17956 17957
    if (maxController == -1)
        return 0;

17958
    for (i = 0; i <= maxController; i++) {
17959
        if (virDomainDefMaybeAddController(def, controllerType, i, -1) < 0)
17960 17961 17962 17963 17964 17965 17966
            return -1;
    }

    return 0;
}


17967 17968
static int
virDomainDefMaybeAddVirtioSerialController(virDomainDefPtr def)
17969
{
C
Cole Robinson 已提交
17970
    /* Look for any virtio serial or virtio console devs */
17971
    size_t i;
17972

17973
    for (i = 0; i < def->nchannels; i++) {
17974 17975
        virDomainChrDefPtr channel = def->channels[i];

17976
        if (channel->targetType == VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO) {
17977 17978 17979 17980
            int idx = 0;
            if (channel->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL)
                idx = channel->info.addr.vioserial.controller;

17981
            if (virDomainDefMaybeAddController(def,
17982
                VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL, idx, -1) < 0)
17983 17984 17985 17986
                return -1;
        }
    }

17987
    for (i = 0; i < def->nconsoles; i++) {
17988
        virDomainChrDefPtr console = def->consoles[i];
C
Cole Robinson 已提交
17989 17990 17991 17992 17993 17994 17995 17996

        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,
17997
                VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL, idx, -1) < 0)
C
Cole Robinson 已提交
17998 17999 18000 18001
                return -1;
        }
    }

18002 18003 18004 18005
    return 0;
}


E
Eric Blake 已提交
18006 18007 18008 18009
static int
virDomainDefMaybeAddSmartcardController(virDomainDefPtr def)
{
    /* Look for any smartcard devs */
18010
    size_t i;
E
Eric Blake 已提交
18011

18012
    for (i = 0; i < def->nsmartcards; i++) {
E
Eric Blake 已提交
18013 18014 18015 18016 18017 18018 18019
        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) {
18020
            size_t j;
E
Eric Blake 已提交
18021 18022 18023 18024 18025 18026 18027 18028 18029 18030 18031 18032 18033 18034 18035 18036
            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,
18037
                                           idx, -1) < 0)
E
Eric Blake 已提交
18038 18039 18040 18041 18042 18043
            return -1;
    }

    return 0;
}

18044
/*
18045
 * Based on the declared <address/> info for any devices,
18046
 * add necessary drive controllers which are not already present
18047 18048 18049
 * in the XML. This is for compat with existing apps which will
 * not know/care about <controller> info in the XML
 */
18050 18051
int
virDomainDefAddImplicitControllers(virDomainDefPtr def)
18052 18053 18054 18055 18056 18057 18058 18059 18060 18061 18062 18063 18064 18065 18066 18067
{
    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 已提交
18068 18069 18070 18071 18072
    if (virDomainDefAddDiskControllersForType(def,
                                              VIR_DOMAIN_CONTROLLER_TYPE_SATA,
                                              VIR_DOMAIN_DISK_BUS_SATA) < 0)
        return -1;

18073 18074 18075
    if (virDomainDefMaybeAddVirtioSerialController(def) < 0)
        return -1;

E
Eric Blake 已提交
18076 18077 18078
    if (virDomainDefMaybeAddSmartcardController(def) < 0)
        return -1;

H
Han Cheng 已提交
18079 18080 18081
    if (virDomainDefMaybeAddHostdevSCSIcontroller(def) < 0)
        return -1;

18082 18083 18084
    return 0;
}

18085 18086 18087 18088 18089 18090 18091 18092 18093 18094 18095 18096 18097 18098 18099 18100 18101 18102 18103 18104 18105 18106 18107 18108 18109 18110 18111 18112 18113 18114 18115 18116 18117 18118 18119 18120 18121 18122 18123 18124 18125 18126 18127 18128 18129 18130 18131 18132 18133 18134
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)
{
18135 18136 18137 18138 18139 18140 18141 18142 18143 18144 18145 18146 18147 18148
    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);
18149 18150 18151 18152 18153 18154

            return;
        }
    }
}

18155 18156 18157 18158 18159 18160 18161 18162 18163 18164 18165 18166 18167 18168 18169 18170 18171 18172 18173 18174 18175 18176 18177
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;
        }
    }
}

18178
virDomainPinDefPtr
18179 18180 18181
virDomainPinFind(virDomainPinDefPtr *def,
                 int npin,
                 int id)
18182
{
18183
    size_t i;
18184

18185
    if (!def || !npin)
18186 18187
        return NULL;

18188 18189
    for (i = 0; i < npin; i++) {
        if (def[i]->id == id)
18190 18191 18192 18193 18194 18195
            return def[i];
    }

    return NULL;
}

18196
int
18197 18198 18199 18200 18201
virDomainPinAdd(virDomainPinDefPtr **pindef_list,
                size_t *npin,
                unsigned char *cpumap,
                int maplen,
                int id)
18202
{
18203
    virDomainPinDefPtr pindef = NULL;
18204

18205
    if (!pindef_list)
H
Hu Tao 已提交
18206
        return -1;
18207

18208 18209 18210 18211 18212 18213
    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 已提交
18214
            return -1;
18215

H
Hu Tao 已提交
18216 18217
        return 0;
    }
18218

18219
    /* No existing pindef matches id, adding a new one */
18220

18221
    if (VIR_ALLOC(pindef) < 0)
18222
        goto error;
18223

18224 18225 18226
    pindef->id = id;
    pindef->cpumask = virBitmapNewData(cpumap, maplen);
    if (!pindef->cpumask)
18227
        goto error;
18228

18229
    if (VIR_APPEND_ELEMENT(*pindef_list, *npin, pindef) < 0)
18230
        goto error;
H
Hu Tao 已提交
18231 18232

    return 0;
18233

18234
 error:
18235
    virDomainPinDefFree(pindef);
18236
    return -1;
18237 18238
}

18239
void
18240 18241 18242
virDomainPinDel(virDomainPinDefPtr **pindef_list,
                size_t *npin,
                int id)
18243 18244 18245
{
    int n;

18246 18247 18248 18249 18250
    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);
18251
            return;
18252 18253 18254 18255
        }
    }
}

18256

18257
static int
18258 18259 18260 18261
virDomainEventActionDefFormat(virBufferPtr buf,
                              int type,
                              const char *name,
                              virEventActionToStringFunc convFunc)
18262
{
18263
    const char *typeStr = convFunc(type);
18264
    if (!typeStr) {
18265
        virReportError(VIR_ERR_INTERNAL_ERROR,
18266
                       _("unexpected %s action: %d"), name, type);
18267 18268 18269
        return -1;
    }

18270
    virBufferAsprintf(buf, "<%s>%s</%s>\n", name, typeStr, name);
18271 18272 18273 18274 18275

    return 0;
}


18276
static void
18277
virSecurityLabelDefFormat(virBufferPtr buf,
18278
                          virSecurityLabelDefPtr def)
18279 18280 18281 18282
{
    const char *sectype = virDomainSeclabelTypeToString(def->type);

    if (!sectype)
18283 18284 18285 18286 18287
        return;

    if (def->type == VIR_DOMAIN_SECLABEL_DEFAULT)
        return;

18288 18289
    /* To avoid backward compatibility issues, suppress DAC and 'none' labels
     * that are automatically generated.
18290
     */
18291 18292
    if ((STREQ_NULLABLE(def->model, "dac") ||
         STREQ_NULLABLE(def->model, "none")) && def->implicit)
18293 18294
        return;

18295 18296 18297
    virBufferAsprintf(buf, "<seclabel type='%s'",
                      sectype);

18298
    virBufferEscapeString(buf, " model='%s'", def->model);
18299

18300 18301 18302 18303 18304
    if (def->type == VIR_DOMAIN_SECLABEL_NONE) {
        virBufferAddLit(buf, "/>\n");
        return;
    }

18305
    virBufferAsprintf(buf, " relabel='%s'",
18306
                      def->relabel ? "yes" : "no");
18307

18308 18309
    if (def->label || def->imagelabel || def->baselabel) {
        virBufferAddLit(buf, ">\n");
18310 18311
        virBufferAdjustIndent(buf, 2);
        virBufferEscapeString(buf, "<label>%s</label>\n",
18312
                              def->label);
18313
        if (def->relabel)
18314
            virBufferEscapeString(buf, "<imagelabel>%s</imagelabel>\n",
18315 18316
                                  def->imagelabel);
        if (def->type == VIR_DOMAIN_SECLABEL_DYNAMIC)
18317
            virBufferEscapeString(buf, "<baselabel>%s</baselabel>\n",
18318
                                  def->baselabel);
18319
        virBufferAdjustIndent(buf, -2);
18320
        virBufferAddLit(buf, "</seclabel>\n");
18321 18322
    } else {
        virBufferAddLit(buf, "/>\n");
18323 18324 18325 18326
    }
}


18327 18328
static void
virSecurityDeviceLabelDefFormat(virBufferPtr buf,
18329 18330
                                virSecurityDeviceLabelDefPtr def,
                                unsigned int flags)
18331
{
18332 18333
    /* For offline output, skip elements that allow labels but have no
     * label specified (possible if labelskip was ignored on input).  */
18334
    if ((flags & VIR_DOMAIN_DEF_FORMAT_INACTIVE) && !def->label && def->relabel)
18335 18336
        return;

18337
    virBufferAddLit(buf, "<seclabel");
18338 18339

    if (def->model)
18340
        virBufferEscapeString(buf, " model='%s'", def->model);
18341

18342 18343 18344
    if (def->labelskip)
        virBufferAddLit(buf, " labelskip='yes'");
    else
18345
        virBufferAsprintf(buf, " relabel='%s'", def->relabel ? "yes" : "no");
18346

18347 18348
    if (def->label) {
        virBufferAddLit(buf, ">\n");
18349 18350
        virBufferAdjustIndent(buf, 2);
        virBufferEscapeString(buf, "<label>%s</label>\n",
18351
                              def->label);
18352
        virBufferAdjustIndent(buf, -2);
18353 18354 18355 18356 18357 18358 18359
        virBufferAddLit(buf, "</seclabel>\n");
    } else {
        virBufferAddLit(buf, "/>\n");
    }
}


18360 18361 18362 18363
static int
virDomainLeaseDefFormat(virBufferPtr buf,
                        virDomainLeaseDefPtr def)
{
18364 18365 18366 18367 18368
    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);
18369 18370 18371
    if (def->offset)
        virBufferAsprintf(buf, " offset='%llu'", def->offset);
    virBufferAddLit(buf, "/>\n");
18372 18373
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</lease>\n");
18374 18375 18376 18377

    return 0;
}

18378 18379 18380
static void
virDomainDiskGeometryDefFormat(virBufferPtr buf,
                               virDomainDiskDefPtr def)
J
J.B. Joret 已提交
18381 18382 18383 18384 18385 18386 18387 18388
{
    const char *trans =
        virDomainDiskGeometryTransTypeToString(def->geometry.trans);

    if (def->geometry.cylinders > 0 &&
        def->geometry.heads > 0 &&
        def->geometry.sectors > 0) {
        virBufferAsprintf(buf,
18389
                          "<geometry cyls='%u' heads='%u' secs='%u'",
J
J.B. Joret 已提交
18390 18391 18392 18393 18394 18395 18396 18397 18398 18399
                          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");
    }
}
18400

18401 18402 18403
static void
virDomainDiskBlockIoDefFormat(virBufferPtr buf,
                              virDomainDiskDefPtr def)
18404
{
V
Viktor Mihajlovski 已提交
18405 18406
    if (def->blockio.logical_block_size > 0 ||
        def->blockio.physical_block_size > 0) {
18407
        virBufferAddLit(buf, "<blockio");
V
Viktor Mihajlovski 已提交
18408
        if (def->blockio.logical_block_size > 0) {
18409 18410
            virBufferAsprintf(buf,
                              " logical_block_size='%u'",
V
Viktor Mihajlovski 已提交
18411
                              def->blockio.logical_block_size);
18412
        }
V
Viktor Mihajlovski 已提交
18413
        if (def->blockio.physical_block_size > 0) {
18414 18415
            virBufferAsprintf(buf,
                              " physical_block_size='%u'",
V
Viktor Mihajlovski 已提交
18416
                              def->blockio.physical_block_size);
18417 18418 18419 18420 18421
        }
        virBufferAddLit(buf, "/>\n");
    }
}

18422

18423
/* virDomainSourceDefFormatSeclabel:
18424 18425 18426 18427 18428
 *
 * This function automaticaly closes the <source> element and formats any
 * possible seclabels.
 */
static void
18429 18430 18431 18432 18433
virDomainDiskSourceDefFormatSeclabel(virBufferPtr buf,
                                     size_t nseclabels,
                                     virSecurityDeviceLabelDefPtr *seclabels,
                                     unsigned int flags,
                                     bool skipSeclables)
18434 18435 18436
{
    size_t n;

18437
    if (nseclabels && !skipSeclables) {
18438
        virBufferAddLit(buf, ">\n");
18439
        virBufferAdjustIndent(buf, 2);
18440 18441
        for (n = 0; n < nseclabels; n++)
            virSecurityDeviceLabelDefFormat(buf, seclabels[n], flags);
18442 18443
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</source>\n");
18444 18445 18446 18447 18448
    } else {
        virBufferAddLit(buf, "/>\n");
    }
}

18449 18450 18451 18452 18453 18454 18455 18456 18457 18458 18459 18460 18461 18462 18463
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)
18464
{
18465
    size_t n;
18466
    char *path = NULL;
18467
    const char *startupPolicy = NULL;
18468

18469 18470 18471
    if (policy)
        startupPolicy = virDomainStartupPolicyTypeToString(policy);

18472
    if (src->path || src->nhosts > 0 || src->srcpool || startupPolicy) {
18473
        switch ((virStorageType)src->type) {
E
Eric Blake 已提交
18474
        case VIR_STORAGE_TYPE_FILE:
18475
            virBufferAddLit(buf, "<source");
18476
            virBufferEscapeString(buf, " file='%s'", src->path);
18477 18478
            virBufferEscapeString(buf, " startupPolicy='%s'", startupPolicy);

18479 18480 18481
            virDomainDiskSourceDefFormatSeclabel(buf, src->nseclabels,
                                                 src->seclabels, flags,
                                                 skipSeclabels);
18482
            break;
18483

E
Eric Blake 已提交
18484
        case VIR_STORAGE_TYPE_BLOCK:
18485
            virBufferAddLit(buf, "<source");
18486
            virBufferEscapeString(buf, " dev='%s'", src->path);
18487 18488
            virBufferEscapeString(buf, " startupPolicy='%s'", startupPolicy);

18489 18490 18491
            virDomainDiskSourceDefFormatSeclabel(buf, src->nseclabels,
                                                 src->seclabels, flags,
                                                 skipSeclabels);
18492
            break;
18493

E
Eric Blake 已提交
18494
        case VIR_STORAGE_TYPE_DIR:
18495
            virBufferAddLit(buf, "<source");
18496
            virBufferEscapeString(buf, " dir='%s'", src->path);
18497
            virBufferEscapeString(buf, " startupPolicy='%s'", startupPolicy);
18498
            virBufferAddLit(buf, "/>\n");
18499
            break;
18500

E
Eric Blake 已提交
18501
        case VIR_STORAGE_TYPE_NETWORK:
18502
            virBufferAsprintf(buf, "<source protocol='%s'",
18503
                              virStorageNetProtocolTypeToString(src->protocol));
18504 18505 18506 18507 18508 18509 18510 18511 18512 18513


            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);
18514

18515
            if (src->nhosts == 0 && !src->snapshot && !src->configFile) {
18516 18517 18518
                virBufferAddLit(buf, "/>\n");
            } else {
                virBufferAddLit(buf, ">\n");
18519
                virBufferAdjustIndent(buf, 2);
18520

18521
                for (n = 0; n < src->nhosts; n++) {
18522
                    virBufferAddLit(buf, "<host");
18523 18524 18525 18526
                    virBufferEscapeString(buf, " name='%s'",
                                          src->hosts[n].name);
                    virBufferEscapeString(buf, " port='%s'",
                                          src->hosts[n].port);
18527

18528
                    if (src->hosts[n].transport)
18529
                        virBufferAsprintf(buf, " transport='%s'",
18530
                                          virStorageNetHostTransportTypeToString(src->hosts[n].transport));
18531

18532 18533
                    virBufferEscapeString(buf, " socket='%s'",
                                          src->hosts[n].socket);
18534

18535 18536
                    virBufferAddLit(buf, "/>\n");
                }
18537 18538 18539 18540

                virBufferEscapeString(buf, "<snapshot name='%s'/>\n",
                                      src->snapshot);

18541 18542 18543
                virBufferEscapeString(buf, "<config file='%s'/>\n",
                                      src->configFile);

18544 18545
                virBufferAdjustIndent(buf, -2);
                virBufferAddLit(buf, "</source>\n");
18546 18547
            }
            break;
18548

E
Eric Blake 已提交
18549
        case VIR_STORAGE_TYPE_VOLUME:
18550
            virBufferAddLit(buf, "<source");
18551

18552 18553 18554 18555 18556
            if (src->srcpool) {
                virBufferEscapeString(buf, " pool='%s'", src->srcpool->pool);
                virBufferEscapeString(buf, " volume='%s'",
                                      src->srcpool->volume);
                if (src->srcpool->mode)
18557
                    virBufferAsprintf(buf, " mode='%s'",
18558
                                      virStorageSourcePoolModeTypeToString(src->srcpool->mode));
18559
            }
18560
            virBufferEscapeString(buf, " startupPolicy='%s'", startupPolicy);
18561

18562 18563 18564
            virDomainDiskSourceDefFormatSeclabel(buf, src->nseclabels,
                                                 src->seclabels, flags,
                                                 skipSeclabels);
18565
            break;
18566

18567
        case VIR_STORAGE_TYPE_NONE:
18568
        case VIR_STORAGE_TYPE_LAST:
18569
            virReportError(VIR_ERR_INTERNAL_ERROR,
18570
                           _("unexpected disk type %d"), src->type);
18571 18572 18573 18574 18575 18576
            return -1;
        }
    }

    return 0;
}
J
J.B. Joret 已提交
18577

18578

18579 18580 18581 18582 18583 18584 18585 18586 18587 18588
int
virDomainDiskSourceFormat(virBufferPtr buf,
                          virStorageSourcePtr src,
                          int policy,
                          unsigned int flags)
{
    return virDomainDiskSourceFormatInternal(buf, src, policy, flags, false);
}


18589 18590 18591 18592
static int
virDomainDiskBackingStoreFormat(virBufferPtr buf,
                                virStorageSourcePtr backingStore,
                                const char *backingStoreRaw,
18593
                                unsigned int idx)
18594 18595 18596 18597 18598 18599 18600 18601 18602 18603 18604 18605 18606 18607 18608 18609 18610 18611 18612 18613 18614 18615 18616 18617 18618 18619 18620
{
    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",
18621
                      type, idx);
18622 18623 18624
    virBufferAdjustIndent(buf, 2);

    virBufferAsprintf(buf, "<format type='%s'/>\n", format);
18625 18626
    /* We currently don't output seclabels for backing chain element */
    if (virDomainDiskSourceFormatInternal(buf, backingStore, 0, 0, true) < 0 ||
18627 18628 18629
        virDomainDiskBackingStoreFormat(buf,
                                        backingStore->backingStore,
                                        backingStore->backingStoreRaw,
18630
                                        idx + 1) < 0)
18631 18632 18633 18634 18635 18636 18637 18638
        return -1;

    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</backingStore>\n");
    return 0;
}


18639
static int
18640
virDomainDiskDefFormat(virBufferPtr buf,
D
Daniel P. Berrange 已提交
18641
                       virDomainDiskDefPtr def,
E
Eric Blake 已提交
18642
                       unsigned int flags)
18643
{
18644
    const char *type = virStorageTypeToString(def->src->type);
18645 18646
    const char *device = virDomainDiskDeviceTypeToString(def->device);
    const char *bus = virDomainDiskBusTypeToString(def->bus);
18647
    const char *cachemode = virDomainDiskCacheTypeToString(def->cachemode);
18648
    const char *error_policy = virDomainDiskErrorPolicyTypeToString(def->error_policy);
18649
    const char *rerror_policy = virDomainDiskErrorPolicyTypeToString(def->rerror_policy);
M
Matthias Dahl 已提交
18650
    const char *iomode = virDomainDiskIoTypeToString(def->iomode);
J
Ján Tomko 已提交
18651 18652 18653
    const char *ioeventfd = virTristateSwitchTypeToString(def->ioeventfd);
    const char *event_idx = virTristateSwitchTypeToString(def->event_idx);
    const char *copy_on_read = virTristateSwitchTypeToString(def->copy_on_read);
18654
    const char *sgio = virDomainDeviceSGIOTypeToString(def->sgio);
O
Osier Yang 已提交
18655
    const char *discard = virDomainDiskDiscardTypeToString(def->discard);
18656

18657
    if (!type || !def->src->type) {
18658
        virReportError(VIR_ERR_INTERNAL_ERROR,
18659
                       _("unexpected disk type %d"), def->src->type);
18660 18661 18662
        return -1;
    }
    if (!device) {
18663 18664
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected disk device %d"), def->device);
18665 18666 18667
        return -1;
    }
    if (!bus) {
18668 18669
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected disk bus %d"), def->bus);
18670 18671
        return -1;
    }
18672
    if (!cachemode) {
18673 18674
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected disk cache mode %d"), def->cachemode);
18675 18676
        return -1;
    }
M
Matthias Dahl 已提交
18677
    if (!iomode) {
18678 18679
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected disk io mode %d"), def->iomode);
M
Matthias Dahl 已提交
18680 18681
        return -1;
    }
O
Osier Yang 已提交
18682 18683 18684 18685 18686
    if (!sgio) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unexpected disk sgio mode '%d'"), def->sgio);
        return -1;
    }
18687

18688
    virBufferAsprintf(buf,
18689
                      "<disk type='%s' device='%s'",
18690
                      type, device);
18691 18692 18693
    if (def->rawio) {
        virBufferAsprintf(buf, " rawio='%s'",
                          virTristateBoolTypeToString(def->rawio));
18694
    }
O
Osier Yang 已提交
18695 18696 18697 18698

    if (def->sgio)
        virBufferAsprintf(buf, " sgio='%s'", sgio);

18699
    if (def->snapshot &&
18700 18701
        !(def->snapshot == VIR_DOMAIN_SNAPSHOT_LOCATION_NONE &&
          def->src->readonly))
18702
        virBufferAsprintf(buf, " snapshot='%s'",
E
Eric Blake 已提交
18703
                          virDomainSnapshotLocationTypeToString(def->snapshot));
18704
    virBufferAddLit(buf, ">\n");
18705
    virBufferAdjustIndent(buf, 2);
18706

18707
    if (def->src->driverName || def->src->format > 0 || def->cachemode ||
18708 18709
        def->error_policy || def->rerror_policy || def->iomode ||
        def->ioeventfd || def->event_idx || def->copy_on_read ||
18710
        def->discard || def->iothread) {
18711
        virBufferAddLit(buf, "<driver");
18712
        virBufferEscapeString(buf, " name='%s'", def->src->driverName);
18713
        if (def->src->format > 0)
18714
            virBufferAsprintf(buf, " type='%s'",
18715
                              virStorageFileFormatTypeToString(def->src->format));
18716
        if (def->cachemode)
18717
            virBufferAsprintf(buf, " cache='%s'", cachemode);
18718
        if (def->error_policy)
18719
            virBufferAsprintf(buf, " error_policy='%s'", error_policy);
18720 18721
        if (def->rerror_policy)
            virBufferAsprintf(buf, " rerror_policy='%s'", rerror_policy);
M
Matthias Dahl 已提交
18722
        if (def->iomode)
18723
            virBufferAsprintf(buf, " io='%s'", iomode);
18724 18725
        if (def->ioeventfd)
            virBufferAsprintf(buf, " ioeventfd='%s'", ioeventfd);
18726 18727
        if (def->event_idx)
            virBufferAsprintf(buf, " event_idx='%s'", event_idx);
O
Osier Yang 已提交
18728 18729
        if (def->copy_on_read)
            virBufferAsprintf(buf, " copy_on_read='%s'", copy_on_read);
O
Osier Yang 已提交
18730 18731
        if (def->discard)
            virBufferAsprintf(buf, " discard='%s'", discard);
18732 18733
        if (def->iothread)
            virBufferAsprintf(buf, " iothread='%u'", def->iothread);
18734
        virBufferAddLit(buf, "/>\n");
18735 18736
    }

18737 18738 18739
    if (def->src->auth) {
        if (virStorageAuthDefFormat(buf, def->src->auth) < 0)
            return -1;
18740 18741
    }

18742
    if (virDomainDiskSourceFormat(buf, def->src, def->startupPolicy,
18743
                                  flags) < 0)
18744
        return -1;
18745 18746 18747

    /* Don't format backingStore to inactive XMLs until the code for
     * persistent storage of backing chains is ready. */
18748
    if (!(flags & VIR_DOMAIN_DEF_FORMAT_INACTIVE) &&
18749 18750
        virDomainDiskBackingStoreFormat(buf, def->src->backingStore,
                                        def->src->backingStoreRaw, 1) < 0)
18751 18752
        return -1;

18753 18754
    virBufferEscapeString(buf, "<backenddomain name='%s'/>\n", def->domain_name);

J
J.B. Joret 已提交
18755
    virDomainDiskGeometryDefFormat(buf, def);
V
Viktor Mihajlovski 已提交
18756
    virDomainDiskBlockIoDefFormat(buf, def);
J
J.B. Joret 已提交
18757

18758 18759
    /* For now, mirroring is currently output-only: we only output it
     * for live domains, therefore we ignore it on input except for
18760 18761 18762 18763
     * 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. */
18764
    if (def->mirror && !(flags & VIR_DOMAIN_DEF_FORMAT_INACTIVE)) {
18765 18766 18767 18768
        const char *formatStr = NULL;

        if (def->mirror->format)
            formatStr = virStorageFileFormatTypeToString(def->mirror->format);
E
Eric Blake 已提交
18769 18770
        virBufferAsprintf(buf, "<mirror type='%s'",
                          virStorageTypeToString(def->mirror->type));
E
Eric Blake 已提交
18771 18772
        if (def->mirror->type == VIR_STORAGE_TYPE_FILE &&
            def->mirrorJob == VIR_DOMAIN_BLOCK_JOB_TYPE_COPY) {
18773 18774 18775
            virBufferEscapeString(buf, " file='%s'", def->mirror->path);
            virBufferEscapeString(buf, " format='%s'", formatStr);
        }
E
Eric Blake 已提交
18776 18777
        virBufferEscapeString(buf, " job='%s'",
                              virDomainBlockJobTypeToString(def->mirrorJob));
18778 18779 18780 18781 18782 18783
        if (def->mirrorState) {
            const char *mirror;

            mirror = virDomainDiskMirrorStateTypeToString(def->mirrorState);
            virBufferEscapeString(buf, " ready='%s'", mirror);
        }
E
Eric Blake 已提交
18784 18785
        virBufferAddLit(buf, ">\n");
        virBufferAdjustIndent(buf, 2);
18786
        virBufferEscapeString(buf, "<format type='%s'/>\n", formatStr);
E
Eric Blake 已提交
18787 18788 18789 18790
        if (virDomainDiskSourceFormat(buf, def->mirror, 0, 0) < 0)
            return -1;
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</mirror>\n");
18791 18792
    }

18793
    virBufferAsprintf(buf, "<target dev='%s' bus='%s'",
18794
                      def->dst, bus);
18795 18796
    if ((def->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY ||
         def->device == VIR_DOMAIN_DISK_DEVICE_CDROM) &&
E
Eric Blake 已提交
18797
        def->tray_status != VIR_DOMAIN_DISK_TRAY_CLOSED)
18798
        virBufferAsprintf(buf, " tray='%s'",
18799
                          virDomainDiskTrayTypeToString(def->tray_status));
18800
    if (def->bus == VIR_DOMAIN_DISK_BUS_USB &&
J
Ján Tomko 已提交
18801
        def->removable != VIR_TRISTATE_SWITCH_ABSENT) {
18802
        virBufferAsprintf(buf, " removable='%s'",
J
Ján Tomko 已提交
18803
                          virTristateSwitchTypeToString(def->removable));
18804 18805
    }
    virBufferAddLit(buf, "/>\n");
18806

L
Lei Li 已提交
18807 18808 18809 18810 18811 18812
    /*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 ||
18813 18814 18815 18816 18817 18818 18819 18820
        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) {
18821 18822
        virBufferAddLit(buf, "<iotune>\n");
        virBufferAdjustIndent(buf, 2);
L
Lei Li 已提交
18823
        if (def->blkdeviotune.total_bytes_sec) {
18824
            virBufferAsprintf(buf, "<total_bytes_sec>%llu</total_bytes_sec>\n",
L
Lei Li 已提交
18825 18826 18827 18828
                              def->blkdeviotune.total_bytes_sec);
        }

        if (def->blkdeviotune.read_bytes_sec) {
18829
            virBufferAsprintf(buf, "<read_bytes_sec>%llu</read_bytes_sec>\n",
L
Lei Li 已提交
18830 18831 18832 18833 18834
                              def->blkdeviotune.read_bytes_sec);

        }

        if (def->blkdeviotune.write_bytes_sec) {
18835
            virBufferAsprintf(buf, "<write_bytes_sec>%llu</write_bytes_sec>\n",
L
Lei Li 已提交
18836 18837 18838 18839
                              def->blkdeviotune.write_bytes_sec);
        }

        if (def->blkdeviotune.total_iops_sec) {
18840
            virBufferAsprintf(buf, "<total_iops_sec>%llu</total_iops_sec>\n",
L
Lei Li 已提交
18841 18842 18843 18844
                              def->blkdeviotune.total_iops_sec);
        }

        if (def->blkdeviotune.read_iops_sec) {
18845
            virBufferAsprintf(buf, "<read_iops_sec>%llu</read_iops_sec>\n",
L
Lei Li 已提交
18846 18847 18848 18849
                              def->blkdeviotune.read_iops_sec);
        }

        if (def->blkdeviotune.write_iops_sec) {
18850
            virBufferAsprintf(buf, "<write_iops_sec>%llu</write_iops_sec>\n",
L
Lei Li 已提交
18851 18852
                              def->blkdeviotune.write_iops_sec);
        }
18853 18854 18855 18856 18857 18858 18859 18860 18861 18862 18863 18864 18865 18866 18867 18868 18869 18870 18871 18872 18873 18874 18875 18876 18877 18878 18879 18880 18881 18882 18883 18884 18885 18886 18887 18888

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

18889 18890
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</iotune>\n");
L
Lei Li 已提交
18891 18892
    }

18893
    if (def->src->readonly)
18894
        virBufferAddLit(buf, "<readonly/>\n");
18895
    if (def->src->shared)
18896
        virBufferAddLit(buf, "<shareable/>\n");
18897
    if (def->transient)
18898 18899 18900 18901 18902
        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);
18903 18904
    if (def->src->encryption &&
        virStorageEncryptionFormat(buf, def->src->encryption) < 0)
18905
        return -1;
18906
    if (virDomainDeviceInfoFormat(buf, &def->info,
18907
                                  flags | VIR_DOMAIN_DEF_FORMAT_ALLOW_BOOT) < 0)
18908
        return -1;
18909

18910 18911
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</disk>\n");
18912 18913 18914
    return 0;
}

18915 18916 18917 18918 18919 18920
static const char *
virDomainControllerModelTypeToString(virDomainControllerDefPtr def,
                                     int model)
{
    if (def->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI)
        return virDomainControllerModelSCSITypeToString(model);
18921 18922
    else if (def->type == VIR_DOMAIN_CONTROLLER_TYPE_USB)
        return virDomainControllerModelUSBTypeToString(model);
J
Ján Tomko 已提交
18923 18924
    else if (def->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI)
        return virDomainControllerModelPCITypeToString(model);
18925 18926 18927 18928

    return NULL;
}

18929
static int
18930
virDomainControllerDefFormat(virBufferPtr buf,
D
Daniel P. Berrange 已提交
18931
                             virDomainControllerDefPtr def,
E
Eric Blake 已提交
18932
                             unsigned int flags)
18933 18934
{
    const char *type = virDomainControllerTypeToString(def->type);
18935
    const char *model = NULL;
18936
    const char *modelName = NULL;
18937
    bool pcihole64 = false, pciModel = false, pciTarget = false;
18938 18939

    if (!type) {
18940 18941
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected controller type %d"), def->type);
18942 18943 18944
        return -1;
    }

18945
    if (def->model != -1) {
18946
        model = virDomainControllerModelTypeToString(def, def->model);
18947 18948

        if (!model) {
18949 18950
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected model type %d"), def->model);
18951 18952 18953 18954
            return -1;
        }
    }

18955
    virBufferAsprintf(buf,
18956
                      "<controller type='%s' index='%u'",
18957 18958
                      type, def->idx);

18959
    if (model)
18960 18961
        virBufferEscapeString(buf, " model='%s'", model);

18962 18963 18964
    switch (def->type) {
    case VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL:
        if (def->opts.vioserial.ports != -1) {
18965
            virBufferAsprintf(buf, " ports='%d'",
18966 18967 18968
                              def->opts.vioserial.ports);
        }
        if (def->opts.vioserial.vectors != -1) {
18969
            virBufferAsprintf(buf, " vectors='%d'",
18970 18971 18972 18973
                              def->opts.vioserial.vectors);
        }
        break;

18974 18975 18976
    case VIR_DOMAIN_CONTROLLER_TYPE_PCI:
        if (def->opts.pciopts.pcihole64)
            pcihole64 = true;
18977 18978
        if (def->opts.pciopts.modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_NONE)
            pciModel = true;
18979 18980 18981
        if (def->opts.pciopts.chassisNr != -1 ||
            def->opts.pciopts.chassis != -1 ||
            def->opts.pciopts.port != -1)
18982
            pciTarget = true;
18983 18984
        break;

18985 18986 18987 18988
    default:
        break;
    }

18989
    if (pciModel || pciTarget ||
18990
        def->queues || def->cmd_per_lun || def->max_sectors || def->ioeventfd ||
18991
        virDomainDeviceInfoNeedsFormat(&def->info, flags) || pcihole64) {
18992
        virBufferAddLit(buf, ">\n");
18993
        virBufferAdjustIndent(buf, 2);
18994

18995 18996 18997 18998 18999 19000 19001 19002 19003 19004 19005
        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);
        }

19006 19007 19008 19009 19010
        if (pciTarget) {
            virBufferAddLit(buf, "<target");
            if (def->opts.pciopts.chassisNr != -1)
                virBufferAsprintf(buf, " chassisNr='%d'",
                                  def->opts.pciopts.chassisNr);
19011 19012 19013 19014 19015 19016
            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);
19017 19018 19019
            virBufferAddLit(buf, "/>\n");
        }

19020 19021
        if (def->queues || def->cmd_per_lun ||
            def->max_sectors || def->ioeventfd) {
19022 19023 19024
            virBufferAddLit(buf, "<driver");
            if (def->queues)
                virBufferAsprintf(buf, " queues='%u'", def->queues);
19025

19026 19027 19028 19029 19030
            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);
19031 19032 19033 19034 19035

            if (def->ioeventfd) {
                virBufferAsprintf(buf, " ioeventfd='%s'",
                                  virTristateSwitchTypeToString(def->ioeventfd));
            }
19036 19037
            virBufferAddLit(buf, "/>\n");
        }
19038

19039
        if (virDomainDeviceInfoNeedsFormat(&def->info, flags) &&
19040
            virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
19041
            return -1;
19042

19043
        if (pcihole64) {
19044
            virBufferAsprintf(buf, "<pcihole64 unit='KiB'>%lu</"
19045 19046 19047
                              "pcihole64>\n", def->opts.pciopts.pcihole64size);
        }

19048 19049
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</controller>\n");
19050 19051 19052 19053 19054 19055 19056
    } else {
        virBufferAddLit(buf, "/>\n");
    }

    return 0;
}

19057 19058 19059 19060 19061

int
virDomainFSIndexByName(virDomainDefPtr def, const char *name)
{
    virDomainFSDefPtr fs;
19062
    size_t i;
19063 19064 19065 19066 19067 19068 19069 19070 19071 19072

    for (i = 0; i < def->nfss; i++) {
        fs = def->fss[i];
        if (STREQ(fs->dst, name))
            return i;
    }
    return -1;
}


19073
static int
19074
virDomainFSDefFormat(virBufferPtr buf,
19075
                     virDomainFSDefPtr def,
E
Eric Blake 已提交
19076
                     unsigned int flags)
19077 19078
{
    const char *type = virDomainFSTypeToString(def->type);
19079
    const char *accessmode = virDomainFSAccessModeTypeToString(def->accessmode);
19080
    const char *fsdriver = virDomainFSDriverTypeToString(def->fsdriver);
19081
    const char *wrpolicy = virDomainFSWrpolicyTypeToString(def->wrpolicy);
19082 19083

    if (!type) {
19084 19085
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected filesystem type %d"), def->type);
19086 19087 19088
        return -1;
    }

19089
   if (!accessmode) {
19090 19091
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected accessmode %d"), def->accessmode);
19092 19093 19094 19095
        return -1;
    }


19096
    virBufferAsprintf(buf,
19097
                      "<filesystem type='%s' accessmode='%s'>\n",
19098
                      type, accessmode);
19099
    virBufferAdjustIndent(buf, 2);
19100
    if (def->fsdriver) {
19101
        virBufferAsprintf(buf, "<driver type='%s'", fsdriver);
19102

19103 19104 19105 19106
        if (def->format)
            virBufferAsprintf(buf, " format='%s'",
                              virStorageFileFormatTypeToString(def->format));

19107
        /* Don't generate anything if wrpolicy is set to default */
19108
        if (def->wrpolicy)
19109 19110 19111
            virBufferAsprintf(buf, " wrpolicy='%s'", wrpolicy);

        virBufferAddLit(buf, "/>\n");
19112 19113
    }

19114 19115
    switch (def->type) {
    case VIR_DOMAIN_FS_TYPE_MOUNT:
19116
    case VIR_DOMAIN_FS_TYPE_BIND:
19117
        virBufferEscapeString(buf, "<source dir='%s'/>\n",
19118 19119
                              def->src);
        break;
19120

19121
    case VIR_DOMAIN_FS_TYPE_BLOCK:
19122
        virBufferEscapeString(buf, "<source dev='%s'/>\n",
19123 19124
                              def->src);
        break;
19125

19126
    case VIR_DOMAIN_FS_TYPE_FILE:
19127
        virBufferEscapeString(buf, "<source file='%s'/>\n",
19128 19129
                              def->src);
        break;
19130

19131
    case VIR_DOMAIN_FS_TYPE_TEMPLATE:
19132
        virBufferEscapeString(buf, "<source name='%s'/>\n",
19133 19134 19135 19136
                              def->src);
        break;

    case VIR_DOMAIN_FS_TYPE_RAM:
19137
        virBufferAsprintf(buf, "<source usage='%lld' units='KiB'/>\n",
19138 19139
                          def->usage / 1024);
        break;
19140 19141
    }

19142
    virBufferEscapeString(buf, "<target dir='%s'/>\n",
19143
                          def->dst);
19144 19145

    if (def->readonly)
19146
        virBufferAddLit(buf, "<readonly/>\n");
19147

19148 19149 19150
    if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
        return -1;

19151 19152

    if (def->space_hard_limit)
19153
        virBufferAsprintf(buf, "<space_hard_limit unit='bytes'>"
19154 19155
                          "%llu</space_hard_limit>\n", def->space_hard_limit);
    if (def->space_soft_limit) {
19156
        virBufferAsprintf(buf, "<space_soft_limit unit='bytes'>"
19157 19158
                          "%llu</space_soft_limit>\n", def->space_soft_limit);
    }
19159 19160
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</filesystem>\n");
19161 19162 19163
    return 0;
}

19164
static int
19165 19166 19167 19168 19169 19170 19171 19172 19173
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;
19174 19175 19176

        if (!ipStr)
            return -1;
19177 19178 19179 19180 19181 19182
        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);
19183
        VIR_FREE(ipStr);
19184 19185 19186 19187 19188 19189
        if (familyStr)
            virBufferAsprintf(buf, " family='%s'", familyStr);
        if (ips[i]->prefix != 0)
            virBufferAsprintf(buf, " prefix='%u'", ips[i]->prefix);
        virBufferAddLit(buf, "/>\n");
    }
19190
    return 0;
19191 19192
}

19193
static int
19194
virDomainNetRoutesFormat(virBufferPtr buf,
19195
                         virNetworkRouteDefPtr *routes,
19196 19197 19198 19199
                         size_t nroutes)
{
    size_t i;

19200 19201 19202 19203
    for (i = 0; i < nroutes; i++)
        if (virNetworkRouteDefFormat(buf, routes[i]) < 0)
            return -1;
    return 0;
19204 19205
}

19206
static int
19207 19208 19209 19210
virDomainHostdevDefFormatSubsys(virBufferPtr buf,
                                virDomainHostdevDefPtr def,
                                unsigned int flags,
                                bool includeTypeInAddr)
19211
{
19212
    virDomainHostdevSubsysUSBPtr usbsrc = &def->source.subsys.u.usb;
19213
    virDomainHostdevSubsysPCIPtr pcisrc = &def->source.subsys.u.pci;
19214
    virDomainHostdevSubsysSCSIPtr scsisrc = &def->source.subsys.u.scsi;
19215
    virDomainHostdevSubsysSCSIHostPtr scsihostsrc = &scsisrc->u.host;
J
John Ferlan 已提交
19216
    virDomainHostdevSubsysSCSIiSCSIPtr iscsisrc = &scsisrc->u.iscsi;
19217

19218
    if (def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI &&
19219 19220 19221
        pcisrc->backend != VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT) {
        const char *backend =
            virDomainHostdevSubsysPCIBackendTypeToString(pcisrc->backend);
19222 19223 19224 19225

        if (!backend) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected pci hostdev driver name type %d"),
19226
                           pcisrc->backend);
19227 19228 19229 19230 19231
            return -1;
        }
        virBufferAsprintf(buf, "<driver name='%s'/>\n", backend);
    }

19232
    virBufferAddLit(buf, "<source");
J
John Ferlan 已提交
19233 19234 19235 19236 19237 19238
    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);
        }
19239
        if (usbsrc->autoAddress && (flags & VIR_DOMAIN_DEF_FORMAT_MIGRATABLE))
J
John Ferlan 已提交
19240 19241
            virBufferAddLit(buf, " autoAddress='yes'");

19242
        if (def->missing && !(flags & VIR_DOMAIN_DEF_FORMAT_INACTIVE))
J
John Ferlan 已提交
19243
            virBufferAddLit(buf, " missing='yes'");
19244
    }
19245

J
John Ferlan 已提交
19246 19247 19248 19249 19250 19251 19252 19253
    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);
    }
19254

19255 19256
    virBufferAddLit(buf, ">\n");

19257
    virBufferAdjustIndent(buf, 2);
E
Eric Blake 已提交
19258
    switch (def->source.subsys.type) {
19259
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
19260 19261 19262 19263 19264
        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) {
19265
            virBufferAsprintf(buf, "<address %sbus='%d' device='%d'/>\n",
19266
                              includeTypeInAddr ? "type='usb' " : "",
19267
                              usbsrc->bus, usbsrc->device);
19268 19269 19270
        }
        break;
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
19271
        if (virDevicePCIAddressFormat(buf, pcisrc->addr,
19272 19273 19274
                                      includeTypeInAddr) != 0)
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("PCI address Formatting failed"));
19275

19276
        if ((flags & VIR_DOMAIN_DEF_FORMAT_PCI_ORIG_STATES) &&
19277 19278 19279
            (def->origstates.states.pci.unbind_from_stub ||
             def->origstates.states.pci.remove_slot ||
             def->origstates.states.pci.reprobe)) {
19280
            virBufferAddLit(buf, "<origstates>\n");
19281
            virBufferAdjustIndent(buf, 2);
19282
            if (def->origstates.states.pci.unbind_from_stub)
19283
                virBufferAddLit(buf, "<unbind/>\n");
19284
            if (def->origstates.states.pci.remove_slot)
19285
                virBufferAddLit(buf, "<removeslot/>\n");
19286
            if (def->origstates.states.pci.reprobe)
19287 19288
                virBufferAddLit(buf, "<reprobe/>\n");
            virBufferAdjustIndent(buf, -2);
19289
            virBufferAddLit(buf, "</origstates>\n");
19290 19291
        }
        break;
H
Han Cheng 已提交
19292
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
J
John Ferlan 已提交
19293 19294 19295 19296 19297 19298 19299 19300 19301
        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,
19302
                              "<address %sbus='%u' target='%u' unit='%llu'/>\n",
J
John Ferlan 已提交
19303 19304 19305 19306
                              includeTypeInAddr ? "type='scsi' " : "",
                              scsihostsrc->bus, scsihostsrc->target,
                              scsihostsrc->unit);
        }
H
Han Cheng 已提交
19307
        break;
19308
    default:
19309 19310 19311
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected hostdev type %d"),
                       def->source.subsys.type);
19312 19313 19314
        return -1;
    }

J
John Ferlan 已提交
19315 19316 19317 19318 19319 19320 19321
    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;
    }

19322
    virBufferAdjustIndent(buf, -2);
19323
    virBufferAddLit(buf, "</source>\n");
J
John Ferlan 已提交
19324

19325 19326 19327
    return 0;
}

19328 19329 19330 19331 19332 19333 19334
static int
virDomainHostdevDefFormatCaps(virBufferPtr buf,
                              virDomainHostdevDefPtr def)
{
    virBufferAddLit(buf, "<source>\n");

    virBufferAdjustIndent(buf, 2);
E
Eric Blake 已提交
19335
    switch (def->source.caps.type) {
19336 19337 19338 19339 19340 19341 19342 19343
    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;
19344 19345 19346 19347
    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_NET:
        virBufferEscapeString(buf, "<interface>%s</interface>\n",
                              def->source.caps.u.net.iface);
        break;
19348 19349 19350 19351 19352 19353 19354 19355 19356
    default:
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected hostdev type %d"),
                       def->source.caps.type);
        return -1;
    }

    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</source>\n");
19357 19358

    if (def->source.caps.type == VIR_DOMAIN_HOSTDEV_CAPS_TYPE_NET) {
19359 19360 19361
        if (virDomainNetIpsFormat(buf, def->source.caps.u.net.ips,
                                 def->source.caps.u.net.nips) < 0)
            return -1;
19362 19363 19364
        if (virDomainNetRoutesFormat(buf, def->source.caps.u.net.routes,
                                     def->source.caps.u.net.nroutes) < 0)
            return -1;
19365 19366
    }

19367 19368 19369
    return 0;
}

19370 19371 19372 19373 19374
/* 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.
 */
19375
static int
19376 19377 19378 19379
virDomainActualNetDefContentsFormat(virBufferPtr buf,
                                    virDomainNetDefPtr def,
                                    bool inSubelement,
                                    unsigned int flags)
19380
{
19381
    int actualType = virDomainNetGetActualType(def);
19382

19383
    if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
19384
        if (virDomainHostdevDefFormatSubsys(buf, virDomainNetGetActualHostdev(def),
19385
                                            flags, true) < 0) {
19386 19387
            return -1;
        }
19388 19389 19390 19391 19392
    } 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
19393 19394 19395 19396 19397 19398 19399
             * 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).
19400
             */
19401 19402 19403 19404
            virBufferEscapeString(buf, " network='%s'",
                                  def->data.network.name);
            virBufferEscapeString(buf, " portgroup='%s'",
                                  def->data.network.portgroup);
19405
        }
19406 19407
        if (actualType == VIR_DOMAIN_NET_TYPE_BRIDGE ||
            actualType == VIR_DOMAIN_NET_TYPE_NETWORK) {
19408 19409
            int macTableManager = virDomainNetGetActualBridgeMACTableManager(def);

19410 19411 19412 19413 19414 19415
            /* 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));
19416 19417 19418 19419
            if (macTableManager) {
                virBufferAsprintf(buf, " macTableManager='%s'",
                                  virNetworkBridgeMACTableManagerTypeToString(macTableManager));
            }
19420 19421 19422 19423 19424 19425 19426 19427 19428 19429 19430 19431 19432 19433 19434 19435 19436
        } 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");
    }
19437 19438
    if (flags & VIR_DOMAIN_DEF_FORMAT_STATUS &&
        def->data.network.actual && def->data.network.actual->class_id) {
19439 19440
        virBufferAsprintf(buf, "<class id='%u'/>\n",
                          def->data.network.actual->class_id);
19441
    }
19442

19443
    if (virNetDevVlanFormat(virDomainNetGetActualVlan(def), buf) < 0)
19444
        return -1;
19445
    if (virNetDevVPortProfileFormat(virDomainNetGetActualVirtPortProfile(def), buf) < 0)
19446
        return -1;
19447
    if (virNetDevBandwidthFormat(virDomainNetGetActualBandwidth(def), buf) < 0)
19448
        return -1;
19449 19450 19451 19452 19453 19454 19455 19456 19457 19458 19459 19460
    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)
{
19461 19462
    unsigned int type;
    const char *typeStr;
19463 19464 19465

    if (!def)
        return 0;
19466 19467
    type = virDomainNetGetActualType(def);
    typeStr = virDomainNetTypeToString(type);
19468

19469 19470 19471 19472 19473 19474 19475 19476 19477 19478 19479 19480
    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'");
    }
19481 19482 19483
    if (def->trustGuestRxFilters)
        virBufferAsprintf(buf, " trustGuestRxFilters='%s'",
                          virTristateBoolTypeToString(def->trustGuestRxFilters));
19484 19485 19486
    virBufferAddLit(buf, ">\n");

    virBufferAdjustIndent(buf, 2);
19487
    if (virDomainActualNetDefContentsFormat(buf, def, true, flags) < 0)
19488
       return -1;
19489 19490
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</actual>\n");
19491
    return 0;
19492 19493
}

19494

19495 19496 19497 19498 19499 19500 19501 19502 19503 19504 19505 19506 19507 19508 19509 19510 19511 19512 19513 19514 19515 19516 19517 19518 19519 19520 19521 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
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));
    }
19559 19560 19561 19562
    if (def->driver.virtio.host.mrg_rxbuf) {
        virBufferAsprintf(&buf, "mrg_rxbuf='%s' ",
                          virTristateSwitchTypeToString(def->driver.virtio.host.mrg_rxbuf));
    }
19563 19564 19565 19566 19567 19568 19569 19570 19571 19572
    virBufferTrim(&buf, " ", -1);

    if (virBufferCheckError(&buf) < 0)
        return -1;

    *outstr = virBufferContentAndReset(&buf);
    return 0;
}


19573 19574 19575 19576 19577 19578 19579 19580 19581 19582 19583 19584 19585 19586 19587 19588 19589 19590 19591 19592 19593 19594 19595 19596 19597 19598 19599 19600 19601 19602 19603 19604 19605 19606
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;
}


19607
int
19608
virDomainNetDefFormat(virBufferPtr buf,
19609
                      virDomainNetDefPtr def,
E
Eric Blake 已提交
19610
                      unsigned int flags)
19611
{
19612
    unsigned int actualType = virDomainNetGetActualType(def);
19613
    bool publicActual = false;
19614 19615
    const char *typeStr;
    virDomainHostdevDefPtr hostdef = NULL;
19616
    char macstr[VIR_MAC_STRING_BUFLEN];
19617

19618 19619 19620 19621 19622 19623
    /* 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 &&
19624 19625 19626
        !(flags & (VIR_DOMAIN_DEF_FORMAT_INACTIVE |
                   VIR_DOMAIN_DEF_FORMAT_ACTUAL_NET |
                   VIR_DOMAIN_DEF_FORMAT_MIGRATABLE)))
19627 19628
        publicActual = true;

19629 19630 19631 19632 19633 19634 19635 19636 19637 19638 19639 19640 19641 19642 19643 19644
    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;
19645 19646
    }

19647
    virBufferAsprintf(buf, "<interface type='%s'", typeStr);
19648
    if (hostdef && hostdef->managed)
19649
        virBufferAddLit(buf, " managed='yes'");
19650 19651 19652
    if (def->trustGuestRxFilters)
        virBufferAsprintf(buf, " trustGuestRxFilters='%s'",
                          virTristateBoolTypeToString(def->trustGuestRxFilters));
19653
    virBufferAddLit(buf, ">\n");
19654

19655
    virBufferAdjustIndent(buf, 2);
19656 19657
    virBufferAsprintf(buf, "<mac address='%s'/>\n",
                      virMacAddrFormat(&def->mac, macstr));
19658

19659 19660 19661 19662 19663 19664 19665
    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)
19666
         */
19667
        if (virDomainActualNetDefContentsFormat(buf, def, false, flags) < 0)
19668
            return -1;
19669 19670 19671 19672 19673 19674 19675 19676 19677 19678 19679 19680 19681 19682 19683
    } 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");
19684

19685 19686 19687 19688
            /* ONLY for internal status storage - format the ActualNetDef
             * as a subelement of <interface> so that no persistent config
             * data is overwritten.
             */
19689
            if ((flags & VIR_DOMAIN_DEF_FORMAT_ACTUAL_NET) &&
19690 19691 19692
                (virDomainActualNetDefFormat(buf, def, flags) < 0))
                return -1;
            break;
19693

19694 19695 19696 19697
        case VIR_DOMAIN_NET_TYPE_ETHERNET:
            virBufferEscapeString(buf, "<source dev='%s'/>\n",
                                  def->data.ethernet.dev);
            break;
19698

M
Michele Paolino 已提交
19699 19700 19701 19702 19703
        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);
19704 19705 19706
                virBufferAsprintf(buf, " mode='%s'",
                                  def->data.vhostuser->data.nix.listen ?
                                  "server"  : "client");
M
Michele Paolino 已提交
19707 19708 19709 19710
                virBufferAddLit(buf, "/>\n");
            }
            break;

19711 19712 19713 19714
        case VIR_DOMAIN_NET_TYPE_BRIDGE:
            virBufferEscapeString(buf, "<source bridge='%s'/>\n",
                                  def->data.bridge.brname);
            break;
D
Daniel Veillard 已提交
19715

19716 19717 19718
        case VIR_DOMAIN_NET_TYPE_SERVER:
        case VIR_DOMAIN_NET_TYPE_CLIENT:
        case VIR_DOMAIN_NET_TYPE_MCAST:
19719
        case VIR_DOMAIN_NET_TYPE_UDP:
19720
            if (def->data.socket.address) {
19721 19722 19723
                virBufferAsprintf(buf, "<source address='%s' port='%d'",
                                  def->data.socket.address,
                                  def->data.socket.port);
19724
            } else {
19725
                virBufferAsprintf(buf, "<source port='%d'",
19726 19727
                                  def->data.socket.port);
            }
19728 19729 19730 19731 19732 19733 19734 19735 19736 19737 19738 19739 19740 19741

            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");
19742
            break;
D
Daniel Veillard 已提交
19743

19744 19745 19746 19747
        case VIR_DOMAIN_NET_TYPE_INTERNAL:
            virBufferEscapeString(buf, "<source name='%s'/>\n",
                                  def->data.internal.name);
            break;
S
Stefan Berger 已提交
19748

19749 19750 19751 19752 19753 19754 19755 19756 19757 19758 19759 19760 19761 19762 19763 19764 19765 19766
        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;
19767 19768
        }

19769 19770 19771 19772 19773 19774
        if (virNetDevVlanFormat(&def->vlan, buf) < 0)
            return -1;
        if (virNetDevVPortProfileFormat(def->virtPortProfile, buf) < 0)
            return -1;
        if (virNetDevBandwidthFormat(def->bandwidth, buf) < 0)
            return -1;
19775 19776
    }

19777 19778
    if (virDomainNetIpsFormat(buf, def->ips, def->nips) < 0)
        return -1;
19779 19780
    if (virDomainNetRoutesFormat(buf, def->routes, def->nroutes) < 0)
        return -1;
19781

19782
    virBufferEscapeString(buf, "<script path='%s'/>\n",
19783
                          def->script);
19784
    virBufferEscapeString(buf, "<backenddomain name='%s'/>\n", def->domain_name);
19785
    if (def->ifname &&
19786
        !((flags & VIR_DOMAIN_DEF_FORMAT_INACTIVE) &&
19787 19788
          (STRPREFIX(def->ifname, VIR_NET_GENERATED_PREFIX)))) {
        /* Skip auto-generated target names for inactive config. */
19789
        virBufferEscapeString(buf, "<target dev='%s'/>\n", def->ifname);
19790
    }
19791 19792 19793 19794 19795 19796 19797 19798 19799 19800 19801
    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");
    }
19802
    if (def->model) {
19803
        virBufferEscapeString(buf, "<model type='%s'/>\n",
19804
                              def->model);
19805
        if (STREQ(def->model, "virtio")) {
19806 19807
            char *str = NULL, *gueststr = NULL, *hoststr = NULL;
            int rc = 0;
19808

19809 19810 19811 19812
            if (virDomainVirtioNetDriverFormat(&str, def) < 0 ||
                virDomainVirtioNetGuestOptsFormat(&gueststr, def) < 0 ||
                virDomainVirtioNetHostOptsFormat(&hoststr, def) < 0)
                rc = -1;
19813

19814 19815 19816 19817 19818 19819 19820 19821 19822 19823 19824 19825 19826 19827 19828 19829
            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");
            }
19830
            VIR_FREE(str);
19831 19832 19833 19834 19835
            VIR_FREE(hoststr);
            VIR_FREE(gueststr);

            if (rc < 0)
                return -1;
19836 19837
        }
    }
19838 19839 19840 19841 19842 19843
    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");
    }
19844
    if (def->filter) {
19845 19846 19847
        if (virNWFilterFormatParamAttributes(buf, def->filterparams,
                                             def->filter) < 0)
            return -1;
19848
    }
19849

19850
    if (def->tune.sndbuf_specified) {
19851
        virBufferAddLit(buf,   "<tune>\n");
19852 19853 19854
        virBufferAdjustIndent(buf, 2);
        virBufferAsprintf(buf, "<sndbuf>%lu</sndbuf>\n", def->tune.sndbuf);
        virBufferAdjustIndent(buf, -2);
19855
        virBufferAddLit(buf,   "</tune>\n");
19856 19857
    }

19858 19859
    if (def->linkstate) {
        virBufferAsprintf(buf, "<link state='%s'/>\n",
19860
                          virDomainNetInterfaceLinkStateTypeToString(def->linkstate));
19861
    }
19862
    if (virDomainDeviceInfoFormat(buf, &def->info,
19863 19864
                                  flags | VIR_DOMAIN_DEF_FORMAT_ALLOW_BOOT
                                  | VIR_DOMAIN_DEF_FORMAT_ALLOW_ROM) < 0)
19865 19866
        return -1;

19867 19868
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</interface>\n");
19869 19870 19871 19872
    return 0;
}


19873 19874
/* Assumes that "<device" has already been generated, and starts
 * output at " type='type'>". */
19875
static int
19876
virDomainChrSourceDefFormat(virBufferPtr buf,
J
Ján Tomko 已提交
19877
                            virDomainChrDefPtr chr_def,
19878 19879
                            virDomainChrSourceDefPtr def,
                            bool tty_compat,
E
Eric Blake 已提交
19880
                            unsigned int flags)
19881 19882
{
    const char *type = virDomainChrTypeToString(def->type);
J
Ján Tomko 已提交
19883 19884 19885 19886 19887 19888 19889
    size_t nseclabels = 0;
    virSecurityDeviceLabelDefPtr *seclabels = NULL;

    if (chr_def) {
        nseclabels = chr_def->nseclabels;
        seclabels = chr_def->seclabels;
    }
19890

19891
    if (!type) {
19892 19893
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected char type %d"), def->type);
19894
        return -1;
19895 19896
    }

19897
    /* Compat with legacy <console tty='/dev/pts/5'/> syntax */
19898
    virBufferAsprintf(buf, " type='%s'", type);
19899
    if (tty_compat) {
C
Cole Robinson 已提交
19900
        virBufferEscapeString(buf, " tty='%s'",
19901 19902
                              def->data.file.path);
    }
C
Cole Robinson 已提交
19903
    virBufferAddLit(buf, ">\n");
19904

19905
    switch ((virDomainChrType)def->type) {
19906 19907 19908
    case VIR_DOMAIN_CHR_TYPE_NULL:
    case VIR_DOMAIN_CHR_TYPE_VC:
    case VIR_DOMAIN_CHR_TYPE_STDIO:
19909
    case VIR_DOMAIN_CHR_TYPE_SPICEVMC:
19910
    case VIR_DOMAIN_CHR_TYPE_LAST:
19911 19912 19913 19914 19915 19916 19917 19918
        /* 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 ||
19919
            (def->data.file.path &&
19920
             !(flags & VIR_DOMAIN_DEF_FORMAT_INACTIVE))) {
J
Ján Tomko 已提交
19921
            virBufferEscapeString(buf, "<source path='%s'",
19922
                                  def->data.file.path);
J
Ján Tomko 已提交
19923
            virDomainSourceDefFormatSeclabel(buf, nseclabels, seclabels, flags);
19924 19925 19926
        }
        break;

19927
    case VIR_DOMAIN_CHR_TYPE_NMDM:
19928 19929 19930
        virBufferEscapeString(buf, "<source master='%s' ",
                              def->data.nmdm.master);
        virBufferEscapeString(buf, "slave='%s'/>\n", def->data.nmdm.slave);
19931 19932
        break;

19933 19934 19935
    case VIR_DOMAIN_CHR_TYPE_UDP:
        if (def->data.udp.bindService &&
            def->data.udp.bindHost) {
19936 19937 19938 19939
            virBufferEscapeString(buf, "<source mode='bind' host='%s' ",
                                  def->data.udp.bindHost);
            virBufferEscapeString(buf, "service='%s'/>\n",
                                  def->data.udp.bindService);
19940
        } else if (def->data.udp.bindHost) {
19941 19942
            virBufferEscapeString(buf, "<source mode='bind' host='%s'/>\n",
                                  def->data.udp.bindHost);
19943
        } else if (def->data.udp.bindService) {
19944 19945
            virBufferEscapeString(buf, "<source mode='bind' service='%s'/>\n",
                                  def->data.udp.bindService);
19946 19947 19948 19949
        }

        if (def->data.udp.connectService &&
            def->data.udp.connectHost) {
19950 19951 19952 19953
            virBufferEscapeString(buf, "<source mode='connect' host='%s' ",
                                  def->data.udp.connectHost);
            virBufferEscapeString(buf, "service='%s'/>\n",
                                  def->data.udp.connectService);
19954
        } else if (def->data.udp.connectHost) {
19955 19956
            virBufferEscapeString(buf, "<source mode='connect' host='%s'/>\n",
                                  def->data.udp.connectHost);
19957
        } else if (def->data.udp.connectService) {
19958 19959
            virBufferEscapeString(buf, "<source mode='connect' service='%s'/>\n",
                                  def->data.udp.connectService);
19960 19961 19962 19963
        }
        break;

    case VIR_DOMAIN_CHR_TYPE_TCP:
19964 19965 19966 19967
        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);
19968
        virBufferAsprintf(buf, "<protocol type='%s'/>\n",
19969 19970
                          virDomainChrTcpProtocolTypeToString(
                              def->data.tcp.protocol));
19971 19972 19973
        break;

    case VIR_DOMAIN_CHR_TYPE_UNIX:
19974
        virBufferAsprintf(buf, "<source mode='%s'",
19975
                          def->data.nix.listen ? "bind" : "connect");
19976
        virBufferEscapeString(buf, " path='%s'", def->data.nix.path);
J
Ján Tomko 已提交
19977
        virDomainSourceDefFormatSeclabel(buf, nseclabels, seclabels, flags);
19978
        break;
19979 19980

    case VIR_DOMAIN_CHR_TYPE_SPICEPORT:
19981 19982
        virBufferEscapeString(buf, "<source channel='%s'/>\n",
                              def->data.spiceport.channel);
19983 19984
        break;

19985 19986
    }

19987 19988 19989 19990 19991 19992
    return 0;
}

static int
virDomainChrDefFormat(virBufferPtr buf,
                      virDomainChrDefPtr def,
E
Eric Blake 已提交
19993
                      unsigned int flags)
19994 19995 19996 19997 19998 19999 20000 20001 20002
{
    const char *elementName = virDomainChrDeviceTypeToString(def->deviceType);
    const char *targetType = virDomainChrTargetTypeToString(def->deviceType,
                                                            def->targetType);
    bool tty_compat;

    int ret = 0;

    if (!elementName) {
20003 20004 20005
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected char device type %d"),
                       def->deviceType);
20006 20007 20008
        return -1;
    }

20009 20010
    virBufferAsprintf(buf, "<%s", elementName);
    virBufferAdjustIndent(buf, 2);
20011 20012 20013
    tty_compat = (def->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE &&
                  def->target.port == 0 &&
                  def->source.type == VIR_DOMAIN_CHR_TYPE_PTY &&
20014
                  !(flags & VIR_DOMAIN_DEF_FORMAT_INACTIVE) &&
20015
                  def->source.data.file.path);
J
Ján Tomko 已提交
20016
    if (virDomainChrSourceDefFormat(buf, def, &def->source, tty_compat, flags) < 0)
20017 20018
        return -1;

20019
    /* Format <target> block */
20020
    switch (def->deviceType) {
20021 20022
    case VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL: {
        if (!targetType) {
20023 20024
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Could not format channel target type"));
20025 20026
            return -1;
        }
20027
        virBufferAsprintf(buf, "<target type='%s'", targetType);
20028 20029 20030

        switch (def->targetType) {
        case VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_GUESTFWD: {
20031
            int port = virSocketAddrGetPort(def->target.addr);
20032
            if (port < 0) {
20033 20034
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Unable to format guestfwd port"));
20035 20036
                return -1;
            }
20037

20038
            char *addr = virSocketAddrFormat(def->target.addr);
20039
            if (addr == NULL)
20040
                return -1;
20041

20042
            virBufferAsprintf(buf, " address='%s' port='%d'",
20043 20044 20045
                              addr, port);
            VIR_FREE(addr);
            break;
20046 20047
        }

20048
        case VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO:
20049
            if (def->target.name)
20050
                virBufferEscapeString(buf, " name='%s'", def->target.name);
20051 20052

            if (def->state != VIR_DOMAIN_CHR_DEVICE_STATE_DEFAULT &&
20053
                !(flags & VIR_DOMAIN_DEF_PARSE_INACTIVE)) {
20054 20055 20056
                virBufferAsprintf(buf, " state='%s'",
                                  virDomainChrDeviceStateTypeToString(def->state));
            }
20057 20058 20059
            break;
        }

20060 20061
        virBufferAddLit(buf, "/>\n");
        break;
20062
    }
20063

20064
    case VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE:
20065
        virBufferAsprintf(buf,
20066
                          "<target type='%s' port='%d'/>\n",
20067 20068 20069 20070 20071
                          virDomainChrTargetTypeToString(def->deviceType,
                                                         def->targetType),
                          def->target.port);
        break;

G
Guannan Ren 已提交
20072 20073 20074
    case VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL:
        if (def->targetTypeAttr) {
            virBufferAsprintf(buf,
20075
                              "<target type='%s' port='%d'/>\n",
G
Guannan Ren 已提交
20076 20077 20078 20079 20080
                              virDomainChrTargetTypeToString(def->deviceType,
                                                             def->targetType),
                              def->target.port);
            break;
        }
20081
    default:
20082
        virBufferAsprintf(buf, "<target port='%d'/>\n",
20083
                          def->target.port);
20084
        break;
20085
    }
20086

20087
    if (virDomainDeviceInfoNeedsFormat(&def->info, flags)) {
20088 20089 20090
        if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
            return -1;
    }
20091

20092 20093
    virBufferAdjustIndent(buf, -2);
    virBufferAsprintf(buf, "</%s>\n", elementName);
20094

20095
    return ret;
20096 20097
}

E
Eric Blake 已提交
20098 20099 20100
static int
virDomainSmartcardDefFormat(virBufferPtr buf,
                            virDomainSmartcardDefPtr def,
E
Eric Blake 已提交
20101
                            unsigned int flags)
E
Eric Blake 已提交
20102 20103 20104 20105 20106
{
    const char *mode = virDomainSmartcardTypeToString(def->type);
    size_t i;

    if (!mode) {
20107 20108
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected smartcard type %d"), def->type);
E
Eric Blake 已提交
20109 20110 20111
        return -1;
    }

20112 20113
    virBufferAsprintf(buf, "<smartcard mode='%s'", mode);
    virBufferAdjustIndent(buf, 2);
E
Eric Blake 已提交
20114 20115
    switch (def->type) {
    case VIR_DOMAIN_SMARTCARD_TYPE_HOST:
20116
        if (!virDomainDeviceInfoNeedsFormat(&def->info, flags)) {
20117
            virBufferAdjustIndent(buf, -2);
E
Eric Blake 已提交
20118 20119 20120
            virBufferAddLit(buf, "/>\n");
            return 0;
        }
20121
        virBufferAddLit(buf, ">\n");
E
Eric Blake 已提交
20122 20123 20124 20125 20126
        break;

    case VIR_DOMAIN_SMARTCARD_TYPE_HOST_CERTIFICATES:
        virBufferAddLit(buf, ">\n");
        for (i = 0; i < VIR_DOMAIN_SMARTCARD_NUM_CERTIFICATES; i++)
20127
            virBufferEscapeString(buf, "<certificate>%s</certificate>\n",
E
Eric Blake 已提交
20128
                                  def->data.cert.file[i]);
20129
        virBufferEscapeString(buf, "<database>%s</database>\n",
20130
                              def->data.cert.database);
E
Eric Blake 已提交
20131 20132 20133
        break;

    case VIR_DOMAIN_SMARTCARD_TYPE_PASSTHROUGH:
J
Ján Tomko 已提交
20134
        if (virDomainChrSourceDefFormat(buf, NULL, &def->data.passthru, false,
E
Eric Blake 已提交
20135 20136 20137 20138 20139
                                        flags) < 0)
            return -1;
        break;

    default:
20140 20141
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected smartcard type %d"), def->type);
E
Eric Blake 已提交
20142 20143 20144 20145
        return -1;
    }
    if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
        return -1;
20146 20147
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</smartcard>\n");
E
Eric Blake 已提交
20148 20149 20150
    return 0;
}

20151 20152 20153 20154 20155 20156 20157
static int
virDomainSoundCodecDefFormat(virBufferPtr buf,
                             virDomainSoundCodecDefPtr def)
{
    const char *type = virDomainSoundCodecTypeToString(def->type);

    if (!type) {
20158 20159
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected codec type %d"), def->type);
20160 20161 20162
        return -1;
    }

20163
    virBufferAsprintf(buf, "<codec type='%s'/>\n",  type);
20164 20165 20166 20167

    return 0;
}

20168 20169 20170 20171 20172
static int
virDomainTPMDefFormat(virBufferPtr buf,
                      virDomainTPMDefPtr def,
                      unsigned int flags)
{
20173
    virBufferAsprintf(buf, "<tpm model='%s'>\n",
20174
                      virDomainTPMModelTypeToString(def->model));
20175 20176
    virBufferAdjustIndent(buf, 2);
    virBufferAsprintf(buf, "<backend type='%s'>\n",
20177
                      virDomainTPMBackendTypeToString(def->type));
20178
    virBufferAdjustIndent(buf, 2);
20179 20180 20181

    switch (def->type) {
    case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH:
20182
        virBufferEscapeString(buf, "<device path='%s'/>\n",
20183 20184 20185 20186 20187 20188
                              def->data.passthrough.source.data.file.path);
        break;
    case VIR_DOMAIN_TPM_TYPE_LAST:
        break;
    }

20189 20190
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</backend>\n");
20191

20192
    if (virDomainDeviceInfoNeedsFormat(&def->info, flags)) {
20193 20194 20195 20196
        if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
            return -1;
    }

20197 20198
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</tpm>\n");
20199 20200 20201 20202 20203

    return 0;
}


20204
static int
20205
virDomainSoundDefFormat(virBufferPtr buf,
D
Daniel P. Berrange 已提交
20206
                        virDomainSoundDefPtr def,
E
Eric Blake 已提交
20207
                        unsigned int flags)
20208 20209
{
    const char *model = virDomainSoundModelTypeToString(def->model);
20210
    bool children = false;
20211
    size_t i;
20212 20213

    if (!model) {
20214 20215
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected sound model %d"), def->model);
20216 20217 20218
        return -1;
    }

20219
    virBufferAsprintf(buf, "<sound model='%s'",  model);
20220

20221 20222 20223
    for (i = 0; i < def->ncodecs; i++) {
        if (!children) {
            virBufferAddLit(buf, ">\n");
20224
            virBufferAdjustIndent(buf, 2);
20225 20226 20227 20228 20229
            children = true;
        }
        virDomainSoundCodecDefFormat(buf, def->codecs[i]);
    }

20230
    if (virDomainDeviceInfoNeedsFormat(&def->info, flags)) {
20231 20232
        if (!children) {
            virBufferAddLit(buf, ">\n");
20233
            virBufferAdjustIndent(buf, 2);
20234 20235
            children = true;
        }
D
Daniel P. Berrange 已提交
20236
        if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
20237
            return -1;
20238 20239 20240
    }

    if (children) {
20241 20242
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</sound>\n");
20243 20244 20245 20246
    } else {
        virBufferAddLit(buf, "/>\n");
    }

20247 20248 20249
    return 0;
}

20250

20251 20252 20253
static int
virDomainMemballoonDefFormat(virBufferPtr buf,
                             virDomainMemballoonDefPtr def,
E
Eric Blake 已提交
20254
                             unsigned int flags)
20255 20256
{
    const char *model = virDomainMemballoonModelTypeToString(def->model);
20257 20258
    virBuffer childrenBuf = VIR_BUFFER_INITIALIZER;
    int indent = virBufferGetIndent(buf, false);
20259 20260

    if (!model) {
20261 20262
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected memballoon model %d"), def->model);
20263 20264 20265
        return -1;
    }

20266
    virBufferAsprintf(buf, "<memballoon model='%s'", model);
20267
    virBufferAdjustIndent(&childrenBuf, indent + 2);
20268

20269
    if (def->period)
20270
        virBufferAsprintf(&childrenBuf, "<stats period='%i'/>\n", def->period);
20271

20272 20273 20274 20275
    if (virDomainDeviceInfoNeedsFormat(&def->info, flags) &&
        virDomainDeviceInfoFormat(&childrenBuf, &def->info, flags) < 0) {
        virBufferFreeAndReset(&childrenBuf);
        return -1;
20276 20277
    }

20278
    if (!virBufferUse(&childrenBuf)) {
20279
        virBufferAddLit(buf, "/>\n");
20280 20281 20282
    } else {
        virBufferAddLit(buf, ">\n");
        virBufferAddBuffer(buf, &childrenBuf);
20283
        virBufferAddLit(buf, "</memballoon>\n");
20284
    }
20285

20286 20287 20288
    return 0;
}

L
Li Zhang 已提交
20289 20290 20291 20292 20293
static int
virDomainNVRAMDefFormat(virBufferPtr buf,
                        virDomainNVRAMDefPtr def,
                        unsigned int flags)
{
20294 20295
    virBufferAddLit(buf, "<nvram>\n");
    virBufferAdjustIndent(buf, 2);
20296
    if (virDomainDeviceInfoNeedsFormat(&def->info, flags) &&
L
Li Zhang 已提交
20297 20298 20299
        virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
        return -1;

20300 20301
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</nvram>\n");
L
Li Zhang 已提交
20302 20303 20304 20305

    return 0;
}

20306

R
Richard Jones 已提交
20307
static int
20308
virDomainWatchdogDefFormat(virBufferPtr buf,
D
Daniel P. Berrange 已提交
20309
                           virDomainWatchdogDefPtr def,
E
Eric Blake 已提交
20310
                           unsigned int flags)
R
Richard Jones 已提交
20311
{
20312 20313
    const char *model = virDomainWatchdogModelTypeToString(def->model);
    const char *action = virDomainWatchdogActionTypeToString(def->action);
R
Richard Jones 已提交
20314 20315

    if (!model) {
20316 20317
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected watchdog model %d"), def->model);
R
Richard Jones 已提交
20318 20319 20320 20321
        return -1;
    }

    if (!action) {
20322 20323
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected watchdog action %d"), def->action);
R
Richard Jones 已提交
20324 20325 20326
        return -1;
    }

20327
    virBufferAsprintf(buf, "<watchdog model='%s' action='%s'",
R
Richard Jones 已提交
20328 20329
                      model, action);

20330
    if (virDomainDeviceInfoNeedsFormat(&def->info, flags)) {
20331
        virBufferAddLit(buf, ">\n");
20332
        virBufferAdjustIndent(buf, 2);
D
Daniel P. Berrange 已提交
20333
        if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
20334
            return -1;
20335 20336
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</watchdog>\n");
20337 20338 20339 20340
    } else {
        virBufferAddLit(buf, "/>\n");
    }

R
Richard Jones 已提交
20341 20342 20343
    return 0;
}

H
Hu Tao 已提交
20344
static int virDomainPanicDefFormat(virBufferPtr buf,
20345
                                   virDomainPanicDefPtr def)
H
Hu Tao 已提交
20346
{
20347 20348
    virBuffer childrenBuf = VIR_BUFFER_INITIALIZER;
    int indent = virBufferGetIndent(buf, false);
H
Hu Tao 已提交
20349

20350
    virBufferAddLit(buf, "<panic");
20351 20352 20353 20354 20355

    if (def->model)
        virBufferAsprintf(buf, " model='%s'",
                          virDomainPanicModelTypeToString(def->model));

20356 20357 20358 20359 20360 20361 20362 20363 20364 20365 20366
    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 已提交
20367 20368
    return 0;
}
R
Richard Jones 已提交
20369

20370 20371 20372 20373 20374
static int
virDomainShmemDefFormat(virBufferPtr buf,
                        virDomainShmemDefPtr def,
                        unsigned int flags)
{
M
Martin Kletzander 已提交
20375
    virBufferEscapeString(buf, "<shmem name='%s'", def->name);
20376 20377 20378 20379

    if (!def->size &&
        !def->server.enabled &&
        !def->msi.enabled &&
20380
        !virDomainDeviceInfoNeedsFormat(&def->info, flags)) {
20381 20382 20383 20384 20385 20386 20387 20388 20389
        virBufferAddLit(buf, "/>\n");
        return 0;
    } else {
        virBufferAddLit(buf, ">\n");
    }

    virBufferAdjustIndent(buf, 2);

    if (def->size)
M
Martin Kletzander 已提交
20390
        virBufferAsprintf(buf, "<size unit='M'>%llu</size>\n", def->size >> 20);
20391 20392 20393

    if (def->server.enabled) {
        virBufferAddLit(buf, "<server");
20394
        virBufferEscapeString(buf, " path='%s'", def->server.chr.data.nix.path);
20395 20396 20397 20398 20399 20400 20401 20402 20403 20404 20405 20406 20407 20408 20409 20410 20411 20412 20413 20414 20415 20416
        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;
}

20417 20418 20419 20420 20421 20422 20423 20424
static int
virDomainRNGDefFormat(virBufferPtr buf,
                      virDomainRNGDefPtr def,
                      unsigned int flags)
{
    const char *model = virDomainRNGModelTypeToString(def->model);
    const char *backend = virDomainRNGBackendTypeToString(def->backend);

20425 20426
    virBufferAsprintf(buf, "<rng model='%s'>\n", model);
    virBufferAdjustIndent(buf, 2);
20427
    if (def->rate) {
20428
        virBufferAsprintf(buf, "<rate bytes='%u'", def->rate);
20429 20430 20431 20432
        if (def->period)
            virBufferAsprintf(buf, " period='%u'", def->period);
        virBufferAddLit(buf, "/>\n");
    }
20433
    virBufferAsprintf(buf, "<backend model='%s'", backend);
20434

20435
    switch ((virDomainRNGBackend) def->backend) {
20436
    case VIR_DOMAIN_RNG_BACKEND_RANDOM:
20437
        virBufferEscapeString(buf, ">%s</backend>\n", def->source.file);
20438 20439 20440 20441
        break;

    case VIR_DOMAIN_RNG_BACKEND_EGD:
        virBufferAdjustIndent(buf, 2);
J
Ján Tomko 已提交
20442
        if (virDomainChrSourceDefFormat(buf, NULL, def->source.chardev,
20443 20444 20445
                                        false, flags) < 0)
            return -1;
        virBufferAdjustIndent(buf, -2);
20446
        virBufferAddLit(buf, "</backend>\n");
20447 20448 20449 20450 20451

    case VIR_DOMAIN_RNG_BACKEND_LAST:
        break;
    }

20452
    if (virDomainDeviceInfoNeedsFormat(&def->info, flags)) {
20453 20454 20455 20456
        if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
            return -1;
    }

20457 20458
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</rng>\n");
20459 20460 20461 20462 20463 20464 20465 20466 20467
    return 0;
}

void
virDomainRNGDefFree(virDomainRNGDefPtr def)
{
    if (!def)
        return;

20468
    switch ((virDomainRNGBackend) def->backend) {
20469 20470 20471 20472 20473 20474 20475 20476 20477 20478
    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 已提交
20479
    virDomainDeviceInfoClear(&def->info);
20480 20481 20482
    VIR_FREE(def);
}

20483 20484 20485 20486 20487 20488 20489 20490 20491 20492 20493 20494 20495 20496 20497 20498 20499 20500 20501 20502 20503 20504 20505 20506 20507 20508 20509 20510 20511 20512 20513 20514 20515 20516 20517 20518 20519 20520 20521 20522 20523 20524 20525 20526

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);
20527 20528
    if (def->targetNode >= 0)
        virBufferAsprintf(buf, "<node>%d</node>\n", def->targetNode);
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 20557 20558

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

20559 20560 20561 20562
static void
virDomainVideoAccelDefFormat(virBufferPtr buf,
                             virDomainVideoAccelDefPtr def)
{
20563 20564 20565 20566 20567 20568 20569 20570 20571
    virBufferAddLit(buf, "<acceleration");
    if (def->accel3d) {
        virBufferAsprintf(buf, " accel3d='%s'",
                          virTristateBoolTypeToString(def->accel3d));
    }
    if (def->accel2d) {
        virBufferAsprintf(buf, " accel2d='%s'",
                          virTristateBoolTypeToString(def->accel2d));
    }
20572 20573 20574 20575
    virBufferAddLit(buf, "/>\n");
}


20576
static int
20577
virDomainVideoDefFormat(virBufferPtr buf,
D
Daniel P. Berrange 已提交
20578
                        virDomainVideoDefPtr def,
E
Eric Blake 已提交
20579
                        unsigned int flags)
20580 20581 20582 20583
{
    const char *model = virDomainVideoTypeToString(def->type);

    if (!model) {
20584 20585
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected video model %d"), def->type);
20586 20587 20588
        return -1;
    }

20589 20590 20591
    virBufferAddLit(buf, "<video>\n");
    virBufferAdjustIndent(buf, 2);
    virBufferAsprintf(buf, "<model type='%s'",
20592
                      model);
20593 20594
    if (def->ram)
        virBufferAsprintf(buf, " ram='%u'", def->ram);
20595
    if (def->vram)
20596
        virBufferAsprintf(buf, " vram='%u'", def->vram);
20597 20598
    if (def->vgamem)
        virBufferAsprintf(buf, " vgamem='%u'", def->vgamem);
20599
    if (def->heads)
20600
        virBufferAsprintf(buf, " heads='%u'", def->heads);
20601 20602
    if (def->primary)
        virBufferAddLit(buf, " primary='yes'");
20603 20604
    if (def->accel) {
        virBufferAddLit(buf, ">\n");
20605
        virBufferAdjustIndent(buf, 2);
20606
        virDomainVideoAccelDefFormat(buf, def->accel);
20607 20608
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</model>\n");
20609 20610 20611 20612
    } else {
        virBufferAddLit(buf, "/>\n");
    }

D
Daniel P. Berrange 已提交
20613
    if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
20614 20615
        return -1;

20616 20617
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</video>\n");
20618 20619 20620
    return 0;
}

20621
static int
20622
virDomainInputDefFormat(virBufferPtr buf,
20623
                        virDomainInputDefPtr def,
E
Eric Blake 已提交
20624
                        unsigned int flags)
20625 20626 20627 20628 20629
{
    const char *type = virDomainInputTypeToString(def->type);
    const char *bus = virDomainInputBusTypeToString(def->bus);

    if (!type) {
20630 20631
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected input type %d"), def->type);
20632 20633 20634
        return -1;
    }
    if (!bus) {
20635 20636
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected input bus type %d"), def->bus);
20637 20638 20639
        return -1;
    }

20640
    virBufferAsprintf(buf, "<input type='%s' bus='%s'",
20641 20642
                      type, bus);

20643 20644
    if (virDomainDeviceInfoNeedsFormat(&def->info, flags) ||
        def->type == VIR_DOMAIN_INPUT_TYPE_PASSTHROUGH) {
20645
        virBufferAddLit(buf, ">\n");
20646
        virBufferAdjustIndent(buf, 2);
20647
        virBufferEscapeString(buf, "<source evdev='%s'/>\n", def->source.evdev);
20648 20649
        if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
            return -1;
20650 20651
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</input>\n");
20652 20653 20654 20655
    } else {
        virBufferAddLit(buf, "/>\n");
    }

20656 20657 20658 20659
    return 0;
}


20660 20661 20662 20663 20664 20665 20666
static int
virDomainTimerDefFormat(virBufferPtr buf,
                        virDomainTimerDefPtr def)
{
    const char *name = virDomainTimerNameTypeToString(def->name);

    if (!name) {
20667 20668
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected timer name %d"), def->name);
20669 20670
        return -1;
    }
20671
    virBufferAsprintf(buf, "<timer name='%s'", name);
20672 20673 20674 20675 20676 20677 20678 20679 20680 20681 20682

    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) {
20683 20684 20685
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected timer tickpolicy %d"),
                           def->tickpolicy);
20686 20687
            return -1;
        }
20688
        virBufferAsprintf(buf, " tickpolicy='%s'", tickpolicy);
20689 20690 20691 20692
    }

    if ((def->name == VIR_DOMAIN_TIMER_NAME_PLATFORM)
        || (def->name == VIR_DOMAIN_TIMER_NAME_RTC)) {
20693 20694 20695 20696
        if (def->track != -1) {
            const char *track
                = virDomainTimerTrackTypeToString(def->track);
            if (!track) {
20697 20698 20699
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unexpected timer track %d"),
                               def->track);
20700 20701
                return -1;
            }
20702
            virBufferAsprintf(buf, " track='%s'", track);
20703 20704 20705 20706
        }
    }

    if (def->name == VIR_DOMAIN_TIMER_NAME_TSC) {
20707
        if (def->frequency > 0)
20708
            virBufferAsprintf(buf, " frequency='%lu'", def->frequency);
20709 20710 20711 20712 20713

        if (def->mode != -1) {
            const char *mode
                = virDomainTimerModeTypeToString(def->mode);
            if (!mode) {
20714 20715 20716
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unexpected timer mode %d"),
                               def->mode);
20717 20718
                return -1;
            }
20719
            virBufferAsprintf(buf, " mode='%s'", mode);
20720 20721 20722
        }
    }

E
Eric Blake 已提交
20723 20724
    if (def->catchup.threshold == 0 && def->catchup.slew == 0 &&
        def->catchup.limit == 0) {
20725 20726
        virBufferAddLit(buf, "/>\n");
    } else {
20727
        virBufferAddLit(buf, ">\n");
20728 20729
        virBufferAdjustIndent(buf, 2);
        virBufferAddLit(buf, "<catchup");
20730
        if (def->catchup.threshold > 0)
20731
            virBufferAsprintf(buf, " threshold='%lu'", def->catchup.threshold);
20732
        if (def->catchup.slew > 0)
20733
            virBufferAsprintf(buf, " slew='%lu'", def->catchup.slew);
20734
        if (def->catchup.limit > 0)
20735
            virBufferAsprintf(buf, " limit='%lu'", def->catchup.limit);
20736
        virBufferAddLit(buf, "/>\n");
20737 20738
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</timer>\n");
20739
    }
20740 20741 20742 20743

    return 0;
}

20744 20745 20746 20747 20748 20749 20750 20751
static void
virDomainGraphicsAuthDefFormatAttr(virBufferPtr buf,
                                   virDomainGraphicsAuthDefPtr def,
                                   unsigned int flags)
{
    if (!def->passwd)
        return;

20752
    if (flags & VIR_DOMAIN_DEF_FORMAT_SECURE)
20753 20754 20755 20756 20757 20758 20759 20760
        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);
20761
        virBufferAsprintf(buf, " passwdValidTo='%s'", strbuf);
20762
    }
20763 20764 20765 20766

    if (def->connected)
        virBufferEscapeString(buf, " connected='%s'",
                              virDomainGraphicsAuthConnectedTypeToString(def->connected));
20767 20768
}

20769 20770 20771 20772 20773 20774

static void
virDomainGraphicsListenDefFormat(virBufferPtr buf,
                                 virDomainGraphicsListenDefPtr def,
                                 unsigned int flags)
{
20775 20776
    /* If generating migratable XML, skip listen address
     * dragged in from config file */
20777
    if ((flags & VIR_DOMAIN_DEF_FORMAT_MIGRATABLE) && def->fromConfig)
20778 20779
        return;

20780
    virBufferAddLit(buf, "<listen");
20781 20782 20783 20784 20785 20786
    if (def->type) {
        virBufferAsprintf(buf, " type='%s'",
                          virDomainGraphicsListenTypeToString(def->type));
    }

    if (def->address &&
E
Eric Blake 已提交
20787 20788
        (def->type == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS ||
         (def->type == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NETWORK &&
20789
          !(flags & VIR_DOMAIN_DEF_FORMAT_INACTIVE)))) {
20790 20791 20792 20793 20794 20795 20796
        /* 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)) {
20797
        virBufferEscapeString(buf, " network='%s'", def->network);
20798 20799
    }

20800
    if (flags & VIR_DOMAIN_DEF_FORMAT_STATUS)
20801 20802
        virBufferAsprintf(buf, " fromConfig='%d'", def->fromConfig);

20803 20804 20805 20806
    virBufferAddLit(buf, "/>\n");
}


20807
static int
20808
virDomainGraphicsDefFormat(virBufferPtr buf,
20809
                           virDomainGraphicsDefPtr def,
E
Eric Blake 已提交
20810
                           unsigned int flags)
20811 20812
{
    const char *type = virDomainGraphicsTypeToString(def->type);
20813
    const char *listenAddr = NULL;
20814
    bool children = false;
20815
    size_t i;
20816 20817

    if (!type) {
20818 20819
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected net type %d"), def->type);
20820 20821 20822
        return -1;
    }

20823 20824 20825 20826
    /* 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.
    */
20827
    for (i = 0; i < def->nListens; i++) {
20828 20829 20830 20831
        if (flags & VIR_DOMAIN_DEF_FORMAT_MIGRATABLE &&
            def->listens[i].fromConfig)
            continue;

20832 20833 20834 20835 20836 20837 20838
        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;
20839 20840
    }

20841
    virBufferAsprintf(buf, "<graphics type='%s'", type);
20842 20843 20844

    switch (def->type) {
    case VIR_DOMAIN_GRAPHICS_TYPE_VNC:
20845
        if (def->data.vnc.socket) {
20846
            virBufferEscapeString(buf, " socket='%s'", def->data.vnc.socket);
20847 20848
        } else {
            if (def->data.vnc.port &&
20849
                (!def->data.vnc.autoport || !(flags & VIR_DOMAIN_DEF_FORMAT_INACTIVE)))
20850
                virBufferAsprintf(buf, " port='%d'",
20851 20852 20853
                                  def->data.vnc.port);
            else if (def->data.vnc.autoport)
                virBufferAddLit(buf, " port='-1'");
20854

20855
            virBufferAsprintf(buf, " autoport='%s'",
20856
                              def->data.vnc.autoport ? "yes" : "no");
20857

M
Martin Kletzander 已提交
20858 20859 20860
            if (def->data.vnc.websocket)
                virBufferAsprintf(buf, " websocket='%d'", def->data.vnc.websocket);

20861 20862
            if (listenAddr)
                virBufferAsprintf(buf, " listen='%s'", listenAddr);
20863
        }
20864 20865 20866 20867 20868

        if (def->data.vnc.keymap)
            virBufferEscapeString(buf, " keymap='%s'",
                                  def->data.vnc.keymap);

20869 20870 20871 20872 20873
        if (def->data.vnc.sharePolicy)
            virBufferAsprintf(buf, " sharePolicy='%s'",
                              virDomainGraphicsVNCSharePolicyTypeToString(
                              def->data.vnc.sharePolicy));

20874
        virDomainGraphicsAuthDefFormatAttr(buf, &def->data.vnc.auth, flags);
20875 20876 20877 20878 20879 20880 20881 20882 20883 20884
        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);
20885 20886 20887
        if (def->data.sdl.fullscreen)
            virBufferAddLit(buf, " fullscreen='yes'");

20888
        break;
20889 20890 20891

    case VIR_DOMAIN_GRAPHICS_TYPE_RDP:
        if (def->data.rdp.port)
20892
            virBufferAsprintf(buf, " port='%d'",
20893 20894 20895 20896 20897
                              def->data.rdp.port);
        else if (def->data.rdp.autoport)
            virBufferAddLit(buf, " port='0'");

        if (def->data.rdp.autoport)
20898
            virBufferAddLit(buf, " autoport='yes'");
20899 20900

        if (def->data.rdp.replaceUser)
20901
            virBufferAddLit(buf, " replaceUser='yes'");
20902 20903

        if (def->data.rdp.multiUser)
20904
            virBufferAddLit(buf, " multiUser='yes'");
20905

20906 20907
        if (listenAddr)
            virBufferAsprintf(buf, " listen='%s'", listenAddr);
20908 20909 20910 20911 20912 20913 20914 20915 20916 20917 20918 20919 20920

        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;

20921 20922
    case VIR_DOMAIN_GRAPHICS_TYPE_SPICE:
        if (def->data.spice.port)
20923
            virBufferAsprintf(buf, " port='%d'",
20924 20925 20926
                              def->data.spice.port);

        if (def->data.spice.tlsPort)
20927
            virBufferAsprintf(buf, " tlsPort='%d'",
20928 20929
                              def->data.spice.tlsPort);

20930
        virBufferAsprintf(buf, " autoport='%s'",
20931 20932
                          def->data.spice.autoport ? "yes" : "no");

20933 20934
        if (listenAddr)
            virBufferAsprintf(buf, " listen='%s'", listenAddr);
20935 20936 20937 20938 20939

        if (def->data.spice.keymap)
            virBufferEscapeString(buf, " keymap='%s'",
                                  def->data.spice.keymap);

20940 20941 20942 20943
        if (def->data.spice.defaultMode != VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_ANY)
            virBufferAsprintf(buf, " defaultMode='%s'",
              virDomainGraphicsSpiceChannelModeTypeToString(def->data.spice.defaultMode));

20944
        virDomainGraphicsAuthDefFormatAttr(buf, &def->data.spice.auth, flags);
20945 20946
        break;

20947 20948
    }

20949 20950 20951 20952
    for (i = 0; i < def->nListens; i++) {
        if (virDomainGraphicsListenGetType(def, i)
            == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NONE)
            continue;
20953
        if (flags & VIR_DOMAIN_DEF_FORMAT_MIGRATABLE &&
20954 20955
            def->listens[i].fromConfig)
            continue;
20956 20957
        if (!children) {
            virBufferAddLit(buf, ">\n");
20958
            virBufferAdjustIndent(buf, 2);
20959
            children = true;
20960 20961 20962 20963
        }
        virDomainGraphicsListenDefFormat(buf, &def->listens[i], flags);
    }

20964
    if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) {
20965
        for (i = 0; i < VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_LAST; i++) {
20966 20967 20968 20969 20970 20971
            int mode = def->data.spice.channels[i];
            if (mode == VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_ANY)
                continue;

            if (!children) {
                virBufferAddLit(buf, ">\n");
20972
                virBufferAdjustIndent(buf, 2);
20973
                children = true;
20974 20975
            }

20976
            virBufferAsprintf(buf, "<channel name='%s' mode='%s'/>\n",
20977 20978 20979
                              virDomainGraphicsSpiceChannelNameTypeToString(i),
                              virDomainGraphicsSpiceChannelModeTypeToString(mode));
        }
20980 20981
        if (!children && (def->data.spice.image || def->data.spice.jpeg ||
                          def->data.spice.zlib || def->data.spice.playback ||
P
Peng Zhou 已提交
20982
                          def->data.spice.streaming || def->data.spice.copypaste ||
20983
                          def->data.spice.mousemode || def->data.spice.filetransfer)) {
20984
            virBufferAddLit(buf, ">\n");
20985
            virBufferAdjustIndent(buf, 2);
20986
            children = true;
20987
        }
20988
        if (def->data.spice.image)
20989
            virBufferAsprintf(buf, "<image compression='%s'/>\n",
20990 20991
                              virDomainGraphicsSpiceImageCompressionTypeToString(def->data.spice.image));
        if (def->data.spice.jpeg)
20992
            virBufferAsprintf(buf, "<jpeg compression='%s'/>\n",
20993 20994
                              virDomainGraphicsSpiceJpegCompressionTypeToString(def->data.spice.jpeg));
        if (def->data.spice.zlib)
20995
            virBufferAsprintf(buf, "<zlib compression='%s'/>\n",
20996 20997
                              virDomainGraphicsSpiceZlibCompressionTypeToString(def->data.spice.zlib));
        if (def->data.spice.playback)
20998
            virBufferAsprintf(buf, "<playback compression='%s'/>\n",
J
Ján Tomko 已提交
20999
                              virTristateSwitchTypeToString(def->data.spice.playback));
21000
        if (def->data.spice.streaming)
21001
            virBufferAsprintf(buf, "<streaming mode='%s'/>\n",
21002
                              virDomainGraphicsSpiceStreamingModeTypeToString(def->data.spice.streaming));
P
Peng Zhou 已提交
21003
        if (def->data.spice.mousemode)
21004
            virBufferAsprintf(buf, "<mouse mode='%s'/>\n",
P
Peng Zhou 已提交
21005
                              virDomainGraphicsSpiceMouseModeTypeToString(def->data.spice.mousemode));
21006
        if (def->data.spice.copypaste)
21007
            virBufferAsprintf(buf, "<clipboard copypaste='%s'/>\n",
J
Ján Tomko 已提交
21008
                              virTristateBoolTypeToString(def->data.spice.copypaste));
21009
        if (def->data.spice.filetransfer)
21010
            virBufferAsprintf(buf, "<filetransfer enable='%s'/>\n",
J
Ján Tomko 已提交
21011
                              virTristateBoolTypeToString(def->data.spice.filetransfer));
21012 21013 21014
    }

    if (children) {
21015 21016
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</graphics>\n");
21017 21018 21019
    } else {
        virBufferAddLit(buf, "/>\n");
    }
21020 21021 21022 21023

    return 0;
}

21024 21025

static int
21026
virDomainHostdevDefFormat(virBufferPtr buf,
D
Daniel P. Berrange 已提交
21027
                          virDomainHostdevDefPtr def,
E
Eric Blake 已提交
21028
                          unsigned int flags)
21029 21030
{
    const char *mode = virDomainHostdevModeTypeToString(def->mode);
21031
    virDomainHostdevSubsysSCSIPtr scsisrc = &def->source.subsys.u.scsi;
21032 21033
    const char *type;

21034
    if (!mode) {
21035 21036
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected hostdev mode %d"), def->mode);
21037 21038 21039
        return -1;
    }

21040 21041 21042 21043 21044 21045 21046 21047 21048 21049
    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;
21050 21051 21052 21053 21054 21055 21056 21057 21058
    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;
21059
    default:
21060
        virReportError(VIR_ERR_INTERNAL_ERROR,
21061
                       _("unexpected hostdev mode %d"), def->mode);
21062 21063 21064
        return -1;
    }

21065
    virBufferAsprintf(buf, "<hostdev mode='%s' type='%s'",
21066
                      mode, type);
O
Osier Yang 已提交
21067 21068
    if (def->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
        virBufferAsprintf(buf, " managed='%s'",
21069
                          def->managed ? "yes" : "no");
O
Osier Yang 已提交
21070

21071 21072
        if (def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI &&
            scsisrc->sgio)
O
Osier Yang 已提交
21073
            virBufferAsprintf(buf, " sgio='%s'",
21074
                              virDomainDeviceSGIOTypeToString(scsisrc->sgio));
21075 21076 21077 21078 21079 21080

        if (def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI &&
            scsisrc->rawio) {
            virBufferAsprintf(buf, " rawio='%s'",
                              virTristateBoolTypeToString(scsisrc->rawio));
        }
O
Osier Yang 已提交
21081 21082
    }
    virBufferAddLit(buf, ">\n");
21083
    virBufferAdjustIndent(buf, 2);
21084

21085 21086 21087 21088 21089
    switch (def->mode) {
    case VIR_DOMAIN_HOSTDEV_MODE_SUBSYS:
        if (virDomainHostdevDefFormatSubsys(buf, def, flags, false) < 0)
            return -1;
        break;
21090 21091 21092 21093
    case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
        if (virDomainHostdevDefFormatCaps(buf, def) < 0)
            return -1;
        break;
21094
    }
O
Osier Yang 已提交
21095 21096 21097

    if (def->readonly)
        virBufferAddLit(buf, "<readonly/>\n");
21098 21099
    if (def->shareable)
        virBufferAddLit(buf, "<shareable/>\n");
21100

21101
    if (virDomainDeviceInfoFormat(buf, def->info,
21102 21103
                                  flags | VIR_DOMAIN_DEF_FORMAT_ALLOW_BOOT
                                  | VIR_DOMAIN_DEF_FORMAT_ALLOW_ROM) < 0)
21104 21105
        return -1;

21106 21107
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</hostdev>\n");
21108 21109 21110 21111

    return 0;
}

21112 21113 21114 21115 21116 21117 21118 21119 21120
static int
virDomainRedirdevDefFormat(virBufferPtr buf,
                           virDomainRedirdevDefPtr def,
                           unsigned int flags)
{
    const char *bus;

    bus = virDomainRedirdevBusTypeToString(def->bus);

21121 21122
    virBufferAsprintf(buf, "<redirdev bus='%s'", bus);
    virBufferAdjustIndent(buf, 2);
J
Ján Tomko 已提交
21123
    if (virDomainChrSourceDefFormat(buf, NULL, &def->source.chr, false, flags) < 0)
21124
        return -1;
21125
    if (virDomainDeviceInfoFormat(buf, &def->info,
21126
                                  flags | VIR_DOMAIN_DEF_FORMAT_ALLOW_BOOT) < 0)
21127
        return -1;
21128 21129
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</redirdev>\n");
21130 21131
    return 0;
}
21132

21133 21134 21135 21136 21137 21138
static int
virDomainRedirFilterDefFormat(virBufferPtr buf,
                              virDomainRedirFilterDefPtr filter)
{
    size_t i;

21139 21140 21141 21142
    /* no need format an empty redirfilter */
    if (filter->nusbdevs == 0)
        return 0;

21143 21144
    virBufferAddLit(buf, "<redirfilter>\n");
    virBufferAdjustIndent(buf, 2);
21145
    for (i = 0; i < filter->nusbdevs; i++) {
21146
        virDomainRedirFilterUSBDevDefPtr usbdev = filter->usbdevs[i];
21147
        virBufferAddLit(buf, "<usbdev");
21148 21149 21150 21151 21152 21153 21154 21155 21156 21157
        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)
21158
            virBufferAsprintf(buf, " version='%d.%02d'",
21159 21160 21161 21162 21163 21164 21165 21166
                                 ((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");

    }
21167 21168
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</redirfilter>\n");
21169 21170 21171
    return 0;
}

M
Marc-André Lureau 已提交
21172 21173
static int
virDomainHubDefFormat(virBufferPtr buf,
21174 21175
                      virDomainHubDefPtr def,
                      unsigned int flags)
M
Marc-André Lureau 已提交
21176 21177 21178 21179
{
    const char *type = virDomainHubTypeToString(def->type);

    if (!type) {
21180 21181
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected hub type %d"), def->type);
M
Marc-André Lureau 已提交
21182 21183 21184
        return -1;
    }

21185
    virBufferAsprintf(buf, "<hub type='%s'", type);
M
Marc-André Lureau 已提交
21186

21187
    if (virDomainDeviceInfoNeedsFormat(&def->info, flags)) {
M
Marc-André Lureau 已提交
21188
        virBufferAddLit(buf, ">\n");
21189
        virBufferAdjustIndent(buf, 2);
M
Marc-André Lureau 已提交
21190 21191
        if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
            return -1;
21192 21193
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</hub>\n");
M
Marc-André Lureau 已提交
21194 21195 21196 21197 21198 21199 21200
    } else {
        virBufferAddLit(buf, "/>\n");
    }

    return 0;
}

21201 21202 21203 21204 21205

static void
virDomainResourceDefFormat(virBufferPtr buf,
                           virDomainResourceDefPtr def)
{
21206 21207 21208 21209 21210
    virBufferAddLit(buf, "<resource>\n");
    virBufferAdjustIndent(buf, 2);
    virBufferEscapeString(buf, "<partition>%s</partition>\n", def->partition);
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</resource>\n");
21211 21212 21213
}


21214 21215 21216 21217 21218 21219 21220 21221 21222 21223 21224 21225 21226 21227 21228 21229 21230 21231 21232 21233 21234 21235 21236 21237 21238 21239 21240 21241 21242 21243 21244 21245 21246 21247 21248 21249 21250 21251 21252 21253 21254 21255 21256 21257 21258 21259 21260
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");
}

21261 21262 21263 21264 21265 21266 21267 21268 21269 21270 21271 21272 21273 21274 21275
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);
21276 21277 21278 21279 21280 21281 21282 21283
    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");
    }
21284
}
21285

21286 21287 21288 21289 21290 21291 21292 21293 21294 21295 21296 21297 21298 21299 21300 21301 21302 21303
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");
}

21304 21305 21306 21307 21308 21309
static bool
virDomainDefHasCapabilitiesFeatures(virDomainDefPtr def)
{
    size_t i;

    for (i = 0; i < VIR_DOMAIN_CAPS_FEATURE_LAST; i++) {
J
Ján Tomko 已提交
21310
        if (def->caps_features[i] != VIR_TRISTATE_SWITCH_ABSENT)
21311 21312 21313 21314 21315 21316
            return true;
    }

    return false;
}

21317 21318 21319
/* This internal version appends to an existing buffer
 * (possibly with auto-indent), rather than flattening
 * to string.
21320 21321
 * Return -1 on failure.  */
int
21322
virDomainDefFormatInternal(virDomainDefPtr def,
21323 21324
                           unsigned int flags,
                           virBufferPtr buf)
21325 21326 21327
{
    unsigned char *uuid;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
21328
    const char *type = NULL;
H
Hu Tao 已提交
21329
    int n;
21330
    size_t i;
21331 21332
    virBuffer childrenBuf = VIR_BUFFER_INITIALIZER;
    int indent;
21333

21334 21335 21336 21337 21338
    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,
21339
                  -1);
21340

21341
    if (!(type = virDomainVirtTypeToString(def->virtType))) {
21342 21343
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected domain type %d"), def->virtType);
21344
        goto error;
21345 21346
    }

21347
    if (def->id == -1)
21348
        flags |= VIR_DOMAIN_DEF_FORMAT_INACTIVE;
21349

21350
    virBufferAsprintf(buf, "<domain type='%s'", type);
21351
    if (!(flags & VIR_DOMAIN_DEF_FORMAT_INACTIVE))
21352
        virBufferAsprintf(buf, " id='%d'", def->id);
21353
    if (def->namespaceData && def->ns.href)
21354 21355
        virBufferAsprintf(buf, " %s", (def->ns.href)());
    virBufferAddLit(buf, ">\n");
21356
    virBufferAdjustIndent(buf, 2);
21357

21358
    virBufferEscapeString(buf, "<name>%s</name>\n", def->name);
21359 21360 21361

    uuid = def->uuid;
    virUUIDFormat(uuid, uuidstr);
21362
    virBufferAsprintf(buf, "<uuid>%s</uuid>\n", uuidstr);
21363

21364
    virBufferEscapeString(buf, "<title>%s</title>\n", def->title);
21365

21366
    virBufferEscapeString(buf, "<description>%s</description>\n",
21367
                          def->description);
21368

21369 21370 21371 21372 21373 21374 21375 21376 21377 21378 21379 21380 21381
    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,
21382
                        virBufferGetIndent(buf, false) / 2, 1) < 0) {
21383 21384
            xmlBufferFree(xmlbuf);
            xmlIndentTreeOutput = oldIndentTreeOutput;
21385
            goto error;
21386
        }
21387
        virBufferAsprintf(buf, "%s\n", (char *) xmlBufferContent(xmlbuf));
21388 21389 21390 21391
        xmlBufferFree(xmlbuf);
        xmlIndentTreeOutput = oldIndentTreeOutput;
    }

21392
    if (virDomainDefHasMemoryHotplug(def)) {
21393 21394 21395 21396 21397
        virBufferAsprintf(buf,
                          "<maxMemory slots='%u' unit='KiB'>%llu</maxMemory>\n",
                          def->mem.memory_slots, def->mem.max_memory);
    }

21398
    virBufferAddLit(buf, "<memory");
21399 21400
    if (def->mem.dump_core)
        virBufferAsprintf(buf, " dumpCore='%s'",
J
Ján Tomko 已提交
21401
                          virTristateSwitchTypeToString(def->mem.dump_core));
21402
    virBufferAsprintf(buf, " unit='KiB'>%llu</memory>\n",
21403
                      virDomainDefGetMemoryActual(def));
21404

21405
    virBufferAsprintf(buf, "<currentMemory unit='KiB'>%llu</currentMemory>\n",
21406 21407
                      def->mem.cur_balloon);

21408 21409 21410 21411 21412 21413
    /* start format blkiotune */
    indent = virBufferGetIndent(buf, false);
    virBufferAdjustIndent(&childrenBuf, indent + 2);
    if (def->blkio.weight)
        virBufferAsprintf(&childrenBuf, "<weight>%u</weight>\n",
                          def->blkio.weight);
21414

21415 21416
    for (n = 0; n < def->blkio.ndevices; n++) {
        virBlkioDevicePtr dev = &def->blkio.devices[n];
21417

21418 21419 21420 21421 21422 21423 21424 21425 21426 21427 21428 21429 21430 21431 21432 21433 21434 21435 21436 21437 21438 21439 21440 21441 21442 21443 21444 21445
        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);
21446
        virBufferAddLit(buf, "</blkiotune>\n");
21447
    }
21448
    virBufferFreeAndReset(&childrenBuf);
21449

21450
    /* add memtune only if there are any */
21451 21452 21453
    if (virMemoryLimitIsSet(def->mem.hard_limit) ||
        virMemoryLimitIsSet(def->mem.soft_limit) ||
        virMemoryLimitIsSet(def->mem.swap_hard_limit) ||
21454
        def->mem.min_guarantee) {
21455 21456
        virBufferAddLit(buf, "<memtune>\n");
        virBufferAdjustIndent(buf, 2);
21457
        if (virMemoryLimitIsSet(def->mem.hard_limit)) {
21458
            virBufferAsprintf(buf, "<hard_limit unit='KiB'>"
21459 21460
                              "%llu</hard_limit>\n", def->mem.hard_limit);
        }
21461
        if (virMemoryLimitIsSet(def->mem.soft_limit)) {
21462
            virBufferAsprintf(buf, "<soft_limit unit='KiB'>"
21463 21464 21465
                              "%llu</soft_limit>\n", def->mem.soft_limit);
        }
        if (def->mem.min_guarantee) {
21466
            virBufferAsprintf(buf, "<min_guarantee unit='KiB'>"
21467 21468
                              "%llu</min_guarantee>\n", def->mem.min_guarantee);
        }
21469
        if (virMemoryLimitIsSet(def->mem.swap_hard_limit)) {
21470
            virBufferAsprintf(buf, "<swap_hard_limit unit='KiB'>"
21471 21472
                              "%llu</swap_hard_limit>\n", def->mem.swap_hard_limit);
        }
21473 21474
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</memtune>\n");
21475
    }
21476

21477
    if (def->mem.nhugepages || def->mem.nosharepages || def->mem.locked) {
21478 21479
        virBufferAddLit(buf, "<memoryBacking>\n");
        virBufferAdjustIndent(buf, 2);
21480 21481
        if (def->mem.nhugepages)
            virDomainHugepagesFormat(buf, def->mem.hugepages, def->mem.nhugepages);
21482
        if (def->mem.nosharepages)
21483
            virBufferAddLit(buf, "<nosharepages/>\n");
21484
        if (def->mem.locked)
21485 21486 21487
            virBufferAddLit(buf, "<locked/>\n");
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</memoryBacking>\n");
21488
    }
21489

21490
    virBufferAddLit(buf, "<vcpu");
21491 21492
    virBufferAsprintf(buf, " placement='%s'",
                      virDomainCpuPlacementModeTypeToString(def->placement_mode));
H
Hu Tao 已提交
21493 21494

    if (def->cpumask && !virBitmapIsAllSet(def->cpumask)) {
21495
        char *cpumask = NULL;
H
Hu Tao 已提交
21496
        if ((cpumask = virBitmapFormat(def->cpumask)) == NULL)
21497
            goto error;
21498
        virBufferAsprintf(buf, " cpuset='%s'", cpumask);
21499 21500
        VIR_FREE(cpumask);
    }
E
Eric Blake 已提交
21501
    if (def->vcpus != def->maxvcpus)
21502 21503
        virBufferAsprintf(buf, " current='%u'", def->vcpus);
    virBufferAsprintf(buf, ">%u</vcpu>\n", def->maxvcpus);
21504

21505
    if (def->niothreadids > 0) {
21506 21507 21508 21509 21510 21511 21512 21513 21514 21515 21516 21517 21518 21519 21520 21521 21522 21523 21524 21525
        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");
        }
    }
21526

21527 21528 21529
    /* start format cputune */
    indent = virBufferGetIndent(buf, false);
    virBufferAdjustIndent(&childrenBuf, indent + 2);
21530
    if (def->cputune.sharesSpecified)
21531
        virBufferAsprintf(&childrenBuf, "<shares>%lu</shares>\n",
21532
                          def->cputune.shares);
21533
    if (def->cputune.period)
21534
        virBufferAsprintf(&childrenBuf, "<period>%llu</period>\n",
21535 21536
                          def->cputune.period);
    if (def->cputune.quota)
21537
        virBufferAsprintf(&childrenBuf, "<quota>%lld</quota>\n",
21538
                          def->cputune.quota);
21539 21540

    if (def->cputune.emulator_period)
21541
        virBufferAsprintf(&childrenBuf, "<emulator_period>%llu"
21542 21543 21544 21545
                          "</emulator_period>\n",
                          def->cputune.emulator_period);

    if (def->cputune.emulator_quota)
21546
        virBufferAsprintf(&childrenBuf, "<emulator_quota>%lld"
21547 21548 21549
                          "</emulator_quota>\n",
                          def->cputune.emulator_quota);

21550
    for (i = 0; i < def->cputune.nvcpupin; i++) {
P
Peter Krempa 已提交
21551 21552
        char *cpumask;
        /* Ignore the vcpupin which inherit from "cpuset of "<vcpu>." */
21553
        if (virBitmapEqual(def->cpumask, def->cputune.vcpupin[i]->cpumask))
21554
            continue;
21555

21556
        virBufferAsprintf(&childrenBuf, "<vcpupin vcpu='%u' ",
21557
                          def->cputune.vcpupin[i]->id);
21558

21559
        if (!(cpumask = virBitmapFormat(def->cputune.vcpupin[i]->cpumask)))
21560
            goto error;
21561

21562
        virBufferAsprintf(&childrenBuf, "cpuset='%s'/>\n", cpumask);
21563
        VIR_FREE(cpumask);
21564 21565
    }

T
Tang Chen 已提交
21566
    if (def->cputune.emulatorpin) {
P
Peter Krempa 已提交
21567
        char *cpumask;
21568
        virBufferAddLit(&childrenBuf, "<emulatorpin ");
T
Tang Chen 已提交
21569

21570
        if (!(cpumask = virBitmapFormat(def->cputune.emulatorpin)))
21571
            goto error;
T
Tang Chen 已提交
21572

21573
        virBufferAsprintf(&childrenBuf, "cpuset='%s'/>\n", cpumask);
T
Tang Chen 已提交
21574 21575
        VIR_FREE(cpumask);
    }
21576

21577
    for (i = 0; i < def->niothreadids; i++) {
21578
        char *cpumask;
21579 21580 21581

        /* Ignore iothreadids with no cpumask */
        if (!def->iothreadids[i]->cpumask)
21582 21583
            continue;

21584
        virBufferAsprintf(&childrenBuf, "<iothreadpin iothread='%u' ",
21585
                          def->iothreadids[i]->iothread_id);
21586

21587
        if (!(cpumask = virBitmapFormat(def->iothreadids[i]->cpumask)))
21588 21589
            goto error;

21590
        virBufferAsprintf(&childrenBuf, "cpuset='%s'/>\n", cpumask);
21591 21592 21593
        VIR_FREE(cpumask);
    }

21594 21595 21596 21597 21598 21599
    for (i = 0; i < def->cputune.nvcpusched; i++) {
        virDomainThreadSchedParamPtr sp = &def->cputune.vcpusched[i];
        char *ids = NULL;

        if (!(ids = virBitmapFormat(sp->ids)))
            goto error;
21600
        virBufferAsprintf(&childrenBuf, "<vcpusched vcpus='%s' scheduler='%s'",
21601
                          ids, virProcessSchedPolicyTypeToString(sp->policy));
21602 21603
        VIR_FREE(ids);

21604 21605
        if (sp->policy == VIR_PROC_POLICY_FIFO ||
            sp->policy == VIR_PROC_POLICY_RR)
21606 21607
            virBufferAsprintf(&childrenBuf, " priority='%d'", sp->priority);
        virBufferAddLit(&childrenBuf, "/>\n");
21608 21609 21610 21611 21612 21613 21614 21615
    }

    for (i = 0; i < def->cputune.niothreadsched; i++) {
        virDomainThreadSchedParamPtr sp = &def->cputune.iothreadsched[i];
        char *ids = NULL;

        if (!(ids = virBitmapFormat(sp->ids)))
            goto error;
21616
        virBufferAsprintf(&childrenBuf, "<iothreadsched iothreads='%s' scheduler='%s'",
21617
                          ids, virProcessSchedPolicyTypeToString(sp->policy));
21618 21619
        VIR_FREE(ids);

21620 21621
        if (sp->policy == VIR_PROC_POLICY_FIFO ||
            sp->policy == VIR_PROC_POLICY_RR)
21622 21623
            virBufferAsprintf(&childrenBuf, " priority='%d'", sp->priority);
        virBufferAddLit(&childrenBuf, "/>\n");
21624 21625
    }

21626 21627 21628
    if (virBufferUse(&childrenBuf)) {
        virBufferAddLit(buf, "<cputune>\n");
        virBufferAddBuffer(buf, &childrenBuf);
21629
        virBufferAddLit(buf, "</cputune>\n");
21630 21631
    }
    virBufferFreeAndReset(&childrenBuf);
21632

21633
    if (virDomainNumatuneFormatXML(buf, def->numa) < 0)
21634
        goto error;
21635

21636 21637 21638
    if (def->resource)
        virDomainResourceDefFormat(buf, def->resource);

21639
    if (def->sysinfo)
21640
        ignore_value(virSysinfoFormat(buf, def->sysinfo));
21641

21642
    if (def->os.bootloader) {
21643
        virBufferEscapeString(buf, "<bootloader>%s</bootloader>\n",
21644
                              def->os.bootloader);
21645
        virBufferEscapeString(buf,
21646
                              "<bootloader_args>%s</bootloader_args>\n",
21647
                              def->os.bootloaderArgs);
21648 21649
    }

21650 21651 21652
    virBufferAddLit(buf, "<os>\n");
    virBufferAdjustIndent(buf, 2);
    virBufferAddLit(buf, "<type");
21653
    if (def->os.arch)
21654
        virBufferAsprintf(buf, " arch='%s'", virArchToString(def->os.arch));
21655
    if (def->os.machine)
21656
        virBufferAsprintf(buf, " machine='%s'", def->os.machine);
21657 21658 21659 21660 21661 21662
    /*
     * 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 &&
21663 21664 21665
        def->os.type == VIR_DOMAIN_OSTYPE_XEN)
        virBufferAsprintf(buf, ">%s</type>\n",
                          virDomainOSTypeToString(VIR_DOMAIN_OSTYPE_LINUX));
21666
    else
21667 21668
        virBufferAsprintf(buf, ">%s</type>\n",
                          virDomainOSTypeToString(def->os.type));
21669

21670
    virBufferEscapeString(buf, "<init>%s</init>\n",
21671
                          def->os.init);
21672
    for (i = 0; def->os.initargv && def->os.initargv[i]; i++)
21673
        virBufferEscapeString(buf, "<initarg>%s</initarg>\n",
21674
                              def->os.initargv[i]);
21675 21676
    if (def->os.loader)
        virDomainLoaderDefFormat(buf, def->os.loader);
21677
    virBufferEscapeString(buf, "<kernel>%s</kernel>\n",
21678
                          def->os.kernel);
21679
    virBufferEscapeString(buf, "<initrd>%s</initrd>\n",
21680
                          def->os.initrd);
21681
    virBufferEscapeString(buf, "<cmdline>%s</cmdline>\n",
21682
                          def->os.cmdline);
21683
    virBufferEscapeString(buf, "<dtb>%s</dtb>\n",
21684
                          def->os.dtb);
21685
    virBufferEscapeString(buf, "<root>%s</root>\n",
21686
                          def->os.root);
21687 21688

    if (!def->os.bootloader) {
21689
        for (n = 0; n < def->os.nBootDevs; n++) {
21690 21691 21692
            const char *boottype =
                virDomainBootTypeToString(def->os.bootDevs[n]);
            if (!boottype) {
21693 21694 21695
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unexpected boot device type %d"),
                               def->os.bootDevs[n]);
21696
                goto error;
21697
            }
21698
            virBufferAsprintf(buf, "<boot dev='%s'/>\n", boottype);
21699
        }
21700

21701 21702
        if (def->os.bootmenu) {
            virBufferAsprintf(buf, "<bootmenu enable='%s'",
J
Ján Tomko 已提交
21703
                              virTristateBoolTypeToString(def->os.bootmenu));
21704 21705 21706 21707
            if (def->os.bm_timeout_set)
                virBufferAsprintf(buf, " timeout='%u'", def->os.bm_timeout);
            virBufferAddLit(buf, "/>\n");
        }
M
Michal Privoznik 已提交
21708

21709
        if (def->os.bios.useserial || def->os.bios.rt_set) {
21710
            virBufferAddLit(buf, "<bios");
21711 21712
            if (def->os.bios.useserial)
                virBufferAsprintf(buf, " useserial='%s'",
J
Ján Tomko 已提交
21713
                                  virTristateBoolTypeToString(def->os.bios.useserial));
21714 21715 21716 21717
            if (def->os.bios.rt_set)
                virBufferAsprintf(buf, " rebootTimeout='%d'", def->os.bios.rt_delay);

            virBufferAddLit(buf, "/>\n");
M
Michal Privoznik 已提交
21718
        }
21719 21720
    }

21721 21722 21723 21724 21725
    if (def->os.smbios_mode) {
        const char *mode;

        mode = virDomainSmbiosModeTypeToString(def->os.smbios_mode);
        if (mode == NULL) {
21726 21727
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected smbios mode %d"), def->os.smbios_mode);
21728
            goto error;
21729
        }
21730
        virBufferAsprintf(buf, "<smbios mode='%s'/>\n", mode);
21731 21732
    }

21733 21734
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</os>\n");
21735

21736 21737

    if (def->idmap.uidmap) {
21738 21739
        virBufferAddLit(buf, "<idmap>\n");
        virBufferAdjustIndent(buf, 2);
21740 21741
        for (i = 0; i < def->idmap.nuidmap; i++) {
            virBufferAsprintf(buf,
21742
                              "<uid start='%u' target='%u' count='%u'/>\n",
21743 21744 21745 21746 21747 21748
                              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,
21749
                              "<gid start='%u' target='%u' count='%u'/>\n",
21750 21751 21752 21753
                              def->idmap.gidmap[i].start,
                              def->idmap.gidmap[i].target,
                              def->idmap.gidmap[i].count);
        }
21754 21755
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</idmap>\n");
21756 21757
    }

21758
    for (i = 0; i < VIR_DOMAIN_FEATURE_LAST; i++) {
J
Ján Tomko 已提交
21759
        if (def->features[i] != VIR_TRISTATE_SWITCH_ABSENT)
21760 21761
            break;
    }
21762

21763 21764
    if (i != VIR_DOMAIN_FEATURE_LAST ||
        virDomainDefHasCapabilitiesFeatures(def)) {
21765 21766
        virBufferAddLit(buf, "<features>\n");
        virBufferAdjustIndent(buf, 2);
21767

21768
        for (i = 0; i < VIR_DOMAIN_FEATURE_LAST; i++) {
21769 21770 21771 21772 21773 21774 21775
            const char *name = virDomainFeatureTypeToString(i);
            size_t j;

            if (!name) {
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unexpected feature %zu"), i);
                goto error;
21776
            }
21777

21778
            switch ((virDomainFeature) i) {
21779 21780 21781 21782 21783
            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 已提交
21784 21785
                switch ((virTristateSwitch) def->features[i]) {
                case VIR_TRISTATE_SWITCH_ABSENT:
21786 21787
                    break;

J
Ján Tomko 已提交
21788
                case VIR_TRISTATE_SWITCH_ON:
21789
                   virBufferAsprintf(buf, "<%s/>\n", name);
21790 21791
                   break;

J
Ján Tomko 已提交
21792 21793
                case VIR_TRISTATE_SWITCH_LAST:
                case VIR_TRISTATE_SWITCH_OFF:
21794 21795 21796 21797 21798 21799 21800 21801
                   virReportError(VIR_ERR_INTERNAL_ERROR,
                                 _("Unexpected state of feature '%s'"), name);

                   goto error;
                   break;
                }

                break;
21802

21803
            case VIR_DOMAIN_FEATURE_PMU:
21804
            case VIR_DOMAIN_FEATURE_PVSPINLOCK:
21805
            case VIR_DOMAIN_FEATURE_VMPORT:
J
Ján Tomko 已提交
21806 21807 21808
                switch ((virTristateSwitch) def->features[i]) {
                case VIR_TRISTATE_SWITCH_LAST:
                case VIR_TRISTATE_SWITCH_ABSENT:
21809 21810
                    break;

J
Ján Tomko 已提交
21811
                case VIR_TRISTATE_SWITCH_ON:
21812
                   virBufferAsprintf(buf, "<%s state='on'/>\n", name);
21813 21814
                   break;

J
Ján Tomko 已提交
21815
                case VIR_TRISTATE_SWITCH_OFF:
21816
                   virBufferAsprintf(buf, "<%s state='off'/>\n", name);
21817 21818 21819 21820 21821
                   break;
                }

                break;

21822
            case VIR_DOMAIN_FEATURE_APIC:
J
Ján Tomko 已提交
21823
                if (def->features[i] == VIR_TRISTATE_SWITCH_ON) {
21824
                    virBufferAddLit(buf, "<apic");
21825 21826
                    if (def->apic_eoi) {
                        virBufferAsprintf(buf, " eoi='%s'",
J
Ján Tomko 已提交
21827
                                          virTristateSwitchTypeToString(def->apic_eoi));
21828
                    }
21829
                    virBufferAddLit(buf, "/>\n");
21830 21831
                }
                break;
21832

21833
            case VIR_DOMAIN_FEATURE_HYPERV:
J
Ján Tomko 已提交
21834
                if (def->features[i] != VIR_TRISTATE_SWITCH_ON)
21835
                    break;
21836

21837 21838
                virBufferAddLit(buf, "<hyperv>\n");
                virBufferAdjustIndent(buf, 2);
21839
                for (j = 0; j < VIR_DOMAIN_HYPERV_LAST; j++) {
21840
                    switch ((virDomainHyperv) j) {
21841 21842 21843
                    case VIR_DOMAIN_HYPERV_RELAXED:
                    case VIR_DOMAIN_HYPERV_VAPIC:
                        if (def->hyperv_features[j])
21844
                            virBufferAsprintf(buf, "<%s state='%s'/>\n",
21845
                                              virDomainHypervTypeToString(j),
J
Ján Tomko 已提交
21846
                                              virTristateSwitchTypeToString(
21847 21848 21849 21850 21851 21852 21853
                                                  def->hyperv_features[j]));
                        break;

                    case VIR_DOMAIN_HYPERV_SPINLOCKS:
                        if (def->hyperv_features[j] == 0)
                            break;

21854
                        virBufferAsprintf(buf, "<spinlocks state='%s'",
J
Ján Tomko 已提交
21855
                                          virTristateSwitchTypeToString(
21856
                                              def->hyperv_features[j]));
J
Ján Tomko 已提交
21857
                        if (def->hyperv_features[j] == VIR_TRISTATE_SWITCH_ON)
21858 21859 21860 21861 21862
                            virBufferAsprintf(buf, " retries='%d'",
                                              def->hyperv_spinlocks);
                        virBufferAddLit(buf, "/>\n");
                        break;

21863
                    /* coverity[dead_error_begin] */
21864 21865 21866
                    case VIR_DOMAIN_HYPERV_LAST:
                        break;
                    }
21867
                }
21868 21869
                virBufferAdjustIndent(buf, -2);
                virBufferAddLit(buf, "</hyperv>\n");
21870 21871
                break;

21872 21873 21874 21875 21876 21877 21878 21879 21880 21881 21882 21883 21884 21885 21886 21887
            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;

21888
                    /* coverity[dead_error_begin] */
21889 21890 21891 21892 21893 21894 21895 21896
                    case VIR_DOMAIN_KVM_LAST:
                        break;
                    }
                }
                virBufferAdjustIndent(buf, -2);
                virBufferAddLit(buf, "</kvm>\n");
                break;

21897 21898 21899 21900 21901 21902 21903 21904 21905
            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 已提交
21906
                    if (def->caps_features[j] != VIR_TRISTATE_SWITCH_ABSENT)
21907 21908
                        virBufferAsprintf(buf, "<%s state='%s'/>\n",
                                          virDomainCapsFeatureTypeToString(j),
J
Ján Tomko 已提交
21909
                                          virTristateSwitchTypeToString(
21910 21911 21912 21913 21914 21915
                                              def->caps_features[j]));
                }
                virBufferAdjustIndent(buf, -2);
                virBufferAddLit(buf, "</capabilities>\n");
                break;

M
Michal Privoznik 已提交
21916 21917 21918 21919 21920 21921 21922 21923 21924 21925
            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;

21926
            /* coverity[dead_error_begin] */
21927 21928
            case VIR_DOMAIN_FEATURE_LAST:
                break;
21929 21930 21931
            }
        }

21932 21933
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</features>\n");
21934 21935
    }

21936
    if (virCPUDefFormatBufFull(buf, def->cpu, def->numa,
21937
                               !!(flags & VIR_DOMAIN_DEF_FORMAT_UPDATE_CPU)) < 0)
21938
        goto error;
21939

21940
    virBufferAsprintf(buf, "<clock offset='%s'",
21941
                      virDomainClockOffsetTypeToString(def->clock.offset));
21942
    switch (def->clock.offset) {
21943 21944 21945 21946 21947
    case VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME:
    case VIR_DOMAIN_CLOCK_OFFSET_UTC:
        if (def->clock.data.utc_reset)
            virBufferAddLit(buf, " adjustment='reset'");
        break;
21948
    case VIR_DOMAIN_CLOCK_OFFSET_VARIABLE:
21949 21950 21951
        virBufferAsprintf(buf, " adjustment='%lld' basis='%s'",
                          def->clock.data.variable.adjustment,
                          virDomainClockBasisTypeToString(def->clock.data.variable.basis));
21952
        if (flags & VIR_DOMAIN_DEF_FORMAT_CLOCK_ADJUST) {
21953 21954 21955 21956
            if (def->clock.data.variable.adjustment0)
                virBufferAsprintf(buf, " adjustment0='%lld'",
                                  def->clock.data.variable.adjustment0);
        }
21957 21958
        break;
    case VIR_DOMAIN_CLOCK_OFFSET_TIMEZONE:
21959
        virBufferEscapeString(buf, " timezone='%s'", def->clock.data.timezone);
21960 21961
        break;
    }
21962
    if (def->clock.ntimers == 0) {
21963
        virBufferAddLit(buf, "/>\n");
21964
    } else {
21965
        virBufferAddLit(buf, ">\n");
21966
        virBufferAdjustIndent(buf, 2);
21967
        for (n = 0; n < def->clock.ntimers; n++) {
21968
            if (virDomainTimerDefFormat(buf, def->clock.timers[n]) < 0)
21969
                goto error;
21970
        }
21971 21972
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</clock>\n");
21973
    }
21974

21975 21976 21977
    if (virDomainEventActionDefFormat(buf, def->onPoweroff,
                                      "on_poweroff",
                                      virDomainLifecycleTypeToString) < 0)
21978
        goto error;
21979 21980 21981
    if (virDomainEventActionDefFormat(buf, def->onReboot,
                                      "on_reboot",
                                      virDomainLifecycleTypeToString) < 0)
21982
        goto error;
21983 21984 21985
    if (virDomainEventActionDefFormat(buf, def->onCrash,
                                      "on_crash",
                                      virDomainLifecycleCrashTypeToString) < 0)
21986
        goto error;
21987 21988 21989 21990
    if (def->onLockFailure != VIR_DOMAIN_LOCK_FAILURE_DEFAULT &&
        virDomainEventActionDefFormat(buf, def->onLockFailure,
                                      "on_lockfailure",
                                      virDomainLockFailureTypeToString) < 0)
21991
        goto error;
21992

21993
    if (def->pm.s3 || def->pm.s4) {
21994 21995
        virBufferAddLit(buf, "<pm>\n");
        virBufferAdjustIndent(buf, 2);
21996
        if (def->pm.s3) {
21997
            virBufferAsprintf(buf, "<suspend-to-mem enabled='%s'/>\n",
J
Ján Tomko 已提交
21998
                              virTristateBoolTypeToString(def->pm.s3));
21999 22000
        }
        if (def->pm.s4) {
22001
            virBufferAsprintf(buf, "<suspend-to-disk enabled='%s'/>\n",
J
Ján Tomko 已提交
22002
                              virTristateBoolTypeToString(def->pm.s4));
22003
        }
22004 22005
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "</pm>\n");
22006 22007
    }

22008 22009
    virBufferAddLit(buf, "<devices>\n");
    virBufferAdjustIndent(buf, 2);
22010

22011
    virBufferEscapeString(buf, "<emulator>%s</emulator>\n",
22012
                          def->emulator);
22013

22014
    for (n = 0; n < def->ndisks; n++)
22015
        if (virDomainDiskDefFormat(buf, def->disks[n], flags) < 0)
22016
            goto error;
22017

22018
    for (n = 0; n < def->ncontrollers; n++)
22019
        if (virDomainControllerDefFormat(buf, def->controllers[n], flags) < 0)
22020
            goto error;
22021

22022
    for (n = 0; n < def->nleases; n++)
22023
        if (virDomainLeaseDefFormat(buf, def->leases[n]) < 0)
22024
            goto error;
22025

22026
    for (n = 0; n < def->nfss; n++)
22027
        if (virDomainFSDefFormat(buf, def->fss[n], flags) < 0)
22028
            goto error;
22029

22030
    for (n = 0; n < def->nnets; n++)
22031
        if (virDomainNetDefFormat(buf, def->nets[n], flags) < 0)
22032
            goto error;
22033

22034
    for (n = 0; n < def->nsmartcards; n++)
22035
        if (virDomainSmartcardDefFormat(buf, def->smartcards[n], flags) < 0)
22036
            goto error;
E
Eric Blake 已提交
22037

22038
    for (n = 0; n < def->nserials; n++)
22039
        if (virDomainChrDefFormat(buf, def->serials[n], flags) < 0)
22040
            goto error;
22041

22042
    for (n = 0; n < def->nparallels; n++)
22043
        if (virDomainChrDefFormat(buf, def->parallels[n], flags) < 0)
22044
            goto error;
22045

22046
    for (n = 0; n < def->nconsoles; n++) {
22047 22048 22049 22050
        virDomainChrDef console;
        /* Back compat, ignore the console element for hvm guests
         * if it is type == serial
         */
22051
        if (def->os.type == VIR_DOMAIN_OSTYPE_HVM &&
22052 22053
            (def->consoles[n]->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL ||
             def->consoles[n]->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_NONE) &&
22054 22055 22056
            (n < def->nserials)) {
            memcpy(&console, def->serials[n], sizeof(console));
            console.deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE;
G
Guannan Ren 已提交
22057
            console.targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL;
22058 22059 22060 22061
        } else {
            memcpy(&console, def->consoles[n], sizeof(console));
        }
        if (virDomainChrDefFormat(buf, &console, flags) < 0)
22062
            goto error;
22063
    }
22064 22065 22066 22067
    /* 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.
     */
22068
    if (def->os.type == VIR_DOMAIN_OSTYPE_HVM &&
22069 22070
        def->nconsoles == 0 &&
        def->nserials > 0) {
22071
        virDomainChrDef console;
22072
        memcpy(&console, def->serials[n], sizeof(console));
22073
        console.deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE;
22074
        console.targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL;
22075
        if (virDomainChrDefFormat(buf, &console, flags) < 0)
22076
            goto error;
22077 22078
    }

22079
    for (n = 0; n < def->nchannels; n++)
22080
        if (virDomainChrDefFormat(buf, def->channels[n], flags) < 0)
22081
            goto error;
22082

22083
    for (n = 0; n < def->ninputs; n++)
22084 22085
        if ((def->inputs[n]->bus == VIR_DOMAIN_INPUT_BUS_USB ||
             def->inputs[n]->bus == VIR_DOMAIN_INPUT_BUS_VIRTIO) &&
22086
            virDomainInputDefFormat(buf, def->inputs[n], flags) < 0)
22087
            goto error;
22088

22089 22090 22091 22092 22093
    if (def->tpm) {
        if (virDomainTPMDefFormat(buf, def->tpm, flags) < 0)
            goto error;
    }

22094
    if (def->ngraphics > 0) {
L
Li Zhang 已提交
22095
        /* If graphics is enabled, add the implicit mouse/keyboard */
22096 22097
        if ((ARCH_IS_X86(def->os.arch)) || def->os.arch == VIR_ARCH_NONE) {
            virDomainInputDef autoInput = {
22098 22099
                .type = VIR_DOMAIN_INPUT_TYPE_MOUSE,
                .info = { .alias = NULL },
22100
            };
22101

22102
            if (def->os.type == VIR_DOMAIN_OSTYPE_HVM)
22103
                autoInput.bus = VIR_DOMAIN_INPUT_BUS_PS2;
22104
            else if (def->os.type == VIR_DOMAIN_OSTYPE_EXE &&
22105 22106
                     (def->virtType == VIR_DOMAIN_VIRT_VZ ||
                      def->virtType == VIR_DOMAIN_VIRT_PARALLELS))
22107 22108 22109 22110
                autoInput.bus = VIR_DOMAIN_INPUT_BUS_PARALLELS;
            else
               autoInput.bus = VIR_DOMAIN_INPUT_BUS_XEN;

L
Li Zhang 已提交
22111 22112
            if (virDomainInputDefFormat(buf, &autoInput, flags) < 0)
                goto error;
22113

22114
            if (!(flags & VIR_DOMAIN_DEF_FORMAT_MIGRATABLE)) {
22115 22116 22117 22118
                autoInput.type = VIR_DOMAIN_INPUT_TYPE_KBD;
                if (virDomainInputDefFormat(buf, &autoInput, flags) < 0)
                    goto error;
            }
L
Li Zhang 已提交
22119 22120
        }

22121
        for (n = 0; n < def->ngraphics; n++)
22122
            if (virDomainGraphicsDefFormat(buf, def->graphics[n], flags) < 0)
22123
                goto error;
22124 22125
    }

22126
    for (n = 0; n < def->nsounds; n++)
22127
        if (virDomainSoundDefFormat(buf, def->sounds[n], flags) < 0)
22128
            goto error;
22129

22130
    for (n = 0; n < def->nvideos; n++)
22131
        if (virDomainVideoDefFormat(buf, def->videos[n], flags) < 0)
22132
            goto error;
22133

22134
    for (n = 0; n < def->nhostdevs; n++) {
22135 22136 22137 22138
        /* 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 已提交
22139 22140
        if (def->hostdevs[n]->parent.type == VIR_DOMAIN_DEVICE_NONE &&
            virDomainHostdevDefFormat(buf, def->hostdevs[n], flags) < 0) {
22141
            goto error;
22142 22143
        }
    }
22144

22145
    for (n = 0; n < def->nredirdevs; n++)
22146
        if (virDomainRedirdevDefFormat(buf, def->redirdevs[n], flags) < 0)
22147
            goto error;
22148

22149 22150 22151
    if (def->redirfilter)
        virDomainRedirFilterDefFormat(buf, def->redirfilter);

22152
    for (n = 0; n < def->nhubs; n++)
22153
        if (virDomainHubDefFormat(buf, def->hubs[n], flags) < 0)
22154
            goto error;
M
Marc-André Lureau 已提交
22155

R
Richard Jones 已提交
22156
    if (def->watchdog)
22157
        virDomainWatchdogDefFormat(buf, def->watchdog, flags);
R
Richard Jones 已提交
22158

22159
    if (def->memballoon)
22160
        virDomainMemballoonDefFormat(buf, def->memballoon, flags);
22161

22162 22163 22164 22165
    for (n = 0; n < def->nrngs; n++) {
        if (virDomainRNGDefFormat(buf, def->rngs[n], flags))
            goto error;
    }
22166

L
Li Zhang 已提交
22167 22168 22169
    if (def->nvram)
        virDomainNVRAMDefFormat(buf, def->nvram, flags);

D
Dmitry Andreev 已提交
22170 22171 22172
    for (n = 0; n < def->npanics; n++)
        if (virDomainPanicDefFormat(buf, def->panics[n]) < 0)
            goto error;
H
Hu Tao 已提交
22173

22174 22175 22176 22177
    for (n = 0; n < def->nshmems; n++)
        if (virDomainShmemDefFormat(buf, def->shmems[n], flags) < 0)
            goto error;

22178 22179 22180 22181
    for (n = 0; n < def->nmems; n++)
        if (virDomainMemoryDefFormat(buf, def->mems[n], flags) < 0)
            goto error;

22182 22183
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</devices>\n");
22184

22185
    for (n = 0; n < def->nseclabels; n++)
22186
        virSecurityLabelDefFormat(buf, def->seclabels[n]);
22187

22188
    if (def->namespaceData && def->ns.format) {
22189
        if ((def->ns.format)(buf, def->namespaceData) < 0)
22190
            goto error;
22191 22192
    }

22193 22194 22195
    if (def->keywrap)
        virDomainKeyWrapDefFormat(buf, def->keywrap);

22196
    virBufferAdjustIndent(buf, -2);
22197
    virBufferAddLit(buf, "</domain>\n");
22198

22199 22200
    if (virBufferCheckError(buf) < 0)
        goto error;
22201

22202
    return 0;
22203

22204
 error:
22205
    virBufferFreeAndReset(buf);
22206
    virBufferFreeAndReset(&childrenBuf);
22207
    return -1;
22208 22209
}

22210 22211 22212 22213 22214 22215 22216 22217 22218 22219 22220 22221 22222 22223 22224 22225 22226
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;
}


22227 22228 22229
char *
virDomainDefFormat(virDomainDefPtr def, unsigned int flags)
{
22230 22231
    virBuffer buf = VIR_BUFFER_INITIALIZER;

22232
    virCheckFlags(VIR_DOMAIN_DEF_FORMAT_COMMON_FLAGS, NULL);
22233 22234 22235 22236
    if (virDomainDefFormatInternal(def, flags, &buf) < 0)
        return NULL;

    return virBufferContentAndReset(&buf);
22237 22238
}

22239

22240
char *
22241
virDomainObjFormat(virDomainXMLOptionPtr xmlopt,
22242 22243
                   virDomainObjPtr obj,
                   unsigned int flags)
22244 22245
{
    virBuffer buf = VIR_BUFFER_INITIALIZER;
J
Jiri Denemark 已提交
22246 22247
    int state;
    int reason;
22248
    size_t i;
22249

J
Jiri Denemark 已提交
22250
    state = virDomainObjGetState(obj, &reason);
22251
    virBufferAsprintf(&buf, "<domstatus state='%s' reason='%s' pid='%lld'>\n",
J
Jiri Denemark 已提交
22252 22253
                      virDomainStateTypeToString(state),
                      virDomainStateReasonToString(state, reason),
22254
                      (long long)obj->pid);
22255
    virBufferAdjustIndent(&buf, 2);
22256

22257
    for (i = 0; i < VIR_DOMAIN_TAINT_LAST; i++) {
22258
        if (obj->taint & (1 << i))
22259
            virBufferAsprintf(&buf, "<taint flag='%s'/>\n",
22260 22261 22262
                              virDomainTaintTypeToString(i));
    }

22263
    if (xmlopt->privateData.format &&
22264
        xmlopt->privateData.format(&buf, obj) < 0)
22265
        goto error;
22266

22267
    if (virDomainDefFormatInternal(obj->def, flags, &buf) < 0)
22268 22269
        goto error;

22270
    virBufferAdjustIndent(&buf, -2);
22271 22272
    virBufferAddLit(&buf, "</domstatus>\n");

22273 22274
    if (virBufferCheckError(&buf) < 0)
        goto error;
22275 22276 22277

    return virBufferContentAndReset(&buf);

22278
 error:
22279
    virBufferFreeAndReset(&buf);
22280 22281 22282
    return NULL;
}

22283 22284 22285
static bool
virDomainDefHasUSB(virDomainDefPtr def)
{
22286
    size_t i;
22287 22288 22289 22290 22291 22292 22293 22294 22295 22296 22297 22298 22299 22300 22301 22302 22303 22304 22305 22306 22307 22308 22309 22310 22311 22312 22313 22314 22315 22316 22317

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

22318 22319 22320 22321 22322 22323 22324 22325 22326 22327 22328 22329 22330 22331 22332 22333 22334
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;
}

22335 22336 22337 22338 22339 22340 22341 22342 22343 22344 22345 22346 22347 22348 22349 22350 22351 22352 22353 22354 22355 22356 22357 22358 22359 22360 22361 22362

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


22363 22364
int
virDomainDefCompatibleDevice(virDomainDefPtr def,
22365 22366
                             virDomainDeviceDefPtr dev,
                             virDomainDeviceAction action)
22367
{
22368 22369
    virDomainDeviceInfoPtr info = virDomainDeviceGetInfo(dev);

22370 22371 22372
    if (action != VIR_DOMAIN_DEVICE_ACTION_ATTACH)
        return 0;

22373
    if (!virDomainDefHasUSB(def) &&
22374
        def->os.type != VIR_DOMAIN_OSTYPE_EXE &&
22375 22376 22377 22378 22379 22380 22381
        virDomainDeviceIsUSB(dev)) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Device configuration is not compatible: "
                         "Domain has no USB bus support"));
        return -1;
    }

22382 22383 22384 22385 22386 22387 22388 22389 22390 22391 22392 22393 22394
    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;
    }

22395 22396 22397 22398 22399 22400 22401 22402 22403 22404 22405
    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;
        }
    }

22406 22407 22408 22409 22410 22411 22412 22413 22414
    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;
        }
    }

22415 22416 22417
    return 0;
}

22418 22419 22420 22421
int
virDomainSaveXML(const char *configDir,
                 virDomainDefPtr def,
                 const char *xml)
22422
{
J
Ján Tomko 已提交
22423
    char uuidstr[VIR_UUID_STRING_BUFLEN];
22424
    char *configFile = NULL;
22425
    int ret = -1;
22426

22427 22428 22429
    if (!configDir)
        return 0;

22430
    if ((configFile = virDomainConfigFile(configDir, def->name)) == NULL)
22431 22432
        goto cleanup;

22433
    if (virFileMakePath(configDir) < 0) {
22434
        virReportSystemError(errno,
22435 22436
                             _("cannot create config directory '%s'"),
                             configDir);
22437 22438 22439
        goto cleanup;
    }

J
Ján Tomko 已提交
22440 22441 22442 22443
    virUUIDFormat(def->uuid, uuidstr);
    ret = virXMLSaveFile(configFile,
                         virXMLPickShellSafeComment(def->name, uuidstr), "edit",
                         xml);
22444

22445
 cleanup:
R
Ryota Ozaki 已提交
22446
    VIR_FREE(configFile);
22447 22448 22449
    return ret;
}

22450 22451 22452
int
virDomainSaveConfig(const char *configDir,
                    virDomainDefPtr def)
22453 22454 22455
{
    int ret = -1;
    char *xml;
22456

22457
    if (!(xml = virDomainDefFormat(def, VIR_DOMAIN_DEF_FORMAT_SECURE)))
22458 22459
        goto cleanup;

22460
    if (virDomainSaveXML(configDir, def, xml))
22461 22462 22463
        goto cleanup;

    ret = 0;
22464
 cleanup:
22465
    VIR_FREE(xml);
22466 22467 22468
    return ret;
}

22469
int
22470
virDomainSaveStatus(virDomainXMLOptionPtr xmlopt,
22471 22472
                    const char *statusDir,
                    virDomainObjPtr obj)
22473
{
22474 22475 22476 22477 22478
    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);
22479

22480 22481 22482
    int ret = -1;
    char *xml;

22483
    if (!(xml = virDomainObjFormat(xmlopt, obj, flags)))
22484 22485
        goto cleanup;

22486
    if (virDomainSaveXML(statusDir, obj->def, xml))
22487 22488 22489
        goto cleanup;

    ret = 0;
22490
 cleanup:
22491 22492 22493 22494
    VIR_FREE(xml);
    return ret;
}

22495

22496 22497 22498 22499
int
virDomainDeleteConfig(const char *configDir,
                      const char *autostartDir,
                      virDomainObjPtr dom)
22500
{
22501 22502 22503
    char *configFile = NULL, *autostartLink = NULL;
    int ret = -1;

22504
    if ((configFile = virDomainConfigFile(configDir, dom->def->name)) == NULL)
22505
        goto cleanup;
22506 22507
    if ((autostartLink = virDomainConfigFile(autostartDir,
                                             dom->def->name)) == NULL)
22508
        goto cleanup;
22509 22510

    /* Not fatal if this doesn't work */
22511
    unlink(autostartLink);
22512
    dom->autostart = 0;
22513

22514 22515
    if (unlink(configFile) < 0 &&
        errno != ENOENT) {
22516
        virReportSystemError(errno,
22517 22518
                             _("cannot remove config %s"),
                             configFile);
22519
        goto cleanup;
22520 22521
    }

22522 22523
    ret = 0;

22524
 cleanup:
22525 22526 22527
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
    return ret;
22528
}
22529

22530 22531 22532
char
*virDomainConfigFile(const char *dir,
                     const char *name)
22533
{
22534
    char *ret;
22535

22536
    ignore_value(virAsprintf(&ret, "%s/%s.xml", dir, name));
22537 22538 22539
    return ret;
}

22540 22541
/* 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 已提交
22542
 *                                               hdd => (1,1), vdaa => (0,26))
22543 22544 22545 22546 22547
 * @param disk The disk device
 * @param busIdx parsed bus number
 * @param devIdx parsed device number
 * @return 0 on success, -1 on failure
 */
22548
int
22549
virDiskNameToBusDeviceIndex(virDomainDiskDefPtr disk,
22550
                            int *busIdx,
22551 22552
                            int *devIdx)
{
22553 22554

    int idx = virDiskNameToIndex(disk->dst);
22555
    if (idx < 0)
22556 22557 22558 22559 22560 22561 22562 22563 22564 22565 22566 22567 22568 22569 22570
        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:
22571
        case VIR_DOMAIN_DISK_BUS_SD:
22572 22573 22574 22575 22576 22577 22578 22579
        default:
            *busIdx = 0;
            *devIdx = idx;
            break;
    }

    return 0;
}
22580

22581 22582 22583 22584 22585 22586 22587 22588 22589 22590 22591 22592 22593 22594 22595 22596
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;
}

22597
virDomainFSDefPtr
22598
virDomainGetFilesystemForTarget(virDomainDefPtr def,
22599
                                const char *target)
22600
{
22601
    size_t i;
22602

22603
    for (i = 0; i < def->nfss; i++) {
22604
        if (STREQ(def->fss[i]->dst, target))
22605 22606 22607 22608 22609 22610
            return def->fss[i];
    }

    return NULL;
}

22611

22612 22613 22614 22615 22616
int
virDomainChrDefForeach(virDomainDefPtr def,
                       bool abortOnError,
                       virDomainChrDefIterator iter,
                       void *opaque)
22617
{
22618
    size_t i;
22619 22620
    int rc = 0;

22621
    for (i = 0; i < def->nserials; i++) {
22622 22623 22624 22625 22626 22627 22628 22629 22630
        if ((iter)(def,
                   def->serials[i],
                   opaque) < 0)
            rc = -1;

        if (abortOnError && rc != 0)
            goto done;
    }

22631
    for (i = 0; i < def->nparallels; i++) {
22632 22633 22634 22635 22636 22637 22638 22639 22640
        if ((iter)(def,
                   def->parallels[i],
                   opaque) < 0)
            rc = -1;

        if (abortOnError && rc != 0)
            goto done;
    }

22641
    for (i = 0; i < def->nchannels; i++) {
22642 22643 22644 22645 22646 22647 22648 22649
        if ((iter)(def,
                   def->channels[i],
                   opaque) < 0)
            rc = -1;

        if (abortOnError && rc != 0)
            goto done;
    }
22650
    for (i = 0; i < def->nconsoles; i++) {
22651
        if ((iter)(def,
22652
                   def->consoles[i],
22653 22654 22655 22656 22657 22658 22659
                   opaque) < 0)
            rc = -1;

        if (abortOnError && rc != 0)
            goto done;
    }

22660
 done:
22661 22662 22663 22664
    return rc;
}


22665 22666 22667 22668 22669
int
virDomainSmartcardDefForeach(virDomainDefPtr def,
                             bool abortOnError,
                             virDomainSmartcardDefIterator iter,
                             void *opaque)
E
Eric Blake 已提交
22670
{
22671
    size_t i;
E
Eric Blake 已提交
22672 22673
    int rc = 0;

22674
    for (i = 0; i < def->nsmartcards; i++) {
E
Eric Blake 已提交
22675 22676 22677 22678 22679 22680 22681 22682 22683
        if ((iter)(def,
                   def->smartcards[i],
                   opaque) < 0)
            rc = -1;

        if (abortOnError && rc != 0)
            goto done;
    }

22684
 done:
E
Eric Blake 已提交
22685 22686 22687 22688
    return rc;
}


22689
/* Call iter(disk, name, depth, opaque) for each element of disk and
22690
 * its backing chain in the pre-populated disk->src.backingStore.
22691 22692 22693
 * ignoreOpenFailure determines whether to warn about a chain that
 * mentions a backing file without also having metadata on that
 * file.  */
22694 22695 22696 22697 22698
int
virDomainDiskDefForeachPath(virDomainDiskDefPtr disk,
                            bool ignoreOpenFailure,
                            virDomainDiskDefPathIterator iter,
                            void *opaque)
22699 22700 22701
{
    int ret = -1;
    size_t depth = 0;
22702
    virStorageSourcePtr tmp;
22703
    char *brokenRaw = NULL;
22704

22705
    if (!ignoreOpenFailure) {
22706
        if (virStorageFileChainGetBroken(disk->src, &brokenRaw) < 0)
22707
            goto cleanup;
22708

22709
        if (brokenRaw) {
22710
            virReportError(VIR_ERR_INTERNAL_ERROR,
22711
                           _("unable to visit backing chain file %s"),
22712
                           brokenRaw);
22713 22714
            goto cleanup;
        }
22715 22716
    }

22717
    for (tmp = disk->src; tmp; tmp = tmp->backingStore) {
22718 22719 22720 22721 22722 22723 22724 22725 22726 22727
        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++;
22728
    }
22729 22730 22731

    ret = 0;

22732
 cleanup:
22733
    VIR_FREE(brokenRaw);
22734 22735
    return ret;
}
22736 22737


22738 22739 22740 22741
/* 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).  */
22742
virDomainDefPtr
22743 22744
virDomainDefCopy(virDomainDefPtr src,
                 virCapsPtr caps,
22745
                 virDomainXMLOptionPtr xmlopt,
22746
                 bool migratable)
22747 22748
{
    char *xml;
22749
    virDomainDefPtr ret;
22750 22751
    unsigned int format_flags = VIR_DOMAIN_DEF_FORMAT_SECURE;
    unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
22752

22753
    if (migratable)
22754
        format_flags |= VIR_DOMAIN_DEF_FORMAT_INACTIVE | VIR_DOMAIN_DEF_FORMAT_MIGRATABLE;
22755

22756
    /* Easiest to clone via a round-trip through XML.  */
22757
    if (!(xml = virDomainDefFormat(src, format_flags)))
22758 22759
        return NULL;

22760
    ret = virDomainDefParseString(xml, caps, xmlopt, parse_flags);
22761 22762 22763 22764

    VIR_FREE(xml);
    return ret;
}
J
Jiri Denemark 已提交
22765

22766
virDomainDefPtr
22767 22768 22769
virDomainObjCopyPersistentDef(virDomainObjPtr dom,
                              virCapsPtr caps,
                              virDomainXMLOptionPtr xmlopt)
22770 22771 22772
{
    virDomainDefPtr cur;

22773
    cur = virDomainObjGetPersistentDef(caps, xmlopt, dom);
22774
    return virDomainDefCopy(cur, caps, xmlopt, false);
22775 22776
}

J
Jiri Denemark 已提交
22777 22778 22779 22780 22781 22782 22783 22784 22785 22786 22787 22788 22789 22790 22791 22792 22793

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 已提交
22794 22795 22796 22797 22798 22799 22800 22801 22802 22803 22804 22805 22806 22807 22808 22809 22810 22811 22812 22813 22814 22815 22816 22817 22818 22819
    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 已提交
22820 22821 22822 22823 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 22850 22851 22852
    }

    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);
22853 22854 22855 22856
    case VIR_DOMAIN_PMSUSPENDED:
        return virDomainPMSuspendedReasonTypeToString(reason);
    case VIR_DOMAIN_LAST:
        break;
J
Jiri Denemark 已提交
22857
    }
22858 22859
    VIR_WARN("Unexpected domain state: %d", state);
    return NULL;
J
Jiri Denemark 已提交
22860 22861 22862 22863 22864 22865 22866 22867 22868 22869 22870 22871 22872 22873 22874 22875 22876 22877 22878 22879 22880
}


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);
22881 22882 22883 22884
    case VIR_DOMAIN_PMSUSPENDED:
        return virDomainPMSuspendedReasonTypeFromString(reason);
    case VIR_DOMAIN_LAST:
        break;
J
Jiri Denemark 已提交
22885
    }
22886 22887
    VIR_WARN("Unexpected domain state: %d", state);
    return -1;
J
Jiri Denemark 已提交
22888
}
22889 22890 22891 22892 22893 22894 22895 22896 22897 22898 22899 22900 22901 22902 22903 22904 22905 22906


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

22907
const char *
22908 22909 22910 22911
virDomainNetGetActualBridgeName(virDomainNetDefPtr iface)
{
    if (iface->type == VIR_DOMAIN_NET_TYPE_BRIDGE)
        return iface->data.bridge.brname;
22912 22913
    if (iface->type == VIR_DOMAIN_NET_TYPE_NETWORK &&
        iface->data.network.actual &&
22914 22915
        (iface->data.network.actual->type == VIR_DOMAIN_NET_TYPE_BRIDGE ||
         iface->data.network.actual->type == VIR_DOMAIN_NET_TYPE_NETWORK))
22916 22917
        return iface->data.network.actual->data.bridge.brname;
    return NULL;
22918 22919
}

22920 22921 22922 22923 22924 22925 22926 22927 22928 22929 22930
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;
}

22931
const char *
22932 22933 22934 22935
virDomainNetGetActualDirectDev(virDomainNetDefPtr iface)
{
    if (iface->type == VIR_DOMAIN_NET_TYPE_DIRECT)
        return iface->data.direct.linkdev;
22936 22937
    if (iface->type == VIR_DOMAIN_NET_TYPE_NETWORK &&
        iface->data.network.actual &&
22938
        iface->data.network.actual->type == VIR_DOMAIN_NET_TYPE_DIRECT)
22939 22940
        return iface->data.network.actual->data.direct.linkdev;
    return NULL;
22941 22942 22943 22944 22945 22946 22947
}

int
virDomainNetGetActualDirectMode(virDomainNetDefPtr iface)
{
    if (iface->type == VIR_DOMAIN_NET_TYPE_DIRECT)
        return iface->data.direct.mode;
22948 22949
    if (iface->type == VIR_DOMAIN_NET_TYPE_NETWORK &&
        iface->data.network.actual &&
22950
        iface->data.network.actual->type == VIR_DOMAIN_NET_TYPE_DIRECT)
22951 22952
        return iface->data.network.actual->data.direct.mode;
    return 0;
22953 22954
}

22955 22956 22957 22958 22959
virDomainHostdevDefPtr
virDomainNetGetActualHostdev(virDomainNetDefPtr iface)
{
    if (iface->type == VIR_DOMAIN_NET_TYPE_HOSTDEV)
        return &iface->data.hostdev.def;
E
Eric Blake 已提交
22960
    if (iface->type == VIR_DOMAIN_NET_TYPE_NETWORK &&
22961
        iface->data.network.actual &&
22962
        iface->data.network.actual->type == VIR_DOMAIN_NET_TYPE_HOSTDEV)
22963 22964 22965 22966
        return &iface->data.network.actual->data.hostdev.def;
    return NULL;
}

22967
virNetDevVPortProfilePtr
22968
virDomainNetGetActualVirtPortProfile(virDomainNetDefPtr iface)
22969
{
A
Ansis Atteka 已提交
22970 22971 22972
    switch (iface->type) {
    case VIR_DOMAIN_NET_TYPE_DIRECT:
    case VIR_DOMAIN_NET_TYPE_BRIDGE:
22973
    case VIR_DOMAIN_NET_TYPE_HOSTDEV:
22974
        return iface->virtPortProfile;
A
Ansis Atteka 已提交
22975 22976 22977 22978 22979 22980
    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:
22981
        case VIR_DOMAIN_NET_TYPE_HOSTDEV:
22982
            return iface->data.network.actual->virtPortProfile;
A
Ansis Atteka 已提交
22983 22984 22985 22986
        default:
            return NULL;
        }
    default:
22987
        return NULL;
A
Ansis Atteka 已提交
22988
    }
22989
}
22990

22991
virNetDevBandwidthPtr
22992 22993
virDomainNetGetActualBandwidth(virDomainNetDefPtr iface)
{
22994 22995 22996
    /* if there is an ActualNetDef, *always* return
     * its bandwidth rather than the NetDef's bandwidth.
     */
E
Eric Blake 已提交
22997
    if (iface->type == VIR_DOMAIN_NET_TYPE_NETWORK &&
22998
        iface->data.network.actual)
22999 23000 23001
        return iface->data.network.actual->bandwidth;
    return iface->bandwidth;
}
23002

23003 23004 23005
virNetDevVlanPtr
virDomainNetGetActualVlan(virDomainNetDefPtr iface)
{
23006 23007 23008 23009 23010
    virNetDevVlanPtr vlan = &iface->vlan;

    /* if there is an ActualNetDef, *always* return
     * its vlan rather than the NetDef's vlan.
     */
23011
    if (iface->type == VIR_DOMAIN_NET_TYPE_NETWORK &&
23012 23013 23014 23015 23016 23017
        iface->data.network.actual)
        vlan = &iface->data.network.actual->vlan;

    if (vlan->nTags > 0)
        return vlan;
    return NULL;
23018
}
23019

23020 23021 23022 23023 23024 23025 23026 23027 23028 23029 23030 23031

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


23032
/* Return listens[i] from the appropriate union for the graphics
23033
 * type, or NULL if this is an unsuitable type, or the index is out of
23034
 * bounds. If force0 is TRUE, i == 0, and there is no listen array,
23035 23036
 * allocate one with a single item. */
static virDomainGraphicsListenDefPtr
23037
virDomainGraphicsGetListen(virDomainGraphicsDefPtr def, size_t i, bool force0)
23038
{
E
Eric Blake 已提交
23039 23040 23041
    if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC ||
        def->type == VIR_DOMAIN_GRAPHICS_TYPE_RDP ||
        def->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) {
23042

23043
        if (!def->listens && (i == 0) && force0) {
23044
            if (VIR_ALLOC(def->listens) >= 0)
23045 23046 23047
                def->nListens = 1;
        }

23048
        if (!def->listens || (def->nListens <= i))
23049 23050
            return NULL;

23051
        return &def->listens[i];
23052 23053 23054 23055 23056 23057 23058 23059 23060 23061 23062 23063 23064 23065 23066 23067 23068 23069 23070 23071 23072
    }

    /* 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
23073
virDomainGraphicsListenGetType(virDomainGraphicsDefPtr def, size_t i)
23074 23075
{
    virDomainGraphicsListenDefPtr listenInfo
23076
        = virDomainGraphicsGetListen(def, i, false);
23077 23078 23079 23080 23081 23082 23083 23084 23085 23086 23087

    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
23088
virDomainGraphicsListenSetType(virDomainGraphicsDefPtr def, size_t i, int val)
23089 23090
{
    virDomainGraphicsListenDefPtr listenInfo
23091
        = virDomainGraphicsGetListen(def, i, true);
23092 23093 23094 23095 23096 23097 23098 23099 23100

    if (!listenInfo)
        return -1;
    listenInfo->type = val;
    return 0;
}


const char *
23101
virDomainGraphicsListenGetAddress(virDomainGraphicsDefPtr def, size_t i)
23102 23103
{
    virDomainGraphicsListenDefPtr listenInfo
23104
        = virDomainGraphicsGetListen(def, i, false);
23105

23106
    /* even a network can have a listen address */
23107
    if (!listenInfo ||
23108 23109
        !(listenInfo->type == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS ||
          listenInfo->type == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NETWORK))
23110 23111 23112 23113 23114 23115
        return NULL;
    return listenInfo->address;
}


/* Make a copy of up to len characters of address, and store it in
23116
 * listens[i].address. If setType is true, set the listen's type
23117 23118 23119
 * to 'address', otherwise leave type alone. */
int
virDomainGraphicsListenSetAddress(virDomainGraphicsDefPtr def,
23120
                                  size_t i, const char *address,
23121 23122 23123
                                  int len, bool setType)
{
    virDomainGraphicsListenDefPtr listenInfo
23124
        = virDomainGraphicsGetListen(def, i, true);
23125 23126 23127 23128 23129 23130 23131 23132

    if (!listenInfo)
        return -1;

    if (setType)
        listenInfo->type = VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS;

    if (!address) {
23133
        VIR_FREE(listenInfo->address);
23134 23135 23136
        return 0;
    }

23137
    if (VIR_STRNDUP(listenInfo->address, address, len) < 0)
23138 23139 23140 23141 23142 23143
        return -1;
    return 0;
}


const char *
23144
virDomainGraphicsListenGetNetwork(virDomainGraphicsDefPtr def, size_t i)
23145 23146
{
    virDomainGraphicsListenDefPtr listenInfo
23147
        = virDomainGraphicsGetListen(def, i, false);
23148 23149 23150 23151 23152 23153 23154 23155 23156

    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
23157
 * listens[i].network */
23158 23159
int
virDomainGraphicsListenSetNetwork(virDomainGraphicsDefPtr def,
23160
                                  size_t i, const char *network, int len)
23161 23162
{
    virDomainGraphicsListenDefPtr listenInfo
23163
        = virDomainGraphicsGetListen(def, i, true);
23164 23165 23166 23167 23168 23169 23170

    if (!listenInfo)
        return -1;

    listenInfo->type = VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NETWORK;

    if (!network) {
23171
        VIR_FREE(listenInfo->network);
23172 23173 23174
        return 0;
    }

23175
    if (VIR_STRNDUP(listenInfo->network, network, len) < 0)
23176 23177 23178
        return -1;
    return 0;
}
23179 23180 23181 23182 23183 23184 23185 23186 23187 23188 23189 23190 23191 23192 23193

/**
 * 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;
23194
    virMacAddr mac;
23195
    size_t i;
23196

23197
    if (virMacAddrParse(device, &mac) == 0)
23198 23199 23200 23201
        isMac = true;

    if (isMac) {
        for (i = 0; i < def->nnets; i++) {
23202
            if (virMacAddrCmp(&mac, &def->nets[i]->mac) == 0) {
23203 23204 23205 23206 23207 23208 23209 23210 23211 23212 23213 23214 23215 23216 23217
                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;
}
23218 23219 23220 23221 23222 23223 23224 23225

/**
 * 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
23226
 * DeviceDef that are valid when just the flag VIR_DOMAIN_DEF_PARSE_INACTIVE is
23227 23228 23229 23230 23231 23232 23233
 * 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
23234
virDomainDeviceDefCopy(virDomainDeviceDefPtr src,
23235
                       const virDomainDef *def,
23236 23237
                       virCapsPtr caps,
                       virDomainXMLOptionPtr xmlopt)
23238 23239 23240
{
    virDomainDeviceDefPtr ret = NULL;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
23241
    int flags = VIR_DOMAIN_DEF_FORMAT_INACTIVE | VIR_DOMAIN_DEF_FORMAT_SECURE;
23242 23243 23244
    char *xmlStr = NULL;
    int rc = -1;

23245
    switch ((virDomainDeviceType) src->type) {
23246 23247 23248 23249 23250 23251 23252 23253 23254 23255 23256 23257 23258 23259 23260 23261 23262 23263 23264 23265 23266 23267 23268 23269 23270 23271 23272 23273 23274 23275 23276 23277 23278 23279 23280 23281 23282 23283 23284
    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;
23285 23286 23287
    case VIR_DOMAIN_DEVICE_RNG:
        rc = virDomainRNGDefFormat(&buf, src->data.rng, flags);
        break;
23288 23289 23290
    case VIR_DOMAIN_DEVICE_CHR:
        rc = virDomainChrDefFormat(&buf, src->data.chr, flags);
        break;
23291 23292 23293
    case VIR_DOMAIN_DEVICE_TPM:
        rc = virDomainTPMDefFormat(&buf, src->data.tpm, flags);
        break;
23294 23295 23296
    case VIR_DOMAIN_DEVICE_PANIC:
        rc = virDomainPanicDefFormat(&buf, src->data.panic);
        break;
23297 23298 23299
    case VIR_DOMAIN_DEVICE_MEMORY:
        rc = virDomainMemoryDefFormat(&buf, src->data.memory, flags);
        break;
23300 23301 23302
    case VIR_DOMAIN_DEVICE_NONE:
    case VIR_DOMAIN_DEVICE_SMARTCARD:
    case VIR_DOMAIN_DEVICE_MEMBALLOON:
L
Li Zhang 已提交
23303
    case VIR_DOMAIN_DEVICE_NVRAM:
23304
    case VIR_DOMAIN_DEVICE_SHMEM:
23305
    case VIR_DOMAIN_DEVICE_LAST:
23306 23307 23308 23309
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Copying definition of '%d' type "
                         "is not implemented yet."),
                       src->type);
23310 23311 23312 23313 23314 23315 23316
        goto cleanup;
    }

    if (rc < 0)
        goto cleanup;

    xmlStr = virBufferContentAndReset(&buf);
23317 23318
    ret = virDomainDeviceDefParse(xmlStr, def, caps, xmlopt,
                                  VIR_DOMAIN_DEF_PARSE_INACTIVE);
23319

23320
 cleanup:
23321 23322 23323
    VIR_FREE(xmlStr);
    return ret;
}
O
Osier Yang 已提交
23324 23325


23326 23327 23328
virSecurityLabelDefPtr
virDomainDefGetSecurityLabelDef(virDomainDefPtr def, const char *model)
{
23329
    size_t i;
23330
    virSecurityLabelDefPtr seclabel = NULL;
23331 23332 23333 23334 23335 23336 23337 23338 23339 23340 23341

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

23342
    return seclabel;
23343 23344 23345
}


23346 23347 23348
virSecurityDeviceLabelDefPtr
virDomainChrDefGetSecurityLabelDef(virDomainChrDefPtr def, const char *model)
{
23349
    size_t i;
23350 23351 23352 23353 23354 23355 23356 23357 23358 23359 23360

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

23361 23362 23363 23364 23365 23366 23367 23368 23369 23370 23371 23372 23373 23374 23375 23376 23377 23378 23379 23380 23381 23382 23383 23384

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,
23385 23386
                       virDomainDeviceDefPtr dev,
                       bool reportError)
23387 23388 23389 23390 23391 23392 23393 23394
{
    virDomainDefFindDeviceCallbackData data = { devAlias, dev };

    dev->type = VIR_DOMAIN_DEVICE_NONE;
    virDomainDeviceInfoIterateInternal(def, virDomainDefFindDeviceCallback,
                                       true, &data);

    if (dev->type == VIR_DOMAIN_DEVICE_NONE) {
23395 23396 23397 23398 23399 23400
        if (reportError) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("no device found with alias %s"), devAlias);
        } else {
            VIR_DEBUG("no device found with alias %s", devAlias);
        }
23401 23402 23403 23404 23405
        return -1;
    }

    return 0;
}
23406 23407 23408 23409 23410 23411 23412 23413 23414 23415 23416

/**
 * 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
23417 23418
virDomainDiskSourceIsBlockType(virStorageSourcePtr src,
                               bool report)
23419
{
23420 23421 23422 23423 23424
    if (!src->path) {
        if (report)
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("source path not found for device='lun' "
                             "using type='%d'"), src->type);
23425
        return false;
23426
    }
23427

23428
    if (src->type == VIR_STORAGE_TYPE_BLOCK)
23429 23430 23431 23432 23433
        return true;

    /* For volume types, check the srcpool.
     * If it's a block type source pool, then it's possible
     */
23434 23435 23436
    if (src->type == VIR_STORAGE_TYPE_VOLUME &&
        src->srcpool &&
        src->srcpool->voltype == VIR_STORAGE_VOL_BLOCK) {
23437 23438 23439 23440
        /* 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.
         */
23441
         if (src->srcpool->pooltype == VIR_STORAGE_POOL_ISCSI &&
23442 23443 23444 23445 23446
             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'."));
23447
             return false;
23448
         }
23449

23450 23451
        return true;
    }
23452 23453 23454 23455
    if (report)
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("disk device='lun' is only valid for block "
                         "type disk source"));
23456 23457
    return false;
}
23458 23459 23460 23461 23462 23463 23464 23465 23466 23467 23468 23469 23470 23471 23472 23473


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

23474 23475 23476 23477 23478 23479
    if (type >= VIR_DOMAIN_METADATA_LAST) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("unknown metadata type '%d'"), type);
        goto cleanup;
    }

23480 23481 23482 23483 23484 23485 23486 23487 23488
    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:
23489 23490
        if (VIR_STRDUP(ret, def->description) < 0)
            goto cleanup;
23491 23492 23493
        break;

    case VIR_DOMAIN_METADATA_TITLE:
23494 23495
        if (VIR_STRDUP(ret, def->title) < 0)
            goto cleanup;
23496 23497 23498
        break;

    case VIR_DOMAIN_METADATA_ELEMENT:
23499 23500 23501 23502 23503
        if (!def->metadata)
            break;

        if (virXMLExtractNamespaceXML(def->metadata, uri, &ret) < 0)
            goto cleanup;
23504 23505
        break;

23506
    /* coverity[dead_error_begin] */
23507
    case VIR_DOMAIN_METADATA_LAST:
23508 23509 23510
        break;
    }

23511
    if (!ret)
23512 23513 23514
        virReportError(VIR_ERR_NO_DOMAIN_METADATA, "%s",
                       _("Requested metadata element is not present"));

23515
 cleanup:
23516 23517
    return ret;
}
23518

23519 23520 23521 23522 23523

static int
virDomainDefSetMetadata(virDomainDefPtr def,
                        int type,
                        const char *metadata,
23524 23525
                        const char *key,
                        const char *uri)
23526
{
23527 23528
    xmlDocPtr doc = NULL;
    xmlNodePtr old;
23529
    xmlNodePtr new = NULL;
23530
    char *tmp;
23531 23532
    int ret = -1;

23533 23534 23535 23536 23537 23538
    if (type >= VIR_DOMAIN_METADATA_LAST) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("unknown metadata type '%d'"), type);
        goto cleanup;
    }

23539 23540
    switch ((virDomainMetadataType) type) {
    case VIR_DOMAIN_METADATA_DESCRIPTION:
23541
        if (VIR_STRDUP(tmp, metadata) < 0)
23542
            goto cleanup;
23543 23544 23545

        VIR_FREE(def->description);
        def->description = tmp;
23546 23547 23548
        break;

    case VIR_DOMAIN_METADATA_TITLE:
23549
        if (VIR_STRDUP(tmp, metadata) < 0)
23550
            goto cleanup;
23551 23552 23553

        VIR_FREE(def->title);
        def->title = tmp;
23554 23555 23556
        break;

    case VIR_DOMAIN_METADATA_ELEMENT:
23557 23558 23559 23560 23561 23562 23563 23564 23565 23566 23567 23568 23569 23570 23571 23572 23573 23574 23575 23576 23577 23578 23579 23580 23581 23582 23583
        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);
        }

23584 23585
        if (new &&
            !(xmlAddChild(def->metadata, new))) {
23586 23587 23588 23589
            xmlFreeNode(new);
            virReportOOMError();
            goto cleanup;
        }
23590 23591
        break;

23592
    /* coverity[dead_error_begin] */
23593
    case VIR_DOMAIN_METADATA_LAST:
23594 23595 23596 23597 23598
        break;
    }

    ret = 0;

23599
 cleanup:
23600
    xmlFreeDoc(doc);
23601 23602 23603 23604
    return ret;
}


23605 23606 23607 23608
int
virDomainObjSetMetadata(virDomainObjPtr vm,
                        int type,
                        const char *metadata,
23609 23610
                        const char *key,
                        const char *uri,
23611 23612
                        virCapsPtr caps,
                        virDomainXMLOptionPtr xmlopt,
23613
                        const char *stateDir,
23614 23615 23616 23617 23618 23619 23620 23621 23622 23623
                        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)
23624
        return -1;
23625

23626
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
23627 23628
        if (virDomainDefSetMetadata(vm->def, type, metadata, key, uri) < 0)
            return -1;
23629

23630 23631 23632 23633
        if (virDomainSaveStatus(xmlopt, stateDir, vm) < 0)
            return -1;
    }

23634
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
23635 23636
        if (virDomainDefSetMetadata(persistentDef, type, metadata, key,
                                    uri) < 0)
23637
            return -1;
23638 23639

        if (virDomainSaveConfig(configDir, persistentDef) < 0)
23640
            return -1;
23641 23642
    }

23643
    return 0;
23644
}
23645 23646 23647 23648 23649 23650 23651 23652


bool
virDomainDefNeedsPlacementAdvice(virDomainDefPtr def)
{
    if (def->placement_mode == VIR_DOMAIN_CPU_PLACEMENT_MODE_AUTO)
        return true;

23653
    if (virDomainNumatuneHasPlacementAuto(def->numa))
23654 23655 23656 23657
        return true;

    return false;
}
23658 23659 23660


int
23661
virDomainDefCheckDuplicateDiskInfo(virDomainDefPtr def)
23662 23663 23664 23665 23666
{
    size_t i;
    size_t j;

    for (i = 0; i < def->ndisks; i++) {
23667
        if (def->disks[i]->wwn || def->disks[i]->serial) {
23668
            for (j = i + 1; j < def->ndisks; j++) {
23669 23670
                if (def->disks[i]->wwn &&
                    STREQ_NULLABLE(def->disks[i]->wwn,
23671 23672 23673 23674 23675 23676 23677
                                   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;
                }
23678 23679 23680 23681 23682 23683 23684 23685 23686 23687

                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;
                }
23688 23689 23690 23691 23692 23693
            }
        }
    }

    return 0;
}