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

#include <config.h>

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

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

57 58
#define VIR_FROM_THIS VIR_FROM_DOMAIN

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

63 64 65 66 67 68 69 70 71

struct _virDomainObjList {
    virObjectLockable parent;

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

72 73 74

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

78 79 80
    /* XML parser callbacks and defaults */
    virDomainDefParserConfig config;

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

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


89 90
/* Private flags used internally by virDomainSaveStatus and
 * virDomainLoadStatus. */
91
typedef enum {
92 93 94 95 96 97
   /* dump internal domain status information */
   VIR_DOMAIN_XML_INTERNAL_STATUS = (1<<16),
   /* dump/parse <actual> element */
   VIR_DOMAIN_XML_INTERNAL_ACTUAL_NET = (1<<17),
   /* dump/parse original states of host PCI device */
   VIR_DOMAIN_XML_INTERNAL_PCI_ORIG_STATES = (1<<18),
98 99
   VIR_DOMAIN_XML_INTERNAL_ALLOW_ROM = (1<<19),
   VIR_DOMAIN_XML_INTERNAL_ALLOW_BOOT = (1<<20),
100
   VIR_DOMAIN_XML_INTERNAL_BASEDATE = (1 << 21),
101 102
} virDomainXMLInternalFlags;

103 104 105 106 107
VIR_ENUM_IMPL(virDomainTaint, VIR_DOMAIN_TAINT_LAST,
              "custom-argv",
              "custom-monitor",
              "high-privileges",
              "shell-scripts",
108
              "disk-probing",
109 110
              "external-launch",
              "host-cpu");
111

112 113 114 115 116 117 118 119 120 121
VIR_ENUM_IMPL(virDomainVirt, VIR_DOMAIN_VIRT_LAST,
              "qemu",
              "kqemu",
              "kvm",
              "xen",
              "lxc",
              "uml",
              "openvz",
              "test",
              "vmware",
122
              "hyperv",
D
Daniel Veillard 已提交
123
              "vbox",
D
Dmitry Guryanov 已提交
124 125
              "phyp",
              "parallels")
126 127 128 129 130 131 132

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

133 134 135 136 137
VIR_ENUM_IMPL(virDomainBootMenu, VIR_DOMAIN_BOOT_MENU_LAST,
              "default",
              "yes",
              "no")

138 139 140
VIR_ENUM_IMPL(virDomainFeature, VIR_DOMAIN_FEATURE_LAST,
              "acpi",
              "apic",
J
Jim Fehlig 已提交
141
              "pae",
142
              "hap",
143
              "viridian",
144 145
              "privnet",
              "hyperv")
146

147
VIR_ENUM_IMPL(virDomainFeatureState, VIR_DOMAIN_FEATURE_STATE_LAST,
148 149 150 151
              "default",
              "on",
              "off")

152
VIR_ENUM_IMPL(virDomainHyperv, VIR_DOMAIN_HYPERV_LAST,
153 154 155
              "relaxed",
              "vapic",
              "spinlocks")
156

157 158 159 160 161 162
VIR_ENUM_IMPL(virDomainLifecycle, VIR_DOMAIN_LIFECYCLE_LAST,
              "destroy",
              "restart",
              "rename-restart",
              "preserve")

163 164 165 166 167 168 169 170
VIR_ENUM_IMPL(virDomainLifecycleCrash, VIR_DOMAIN_LIFECYCLE_CRASH_LAST,
              "destroy",
              "restart",
              "rename-restart",
              "preserve",
              "coredump-destroy",
              "coredump-restart")

171 172 173 174 175 176 177
VIR_ENUM_IMPL(virDomainLockFailure, VIR_DOMAIN_LOCK_FAILURE_LAST,
              "default",
              "poweroff",
              "restart",
              "pause",
              "ignore")

178 179 180 181 182
VIR_ENUM_IMPL(virDomainPMState, VIR_DOMAIN_PM_STATE_LAST,
              "default",
              "yes",
              "no")

183
VIR_ENUM_IMPL(virDomainDevice, VIR_DOMAIN_DEVICE_LAST,
184
              "none",
185
              "disk",
186
              "lease",
187 188 189 190
              "filesystem",
              "interface",
              "input",
              "sound",
191
              "video",
R
Richard Jones 已提交
192
              "hostdev",
193
              "watchdog",
194
              "controller",
M
Marc-André Lureau 已提交
195
              "graphics",
196
              "hub",
197 198 199
              "redirdev",
              "smartcard",
              "chr",
200
              "memballoon",
L
Li Zhang 已提交
201
              "nvram",
202
              "rng")
203

204 205
VIR_ENUM_IMPL(virDomainDeviceAddress, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST,
              "none",
206
              "pci",
207
              "drive",
E
Eric Blake 已提交
208
              "virtio-serial",
209
              "ccid",
210
              "usb",
211
              "spapr-vio",
212
              "virtio-s390",
213 214
              "ccw",
              "virtio-mmio")
215

216 217
VIR_ENUM_IMPL(virDomainDisk, VIR_DOMAIN_DISK_TYPE_LAST,
              "block",
218
              "file",
M
MORITA Kazutaka 已提交
219
              "dir",
220 221
              "network",
              "volume")
222 223 224 225

VIR_ENUM_IMPL(virDomainDiskDevice, VIR_DOMAIN_DISK_DEVICE_LAST,
              "disk",
              "cdrom",
226 227
              "floppy",
              "lun")
228

J
J.B. Joret 已提交
229 230 231 232 233 234
VIR_ENUM_IMPL(virDomainDiskGeometryTrans, VIR_DOMAIN_DISK_TRANS_LAST,
              "default",
              "none",
              "auto",
              "lba")

235 236 237 238 239
VIR_ENUM_IMPL(virDomainDiskBus, VIR_DOMAIN_DISK_BUS_LAST,
              "ide",
              "fdc",
              "scsi",
              "virtio",
240
              "xen",
241
              "usb",
242
              "uml",
243 244
              "sata",
              "sd")
245

246 247 248 249
VIR_ENUM_IMPL(virDomainDiskCache, VIR_DOMAIN_DISK_CACHE_LAST,
              "default",
              "none",
              "writethrough",
250
              "writeback",
251 252
              "directsync",
              "unsafe")
253

254 255 256
VIR_ENUM_IMPL(virDomainDiskErrorPolicy, VIR_DOMAIN_DISK_ERROR_POLICY_LAST,
              "default",
              "stop",
257
              "report",
258 259
              "ignore",
              "enospace")
260

M
MORITA Kazutaka 已提交
261 262 263
VIR_ENUM_IMPL(virDomainDiskProtocol, VIR_DOMAIN_DISK_PROTOCOL_LAST,
              "nbd",
              "rbd",
264
              "sheepdog",
265
              "gluster",
266
              "iscsi",
267
              "http",
268
              "https",
269
              "ftp",
270 271
              "ftps",
              "tftp")
272 273 274 275 276

VIR_ENUM_IMPL(virDomainDiskProtocolTransport, VIR_DOMAIN_DISK_PROTO_TRANS_LAST,
              "tcp",
              "unix",
              "rdma")
M
MORITA Kazutaka 已提交
277

278 279 280 281 282
VIR_ENUM_IMPL(virDomainDiskSecretType, VIR_DOMAIN_DISK_SECRET_TYPE_LAST,
              "none",
              "uuid",
              "usage")

M
Matthias Dahl 已提交
283 284 285 286
VIR_ENUM_IMPL(virDomainDiskIo, VIR_DOMAIN_DISK_IO_LAST,
              "default",
              "native",
              "threads")
O
Osier Yang 已提交
287

288
VIR_ENUM_IMPL(virDomainDeviceSGIO, VIR_DOMAIN_DEVICE_SGIO_LAST,
O
Osier Yang 已提交
289 290 291 292
              "default",
              "filtered",
              "unfiltered")

293 294 295 296 297
VIR_ENUM_IMPL(virDomainIoEventFd, VIR_DOMAIN_IO_EVENT_FD_LAST,
              "default",
              "on",
              "off")

298 299 300 301
VIR_ENUM_IMPL(virDomainVirtioEventIdx, VIR_DOMAIN_VIRTIO_EVENT_IDX_LAST,
              "default",
              "on",
              "off")
M
Matthias Dahl 已提交
302

O
Osier Yang 已提交
303 304 305 306 307
VIR_ENUM_IMPL(virDomainDiskCopyOnRead, VIR_DOMAIN_DISK_COPY_ON_READ_LAST,
              "default",
              "on",
              "off")

308 309 310 311
VIR_ENUM_IMPL(virDomainController, VIR_DOMAIN_CONTROLLER_TYPE_LAST,
              "ide",
              "fdc",
              "scsi",
312
              "sata",
E
Eric Blake 已提交
313
              "virtio-serial",
314
              "ccid",
J
Ján Tomko 已提交
315 316 317 318 319
              "usb",
              "pci")

VIR_ENUM_IMPL(virDomainControllerModelPCI, VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST,
              "pci-root",
L
Laine Stump 已提交
320
              "pcie-root",
321 322
              "pci-bridge",
              "dmi-to-pci-bridge")
323

324
VIR_ENUM_IMPL(virDomainControllerModelSCSI, VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LAST,
325
              "auto",
326 327
              "buslogic",
              "lsilogic",
328
              "lsisas1068",
329
              "vmpvscsi",
330
              "ibmvscsi",
331 332
              "virtio-scsi",
              "lsisas1078");
333

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

347 348 349 350
VIR_ENUM_IMPL(virDomainFS, VIR_DOMAIN_FS_TYPE_LAST,
              "mount",
              "block",
              "file",
351
              "template",
352 353
              "ram",
              "bind")
354

355 356 357
VIR_ENUM_IMPL(virDomainFSDriverType, VIR_DOMAIN_FS_DRIVER_TYPE_LAST,
              "default",
              "path",
358
              "handle",
359 360
              "loop",
              "nbd")
361

362 363 364 365 366
VIR_ENUM_IMPL(virDomainFSAccessMode, VIR_DOMAIN_FS_ACCESSMODE_LAST,
              "passthrough",
              "mapped",
              "squash")

367 368 369
VIR_ENUM_IMPL(virDomainFSWrpolicy, VIR_DOMAIN_FS_WRPOLICY_LAST,
              "default",
              "immediate")
370

371 372 373 374 375 376 377
VIR_ENUM_IMPL(virDomainNet, VIR_DOMAIN_NET_TYPE_LAST,
              "user",
              "ethernet",
              "server",
              "client",
              "mcast",
              "network",
D
Daniel Veillard 已提交
378
              "bridge",
379
              "internal",
380 381
              "direct",
              "hostdev")
382

383 384 385 386 387
VIR_ENUM_IMPL(virDomainNetBackend, VIR_DOMAIN_NET_BACKEND_TYPE_LAST,
              "default",
              "qemu",
              "vhost")

388 389 390 391 392
VIR_ENUM_IMPL(virDomainNetVirtioTxMode, VIR_DOMAIN_NET_VIRTIO_TX_MODE_LAST,
              "default",
              "iothread",
              "timer")

393 394 395 396 397
VIR_ENUM_IMPL(virDomainNetInterfaceLinkState, VIR_DOMAIN_NET_INTERFACE_LINK_STATE_LAST,
              "default",
              "up",
              "down")

G
Guannan Ren 已提交
398 399 400 401 402
VIR_ENUM_IMPL(virDomainChrSerialTarget,
              VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_LAST,
              "isa-serial",
              "usb-serial")

403 404
VIR_ENUM_IMPL(virDomainChrChannelTarget,
              VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_LAST,
405
              "none",
406 407 408
              "guestfwd",
              "virtio")

409 410
VIR_ENUM_IMPL(virDomainChrConsoleTarget,
              VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_LAST,
411
              "none",
412 413
              "serial",
              "xen",
C
Cole Robinson 已提交
414
              "uml",
415 416
              "virtio",
              "lxc",
417 418 419
              "openvz",
              "sclp",
              "sclplm")
420

421
VIR_ENUM_IMPL(virDomainChrDevice, VIR_DOMAIN_CHR_DEVICE_TYPE_LAST,
422 423
              "parallel",
              "serial",
424
              "console",
425
              "channel")
426

427 428 429 430 431 432 433 434 435 436
VIR_ENUM_IMPL(virDomainChr, VIR_DOMAIN_CHR_TYPE_LAST,
              "null",
              "vc",
              "pty",
              "dev",
              "file",
              "pipe",
              "stdio",
              "udp",
              "tcp",
437 438
              "unix",
              "spicevmc")
439

440 441 442 443 444 445
VIR_ENUM_IMPL(virDomainChrTcpProtocol, VIR_DOMAIN_CHR_TCP_PROTOCOL_LAST,
              "raw",
              "telnet",
              "telnets",
              "tls")

E
Eric Blake 已提交
446 447
VIR_ENUM_IMPL(virDomainChrSpicevmc, VIR_DOMAIN_CHR_SPICEVMC_LAST,
              "vdagent",
448 449
              "smartcard",
              "usbredir")
E
Eric Blake 已提交
450

E
Eric Blake 已提交
451 452 453 454 455
VIR_ENUM_IMPL(virDomainSmartcard, VIR_DOMAIN_SMARTCARD_TYPE_LAST,
              "host",
              "host-certificates",
              "passthrough")

456 457 458 459
VIR_ENUM_IMPL(virDomainSoundCodec, VIR_DOMAIN_SOUND_CODEC_TYPE_LAST,
              "duplex",
              "micro")

460 461 462
VIR_ENUM_IMPL(virDomainSoundModel, VIR_DOMAIN_SOUND_MODEL_LAST,
              "sb16",
              "es1370",
463
              "pcspk",
464 465
              "ac97",
              "ich6")
466

467 468 469 470 471
VIR_ENUM_IMPL(virDomainMemDump, VIR_DOMAIN_MEM_DUMP_LAST,
              "default",
              "on",
              "off")

472 473
VIR_ENUM_IMPL(virDomainMemballoonModel, VIR_DOMAIN_MEMBALLOON_MODEL_LAST,
              "virtio",
474
              "xen",
475 476
              "none")

477 478 479 480 481 482
VIR_ENUM_IMPL(virDomainSmbiosMode, VIR_DOMAIN_SMBIOS_LAST,
              "none",
              "emulate",
              "host",
              "sysinfo")

R
Richard Jones 已提交
483 484 485 486 487 488 489 490 491
VIR_ENUM_IMPL(virDomainWatchdogModel, VIR_DOMAIN_WATCHDOG_MODEL_LAST,
              "i6300esb",
              "ib700")

VIR_ENUM_IMPL(virDomainWatchdogAction, VIR_DOMAIN_WATCHDOG_ACTION_LAST,
              "reset",
              "shutdown",
              "poweroff",
              "pause",
H
Hu Tao 已提交
492
              "dump",
R
Richard Jones 已提交
493 494
              "none")

495 496 497 498 499
VIR_ENUM_IMPL(virDomainVideo, VIR_DOMAIN_VIDEO_TYPE_LAST,
              "vga",
              "cirrus",
              "vmvga",
              "xen",
500 501
              "vbox",
              "qxl")
502

503 504 505 506 507 508 509 510 511 512 513
VIR_ENUM_IMPL(virDomainInput, VIR_DOMAIN_INPUT_TYPE_LAST,
              "mouse",
              "tablet")

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

VIR_ENUM_IMPL(virDomainGraphics, VIR_DOMAIN_GRAPHICS_TYPE_LAST,
              "sdl",
514 515
              "vnc",
              "rdp",
516 517
              "desktop",
              "spice")
518

519 520 521 522 523
VIR_ENUM_IMPL(virDomainGraphicsListen, VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_LAST,
              "none",
              "address",
              "network")

524 525 526 527 528 529 530
VIR_ENUM_IMPL(virDomainGraphicsAuthConnected,
              VIR_DOMAIN_GRAPHICS_AUTH_CONNECTED_LAST,
              "default",
              "fail",
              "disconnect",
              "keep")

531 532 533 534 535 536 537
VIR_ENUM_IMPL(virDomainGraphicsVNCSharePolicy,
              VIR_DOMAIN_GRAPHICS_VNC_SHARE_LAST,
              "default",
              "allow-exclusive",
              "force-shared",
              "ignore")

538 539 540 541 542 543 544
VIR_ENUM_IMPL(virDomainGraphicsSpiceChannelName,
              VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_LAST,
              "main",
              "display",
              "inputs",
              "cursor",
              "playback",
E
Eric Blake 已提交
545
              "record",
546 547
              "smartcard",
              "usbredir");
548 549 550 551 552 553 554

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

555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584
VIR_ENUM_IMPL(virDomainGraphicsSpiceImageCompression,
              VIR_DOMAIN_GRAPHICS_SPICE_IMAGE_COMPRESSION_LAST,
              "default",
              "auto_glz",
              "auto_lz",
              "quic",
              "glz",
              "lz",
              "off");

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

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

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

P
Peng Zhou 已提交
585 586 587 588 589 590
VIR_ENUM_IMPL(virDomainGraphicsSpiceMouseMode,
              VIR_DOMAIN_GRAPHICS_SPICE_MOUSE_MODE_LAST,
              "default",
              "server",
              "client");

591 592 593 594 595 596 597
VIR_ENUM_IMPL(virDomainGraphicsSpiceStreamingMode,
              VIR_DOMAIN_GRAPHICS_SPICE_STREAMING_MODE_LAST,
              "default",
              "filter",
              "all",
              "off");

598 599 600 601 602 603
VIR_ENUM_IMPL(virDomainGraphicsSpiceClipboardCopypaste,
              VIR_DOMAIN_GRAPHICS_SPICE_CLIPBOARD_COPYPASTE_LAST,
              "default",
              "yes",
              "no");

604 605 606 607 608 609
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 已提交
610 611
              "pci",
              "scsi")
612

613 614 615 616 617 618
VIR_ENUM_IMPL(virDomainHostdevSubsysPciBackend,
              VIR_DOMAIN_HOSTDEV_PCI_BACKEND_TYPE_LAST,
              "default",
              "kvm",
              "vfio")

619 620
VIR_ENUM_IMPL(virDomainHostdevCaps, VIR_DOMAIN_HOSTDEV_CAPS_TYPE_LAST,
              "storage",
621 622
              "misc",
              "net")
623

624 625 626 627 628 629
VIR_ENUM_IMPL(virDomainPciRombarMode,
              VIR_DOMAIN_PCI_ROMBAR_LAST,
              "default",
              "on",
              "off")

630 631 632 633 634 635 636
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,
637 638 639 640 641 642
              "nostate",
              "running",
              "blocked",
              "paused",
              "shutdown",
              "shutoff",
O
Osier Yang 已提交
643 644
              "crashed",
              "pmsuspended")
645

J
Jiri Denemark 已提交
646 647 648 649 650 651 652 653 654 655 656
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",
657
              "save canceled",
658 659
              "wakeup",
              "crashed")
J
Jiri Denemark 已提交
660 661 662 663 664 665 666 667 668 669 670 671

VIR_ENUM_IMPL(virDomainBlockedReason, VIR_DOMAIN_BLOCKED_LAST,
              "unknown")

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

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

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,
692 693
              "unknown",
              "panicked")
J
Jiri Denemark 已提交
694

695 696 697
VIR_ENUM_IMPL(virDomainPMSuspendedReason, VIR_DOMAIN_PMSUSPENDED_LAST,
              "unknown")

698
VIR_ENUM_IMPL(virDomainSeclabel, VIR_DOMAIN_SECLABEL_LAST,
699 700
              "default",
              "none",
701 702 703
              "dynamic",
              "static")

704 705
VIR_ENUM_IMPL(virDomainClockOffset, VIR_DOMAIN_CLOCK_OFFSET_LAST,
              "utc",
706
              "localtime",
707 708
              "variable",
              "timezone");
709

710 711 712 713
VIR_ENUM_IMPL(virDomainClockBasis, VIR_DOMAIN_CLOCK_BASIS_LAST,
              "utc",
              "localtime");

714 715 716 717 718
VIR_ENUM_IMPL(virDomainTimerName, VIR_DOMAIN_TIMER_NAME_LAST,
              "platform",
              "pit",
              "rtc",
              "hpet",
P
Paolo Bonzini 已提交
719 720
              "tsc",
              "kvmclock");
721

722 723 724 725
VIR_ENUM_IMPL(virDomainTimerTrack, VIR_DOMAIN_TIMER_TRACK_LAST,
              "boot",
              "guest",
              "wall");
726 727 728 729 730 731 732 733 734 735 736

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",
737 738
              "paravirt",
              "smpsafe");
739

740 741 742 743 744 745
VIR_ENUM_IMPL(virDomainStartupPolicy, VIR_DOMAIN_STARTUP_POLICY_LAST,
              "default",
              "mandatory",
              "requisite",
              "optional");

O
Osier Yang 已提交
746 747 748 749
VIR_ENUM_IMPL(virDomainCpuPlacementMode, VIR_DOMAIN_CPU_PLACEMENT_MODE_LAST,
              "static",
              "auto");

750 751 752 753
VIR_ENUM_IMPL(virDomainDiskTray, VIR_DOMAIN_DISK_TRAY_LAST,
              "closed",
              "open");

754 755 756 757 758 759 760 761 762
VIR_ENUM_IMPL(virDomainRNGModel,
              VIR_DOMAIN_RNG_MODEL_LAST,
              "virtio");

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

763 764 765 766 767 768
VIR_ENUM_IMPL(virDomainTPMModel, VIR_DOMAIN_TPM_MODEL_LAST,
              "tpm-tis")

VIR_ENUM_IMPL(virDomainTPMBackend, VIR_DOMAIN_TPM_TYPE_LAST,
              "passthrough")

O
Osier Yang 已提交
769 770
VIR_ENUM_IMPL(virDomainDiskDiscard, VIR_DOMAIN_DISK_DISCARD_LAST,
              "default",
O
Osier Yang 已提交
771 772
              "unmap",
              "ignore")
773 774 775 776 777
VIR_ENUM_IMPL(virDomainDiskSourcePoolMode,
              VIR_DOMAIN_DISK_SOURCE_POOL_MODE_LAST,
              "default",
              "host",
              "direct")
778

779 780 781
#define VIR_DOMAIN_XML_WRITE_FLAGS  VIR_DOMAIN_XML_SECURE
#define VIR_DOMAIN_XML_READ_FLAGS   VIR_DOMAIN_XML_INACTIVE

782
static virClassPtr virDomainObjClass;
783
static virClassPtr virDomainObjListClass;
784
static virClassPtr virDomainXMLOptionClass;
785
static void virDomainObjDispose(void *obj);
786
static void virDomainObjListDispose(void *obj);
787
static void virDomainXMLOptionClassDispose(void *obj);
788 789 790

static int virDomainObjOnceInit(void)
{
791
    if (!(virDomainObjClass = virClassNew(virClassForObjectLockable(),
792
                                          "virDomainObj",
793 794 795 796
                                          sizeof(virDomainObj),
                                          virDomainObjDispose)))
        return -1;

797 798 799 800 801 802
    if (!(virDomainObjListClass = virClassNew(virClassForObjectLockable(),
                                              "virDomainObjList",
                                              sizeof(virDomainObjList),
                                              virDomainObjListDispose)))
        return -1;

803 804 805
    if (!(virDomainXMLOptionClass = virClassNew(virClassForObject(),
                                                "virDomainXMLOption",
                                                sizeof(virDomainXMLOption),
806
                                                virDomainXMLOptionClassDispose)))
807 808
        return -1;

809 810 811 812 813
    return 0;
}

VIR_ONCE_GLOBAL_INIT(virDomainObj)

814

815 816 817 818 819 820 821 822 823 824
static void
virDomainXMLOptionClassDispose(void *obj)
{
    virDomainXMLOptionPtr xmlopt = obj;

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


825
/**
826
 * virDomainXMLOptionNew:
827 828 829
 *
 * Allocate a new domain XML configuration
 */
830
virDomainXMLOptionPtr
831 832
virDomainXMLOptionNew(virDomainDefParserConfigPtr config,
                      virDomainXMLPrivateDataCallbacksPtr priv,
833
                      virDomainXMLNamespacePtr xmlns)
834
{
835
    virDomainXMLOptionPtr xmlopt;
836 837 838 839

    if (virDomainObjInitialize() < 0)
        return NULL;

840
    if (!(xmlopt = virObjectNew(virDomainXMLOptionClass)))
841 842 843
        return NULL;

    if (priv)
844
        xmlopt->privateData = *priv;
845

846 847 848
    if (config)
        xmlopt->config = *config;

849
    if (xmlns)
850
        xmlopt->ns = *xmlns;
851

852 853 854 855 856 857 858 859 860 861 862 863
    /* 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;
    }

864
    return xmlopt;
865 866 867
}

/**
868
 * virDomainXMLOptionGetNamespace:
869
 *
870
 * @xmlopt: XML parser configuration object
871 872
 *
 * Returns a pointer to the stored namespace structure.
873
 * The lifetime of the pointer is equal to @xmlopt;
874 875
 */
virDomainXMLNamespacePtr
876
virDomainXMLOptionGetNamespace(virDomainXMLOptionPtr xmlopt)
877
{
878
    return &xmlopt->ns;
879 880 881
}


882 883 884 885
void
virBlkioDeviceWeightArrayClear(virBlkioDeviceWeightPtr deviceWeights,
                               int ndevices)
{
886
    size_t i;
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

    for (i = 0; i < ndevices; i++)
        VIR_FREE(deviceWeights[i].path);
}

/**
 * virDomainBlkioDeviceWeightParseXML
 *
 * this function parses a XML node:
 *
 *   <device>
 *     <path>/fully/qualified/device/path</path>
 *     <weight>weight</weight>
 *   </device>
 *
 * and fills a virBlkioDeviceWeight struct.
 */
static int
virDomainBlkioDeviceWeightParseXML(xmlNodePtr root,
                                   virBlkioDeviceWeightPtr dw)
{
    char *c;
    xmlNodePtr node;

    node = root->children;
    while (node) {
        if (node->type == XML_ELEMENT_NODE) {
            if (xmlStrEqual(node->name, BAD_CAST "path") && !dw->path) {
                dw->path = (char *)xmlNodeGetContent(node);
            } else if (xmlStrEqual(node->name, BAD_CAST "weight")) {
                c = (char *)xmlNodeGetContent(node);
                if (virStrToLong_ui(c, NULL, 10, &dw->weight) < 0) {
919 920 921
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("could not parse weight %s"),
                                   c);
922 923 924 925 926 927 928 929 930 931
                    VIR_FREE(c);
                    VIR_FREE(dw->path);
                    return -1;
                }
                VIR_FREE(c);
            }
        }
        node = node->next;
    }
    if (!dw->path) {
932 933
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("missing per-device path"));
934 935 936 937 938 939 940 941
        return -1;
    }

    return 0;
}



942
static void
943
virDomainObjListDataFree(void *payload, const void *name ATTRIBUTE_UNUSED)
944 945
{
    virDomainObjPtr obj = payload;
946
    virObjectUnref(obj);
947 948
}

949
virDomainObjListPtr virDomainObjListNew(void)
950
{
951 952
    virDomainObjListPtr doms;

953 954 955 956
    if (virDomainObjInitialize() < 0)
        return NULL;

    if (!(doms = virObjectLockableNew(virDomainObjListClass)))
957 958
        return NULL;

959 960
    if (!(doms->objs = virHashCreate(50, virDomainObjListDataFree))) {
        virObjectUnref(doms);
961 962
        return NULL;
    }
963

964
    return doms;
965
}
966

967

968
static void virDomainObjListDispose(void *obj)
969
{
970 971
    virDomainObjListPtr doms = obj;

972
    virHashFree(doms->objs);
973 974 975 976
}


static int virDomainObjListSearchID(const void *payload,
977
                                    const void *name ATTRIBUTE_UNUSED,
978 979 980 981 982 983
                                    const void *data)
{
    virDomainObjPtr obj = (virDomainObjPtr)payload;
    const int *id = data;
    int want = 0;

984
    virObjectLock(obj);
D
Daniel P. Berrange 已提交
985
    if (virDomainObjIsActive(obj) &&
986 987
        obj->def->id == *id)
        want = 1;
988
    virObjectUnlock(obj);
989 990 991
    return want;
}

992 993
virDomainObjPtr virDomainObjListFindByID(const virDomainObjListPtr doms,
                                         int id)
994 995
{
    virDomainObjPtr obj;
996
    virObjectLock(doms);
997 998
    obj = virHashSearch(doms->objs, virDomainObjListSearchID, &id);
    if (obj)
999
        virObjectLock(obj);
1000
    virObjectUnlock(doms);
1001
    return obj;
1002 1003 1004
}


1005 1006
virDomainObjPtr virDomainObjListFindByUUID(const virDomainObjListPtr doms,
                                           const unsigned char *uuid)
1007
{
1008 1009
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    virDomainObjPtr obj;
1010

1011
    virObjectLock(doms);
1012
    virUUIDFormat(uuid, uuidstr);
1013

1014 1015
    obj = virHashLookup(doms->objs, uuidstr);
    if (obj)
1016
        virObjectLock(obj);
1017
    virObjectUnlock(doms);
1018 1019 1020 1021
    return obj;
}

static int virDomainObjListSearchName(const void *payload,
1022
                                      const void *name ATTRIBUTE_UNUSED,
1023 1024 1025 1026 1027
                                      const void *data)
{
    virDomainObjPtr obj = (virDomainObjPtr)payload;
    int want = 0;

1028
    virObjectLock(obj);
1029 1030
    if (STREQ(obj->def->name, (const char *)data))
        want = 1;
1031
    virObjectUnlock(obj);
1032
    return want;
1033 1034
}

1035 1036
virDomainObjPtr virDomainObjListFindByName(const virDomainObjListPtr doms,
                                           const char *name)
1037
{
1038
    virDomainObjPtr obj;
1039
    virObjectLock(doms);
1040 1041
    obj = virHashSearch(doms->objs, virDomainObjListSearchName, name);
    if (obj)
1042
        virObjectLock(obj);
1043
    virObjectUnlock(doms);
1044
    return obj;
1045 1046
}

1047 1048 1049 1050

bool virDomainObjTaint(virDomainObjPtr obj,
                       enum virDomainTaintFlags taint)
{
E
Eric Blake 已提交
1051
    unsigned int flag = (1 << taint);
1052 1053 1054 1055 1056 1057 1058 1059

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

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

1060 1061 1062 1063 1064 1065 1066 1067 1068
static void
virDomainDeviceInfoFree(virDomainDeviceInfoPtr info)
{
    if (info) {
        virDomainDeviceInfoClear(info);
        VIR_FREE(info);
    }
}

1069

1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080
static void
virDomainGraphicsAuthDefClear(virDomainGraphicsAuthDefPtr def)
{
    if (!def)
        return;

    VIR_FREE(def->passwd);

    /* Don't free def */
}

1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091
static void
virDomainGraphicsListenDefClear(virDomainGraphicsListenDefPtr def)
{
    if (!def)
        return;

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

1092
void
1093
virSecurityLabelDefFree(virSecurityLabelDefPtr def)
E
Eric Blake 已提交
1094
{
1095 1096
    if (!def)
        return;
E
Eric Blake 已提交
1097 1098 1099 1100
    VIR_FREE(def->model);
    VIR_FREE(def->label);
    VIR_FREE(def->imagelabel);
    VIR_FREE(def->baselabel);
1101
    VIR_FREE(def);
E
Eric Blake 已提交
1102 1103
}

1104

1105
void
1106 1107 1108 1109
virSecurityDeviceLabelDefFree(virSecurityDeviceLabelDefPtr def)
{
    if (!def)
        return;
1110
    VIR_FREE(def->model);
1111 1112 1113 1114 1115
    VIR_FREE(def->label);
    VIR_FREE(def);
}


1116 1117
void virDomainGraphicsDefFree(virDomainGraphicsDefPtr def)
{
1118
    size_t i;
1119

1120 1121 1122 1123 1124
    if (!def)
        return;

    switch (def->type) {
    case VIR_DOMAIN_GRAPHICS_TYPE_VNC:
1125
        VIR_FREE(def->data.vnc.socket);
1126
        VIR_FREE(def->data.vnc.keymap);
1127
        virDomainGraphicsAuthDefClear(&def->data.vnc.auth);
1128 1129 1130 1131 1132 1133
        break;

    case VIR_DOMAIN_GRAPHICS_TYPE_SDL:
        VIR_FREE(def->data.sdl.display);
        VIR_FREE(def->data.sdl.xauth);
        break;
1134 1135 1136 1137 1138 1139 1140

    case VIR_DOMAIN_GRAPHICS_TYPE_RDP:
        break;

    case VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP:
        VIR_FREE(def->data.desktop.display);
        break;
1141 1142 1143

    case VIR_DOMAIN_GRAPHICS_TYPE_SPICE:
        VIR_FREE(def->data.spice.keymap);
1144
        virDomainGraphicsAuthDefClear(&def->data.spice.auth);
1145
        break;
1146 1147
    }

1148 1149
    for (i = 0; i < def->nListens; i++)
        virDomainGraphicsListenDefClear(&def->listens[i]);
1150 1151
    VIR_FREE(def->listens);

1152 1153 1154 1155 1156 1157 1158 1159
    VIR_FREE(def);
}

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

1160
    virDomainDeviceInfoClear(&def->info);
1161 1162 1163
    VIR_FREE(def);
}

1164
void virDomainLeaseDefFree(virDomainLeaseDefPtr def)
1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175
{
    if (!def)
        return;

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

    VIR_FREE(def);
}

1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187
static void
virDomainDiskSourcePoolDefFree(virDomainDiskSourcePoolDefPtr def)
{
    if (!def)
        return;

    VIR_FREE(def->pool);
    VIR_FREE(def->volume);

    VIR_FREE(def);
}

1188 1189
void virDomainDiskDefFree(virDomainDiskDefPtr def)
{
1190
    size_t i;
1191

1192 1193 1194
    if (!def)
        return;

1195
    VIR_FREE(def->serial);
1196
    VIR_FREE(def->src);
1197
    virDomainDiskSourcePoolDefFree(def->srcpool);
1198 1199
    VIR_FREE(def->dst);
    VIR_FREE(def->driverName);
1200
    virStorageFileFreeMetadata(def->backingChain);
1201
    VIR_FREE(def->mirror);
1202
    VIR_FREE(def->auth.username);
O
Osier Yang 已提交
1203
    VIR_FREE(def->wwn);
1204 1205
    VIR_FREE(def->vendor);
    VIR_FREE(def->product);
1206 1207
    if (def->auth.secretType == VIR_DOMAIN_DISK_SECRET_TYPE_USAGE)
        VIR_FREE(def->auth.secret.usage);
1208
    virStorageEncryptionFree(def->encryption);
1209
    virDomainDeviceInfoClear(&def->info);
1210

1211 1212 1213 1214 1215
    if (def->seclabels) {
        for (i = 0; i < def->nseclabels; i++)
            virSecurityDeviceLabelDefFree(def->seclabels[i]);
        VIR_FREE(def->seclabels);
    }
1216

1217
    for (i = 0; i < def->nhosts; i++)
1218
        virDomainDiskHostDefFree(&def->hosts[i]);
E
Eric Blake 已提交
1219
    VIR_FREE(def->hosts);
1220

1221 1222 1223
    VIR_FREE(def);
}

1224 1225 1226 1227 1228 1229 1230
void virDomainDiskHostDefFree(virDomainDiskHostDefPtr def)
{
    if (!def)
        return;

    VIR_FREE(def->name);
    VIR_FREE(def->port);
1231
    VIR_FREE(def->socket);
1232 1233
}

1234 1235 1236 1237 1238 1239 1240 1241 1242 1243
void virDomainControllerDefFree(virDomainControllerDefPtr def)
{
    if (!def)
        return;

    virDomainDeviceInfoClear(&def->info);

    VIR_FREE(def);
}

1244 1245 1246 1247 1248 1249 1250
void virDomainFSDefFree(virDomainFSDefPtr def)
{
    if (!def)
        return;

    VIR_FREE(def->src);
    VIR_FREE(def->dst);
1251
    virDomainDeviceInfoClear(&def->info);
1252 1253 1254 1255

    VIR_FREE(def);
}

1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268
void
virDomainActualNetDefFree(virDomainActualNetDefPtr def)
{
    if (!def)
        return;

    switch (def->type) {
    case VIR_DOMAIN_NET_TYPE_BRIDGE:
        VIR_FREE(def->data.bridge.brname);
        break;
    case VIR_DOMAIN_NET_TYPE_DIRECT:
        VIR_FREE(def->data.direct.linkdev);
        break;
1269 1270 1271
    case VIR_DOMAIN_NET_TYPE_HOSTDEV:
        virDomainHostdevDefClear(&def->data.hostdev.def);
        break;
1272 1273 1274 1275
    default:
        break;
    }

1276
    VIR_FREE(def->virtPortProfile);
1277
    virNetDevBandwidthFree(def->bandwidth);
1278
    virNetDevVlanClear(&def->vlan);
1279 1280 1281
    VIR_FREE(def);
}

1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302
void virDomainNetDefFree(virDomainNetDefPtr def)
{
    if (!def)
        return;

    VIR_FREE(def->model);

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

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

    case VIR_DOMAIN_NET_TYPE_NETWORK:
        VIR_FREE(def->data.network.name);
1303 1304
        VIR_FREE(def->data.network.portgroup);
        virDomainActualNetDefFree(def->data.network.actual);
1305 1306 1307 1308
        break;

    case VIR_DOMAIN_NET_TYPE_BRIDGE:
        VIR_FREE(def->data.bridge.brname);
1309
        VIR_FREE(def->data.bridge.ipaddr);
1310
        break;
D
Daniel Veillard 已提交
1311 1312 1313 1314

    case VIR_DOMAIN_NET_TYPE_INTERNAL:
        VIR_FREE(def->data.internal.name);
        break;
1315 1316 1317 1318

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

1320 1321 1322 1323
    case VIR_DOMAIN_NET_TYPE_HOSTDEV:
        virDomainHostdevDefClear(&def->data.hostdev.def);
        break;

S
Stefan Berger 已提交
1324 1325 1326
    case VIR_DOMAIN_NET_TYPE_USER:
    case VIR_DOMAIN_NET_TYPE_LAST:
        break;
1327 1328
    }

1329
    VIR_FREE(def->virtPortProfile);
1330
    VIR_FREE(def->script);
1331
    VIR_FREE(def->ifname);
1332 1333 1334

    virDomainDeviceInfoClear(&def->info);

1335 1336 1337
    VIR_FREE(def->filter);
    virNWFilterHashTableFree(def->filterparams);

1338
    virNetDevBandwidthFree(def->bandwidth);
1339
    virNetDevVlanClear(&def->vlan);
1340

1341 1342 1343
    VIR_FREE(def);
}

1344
void ATTRIBUTE_NONNULL(1)
1345
virDomainChrSourceDefClear(virDomainChrSourceDefPtr def)
1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370
{
    switch (def->type) {
    case VIR_DOMAIN_CHR_TYPE_PTY:
    case VIR_DOMAIN_CHR_TYPE_DEV:
    case VIR_DOMAIN_CHR_TYPE_FILE:
    case VIR_DOMAIN_CHR_TYPE_PIPE:
        VIR_FREE(def->data.file.path);
        break;

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

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

    case VIR_DOMAIN_CHR_TYPE_UNIX:
        VIR_FREE(def->data.nix.path);
        break;
    }
1371 1372
}

1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388
/* 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:
1389
        if (VIR_STRDUP(dest->data.file.path, src->data.file.path) < 0)
1390 1391 1392 1393
            return -1;
        break;

    case VIR_DOMAIN_CHR_TYPE_UDP:
1394
        if (VIR_STRDUP(dest->data.udp.bindHost, src->data.udp.bindHost) < 0)
1395 1396
            return -1;

1397
        if (VIR_STRDUP(dest->data.udp.bindService, src->data.udp.bindService) < 0)
1398 1399
            return -1;

1400
        if (VIR_STRDUP(dest->data.udp.connectHost, src->data.udp.connectHost) < 0)
1401 1402
            return -1;

1403
        if (VIR_STRDUP(dest->data.udp.connectService, src->data.udp.connectService) < 0)
1404 1405 1406 1407
            return -1;
        break;

    case VIR_DOMAIN_CHR_TYPE_TCP:
1408
        if (VIR_STRDUP(dest->data.tcp.host, src->data.tcp.host) < 0)
1409 1410
            return -1;

1411
        if (VIR_STRDUP(dest->data.tcp.service, src->data.tcp.service) < 0)
1412 1413 1414 1415
            return -1;
        break;

    case VIR_DOMAIN_CHR_TYPE_UNIX:
1416
        if (VIR_STRDUP(dest->data.nix.path, src->data.nix.path) < 0)
1417 1418 1419 1420
            return -1;
        break;
    }

S
Stefan Berger 已提交
1421 1422
    dest->type = src->type;

1423 1424 1425
    return 0;
}

1426 1427 1428 1429 1430 1431 1432 1433 1434
void virDomainChrSourceDefFree(virDomainChrSourceDefPtr def)
{
    if (!def)
        return;

    virDomainChrSourceDefClear(def);

    VIR_FREE(def);
}
1435

1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486
/* 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;

    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:
        return STREQ_NULLABLE(src->data.file.path, tgt->data.file.path);
        break;
    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;

    case VIR_DOMAIN_CHR_TYPE_VC:
    case VIR_DOMAIN_CHR_TYPE_STDIO:
    case VIR_DOMAIN_CHR_TYPE_SPICEVMC:
        /* nada */
        return true;
    }

    /* This should happen only on new,
     * yet unhandled type */

    return false;
}

1487 1488
void virDomainChrDefFree(virDomainChrDefPtr def)
{
1489 1490
    size_t i;

1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511
    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);
1512 1513
    virDomainDeviceInfoClear(&def->info);

1514 1515 1516 1517 1518 1519
    if (def->seclabels) {
        for (i = 0; i < def->nseclabels; i++)
            virSecurityDeviceLabelDefFree(def->seclabels[i]);
        VIR_FREE(def->seclabels);
    }

1520 1521 1522
    VIR_FREE(def);
}

E
Eric Blake 已提交
1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551
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);
}

1552 1553 1554 1555 1556 1557 1558 1559
void virDomainSoundCodecDefFree(virDomainSoundCodecDefPtr def)
{
    if (!def)
        return;

    VIR_FREE(def);
}

1560 1561 1562 1563 1564
void virDomainSoundDefFree(virDomainSoundDefPtr def)
{
    if (!def)
        return;

1565 1566
    virDomainDeviceInfoClear(&def->info);

1567
    size_t i;
1568
    for (i = 0; i < def->ncodecs; i++)
1569 1570 1571
        virDomainSoundCodecDefFree(def->codecs[i]);
    VIR_FREE(def->codecs);

1572 1573 1574
    VIR_FREE(def);
}

1575 1576 1577 1578 1579 1580 1581 1582 1583 1584
void virDomainMemballoonDefFree(virDomainMemballoonDefPtr def)
{
    if (!def)
        return;

    virDomainDeviceInfoClear(&def->info);

    VIR_FREE(def);
}

L
Li Zhang 已提交
1585 1586 1587 1588 1589 1590 1591 1592 1593 1594
void virDomainNVRAMDefFree(virDomainNVRAMDefPtr def)
{
    if (!def)
        return;

    virDomainDeviceInfoClear(&def->info);

    VIR_FREE(def);
}

R
Richard Jones 已提交
1595 1596 1597 1598 1599
void virDomainWatchdogDefFree(virDomainWatchdogDefPtr def)
{
    if (!def)
        return;

1600 1601
    virDomainDeviceInfoClear(&def->info);

R
Richard Jones 已提交
1602 1603 1604
    VIR_FREE(def);
}

1605 1606 1607 1608 1609
void virDomainVideoDefFree(virDomainVideoDefPtr def)
{
    if (!def)
        return;

1610 1611
    virDomainDeviceInfoClear(&def->info);

1612
    VIR_FREE(def->accel);
1613 1614 1615
    VIR_FREE(def);
}

1616 1617 1618 1619
virDomainHostdevDefPtr virDomainHostdevDefAlloc(void)
{
    virDomainHostdevDefPtr def = NULL;

1620 1621
    if (VIR_ALLOC(def) < 0 ||
        VIR_ALLOC(def->info) < 0)
1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634
        VIR_FREE(def);
    return def;
}

void virDomainHostdevDefClear(virDomainHostdevDefPtr def)
{
    if (!def)
        return;

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

1635 1636 1637 1638 1639
    /* If there is a parent device object, it will handle freeing
     * def->info.
     */
    if (def->parent.type == VIR_DOMAIN_DEVICE_NONE)
        virDomainDeviceInfoFree(def->info);
1640

H
Han Cheng 已提交
1641 1642
    switch (def->mode) {
    case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
1643 1644 1645 1646 1647 1648 1649
        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;
1650 1651 1652
        case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_NET:
            VIR_FREE(def->source.caps.u.net.iface);
            break;
1653
        }
H
Han Cheng 已提交
1654 1655 1656 1657 1658
        break;
    case VIR_DOMAIN_HOSTDEV_MODE_SUBSYS:
        if (def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI)
            VIR_FREE(def->source.subsys.u.scsi.adapter);
        break;
1659
    }
1660 1661
}

1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678
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);
}

1679 1680 1681 1682 1683
void virDomainHostdevDefFree(virDomainHostdevDefPtr def)
{
    if (!def)
        return;

1684 1685 1686
    /* free all subordinate objects */
    virDomainHostdevDefClear(def);

1687 1688 1689 1690 1691
    /* If there is a parent device object, it will handle freeing
     * the memory.
     */
    if (def->parent.type == VIR_DOMAIN_DEVICE_NONE)
        VIR_FREE(def);
1692 1693
}

M
Marc-André Lureau 已提交
1694 1695 1696 1697 1698 1699 1700 1701 1702
void virDomainHubDefFree(virDomainHubDefPtr def)
{
    if (!def)
        return;

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

1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713
void virDomainRedirdevDefFree(virDomainRedirdevDefPtr def)
{
    if (!def)
        return;

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

    VIR_FREE(def);
}

1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727
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);
}

1728 1729 1730 1731 1732
void virDomainDeviceDefFree(virDomainDeviceDefPtr def)
{
    if (!def)
        return;

1733
    switch ((virDomainDeviceType) def->type) {
1734 1735 1736
    case VIR_DOMAIN_DEVICE_DISK:
        virDomainDiskDefFree(def->data.disk);
        break;
1737 1738 1739
    case VIR_DOMAIN_DEVICE_LEASE:
        virDomainLeaseDefFree(def->data.lease);
        break;
1740 1741 1742 1743 1744 1745 1746 1747 1748
    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;
1749 1750 1751
    case VIR_DOMAIN_DEVICE_VIDEO:
        virDomainVideoDefFree(def->data.video);
        break;
1752 1753 1754
    case VIR_DOMAIN_DEVICE_HOSTDEV:
        virDomainHostdevDefFree(def->data.hostdev);
        break;
R
Richard Jones 已提交
1755 1756 1757
    case VIR_DOMAIN_DEVICE_WATCHDOG:
        virDomainWatchdogDefFree(def->data.watchdog);
        break;
1758 1759 1760
    case VIR_DOMAIN_DEVICE_CONTROLLER:
        virDomainControllerDefFree(def->data.controller);
        break;
1761 1762 1763
    case VIR_DOMAIN_DEVICE_GRAPHICS:
        virDomainGraphicsDefFree(def->data.graphics);
        break;
M
Marc-André Lureau 已提交
1764 1765 1766
    case VIR_DOMAIN_DEVICE_HUB:
        virDomainHubDefFree(def->data.hub);
        break;
1767 1768 1769
    case VIR_DOMAIN_DEVICE_REDIRDEV:
        virDomainRedirdevDefFree(def->data.redirdev);
        break;
1770 1771 1772
    case VIR_DOMAIN_DEVICE_RNG:
        virDomainRNGDefFree(def->data.rng);
        break;
1773 1774 1775
    case VIR_DOMAIN_DEVICE_CHR:
        virDomainChrDefFree(def->data.chr);
        break;
1776
    case VIR_DOMAIN_DEVICE_FS:
1777 1778
        virDomainFSDefFree(def->data.fs);
        break;
1779
    case VIR_DOMAIN_DEVICE_SMARTCARD:
1780 1781
        virDomainSmartcardDefFree(def->data.smartcard);
        break;
1782
    case VIR_DOMAIN_DEVICE_MEMBALLOON:
1783 1784
        virDomainMemballoonDefFree(def->data.memballoon);
        break;
L
Li Zhang 已提交
1785
    case VIR_DOMAIN_DEVICE_NVRAM:
1786 1787
        virDomainNVRAMDefFree(def->data.nvram);
        break;
1788
    case VIR_DOMAIN_DEVICE_LAST:
1789
    case VIR_DOMAIN_DEVICE_NONE:
1790
        break;
1791 1792 1793 1794 1795
    }

    VIR_FREE(def);
}

1796 1797 1798 1799 1800 1801
static void
virDomainClockDefClear(virDomainClockDefPtr def)
{
    if (def->offset == VIR_DOMAIN_CLOCK_OFFSET_TIMEZONE)
        VIR_FREE(def->data.timezone);

1802
    size_t i;
1803 1804 1805 1806 1807
    for (i = 0; i < def->ntimers; i++)
        VIR_FREE(def->timers[i]);
    VIR_FREE(def->timers);
}

1808 1809 1810
virDomainVcpuPinDefPtr *
virDomainVcpuPinDefCopy(virDomainVcpuPinDefPtr *src, int nvcpupin)
{
1811
    size_t i;
1812
    virDomainVcpuPinDefPtr *ret = NULL;
1813

1814 1815
    if (VIR_ALLOC_N(ret, nvcpupin) < 0)
        goto error;
1816 1817 1818

    for (i = 0; i < nvcpupin; i++) {
        if (VIR_ALLOC(ret[i]) < 0)
1819
            goto error;
1820
        ret[i]->vcpuid = src[i]->vcpuid;
H
Hu Tao 已提交
1821
        if ((ret[i]->cpumask = virBitmapNewCopy(src[i]->cpumask)) == NULL)
1822
            goto error;
1823 1824 1825 1826
    }

    return ret;

1827
error:
1828
    if (ret) {
1829
        for (i = 0; i < nvcpupin; i++) {
1830
            if (ret[i]) {
H
Hu Tao 已提交
1831
                virBitmapFree(ret[i]->cpumask);
1832 1833 1834 1835
                VIR_FREE(ret[i]);
            }
        }
        VIR_FREE(ret);
1836 1837 1838 1839 1840 1841
    }

    return NULL;
}

void
H
Hu Tao 已提交
1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852
virDomainVcpuPinDefFree(virDomainVcpuPinDefPtr def)
{
    if (def) {
        virBitmapFree(def->cpumask);
        VIR_FREE(def);
    }
}

void
virDomainVcpuPinDefArrayFree(virDomainVcpuPinDefPtr *def,
                             int nvcpupin)
1853
{
1854
    size_t i;
1855 1856 1857 1858

    if (!def || !nvcpupin)
        return;

1859
    for (i = 0; i < nvcpupin; i++) {
H
Hu Tao 已提交
1860
        virDomainVcpuPinDefFree(def[i]);
1861 1862 1863 1864 1865
    }

    VIR_FREE(def);
}

1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877

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

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


1878 1879
void virDomainDefFree(virDomainDefPtr def)
{
1880
    size_t i;
1881

1882 1883 1884
    if (!def)
        return;

1885 1886
    virDomainResourceDefFree(def->resource);

1887 1888 1889 1890 1891 1892
    /* 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().
     */
1893
    for (i = 0; i < def->nhostdevs; i++)
1894 1895 1896
        virDomainHostdevDefFree(def->hostdevs[i]);
    VIR_FREE(def->hostdevs);

1897
    for (i = 0; i < def->nleases; i++)
1898 1899 1900
        virDomainLeaseDefFree(def->leases[i]);
    VIR_FREE(def->leases);

1901
    for (i = 0; i < def->ngraphics; i++)
1902 1903
        virDomainGraphicsDefFree(def->graphics[i]);
    VIR_FREE(def->graphics);
1904

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

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

1913
    for (i = 0; i < def->ncontrollers; i++)
1914 1915 1916
        virDomainControllerDefFree(def->controllers[i]);
    VIR_FREE(def->controllers);

1917
    for (i = 0; i < def->nfss; i++)
1918 1919 1920
        virDomainFSDefFree(def->fss[i]);
    VIR_FREE(def->fss);

1921
    for (i = 0; i < def->nnets; i++)
1922 1923
        virDomainNetDefFree(def->nets[i]);
    VIR_FREE(def->nets);
1924

1925
    for (i = 0; i < def->nsmartcards; i++)
E
Eric Blake 已提交
1926 1927 1928
        virDomainSmartcardDefFree(def->smartcards[i]);
    VIR_FREE(def->smartcards);

1929
    for (i = 0; i < def->nserials; i++)
1930 1931 1932
        virDomainChrDefFree(def->serials[i]);
    VIR_FREE(def->serials);

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

1937
    for (i = 0; i < def->nchannels; i++)
1938 1939 1940
        virDomainChrDefFree(def->channels[i]);
    VIR_FREE(def->channels);

1941
    for (i = 0; i < def->nconsoles; i++)
1942 1943
        virDomainChrDefFree(def->consoles[i]);
    VIR_FREE(def->consoles);
1944

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

1949
    for (i = 0; i < def->nvideos; i++)
1950 1951 1952
        virDomainVideoDefFree(def->videos[i]);
    VIR_FREE(def->videos);

1953
    for (i = 0; i < def->nhubs; i++)
M
Marc-André Lureau 已提交
1954 1955 1956
        virDomainHubDefFree(def->hubs[i]);
    VIR_FREE(def->hubs);

1957
    for (i = 0; i < def->nredirdevs; i++)
1958 1959 1960
        virDomainRedirdevDefFree(def->redirdevs[i]);
    VIR_FREE(def->redirdevs);

1961 1962
    virDomainRNGDefFree(def->rng);

1963 1964
    virDomainTPMDefFree(def->tpm);

1965 1966 1967
    VIR_FREE(def->idmap.uidmap);
    VIR_FREE(def->idmap.gidmap);

1968 1969
    VIR_FREE(def->os.type);
    VIR_FREE(def->os.machine);
1970
    VIR_FREE(def->os.init);
1971
    for (i = 0; def->os.initargv && def->os.initargv[i]; i++)
1972 1973
        VIR_FREE(def->os.initargv[i]);
    VIR_FREE(def->os.initargv);
1974 1975 1976
    VIR_FREE(def->os.kernel);
    VIR_FREE(def->os.initrd);
    VIR_FREE(def->os.cmdline);
1977
    VIR_FREE(def->os.dtb);
1978 1979 1980 1981 1982
    VIR_FREE(def->os.root);
    VIR_FREE(def->os.loader);
    VIR_FREE(def->os.bootloader);
    VIR_FREE(def->os.bootloaderArgs);

1983
    virDomainClockDefClear(&def->clock);
1984

1985
    VIR_FREE(def->name);
1986
    virBitmapFree(def->cpumask);
1987
    VIR_FREE(def->emulator);
1988
    VIR_FREE(def->description);
1989
    VIR_FREE(def->title);
1990

1991 1992 1993 1994
    virBlkioDeviceWeightArrayClear(def->blkio.devices,
                                   def->blkio.ndevices);
    VIR_FREE(def->blkio.devices);

R
Richard Jones 已提交
1995 1996
    virDomainWatchdogDefFree(def->watchdog);

C
Chris Lalancette 已提交
1997
    virDomainMemballoonDefFree(def->memballoon);
L
Li Zhang 已提交
1998
    virDomainNVRAMDefFree(def->nvram);
C
Chris Lalancette 已提交
1999

2000 2001 2002
    for (i = 0; i < def->nseclabels; i++)
        virSecurityLabelDefFree(def->seclabels[i]);
    VIR_FREE(def->seclabels);
2003

2004 2005
    virCPUDefFree(def->cpu);

H
Hu Tao 已提交
2006 2007 2008
    virDomainVcpuPinDefArrayFree(def->cputune.vcpupin, def->cputune.nvcpupin);

    virDomainVcpuPinDefFree(def->cputune.emulatorpin);
2009

2010
    virBitmapFree(def->numatune.memory.nodemask);
O
Osier Yang 已提交
2011

2012 2013
    virSysinfoDefFree(def->sysinfo);

2014 2015
    virDomainRedirFilterDefFree(def->redirfilter);

2016 2017 2018
    if (def->namespaceData && def->ns.free)
        (def->ns.free)(def->namespaceData);

2019 2020
    xmlFreeNode(def->metadata);

2021 2022 2023
    VIR_FREE(def);
}

2024
static void virDomainObjDispose(void *obj)
2025
{
2026
    virDomainObjPtr dom = obj;
2027

2028
    VIR_DEBUG("obj=%p", dom);
2029 2030 2031
    virDomainDefFree(dom->def);
    virDomainDefFree(dom->newDef);

2032 2033 2034
    if (dom->privateDataFreeFunc)
        (dom->privateDataFreeFunc)(dom->privateData);

2035
    virDomainSnapshotObjListFree(dom->snapshots);
2036 2037
}

2038
virDomainObjPtr
2039
virDomainObjNew(virDomainXMLOptionPtr xmlopt)
2040 2041 2042
{
    virDomainObjPtr domain;

2043 2044 2045
    if (virDomainObjInitialize() < 0)
        return NULL;

2046
    if (!(domain = virObjectLockableNew(virDomainObjClass)))
2047 2048
        return NULL;

2049
    if (xmlopt->privateData.alloc) {
2050
        if (!(domain->privateData = (xmlopt->privateData.alloc)()))
2051
            goto error;
2052
        domain->privateDataFreeFunc = xmlopt->privateData.free;
2053 2054 2055 2056 2057
    }

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

2058
    virObjectLock(domain);
J
Jiri Denemark 已提交
2059 2060
    virDomainObjSetState(domain, VIR_DOMAIN_SHUTOFF,
                                 VIR_DOMAIN_SHUTOFF_UNKNOWN);
2061

2062
    VIR_DEBUG("obj=%p", domain);
2063
    return domain;
2064 2065 2066 2067

error:
    virObjectUnref(domain);
    return NULL;
2068 2069
}

2070 2071 2072 2073 2074 2075 2076

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

2077
    if (VIR_ALLOC(def) < 0)
2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091
        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;
}


2092 2093
void virDomainObjAssignDef(virDomainObjPtr domain,
                           const virDomainDefPtr def,
2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105
                           bool live,
                           virDomainDefPtr *oldDef)
{
    if (oldDef)
        *oldDef = NULL;
    if (virDomainObjIsActive(domain)) {
        if (oldDef)
            *oldDef = domain->newDef;
        else
            virDomainDefFree(domain->newDef);
        domain->newDef = def;
    } else {
2106
        if (live) {
2107 2108 2109 2110 2111 2112 2113
            if (domain->def) {
                /* save current configuration to be restored on domain shutdown */
                if (!domain->newDef)
                    domain->newDef = domain->def;
                else
                    virDomainDefFree(domain->def);
            }
2114 2115
            domain->def = def;
        } else {
2116 2117 2118 2119
            if (oldDef)
                *oldDef = domain->def;
            else
                virDomainDefFree(domain->def);
2120 2121 2122 2123 2124
            domain->def = def;
        }
    }
}

2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137


/*
 *
 * If flags & VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE then
 * this will refuse updating an existing def if the
 * current def is Live
 *
 * If flags & VIR_DOMAIN_OBJ_LIST_ADD_LIVE then
 * the @def being added is assumed to represent a
 * live config, not a future inactive config
 *
 */
2138 2139 2140
static virDomainObjPtr
virDomainObjListAddLocked(virDomainObjListPtr doms,
                          const virDomainDefPtr def,
2141
                          virDomainXMLOptionPtr xmlopt,
2142 2143
                          unsigned int flags,
                          virDomainDefPtr *oldDef)
2144
{
2145
    virDomainObjPtr vm;
2146
    char uuidstr[VIR_UUID_STRING_BUFLEN];
2147

2148 2149
    if (oldDef)
        *oldDef = false;
2150

2151 2152
    virUUIDFormat(def->uuid, uuidstr);

2153
    /* See if a VM with matching UUID already exists */
2154 2155
    if ((vm = virHashLookup(doms->objs, uuidstr))) {
        virObjectLock(vm);
2156 2157 2158 2159 2160 2161 2162 2163
        /* UUID matches, but if names don't match, refuse it */
        if (STRNEQ(vm->def->name, def->name)) {
            virUUIDFormat(vm->def->uuid, uuidstr);
            virReportError(VIR_ERR_OPERATION_FAILED,
                           _("domain '%s' is already defined with uuid %s"),
                           vm->def->name, uuidstr);
            goto error;
        }
2164

2165 2166 2167 2168 2169 2170 2171 2172 2173
        if (flags & VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE) {
            /* UUID & name match, but if VM is already active, refuse it */
            if (virDomainObjIsActive(vm)) {
                virReportError(VIR_ERR_OPERATION_INVALID,
                               _("domain is already active as '%s'"),
                               vm->def->name);
                goto error;
            }
        }
2174

2175 2176 2177 2178 2179 2180
        virDomainObjAssignDef(vm,
                              def,
                              !!(flags & VIR_DOMAIN_OBJ_LIST_ADD_LIVE),
                              oldDef);
    } else {
        /* UUID does not match, but if a name matches, refuse it */
2181 2182
        if ((vm = virHashSearch(doms->objs, virDomainObjListSearchName, def->name))) {
            virObjectLock(vm);
2183 2184 2185 2186 2187 2188 2189
            virUUIDFormat(vm->def->uuid, uuidstr);
            virReportError(VIR_ERR_OPERATION_FAILED,
                           _("domain '%s' already exists with uuid %s"),
                           def->name, uuidstr);
            goto error;
        }

2190
        if (!(vm = virDomainObjNew(xmlopt)))
2191 2192 2193 2194 2195 2196 2197 2198
            goto cleanup;
        vm->def = def;

        virUUIDFormat(def->uuid, uuidstr);
        if (virHashAddEntry(doms->objs, uuidstr, vm) < 0) {
            virObjectUnref(vm);
            return NULL;
        }
2199
    }
2200 2201
cleanup:
    return vm;
2202

2203 2204 2205 2206
error:
    virObjectUnlock(vm);
    vm = NULL;
    goto cleanup;
2207 2208
}

2209 2210 2211

virDomainObjPtr virDomainObjListAdd(virDomainObjListPtr doms,
                                    const virDomainDefPtr def,
2212
                                    virDomainXMLOptionPtr xmlopt,
2213 2214 2215 2216 2217 2218
                                    unsigned int flags,
                                    virDomainDefPtr *oldDef)
{
    virDomainObjPtr ret;

    virObjectLock(doms);
2219
    ret = virDomainObjListAddLocked(doms, def, xmlopt, flags, oldDef);
2220 2221 2222 2223
    virObjectUnlock(doms);
    return ret;
}

2224 2225 2226 2227 2228 2229
/*
 * Mark the running VM config as transient. Ensures transient hotplug
 * operations do not persist past shutdown.
 *
 * @param caps pointer to capabilities info
 * @param domain domain object pointer
2230 2231 2232 2233
 * @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.
2234 2235 2236 2237
 * @return 0 on success, -1 on failure
 */
int
virDomainObjSetDefTransient(virCapsPtr caps,
2238
                            virDomainXMLOptionPtr xmlopt,
2239 2240
                            virDomainObjPtr domain,
                            bool live)
2241 2242 2243
{
    int ret = -1;

2244
    if (!virDomainObjIsActive(domain) && !live)
2245 2246 2247 2248 2249 2250 2251 2252
        return 0;

    if (!domain->persistent)
        return 0;

    if (domain->newDef)
        return 0;

2253
    if (!(domain->newDef = virDomainDefCopy(domain->def, caps, xmlopt, false)))
2254 2255 2256 2257 2258 2259 2260
        goto out;

    ret = 0;
out:
    return ret;
}

2261 2262 2263 2264 2265 2266 2267 2268 2269 2270
/*
 * Return the persistent domain configuration. If domain is transient,
 * return the running config.
 *
 * @param caps pointer to capabilities info
 * @param domain domain object pointer
 * @return NULL on error, virDOmainDefPtr on success
 */
virDomainDefPtr
virDomainObjGetPersistentDef(virCapsPtr caps,
2271
                             virDomainXMLOptionPtr xmlopt,
2272 2273
                             virDomainObjPtr domain)
{
2274
    if (virDomainObjSetDefTransient(caps, xmlopt, domain, false) < 0)
2275 2276 2277 2278 2279 2280 2281 2282
        return NULL;

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

2283 2284 2285 2286 2287 2288 2289 2290 2291
/*
 * 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,
2292
                                virDomainXMLOptionPtr xmlopt,
2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310
                                virDomainObjPtr dom,
                                unsigned int *flags,
                                virDomainDefPtr *persistentDef)
{
    bool isActive;
    int ret = -1;

    isActive = virDomainObjIsActive(dom);

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

    if (!isActive && (*flags & VIR_DOMAIN_AFFECT_LIVE)) {
2311 2312
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("domain is not running"));
2313 2314 2315 2316 2317
        goto cleanup;
    }

    if (*flags & VIR_DOMAIN_AFFECT_CONFIG) {
        if (!dom->persistent) {
2318
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
2319 2320
                           _("transient domains do not have any "
                             "persistent config"));
2321 2322
            goto cleanup;
        }
2323
        if (!(*persistentDef = virDomainObjGetPersistentDef(caps, xmlopt, dom))) {
2324 2325
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Get persistent config failed"));
2326 2327 2328 2329 2330 2331 2332 2333 2334 2335
            goto cleanup;
        }
    }

    ret = 0;

cleanup:
    return ret;
}

2336
/*
2337
 * The caller must hold a lock on the driver owning 'doms',
2338
 * and must also have locked 'dom', to ensure no one else
2339
 * is either waiting for 'dom' or still using it
2340
 */
2341 2342
void virDomainObjListRemove(virDomainObjListPtr doms,
                            virDomainObjPtr dom)
2343
{
2344
    char uuidstr[VIR_UUID_STRING_BUFLEN];
2345

2346
    virUUIDFormat(dom->def->uuid, uuidstr);
2347
    virObjectRef(dom);
2348
    virObjectUnlock(dom);
2349

2350
    virObjectLock(doms);
2351
    virObjectLock(dom);
2352
    virHashRemoveEntry(doms->objs, uuidstr);
2353 2354
    virObjectUnlock(dom);
    virObjectUnref(dom);
2355
    virObjectUnlock(doms);
2356
}
D
Daniel P. Berrange 已提交
2357

2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374
/* The caller must hold lock on 'doms' in addition to 'virDomainObjListRemove'
 * requirements
 *
 * Can be used to remove current element while iterating with
 * virDomainObjListForEach
 */
void virDomainObjListRemoveLocked(virDomainObjListPtr doms,
                                  virDomainObjPtr dom)
{
    char uuidstr[VIR_UUID_STRING_BUFLEN];

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

    virHashRemoveEntry(doms->objs, uuidstr);
}

2375 2376 2377 2378 2379 2380 2381
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;
}
2382

2383 2384 2385 2386 2387 2388 2389 2390
int virDomainDeviceAddressIsValid(virDomainDeviceInfoPtr info,
                                  int type)
{
    if (info->type != type)
        return 0;

    switch (info->type) {
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI:
2391
        return virDevicePCIAddressIsValid(&info->addr.pci);
2392 2393

    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE:
2394
        return 1;
2395

2396
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390:
2397
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO:
2398 2399 2400 2401 2402
        return 1;

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

2403
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB:
2404
        return 1;
2405 2406 2407 2408 2409
    }

    return 0;
}

2410
static bool
2411
virDomainDeviceInfoIsSet(virDomainDeviceInfoPtr info, unsigned int flags)
2412 2413
{
    if (info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
2414
        return true;
2415
    if (info->alias && !(flags & VIR_DOMAIN_XML_INACTIVE))
2416 2417 2418 2419 2420 2421 2422 2423 2424
        return true;
    if (info->mastertype != VIR_DOMAIN_CONTROLLER_MASTER_NONE)
        return true;
    if ((info->rombar != VIR_DOMAIN_PCI_ROMBAR_DEFAULT) ||
        info->romfile)
        return true;
    if (info->bootIndex)
        return true;
    return false;
2425 2426
}

2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439
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;

2440 2441
    if (VIR_STRDUP(dst->alias, src->alias) < 0 ||
        VIR_STRDUP(dst->romfile, src->romfile) < 0)
2442 2443 2444 2445
        return -1;
    return 0;
}

2446 2447
void virDomainDeviceInfoClear(virDomainDeviceInfoPtr info)
{
2448 2449 2450 2451
    VIR_FREE(info->alias);
    if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB) {
        VIR_FREE(info->addr.usb.port);
    }
2452 2453
    memset(&info->addr, 0, sizeof(info->addr));
    info->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE;
2454
    VIR_FREE(info->romfile);
2455 2456 2457
}


2458
static int virDomainDeviceInfoClearAlias(virDomainDefPtr def ATTRIBUTE_UNUSED,
2459
                                         virDomainDeviceDefPtr device ATTRIBUTE_UNUSED,
2460 2461
                                         virDomainDeviceInfoPtr info,
                                         void *opaque ATTRIBUTE_UNUSED)
2462
{
2463 2464 2465 2466 2467
    VIR_FREE(info->alias);
    return 0;
}

static int virDomainDeviceInfoClearPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED,
2468
                                              virDomainDeviceDefPtr device ATTRIBUTE_UNUSED,
2469 2470 2471 2472
                                              virDomainDeviceInfoPtr info,
                                              void *opaque ATTRIBUTE_UNUSED)
{
    if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
2473 2474 2475
        memset(&info->addr, 0, sizeof(info->addr));
        info->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE;
    }
2476
    return 0;
2477 2478
}

2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491
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;
}

2492 2493 2494 2495 2496
static int
virDomainDeviceInfoIterateInternal(virDomainDefPtr def,
                                   virDomainDeviceInfoCallback cb,
                                   bool all,
                                   void *opaque)
2497
{
2498
    size_t i;
2499
    virDomainDeviceDef device;
2500

2501
    device.type = VIR_DOMAIN_DEVICE_DISK;
2502
    for (i = 0; i < def->ndisks; i++) {
2503 2504
        device.data.disk = def->disks[i];
        if (cb(def, &device, &def->disks[i]->info, opaque) < 0)
2505
            return -1;
2506 2507
    }
    device.type = VIR_DOMAIN_DEVICE_NET;
2508
    for (i = 0; i < def->nnets; i++) {
2509 2510
        device.data.net = def->nets[i];
        if (cb(def, &device, &def->nets[i]->info, opaque) < 0)
2511
            return -1;
2512 2513
    }
    device.type = VIR_DOMAIN_DEVICE_SOUND;
2514
    for (i = 0; i < def->nsounds; i++) {
2515 2516
        device.data.sound = def->sounds[i];
        if (cb(def, &device, &def->sounds[i]->info, opaque) < 0)
2517
            return -1;
2518 2519
    }
    device.type = VIR_DOMAIN_DEVICE_HOSTDEV;
2520
    for (i = 0; i < def->nhostdevs; i++) {
2521
        device.data.hostdev = def->hostdevs[i];
2522
        if (cb(def, &device, def->hostdevs[i]->info, opaque) < 0)
2523
            return -1;
2524 2525
    }
    device.type = VIR_DOMAIN_DEVICE_VIDEO;
2526
    for (i = 0; i < def->nvideos; i++) {
2527 2528
        device.data.video = def->videos[i];
        if (cb(def, &device, &def->videos[i]->info, opaque) < 0)
2529
            return -1;
2530 2531
    }
    device.type = VIR_DOMAIN_DEVICE_CONTROLLER;
2532
    for (i = 0; i < def->ncontrollers; i++) {
2533 2534
        device.data.controller = def->controllers[i];
        if (cb(def, &device, &def->controllers[i]->info, opaque) < 0)
2535
            return -1;
2536 2537
    }
    device.type = VIR_DOMAIN_DEVICE_SMARTCARD;
2538
    for (i = 0; i < def->nsmartcards; i++) {
2539 2540
        device.data.smartcard = def->smartcards[i];
        if (cb(def, &device, &def->smartcards[i]->info, opaque) < 0)
E
Eric Blake 已提交
2541
            return -1;
2542 2543
    }
    device.type = VIR_DOMAIN_DEVICE_CHR;
2544
    for (i = 0; i < def->nserials; i++) {
2545 2546
        device.data.chr = def->serials[i];
        if (cb(def, &device, &def->serials[i]->info, opaque) < 0)
2547
            return -1;
2548
    }
2549
    for (i = 0; i < def->nparallels; i++) {
2550 2551
        device.data.chr = def->parallels[i];
        if (cb(def, &device, &def->parallels[i]->info, opaque) < 0)
2552
            return -1;
2553
    }
2554
    for (i = 0; i < def->nchannels; i++) {
2555 2556
        device.data.chr = def->channels[i];
        if (cb(def, &device, &def->channels[i]->info, opaque) < 0)
2557
            return -1;
2558
    }
2559
    for (i = 0; i < def->nconsoles; i++) {
2560 2561 2562 2563 2564
        if (!all &&
            i == 0 &&
            (def->consoles[i]->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL ||
             def->consoles[i]->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_NONE) &&
             STREQ_NULLABLE(def->os.type, "hvm"))
2565
            continue;
2566 2567
        device.data.chr = def->consoles[i];
        if (cb(def, &device, &def->consoles[i]->info, opaque) < 0)
2568
            return -1;
2569 2570
    }
    device.type = VIR_DOMAIN_DEVICE_INPUT;
2571
    for (i = 0; i < def->ninputs; i++) {
2572 2573
        device.data.input = def->inputs[i];
        if (cb(def, &device, &def->inputs[i]->info, opaque) < 0)
2574
            return -1;
2575 2576
    }
    device.type = VIR_DOMAIN_DEVICE_FS;
2577
    for (i = 0; i < def->nfss; i++) {
2578 2579
        device.data.fs = def->fss[i];
        if (cb(def, &device, &def->fss[i]->info, opaque) < 0)
2580
            return -1;
2581 2582 2583 2584 2585
    }
    if (def->watchdog) {
        device.type = VIR_DOMAIN_DEVICE_WATCHDOG;
        device.data.watchdog = def->watchdog;
        if (cb(def, &device, &def->watchdog->info, opaque) < 0)
2586
            return -1;
2587 2588 2589 2590 2591
    }
    if (def->memballoon) {
        device.type = VIR_DOMAIN_DEVICE_MEMBALLOON;
        device.data.memballoon = def->memballoon;
        if (cb(def, &device, &def->memballoon->info, opaque) < 0)
2592
            return -1;
2593
    }
2594 2595 2596 2597 2598 2599
    if (def->rng) {
        device.type = VIR_DOMAIN_DEVICE_RNG;
        device.data.rng = def->rng;
        if (cb(def, &device, &def->rng->info, opaque) < 0)
            return -1;
    }
L
Li Zhang 已提交
2600 2601 2602 2603 2604 2605
    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;
    }
2606
    device.type = VIR_DOMAIN_DEVICE_HUB;
2607
    for (i = 0; i < def->nhubs; i++) {
2608 2609
        device.data.hub = def->hubs[i];
        if (cb(def, &device, &def->hubs[i]->info, opaque) < 0)
M
Marc-André Lureau 已提交
2610
            return -1;
2611
    }
2612 2613

    /* This switch statement is here to trigger compiler warning when adding
E
Eric Blake 已提交
2614
     * a new device type. When you are adding a new field to the switch you
2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636
     * also have to add a iteration statement 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:
L
Li Zhang 已提交
2637
    case VIR_DOMAIN_DEVICE_NVRAM:
2638
    case VIR_DOMAIN_DEVICE_LAST:
2639
    case VIR_DOMAIN_DEVICE_RNG:
2640 2641 2642
        break;
    }

2643
    return 0;
2644 2645 2646
}


2647 2648 2649 2650 2651 2652 2653 2654 2655
int
virDomainDeviceInfoIterate(virDomainDefPtr def,
                           virDomainDeviceInfoCallback cb,
                           void *opaque)
{
    return virDomainDeviceInfoIterateInternal(def, cb, false, opaque);
}


2656 2657 2658 2659 2660 2661 2662 2663 2664
static int
virDomainDefRejectDuplicateControllers(virDomainDefPtr def)
{
    int max_idx[VIR_DOMAIN_CONTROLLER_TYPE_LAST];
    virBitmapPtr bitmaps[VIR_DOMAIN_CONTROLLER_TYPE_LAST] = { NULL };
    virDomainControllerDefPtr cont;
    size_t nbitmaps = 0;
    int ret = -1;
    bool b;
2665
    size_t i;
2666 2667 2668 2669 2670

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

    for (i = 0; i < def->ncontrollers; i++) {
        cont = def->controllers[i];
2671
        if ((int) cont->idx > max_idx[cont->type])
2672 2673 2674 2675 2676 2677 2678 2679
            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)))
2680
            goto cleanup;
2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708
        nbitmaps++;
    }

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

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

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

    ret = 0;
cleanup:
    for (i = 0; i < nbitmaps; i++)
        virBitmapFree(bitmaps[i]);
    return ret;
}


2709 2710 2711 2712
static int
virDomainDefPostParseInternal(virDomainDefPtr def,
                              virCapsPtr caps ATTRIBUTE_UNUSED)
{
2713
    size_t i;
2714

2715 2716 2717 2718 2719 2720
    if (!def->os.type) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("hypervisor type must be specified"));
        return -1;
    }

2721 2722 2723 2724 2725 2726 2727
    /* verify init path for container based domains */
    if (STREQ(def->os.type, "exe") && !def->os.init) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("init binary must be specified"));
        return -1;
    }

2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766
    /*
     * Some really crazy backcompat stuff for consoles
     *
     * Historically the first (and only) '<console>' element in an HVM guest
     * was treated as being an alias for a <serial> device.
     *
     * So if we see that this console device should be a serial device, then we
     * move the config over to def->serials[0] (or discard it if that already
     * exists). However, given console can already be filled with aliased data
     * of def->serials[0]. Keep it then.
     *
     * We then fill def->consoles[0] with a stub just so we get sequencing
     * correct for consoles > 0
     */
    if (def->nconsoles > 0 && STREQ(def->os.type, "hvm") &&
        (def->consoles[0]->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL ||
         def->consoles[0]->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_NONE)) {
        /* First verify that only the first console is of type serial */
        for (i = 1; i < def->nconsoles; i++) {
            virDomainChrDefPtr cons = def->consoles[i];

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

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

        /* create the serial port definition from the console definition */
        if (def->nserials == 0) {
2767 2768 2769 2770
            if (VIR_APPEND_ELEMENT(def->serials,
                                   def->nserials,
                                   def->consoles[0]) < 0)
                return -1;
2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787

            /* 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)
2788
                return -1;
2789 2790 2791 2792 2793 2794 2795

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

2796 2797
    if (virDomainDefRejectDuplicateControllers(def) < 0)
        return -1;
2798 2799 2800 2801 2802 2803
    return 0;
}


static int
virDomainDeviceDefPostParseInternal(virDomainDeviceDefPtr dev,
2804
                                    virDomainDefPtr def,
2805 2806
                                    virCapsPtr caps ATTRIBUTE_UNUSED)
{
2807 2808 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 2838 2839 2840 2841 2842 2843 2844 2845 2846
    if (dev->type == VIR_DOMAIN_DEVICE_CHR) {
        virDomainChrDefPtr chr = dev->data.chr;
        virDomainChrDefPtr **arrPtr;
        size_t i, *cnt;

        virDomainChrGetDomainPtrs(def, chr, &arrPtr, &cnt);

        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;

            for (i = 0; i < *cnt; i++) {
                if ((*arrPtr)[i]->target.port > maxport)
                    maxport = (*arrPtr)[i]->target.port;
            }

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

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

            for (i = 0; i < *cnt; i++) {
                virDomainChrDefPtr thischr = (*arrPtr)[i];
                if (thischr->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL &&
                    thischr->info.addr.vioserial.controller == chr->info.addr.vioserial.controller &&
                    thischr->info.addr.vioserial.bus == chr->info.addr.vioserial.bus &&
                    (int)thischr->info.addr.vioserial.port > maxport)
                    maxport = thischr->info.addr.vioserial.port;
            }
            chr->info.addr.vioserial.port = maxport + 1;
        }
    }
2847

2848 2849 2850 2851
    return 0;
}


2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866
static int
virDomainDeviceDefPostParse(virDomainDeviceDefPtr dev,
                            virDomainDefPtr def,
                            virCapsPtr caps,
                            virDomainXMLOptionPtr xmlopt)
{
    int ret;

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

2867 2868 2869
    if ((ret = virDomainDeviceDefPostParseInternal(dev, def, caps)) < 0)
        return ret;

2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891
    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);
}


2892
int
2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912
virDomainDefPostParse(virDomainDefPtr def,
                      virCapsPtr caps,
                      virDomainXMLOptionPtr xmlopt)
{
    int ret;
    struct virDomainDefPostParseDeviceIteratorData data = {
        .def = def,
        .caps = caps,
        .xmlopt = xmlopt,
    };

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

    /* iterate the devices */
2913 2914 2915 2916
    if ((ret = virDomainDeviceInfoIterateInternal(def,
                                                  virDomainDefPostParseDeviceIterator,
                                                  true,
                                                  &data)) < 0)
2917 2918
        return ret;

2919 2920 2921 2922

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

2923 2924 2925 2926
    return 0;
}


2927 2928
void virDomainDefClearPCIAddresses(virDomainDefPtr def)
{
2929
    virDomainDeviceInfoIterate(def, virDomainDeviceInfoClearPCIAddress, NULL);
D
Daniel P. Berrange 已提交
2930 2931
}

2932 2933 2934 2935 2936
void virDomainDefClearCCWAddresses(virDomainDefPtr def)
{
    virDomainDeviceInfoIterate(def, virDomainDeviceInfoClearCCWAddress, NULL);
}

D
Daniel P. Berrange 已提交
2937 2938
void virDomainDefClearDeviceAliases(virDomainDefPtr def)
{
2939
    virDomainDeviceInfoIterate(def, virDomainDeviceInfoClearAlias, NULL);
2940 2941 2942
}


2943
/* Generate a string representation of a device address
2944
 * @info address Device address to stringify
2945
 */
E
Eric Blake 已提交
2946 2947 2948
static int ATTRIBUTE_NONNULL(2)
virDomainDeviceInfoFormat(virBufferPtr buf,
                          virDomainDeviceInfoPtr info,
E
Eric Blake 已提交
2949
                          unsigned int flags)
2950
{
2951 2952 2953
    if ((flags & VIR_DOMAIN_XML_INTERNAL_ALLOW_BOOT) && info->bootIndex)
        virBufferAsprintf(buf, "      <boot order='%d'/>\n", info->bootIndex);

D
Daniel P. Berrange 已提交
2954 2955
    if (info->alias &&
        !(flags & VIR_DOMAIN_XML_INACTIVE)) {
2956
        virBufferAsprintf(buf, "      <alias name='%s'/>\n", info->alias);
D
Daniel P. Berrange 已提交
2957 2958
    }

2959 2960 2961 2962 2963
    if (info->mastertype == VIR_DOMAIN_CONTROLLER_MASTER_USB) {
        virBufferAsprintf(buf, "      <master startport='%d'/>\n",
                          info->master.usb.startport);
    }

2964 2965 2966 2967 2968 2969 2970 2971 2972
    if ((flags & VIR_DOMAIN_XML_INTERNAL_ALLOW_ROM) &&
        (info->rombar || info->romfile)) {

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

            const char *rombar = virDomainPciRombarModeTypeToString(info->rombar);

            if (!rombar) {
2973 2974 2975
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unexpected rom bar value %d"),
                               info->rombar);
2976 2977 2978
                return -1;
            }
            virBufferAsprintf(buf, " bar='%s'", rombar);
2979
        }
2980 2981 2982
        if (info->romfile)
            virBufferAsprintf(buf, " file='%s'", info->romfile);
        virBufferAddLit(buf, "/>\n");
2983 2984
    }

2985 2986
    if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE ||
        info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390)
2987 2988 2989
        return 0;

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

    switch (info->type) {
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI:
2995
        virBufferAsprintf(buf, " domain='0x%.4x' bus='0x%.2x' slot='0x%.2x' function='0x%.1x'",
2996 2997 2998 2999
                          info->addr.pci.domain,
                          info->addr.pci.bus,
                          info->addr.pci.slot,
                          info->addr.pci.function);
3000 3001
        if (info->addr.pci.multi) {
           virBufferAsprintf(buf, " multifunction='%s'",
3002
                             virDeviceAddressPciMultiTypeToString(info->addr.pci.multi));
3003
        }
3004 3005
        break;

3006
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE:
3007
        virBufferAsprintf(buf, " controller='%d' bus='%d' target='%d' unit='%d'",
3008 3009
                          info->addr.drive.controller,
                          info->addr.drive.bus,
3010
                          info->addr.drive.target,
3011 3012 3013
                          info->addr.drive.unit);
        break;

3014
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL:
3015
        virBufferAsprintf(buf, " controller='%d' bus='%d' port='%d'",
3016
                          info->addr.vioserial.controller,
3017 3018
                          info->addr.vioserial.bus,
                          info->addr.vioserial.port);
3019 3020
        break;

E
Eric Blake 已提交
3021
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCID:
3022
        virBufferAsprintf(buf, " controller='%d' slot='%d'",
E
Eric Blake 已提交
3023 3024 3025 3026
                          info->addr.ccid.controller,
                          info->addr.ccid.slot);
        break;

M
Marc-André Lureau 已提交
3027
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB:
3028
        virBufferAsprintf(buf, " bus='%d' port='%s'",
M
Marc-André Lureau 已提交
3029 3030 3031 3032
                          info->addr.usb.bus,
                          info->addr.usb.port);
        break;

3033 3034 3035 3036 3037
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO:
        if (info->addr.spaprvio.has_reg)
            virBufferAsprintf(buf, " reg='0x%llx'", info->addr.spaprvio.reg);
        break;

3038 3039 3040 3041 3042 3043 3044
    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;

3045 3046 3047
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO:
        break;

3048
    default:
3049 3050
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown address type '%d'"), info->type);
3051 3052 3053 3054 3055 3056 3057 3058
        return -1;
    }

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

    return 0;
}

3059
static int
3060
virDomainDeviceDriveAddressParseXML(xmlNodePtr node,
3061 3062
                                    virDomainDeviceDriveAddressPtr addr)
{
3063
    char *bus, *unit, *controller, *target;
3064 3065 3066 3067 3068 3069
    int ret = -1;

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

    controller = virXMLPropString(node, "controller");
    bus = virXMLPropString(node, "bus");
3070
    target = virXMLPropString(node, "target");
3071 3072 3073 3074
    unit = virXMLPropString(node, "unit");

    if (controller &&
        virStrToLong_ui(controller, NULL, 10, &addr->controller) < 0) {
3075 3076
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Cannot parse <address> 'controller' attribute"));
3077 3078 3079 3080 3081
        goto cleanup;
    }

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

3087 3088
    if (target &&
        virStrToLong_ui(target, NULL, 10, &addr->target) < 0) {
3089 3090
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Cannot parse <address> 'target' attribute"));
3091 3092 3093
        goto cleanup;
    }

3094 3095
    if (unit &&
        virStrToLong_ui(unit, NULL, 10, &addr->unit) < 0) {
3096 3097
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Cannot parse <address> 'unit' attribute"));
3098 3099 3100 3101 3102 3103 3104 3105
        goto cleanup;
    }

    ret = 0;

cleanup:
    VIR_FREE(controller);
    VIR_FREE(bus);
3106
    VIR_FREE(target);
3107 3108 3109 3110
    VIR_FREE(unit);
    return ret;
}

3111 3112 3113 3114 3115 3116 3117

static int
virDomainDeviceVirtioSerialAddressParseXML(
    xmlNodePtr node,
    virDomainDeviceVirtioSerialAddressPtr addr
)
{
3118
    char *controller, *bus, *port;
3119 3120 3121 3122 3123 3124
    int ret = -1;

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

    controller = virXMLPropString(node, "controller");
    bus = virXMLPropString(node, "bus");
3125
    port = virXMLPropString(node, "port");
3126 3127 3128

    if (controller &&
        virStrToLong_ui(controller, NULL, 10, &addr->controller) < 0) {
3129 3130
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Cannot parse <address> 'controller' attribute"));
3131 3132 3133 3134 3135
        goto cleanup;
    }

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

3141 3142
    if (port &&
        virStrToLong_ui(port, NULL, 10, &addr->port) < 0) {
3143 3144
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Cannot parse <address> 'port' attribute"));
3145 3146 3147
        goto cleanup;
    }

3148 3149 3150 3151 3152
    ret = 0;

cleanup:
    VIR_FREE(controller);
    VIR_FREE(bus);
E
Eric Blake 已提交
3153
    VIR_FREE(port);
3154 3155 3156
    return ret;
}

3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214
static int
virDomainDeviceCCWAddressParseXML(xmlNodePtr node,
                                  virDomainDeviceCCWAddressPtr addr)
{
    int   ret = -1;
    char *cssid;
    char *ssid;
    char *devno;

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

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

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

    ret = 0;

cleanup:
    VIR_FREE(cssid);
    VIR_FREE(ssid);
    VIR_FREE(devno);
    return ret;
}

E
Eric Blake 已提交
3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228
static int
virDomainDeviceCcidAddressParseXML(xmlNodePtr node,
                                   virDomainDeviceCcidAddressPtr addr)
{
    char *controller, *slot;
    int ret = -1;

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

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

    if (controller &&
        virStrToLong_ui(controller, NULL, 10, &addr->controller) < 0) {
3229 3230
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Cannot parse <address> 'controller' attribute"));
E
Eric Blake 已提交
3231 3232 3233 3234 3235
        goto cleanup;
    }

    if (slot &&
        virStrToLong_ui(slot, NULL, 10, &addr->slot) < 0) {
3236 3237
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Cannot parse <address> 'slot' attribute"));
E
Eric Blake 已提交
3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248
        goto cleanup;
    }

    ret = 0;

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

3249 3250 3251 3252
static int
virDomainDeviceUSBAddressParseXML(xmlNodePtr node,
                                  virDomainDeviceUSBAddressPtr addr)
{
3253 3254
    char *port, *bus, *tmp;
    unsigned int p;
3255 3256 3257 3258 3259 3260 3261 3262
    int ret = -1;

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

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

    if (port &&
3263 3264 3265 3266
        ((virStrToLong_ui(port, &tmp, 10, &p) < 0 || (*tmp != '\0' && *tmp != '.')) ||
         (*tmp == '.' && (virStrToLong_ui(tmp + 1, &tmp, 10, &p) < 0 || (*tmp != '\0' && *tmp != '.'))) ||
         (*tmp == '.' && (virStrToLong_ui(tmp + 1, &tmp, 10, &p) < 0 || (*tmp != '\0' && *tmp != '.'))) ||
         (*tmp == '.' && (virStrToLong_ui(tmp + 1, &tmp, 10, &p) < 0 || (*tmp != '\0'))))) {
3267 3268
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Cannot parse <address> 'port' attribute"));
3269 3270 3271
        goto cleanup;
    }

3272 3273 3274
    addr->port = port;
    port = NULL;

3275 3276
    if (bus &&
        virStrToLong_ui(bus, NULL, 10, &addr->bus) < 0) {
3277 3278
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Cannot parse <address> 'bus' attribute"));
3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289
        goto cleanup;
    }

    ret = 0;

cleanup:
    VIR_FREE(bus);
    VIR_FREE(port);
    return ret;
}

3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301
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) {
3302 3303
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Cannot parse <address> 'reg' attribute"));
3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316
            ret = -1;
            goto cleanup;
        }

        addr->has_reg = true;
    }

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

3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329
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) {
3330 3331
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Cannot parse <master> 'startport' attribute"));
3332 3333 3334 3335 3336 3337 3338 3339 3340 3341
        goto cleanup;
    }

    ret = 0;

cleanup:
    VIR_FREE(startport);
    return ret;
}

3342 3343 3344
static int
virDomainDeviceBootParseXML(xmlNodePtr node,
                            int *bootIndex,
3345
                            virHashTablePtr bootHash)
3346 3347 3348 3349 3350 3351 3352
{
    char *order;
    int boot;
    int ret = -1;

    order = virXMLPropString(node, "order");
    if (!order) {
3353 3354
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing boot order attribute"));
3355 3356 3357
        goto cleanup;
    } else if (virStrToLong_i(order, NULL, 10, &boot) < 0 ||
               boot <= 0) {
3358 3359 3360
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("incorrect boot order '%s', expecting positive integer"),
                       order);
3361 3362 3363
        goto cleanup;
    }

3364 3365 3366 3367 3368
    if (bootHash) {
        if (virHashLookup(bootHash, order)) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("boot order '%s' used for more than one device"),
                           order);
3369 3370
            goto cleanup;
        }
3371 3372 3373

        if (virHashAddEntry(bootHash, order, (void *) 1) < 0)
            goto cleanup;
3374 3375 3376 3377 3378 3379 3380 3381 3382 3383
    }

    *bootIndex = boot;
    ret = 0;

cleanup:
    VIR_FREE(order);
    return ret;
}

3384 3385 3386 3387
/* Parse the XML definition for a device address
 * @param node XML nodeset to parse for device address definition
 */
static int
3388
virDomainDeviceInfoParseXML(xmlNodePtr node,
3389
                            virHashTablePtr bootHash,
3390
                            virDomainDeviceInfoPtr info,
E
Eric Blake 已提交
3391
                            unsigned int flags)
3392 3393 3394
{
    xmlNodePtr cur;
    xmlNodePtr address = NULL;
3395
    xmlNodePtr master = NULL;
D
Daniel P. Berrange 已提交
3396
    xmlNodePtr alias = NULL;
3397 3398
    xmlNodePtr boot = NULL;
    xmlNodePtr rom = NULL;
3399 3400 3401 3402 3403 3404 3405 3406
    char *type = NULL;
    int ret = -1;

    virDomainDeviceInfoClear(info);

    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
D
Daniel P. Berrange 已提交
3407 3408 3409 3410 3411 3412
            if (alias == NULL &&
                !(flags & VIR_DOMAIN_XML_INACTIVE) &&
                xmlStrEqual(cur->name, BAD_CAST "alias")) {
                alias = cur;
            } else if (address == NULL &&
                       xmlStrEqual(cur->name, BAD_CAST "address")) {
3413
                address = cur;
3414 3415 3416
            } else if (master == NULL &&
                       xmlStrEqual(cur->name, BAD_CAST "master")) {
                master = cur;
3417
            } else if (boot == NULL &&
3418 3419 3420 3421 3422 3423 3424
                       (flags & VIR_DOMAIN_XML_INTERNAL_ALLOW_BOOT) &&
                       xmlStrEqual(cur->name, BAD_CAST "boot")) {
                boot = cur;
            } else if (rom == NULL &&
                       (flags & VIR_DOMAIN_XML_INTERNAL_ALLOW_ROM) &&
                       xmlStrEqual(cur->name, BAD_CAST "rom")) {
                rom = cur;
3425 3426 3427 3428 3429
            }
        }
        cur = cur->next;
    }

D
Daniel P. Berrange 已提交
3430 3431 3432
    if (alias)
        info->alias = virXMLPropString(alias, "name");

3433 3434 3435 3436 3437 3438
    if (master) {
        info->mastertype = VIR_DOMAIN_CONTROLLER_MASTER_USB;
        if (virDomainDeviceUSBMasterParseXML(master, &info->master.usb) < 0)
            goto cleanup;
    }

3439
    if (boot) {
3440
        if (virDomainDeviceBootParseXML(boot, &info->bootIndex, bootHash))
3441 3442 3443 3444 3445
            goto cleanup;
    }

    if (rom) {
        char *rombar = virXMLPropString(rom, "bar");
3446 3447
        if (rombar &&
            ((info->rombar = virDomainPciRombarModeTypeFromString(rombar)) <= 0)) {
3448 3449
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown rom bar value '%s'"), rombar);
3450 3451 3452 3453
            VIR_FREE(rombar);
            goto cleanup;
        }
        VIR_FREE(rombar);
3454
        info->romfile = virXMLPropString(rom, "file");
3455 3456
    }

3457 3458 3459 3460 3461 3462 3463
    if (!address)
        return 0;

    type = virXMLPropString(address, "type");

    if (type) {
        if ((info->type = virDomainDeviceAddressTypeFromString(type)) < 0) {
3464 3465
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown address type '%s'"), type);
3466 3467 3468
            goto cleanup;
        }
    } else {
3469 3470
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("No type specified for device address"));
3471 3472 3473 3474 3475
        goto cleanup;
    }

    switch (info->type) {
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI:
3476
        if (virDevicePCIAddressParseXML(address, &info->addr.pci) < 0)
3477 3478 3479
            goto cleanup;
        break;

3480
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE:
3481
        if (virDomainDeviceDriveAddressParseXML(address, &info->addr.drive) < 0)
3482 3483 3484
            goto cleanup;
        break;

3485 3486 3487 3488 3489 3490
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL:
        if (virDomainDeviceVirtioSerialAddressParseXML
                (address, &info->addr.vioserial) < 0)
            goto cleanup;
        break;

E
Eric Blake 已提交
3491 3492 3493 3494 3495
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCID:
        if (virDomainDeviceCcidAddressParseXML(address, &info->addr.ccid) < 0)
            goto cleanup;
        break;

3496 3497 3498 3499 3500
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB:
        if (virDomainDeviceUSBAddressParseXML(address, &info->addr.usb) < 0)
            goto cleanup;
        break;

3501 3502 3503 3504 3505
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO:
        if (virDomainDeviceSpaprVioAddressParseXML(address, &info->addr.spaprvio) < 0)
            goto cleanup;
        break;

3506 3507 3508 3509 3510 3511
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW:
        if (virDomainDeviceCCWAddressParseXML
                (address, &info->addr.ccw) < 0)
            goto cleanup;
        break;

3512 3513 3514
    case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO:
        break;

3515 3516
    default:
        /* Should not happen */
3517 3518
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("Unknown device address type"));
3519 3520 3521 3522 3523 3524
        goto cleanup;
    }

    ret = 0;

cleanup:
D
Daniel P. Berrange 已提交
3525 3526
    if (ret == -1)
        VIR_FREE(info->alias);
3527 3528 3529 3530
    VIR_FREE(type);
    return ret;
}

3531 3532
static int
virDomainParseLegacyDeviceAddress(char *devaddr,
3533
                                  virDevicePCIAddressPtr pci)
3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547
{
    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;
}
3548

3549 3550 3551 3552 3553 3554
static int
virDomainHostdevSubsysUsbDefParseXML(const xmlNodePtr node,
                                     virDomainHostdevDefPtr def)
{

    int ret = -1;
3555
    bool got_product, got_vendor;
3556
    xmlNodePtr cur;
3557
    char *startupPolicy = NULL;
3558
    char *autoAddress;
3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571

    if ((startupPolicy = virXMLPropString(node, "startupPolicy"))) {
        def->startupPolicy =
            virDomainStartupPolicyTypeFromString(startupPolicy);
        if (def->startupPolicy <= 0) {
            virReportError(VIR_ERR_XML_ERROR,
                           _("Unknown startup policy '%s'"),
                           startupPolicy);
            VIR_FREE(startupPolicy);
            goto out;
        }
        VIR_FREE(startupPolicy);
    }
3572

3573 3574 3575 3576 3577 3578
    if ((autoAddress = virXMLPropString(node, "autoAddress"))) {
        if (STREQ(autoAddress, "yes"))
            def->source.subsys.u.usb.autoAddress = true;
        VIR_FREE(autoAddress);
    }

3579 3580
    /* Product can validly be 0, so we need some extra help to determine
     * if it is uninitialized*/
3581 3582
    got_product = false;
    got_vendor = false;
3583 3584 3585 3586 3587 3588 3589 3590

    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) {
3591
                    got_vendor = true;
3592 3593
                    if (virStrToLong_ui(vendor, NULL, 0,
                                    &def->source.subsys.u.usb.vendor) < 0) {
3594 3595
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("cannot parse vendor id %s"), vendor);
3596 3597 3598 3599 3600
                        VIR_FREE(vendor);
                        goto out;
                    }
                    VIR_FREE(vendor);
                } else {
3601 3602
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   "%s", _("usb vendor needs id"));
3603 3604 3605 3606 3607 3608
                    goto out;
                }
            } else if (xmlStrEqual(cur->name, BAD_CAST "product")) {
                char* product = virXMLPropString(cur, "id");

                if (product) {
3609
                    got_product = true;
3610 3611
                    if (virStrToLong_ui(product, NULL, 0,
                                        &def->source.subsys.u.usb.product) < 0) {
3612 3613 3614
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("cannot parse product %s"),
                                       product);
3615 3616 3617 3618 3619
                        VIR_FREE(product);
                        goto out;
                    }
                    VIR_FREE(product);
                } else {
3620 3621
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   "%s", _("usb product needs id"));
3622 3623 3624 3625 3626 3627 3628 3629 3630
                    goto out;
                }
            } else if (xmlStrEqual(cur->name, BAD_CAST "address")) {
                char *bus, *device;

                bus = virXMLPropString(cur, "bus");
                if (bus) {
                    if (virStrToLong_ui(bus, NULL, 0,
                                        &def->source.subsys.u.usb.bus) < 0) {
3631 3632
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("cannot parse bus %s"), bus);
3633 3634 3635 3636 3637
                        VIR_FREE(bus);
                        goto out;
                    }
                    VIR_FREE(bus);
                } else {
3638 3639
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   "%s", _("usb address needs bus id"));
3640 3641 3642 3643 3644 3645 3646
                    goto out;
                }

                device = virXMLPropString(cur, "device");
                if (device) {
                    if (virStrToLong_ui(device, NULL, 0,
                                        &def->source.subsys.u.usb.device) < 0)  {
3647 3648 3649
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("cannot parse device %s"),
                                       device);
3650 3651 3652 3653 3654
                        VIR_FREE(device);
                        goto out;
                    }
                    VIR_FREE(device);
                } else {
3655 3656
                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                   _("usb address needs device id"));
3657 3658 3659
                    goto out;
                }
            } else {
3660 3661 3662
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unknown usb source type '%s'"),
                               cur->name);
3663 3664 3665 3666 3667 3668 3669
                goto out;
            }
        }
        cur = cur->next;
    }

    if (got_vendor && def->source.subsys.u.usb.vendor == 0) {
3670 3671
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("vendor cannot be 0."));
3672 3673 3674 3675
        goto out;
    }

    if (!got_vendor && got_product) {
3676 3677
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing vendor"));
3678 3679 3680
        goto out;
    }
    if (got_vendor && !got_product) {
3681 3682
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing product"));
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
        goto out;
    }

    ret = 0;
out:
    return ret;
}

/* The internal XML for host PCI device's original states:
 *
 * <origstates>
 *   <unbind/>
 *   <removeslot/>
 *   <reprobe/>
 * </origstates>
 */
static int
virDomainHostdevSubsysPciOrigStatesDefParseXML(const xmlNodePtr node,
                                               virDomainHostdevOrigStatesPtr def)
{
    xmlNodePtr cur;
    cur = node->children;

    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
            if (xmlStrEqual(cur->name, BAD_CAST "unbind")) {
3709
                def->states.pci.unbind_from_stub = true;
3710
            } else if (xmlStrEqual(cur->name, BAD_CAST "removeslot")) {
3711
                def->states.pci.remove_slot = true;
3712
            } else if (xmlStrEqual(cur->name, BAD_CAST "reprobe")) {
3713
                def->states.pci.reprobe = true;
3714
            } else {
3715 3716 3717
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unsupported element '%s' of 'origstates'"),
                               cur->name);
3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738
                return -1;
            }
        }
        cur = cur->next;
    }

    return 0;
}

static int
virDomainHostdevSubsysPciDefParseXML(const xmlNodePtr node,
                                     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")) {
3739
                virDevicePCIAddressPtr addr =
3740
                    &def->source.subsys.u.pci.addr;
3741

3742
                if (virDevicePCIAddressParseXML(cur, addr) < 0)
3743 3744 3745 3746 3747 3748 3749
                    goto out;
            } else if ((flags & VIR_DOMAIN_XML_INTERNAL_STATUS) &&
                       xmlStrEqual(cur->name, BAD_CAST "state")) {
                /* Legacy back-compat. Don't add any more attributes here */
                char *devaddr = virXMLPropString(cur, "devaddr");
                if (devaddr &&
                    virDomainParseLegacyDeviceAddress(devaddr,
3750
                                                      &def->info->addr.pci) < 0) {
3751 3752 3753
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Unable to parse devaddr parameter '%s'"),
                                   devaddr);
3754 3755 3756
                    VIR_FREE(devaddr);
                    goto out;
                }
3757
                def->info->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
3758 3759 3760 3761 3762 3763
            } else if ((flags & VIR_DOMAIN_XML_INTERNAL_PCI_ORIG_STATES) &&
                       xmlStrEqual(cur->name, BAD_CAST "origstates")) {
                virDomainHostdevOrigStatesPtr states = &def->origstates;
                if (virDomainHostdevSubsysPciOrigStatesDefParseXML(cur, states) < 0)
                    goto out;
            } else {
3764 3765 3766
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unknown pci source type '%s'"),
                               cur->name);
3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777
                goto out;
            }
        }
        cur = cur->next;
    }

    ret = 0;
out:
    return ret;
}

H
Han Cheng 已提交
3778 3779 3780 3781 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 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865
static int
virDomainHostdevSubsysScsiDefParseXML(const xmlNodePtr node,
                                      virDomainHostdevDefPtr def)
{
    int ret = -1;
    bool got_address = false, got_adapter = false;
    xmlNodePtr cur;
    char *bus = NULL, *target = NULL, *unit = NULL;

    cur = node->children;
    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;
                }

                if (virStrToLong_ui(bus, NULL, 0, &def->source.subsys.u.scsi.bus) < 0) {
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("cannot parse bus '%s'"), bus);
                    goto cleanup;
                }

                if (virStrToLong_ui(target, NULL, 0, &def->source.subsys.u.scsi.target) < 0) {
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("cannot parse target '%s'"), target);
                    goto cleanup;
                }

                if (virStrToLong_ui(unit, NULL, 0, &def->source.subsys.u.scsi.unit) < 0) {
                    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;
                }
                if (!(def->source.subsys.u.scsi.adapter =
                      virXMLPropString(cur, "name"))) {
                    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;
cleanup:
    VIR_FREE(bus);
    VIR_FREE(target);
    VIR_FREE(unit);
    return ret;
}

3866 3867 3868 3869 3870 3871 3872 3873 3874 3875
/* Check if a drive type address $controller:0:0:$unit is already
 * taken by a disk or not.
 */
static bool
virDomainDriveAddressIsUsedByDisk(virDomainDefPtr def,
                                  enum virDomainDiskBus type,
                                  unsigned int controller,
                                  unsigned int unit)
{
    virDomainDiskDefPtr disk;
3876
    size_t i;
3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904

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

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

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

    return false;
}

/* Check if a drive type address $controller:0:0:$unit is already
 * taken by a host device or not.
 */
static bool
virDomainDriveAddressIsUsedByHostdev(virDomainDefPtr def,
                                     enum virDomainHostdevSubsysType type,
                                     unsigned int controller,
                                     unsigned int unit)
{
    virDomainHostdevDefPtr hostdev;
3905
    size_t i;
3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948

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

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

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

    return false;
}

static bool
virDomainSCSIDriveAddressIsUsed(virDomainDefPtr def,
                                unsigned int controller,
                                unsigned int unit)
{
    /* In current implementation, the maximum unit number of a controller
     * is either 16 or 7 (narrow SCSI bus), and if the maximum unit number
     * is 16, the controller itself is on unit 7 */
    if (unit == 7)
        return true;

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

    return false;
}

/* Find out the next usable "unit" of a specific controller */
static int
virDomainControllerSCSINextUnit(virDomainDefPtr def,
                                unsigned int max_unit,
                                unsigned int controller)
{
3949
    size_t i;
3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966

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

    return -1;
}

#define SCSI_WIDE_BUS_MAX_CONT_UNIT 16
#define SCSI_NARROW_BUS_MAX_CONT_UNIT 7

static int
virDomainHostdevAssignAddress(virDomainXMLOptionPtr xmlopt,
                              virDomainDefPtr def,
                              virDomainHostdevDefPtr hostdev)
{
3967 3968
    int next_unit = 0;
    unsigned controller = 0;
3969
    size_t i;
3970
    int ret;
3971 3972 3973 3974

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

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

3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989
        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;
        }
3990 3991 3992
    }

    hostdev->info->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE;
3993
    hostdev->info->addr.drive.controller = controller;
3994 3995
    hostdev->info->addr.drive.bus = 0;
    hostdev->info->addr.drive.target = 0;
3996
    hostdev->info->addr.drive.unit = next_unit;
3997 3998 3999 4000

    return 0;
}

4001
static int
4002 4003 4004 4005 4006
virDomainHostdevDefParseXMLSubsys(xmlNodePtr node,
                                  xmlXPathContextPtr ctxt,
                                  const char *type,
                                  virDomainHostdevDefPtr def,
                                  unsigned int flags)
4007 4008 4009
{
    xmlNodePtr sourcenode;
    char *managed = NULL;
O
Osier Yang 已提交
4010
    char *sgio = NULL;
4011 4012
    char *backendStr = NULL;
    int backend;
4013 4014 4015 4016 4017 4018 4019 4020 4021
    int ret = -1;

    /* @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')
     */
    if ((managed = virXMLPropString(node, "managed"))!= NULL) {
        if (STREQ(managed, "yes"))
4022
            def->managed = true;
4023 4024
    }

O
Osier Yang 已提交
4025 4026
    sgio = virXMLPropString(node, "sgio");

4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037
    /* @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) {
4038 4039 4040
            virReportError(VIR_ERR_XML_ERROR,
                           _("unknown host device source address type '%s'"),
                           type);
4041 4042 4043
            goto error;
        }
    } else {
4044 4045
        virReportError(VIR_ERR_XML_ERROR,
                       "%s", _("missing source address type"));
4046 4047 4048 4049
        goto error;
    }

    if (!(sourcenode = virXPathNode("./source", ctxt))) {
4050 4051
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Missing <source> element in hostdev device"));
4052 4053
        goto error;
    }
4054 4055 4056 4057 4058 4059 4060 4061 4062

    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 已提交
4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078
    if (sgio) {
        if (def->source.subsys.type !=
            VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("sgio is only supported for scsi host device"));
            goto error;
        }

        if ((def->source.subsys.u.scsi.sgio =
             virDomainDeviceSGIOTypeFromString(sgio)) <= 0) {
            virReportError(VIR_ERR_XML_ERROR,
                           _("unknown sgio mode '%s'"), sgio);
            goto error;
        }
    }

4079 4080 4081 4082
    switch (def->source.subsys.type) {
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
        if (virDomainHostdevSubsysPciDefParseXML(sourcenode, def, flags) < 0)
            goto error;
4083

4084
        backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT;
4085 4086
        if ((backendStr = virXPathString("string(./driver/@name)", ctxt)) &&
            (((backend = virDomainHostdevSubsysPciBackendTypeFromString(backendStr)) < 0) ||
4087
             backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT)) {
4088 4089 4090 4091 4092 4093 4094
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unknown PCI device <driver name='%s'/> "
                             "has been specified"), backendStr);
            goto error;
        }
        def->source.subsys.u.pci.backend = backend;

4095
        break;
4096

4097 4098 4099 4100
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
        if (virDomainHostdevSubsysUsbDefParseXML(sourcenode, def) < 0)
            goto error;
        break;
H
Han Cheng 已提交
4101 4102 4103 4104 4105 4106

    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
        if (virDomainHostdevSubsysScsiDefParseXML(sourcenode, def) < 0)
            goto error;
        break;

4107
    default:
4108 4109 4110
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("address type='%s' not supported in hostdev interfaces"),
                       virDomainHostdevSubsysTypeToString(def->source.subsys.type));
4111 4112
        goto error;
    }
4113

4114 4115 4116
    ret = 0;
error:
    VIR_FREE(managed);
O
Osier Yang 已提交
4117
    VIR_FREE(sgio);
4118
    VIR_FREE(backendStr);
4119 4120 4121
    return ret;
}

4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175
static int
virDomainHostdevDefParseXMLCaps(xmlNodePtr node ATTRIBUTE_UNUSED,
                                xmlXPathContextPtr ctxt,
                                const char *type,
                                virDomainHostdevDefPtr def)
{
    xmlNodePtr sourcenode;
    int ret = -1;

    /* @type is passed in from the caller rather than read from the
     * xml document, because it is specified in different places for
     * different kinds of defs - it is an attribute of
     * <source>/<address> for an intelligent hostdev (<interface>),
     * but an attribute of the toplevel element for a standard
     * <hostdev>.  (the functions we're going to call expect address
     * type to already be known).
     */
    if (type) {
        if ((def->source.caps.type
             = virDomainHostdevCapsTypeFromString(type)) < 0) {
            virReportError(VIR_ERR_XML_ERROR,
                           _("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;
4176 4177 4178 4179 4180 4181 4182 4183
    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_NET:
        if (!(def->source.caps.u.net.iface =
              virXPathString("string(./source/interface[1])", ctxt))) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("Missing <interface> element in hostdev net device"));
            goto error;
        }
        break;
4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("address type='%s' not supported in hostdev interfaces"),
                       virDomainHostdevCapsTypeToString(def->source.caps.type));
        goto error;
    }
    ret = 0;
error:
    return ret;
}

4195
int
H
Han Cheng 已提交
4196 4197 4198
virDomainDeviceFindControllerModel(virDomainDefPtr def,
                                   virDomainDeviceInfoPtr info,
                                   int controllerType)
4199 4200
{
    int model = -1;
4201
    size_t i;
4202 4203 4204

    for (i = 0; i < def->ncontrollers; i++) {
        if (def->controllers[i]->type == controllerType &&
H
Han Cheng 已提交
4205
            def->controllers[i]->idx == info->addr.drive.controller)
4206 4207 4208 4209 4210 4211
            model = def->controllers[i]->model;
    }

    return model;
}

4212 4213 4214 4215 4216
virDomainDiskDefPtr
virDomainDiskFindByBusAndDst(virDomainDefPtr def,
                             int bus,
                             char *dst)
{
4217
    size_t i;
4218 4219 4220 4221

    if (!dst)
        return NULL;

4222
    for (i = 0; i < def->ndisks; i++) {
4223 4224 4225 4226 4227 4228 4229 4230 4231
        if (def->disks[i]->bus == bus &&
            STREQ(def->disks[i]->dst, dst)) {
            return def->disks[i];
        }
    }

    return NULL;
}

4232
int
4233 4234
virDomainDiskDefAssignAddress(virDomainXMLOptionPtr xmlopt,
                              virDomainDiskDefPtr def)
4235 4236
{
    int idx = virDiskNameToIndex(def->dst);
4237 4238 4239 4240
    if (idx < 0) {
        virReportError(VIR_ERR_XML_ERROR,
                       _("Unknown disk name '%s' and no address specified"),
                       def->dst);
4241
        return -1;
4242
    }
4243 4244 4245 4246

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

4248
        if (xmlopt->config.hasWideScsiBus) {
4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269
            /* For a wide SCSI bus we define the default mapping to be
             * 16 units per bus, 1 bus per controller, many controllers.
             * Unit 7 is the SCSI controller itself. Therefore unit 7
             * cannot be assigned to disks and is skipped.
             */
            def->info.addr.drive.controller = idx / 15;
            def->info.addr.drive.bus = 0;
            def->info.addr.drive.unit = idx % 15;

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

4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280
        break;

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

J
Jim Fehlig 已提交
4281 4282 4283 4284 4285 4286 4287 4288 4289
    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;

4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302
    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;
    }
4303 4304

    return 0;
4305 4306
}

4307 4308
static virSecurityLabelDefPtr
virSecurityLabelDefParseXML(xmlXPathContextPtr ctxt,
4309
                            unsigned int flags)
E
Eric Blake 已提交
4310 4311
{
    char *p;
4312
    virSecurityLabelDefPtr def = NULL;
E
Eric Blake 已提交
4313

4314
    if (VIR_ALLOC(def) < 0)
4315
        goto error;
E
Eric Blake 已提交
4316

4317
    p = virXPathStringLimit("string(./@type)",
4318 4319
                            VIR_SECURITY_LABEL_BUFLEN-1, ctxt);
    if (p == NULL) {
E
Eric Blake 已提交
4320 4321 4322 4323 4324
        def->type = VIR_DOMAIN_SECLABEL_DYNAMIC;
    } else {
        def->type = virDomainSeclabelTypeFromString(p);
        VIR_FREE(p);
        if (def->type <= 0) {
4325 4326
            virReportError(VIR_ERR_XML_ERROR,
                           "%s", _("invalid security type"));
E
Eric Blake 已提交
4327 4328
            goto error;
        }
4329
    }
4330

4331
    p = virXPathStringLimit("string(./@relabel)",
E
Eric Blake 已提交
4332 4333 4334 4335 4336 4337 4338
                            VIR_SECURITY_LABEL_BUFLEN-1, ctxt);
    if (p != NULL) {
        if (STREQ(p, "yes")) {
            def->norelabel = false;
        } else if (STREQ(p, "no")) {
            def->norelabel = true;
        } else {
4339 4340
            virReportError(VIR_ERR_XML_ERROR,
                           _("invalid security relabel value %s"), p);
E
Eric Blake 已提交
4341
            VIR_FREE(p);
4342
            goto error;
E
Eric Blake 已提交
4343 4344
        }
        VIR_FREE(p);
4345
        if (def->type == VIR_DOMAIN_SECLABEL_DYNAMIC &&
E
Eric Blake 已提交
4346
            def->norelabel) {
4347 4348
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           "%s", _("dynamic label type must use resource relabeling"));
4349
            goto error;
E
Eric Blake 已提交
4350
        }
4351 4352
        if (def->type == VIR_DOMAIN_SECLABEL_NONE &&
            !def->norelabel) {
4353 4354
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           "%s", _("resource relabeling is not compatible with 'none' label type"));
4355 4356
            goto error;
        }
E
Eric Blake 已提交
4357
    } else {
4358 4359
        if (def->type == VIR_DOMAIN_SECLABEL_STATIC ||
            def->type == VIR_DOMAIN_SECLABEL_NONE)
E
Eric Blake 已提交
4360 4361 4362 4363 4364 4365
            def->norelabel = true;
        else
            def->norelabel = false;
    }

    /* Only parse label, if using static labels, or
4366
     * if the 'live' VM XML is requested
E
Eric Blake 已提交
4367
     */
4368
    if (def->type == VIR_DOMAIN_SECLABEL_STATIC ||
E
Eric Blake 已提交
4369 4370
        (!(flags & VIR_DOMAIN_XML_INACTIVE) &&
         def->type != VIR_DOMAIN_SECLABEL_NONE)) {
4371
        p = virXPathStringLimit("string(./label[1])",
E
Eric Blake 已提交
4372
                                VIR_SECURITY_LABEL_BUFLEN-1, ctxt);
4373
        if (p == NULL) {
4374 4375
            virReportError(VIR_ERR_XML_ERROR,
                           "%s", _("security label is missing"));
4376
            goto error;
E
Eric Blake 已提交
4377 4378 4379 4380 4381 4382 4383
        }

        def->label = p;
    }

    /* Only parse imagelabel, if requested live XML with relabeling */
    if (!def->norelabel &&
E
Eric Blake 已提交
4384 4385
        (!(flags & VIR_DOMAIN_XML_INACTIVE) &&
         def->type != VIR_DOMAIN_SECLABEL_NONE)) {
4386
        p = virXPathStringLimit("string(./imagelabel[1])",
E
Eric Blake 已提交
4387 4388
                                VIR_SECURITY_LABEL_BUFLEN-1, ctxt);
        if (p == NULL) {
4389 4390
            virReportError(VIR_ERR_XML_ERROR,
                           "%s", _("security imagelabel is missing"));
E
Eric Blake 已提交
4391 4392 4393 4394 4395
            goto error;
        }
        def->imagelabel = p;
    }

E
Eric Blake 已提交
4396 4397
    /* Only parse baselabel for dynamic label type */
    if (def->type == VIR_DOMAIN_SECLABEL_DYNAMIC) {
4398
        p = virXPathStringLimit("string(./baselabel[1])",
E
Eric Blake 已提交
4399
                                VIR_SECURITY_LABEL_BUFLEN-1, ctxt);
E
Eric Blake 已提交
4400
        def->baselabel = p;
E
Eric Blake 已提交
4401 4402
    }

4403 4404 4405 4406
    /* Always parse model */
    p = virXPathStringLimit("string(./@model)",
                            VIR_SECURITY_MODEL_BUFLEN-1, ctxt);
    def->model = p;
E
Eric Blake 已提交
4407

4408
    return def;
E
Eric Blake 已提交
4409 4410

error:
4411
    virSecurityLabelDefFree(def);
4412
    return NULL;
E
Eric Blake 已提交
4413 4414
}

4415
static int
4416 4417
virSecurityLabelDefsParseXML(virDomainDefPtr def,
                            xmlXPathContextPtr ctxt,
4418
                            virCapsPtr caps,
4419
                            unsigned int flags)
4420
{
4421 4422
    size_t i = 0;
    int n;
4423
    xmlNodePtr *list = NULL, saved_node;
4424
    virCapsHostPtr host = &caps->host;
4425

4426 4427 4428 4429
    /* Check args and save context */
    if (def == NULL || ctxt == NULL)
        return 0;
    saved_node = ctxt->node;
4430

4431
    /* Allocate a security labels based on XML */
4432 4433 4434
    if ((n = virXPathNodeSet("./seclabel", ctxt, &list)) < 0)
        goto error;
    if (n == 0)
4435 4436
        return 0;

4437
    if (VIR_ALLOC_N(def->seclabels, n) < 0)
4438
        goto error;
4439

4440 4441 4442 4443 4444 4445
    /* Parse each "seclabel" tag */
    for (i = 0; i < n; i++) {
        ctxt->node = list[i];
        def->seclabels[i] = virSecurityLabelDefParseXML(ctxt, flags);
        if (def->seclabels[i] == NULL)
            goto error;
4446
    }
4447 4448 4449
    def->nseclabels = n;
    ctxt->node = saved_node;
    VIR_FREE(list);
4450

4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467
    /* libvirt versions prior to 0.10.0 support just a single seclabel element
     * in guest's XML and model attribute can be suppressed if type is none or
     * type is dynamic, baselabel is not defined and INACTIVE flag is set.
     *
     * To avoid compatibility issues, for this specific case the first model
     * defined in host's capabilities is used as model for the seclabel.
     */
    if (def->nseclabels == 1 &&
        !def->seclabels[0]->model &&
        host->nsecModels > 0) {
        if (def->seclabels[0]->type == VIR_DOMAIN_SECLABEL_NONE ||
            (def->seclabels[0]->type == VIR_DOMAIN_SECLABEL_DYNAMIC &&
             !def->seclabels[0]->baselabel &&
             (flags & VIR_DOMAIN_XML_INACTIVE))) {
            /* Copy model from host. */
            VIR_DEBUG("Found seclabel without a model, using '%s'",
                      host->secModels[0].model);
4468
            if (VIR_STRDUP(def->seclabels[0]->model, host->secModels[0].model) < 0)
4469 4470 4471 4472 4473 4474 4475 4476 4477 4478
                goto error;
        } else {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("missing security model in domain seclabel"));
            goto error;
        }
    }

    /* Checking missing model information */
    if (def->nseclabels > 1) {
4479
        for (; n; n--) {
4480 4481
            if (def->seclabels[n - 1]->model == NULL) {
                virReportError(VIR_ERR_XML_ERROR, "%s",
4482 4483
                               _("missing security model "
                                 "when using multiple labels"));
4484 4485
                goto error;
            }
4486 4487
        }
    }
4488

4489
    return 0;
4490

4491 4492 4493 4494 4495 4496
error:
    ctxt->node = saved_node;
    for (; i > 0; i--) {
        virSecurityLabelDefFree(def->seclabels[i - 1]);
    }
    VIR_FREE(def->seclabels);
4497
    def->nseclabels = 0;
4498 4499 4500
    VIR_FREE(list);
    return -1;
}
4501

4502
/* Parse the <seclabel> from a disk or character device. */
4503
static int
4504 4505
virSecurityDeviceLabelDefParseXML(virSecurityDeviceLabelDefPtr **seclabels_rtn,
                                  size_t *nseclabels_rtn,
4506
                                  virSecurityLabelDefPtr *vmSeclabels,
4507 4508
                                  int nvmSeclabels, xmlXPathContextPtr ctxt,
                                  unsigned int flags)
4509
{
4510
    virSecurityDeviceLabelDefPtr *seclabels = NULL;
4511
    size_t nseclabels = 0;
4512 4513
    int n;
    size_t i, j;
4514 4515
    xmlNodePtr *list = NULL;
    virSecurityLabelDefPtr vmDef = NULL;
4516
    char *model, *relabel, *label, *labelskip;
4517

4518 4519 4520
    if ((n = virXPathNodeSet("./seclabel", ctxt, &list)) < 0)
        goto error;
    if (n == 0)
4521 4522
        return 0;

4523
    if (VIR_ALLOC_N(seclabels, n) < 0)
4524
        goto error;
4525
    nseclabels = n;
4526
    for (i = 0; i < n; i++) {
4527
        if (VIR_ALLOC(seclabels[i]) < 0)
4528
            goto error;
4529 4530
    }

4531 4532 4533
    for (i = 0; i < n; i++) {
        /* get model associated to this override */
        model = virXMLPropString(list[i], "model");
4534 4535
        if (model) {
            /* find the security label that it's being overridden */
4536 4537 4538 4539 4540 4541
            for (j = 0; j < nvmSeclabels; j++) {
                if (STREQ(vmSeclabels[j]->model, model)) {
                    vmDef = vmSeclabels[j];
                    break;
                }
            }
4542
            seclabels[i]->model = model;
4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555
        }

        /* Can't use overrides if top-level doesn't allow relabeling.  */
        if (vmDef && vmDef->norelabel) {
            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")) {
4556
                seclabels[i]->norelabel = false;
4557
            } else if (STREQ(relabel, "no")) {
4558
                seclabels[i]->norelabel = true;
4559 4560 4561 4562 4563 4564 4565 4566 4567
            } else {
                virReportError(VIR_ERR_XML_ERROR,
                               _("invalid security relabel value %s"),
                               relabel);
                VIR_FREE(relabel);
                goto error;
            }
            VIR_FREE(relabel);
        } else {
4568
            seclabels[i]->norelabel = false;
4569 4570
        }

4571 4572 4573 4574 4575 4576 4577
        /* labelskip is only parsed on live images */
        labelskip = virXMLPropString(list[i], "labelskip");
        seclabels[i]->labelskip = false;
        if (labelskip && !(flags & VIR_DOMAIN_XML_INACTIVE))
            seclabels[i]->labelskip = STREQ(labelskip, "yes");
        VIR_FREE(labelskip);

4578 4579 4580
        ctxt->node = list[i];
        label = virXPathStringLimit("string(./label)",
                                    VIR_SECURITY_LABEL_BUFLEN-1, ctxt);
4581
        seclabels[i]->label = label;
4582

4583
        if (label && seclabels[i]->norelabel) {
4584 4585 4586
            virReportError(VIR_ERR_XML_ERROR,
                           _("Cannot specify a label if relabelling is "
                             "turned off. model=%s"),
4587
                             NULLSTR(seclabels[i]->model));
4588 4589 4590 4591
            goto error;
        }
    }
    VIR_FREE(list);
4592 4593 4594 4595

    *nseclabels_rtn = nseclabels;
    *seclabels_rtn = seclabels;

4596
    return 0;
4597 4598

error:
4599 4600
    for (i = 0; i < nseclabels; i++) {
        virSecurityDeviceLabelDefFree(seclabels[i]);
4601
    }
4602
    VIR_FREE(seclabels);
4603 4604
    VIR_FREE(list);
    return -1;
4605 4606 4607
}


4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619
/* 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;

4620
    if (VIR_ALLOC(def) < 0)
4621 4622 4623 4624 4625
        return NULL;

    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
E
Eric Blake 已提交
4626
            if (!key && xmlStrEqual(cur->name, BAD_CAST "key")) {
4627
                key = (char *)xmlNodeGetContent(cur);
E
Eric Blake 已提交
4628 4629
            } else if (!lockspace &&
                       xmlStrEqual(cur->name, BAD_CAST "lockspace")) {
4630
                lockspace = (char *)xmlNodeGetContent(cur);
E
Eric Blake 已提交
4631 4632
            } else if (!path &&
                       xmlStrEqual(cur->name, BAD_CAST "target")) {
4633 4634 4635 4636 4637 4638 4639 4640
                path = virXMLPropString(cur, "path");
                offset = virXMLPropString(cur, "offset");
            }
        }
        cur = cur->next;
    }

    if (!key) {
4641 4642
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Missing 'key' element for lease"));
4643 4644 4645
        goto error;
    }
    if (!path) {
4646 4647
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Missing 'target' element for lease"));
4648 4649 4650 4651 4652
        goto error;
    }

    if (offset &&
        virStrToLong_ull(offset, NULL, 10, &def->offset) < 0) {
4653 4654
        virReportError(VIR_ERR_XML_ERROR,
                       _("Malformed lease target offset %s"), offset);
4655 4656 4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674 4675 4676
        goto error;
    }

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

cleanup:
    VIR_FREE(lockspace);
    VIR_FREE(key);
    VIR_FREE(path);
    VIR_FREE(offset);

    return def;

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

4677 4678 4679 4680 4681 4682
static int
virDomainDiskSourcePoolDefParse(xmlNodePtr node,
                                virDomainDiskDefPtr def)
{
    char *pool = NULL;
    char *volume = NULL;
4683
    char *mode = NULL;
4684 4685 4686 4687
    int ret = -1;

    pool = virXMLPropString(node, "pool");
    volume = virXMLPropString(node, "volume");
4688
    mode = virXMLPropString(node, "mode");
4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700

    /* CD-ROM and Floppy allows no source */
    if (!pool && !volume)
        return 0;

    if (!pool || !volume) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("'pool' and 'volume' must be specified together "
                         "for 'pool' type source"));
        goto cleanup;
    }

4701
    if (VIR_ALLOC(def->srcpool) < 0)
4702 4703
        goto cleanup;

4704 4705 4706 4707 4708 4709 4710 4711
    if (mode && (def->srcpool->mode =
                 virDomainDiskSourcePoolModeTypeFromString(mode)) <= 0) {
        virReportError(VIR_ERR_XML_ERROR,
                       _("unknown source mode '%s' for volume type disk"),
                       mode);
        goto cleanup;
    }

4712 4713 4714 4715 4716 4717 4718 4719 4720 4721
    def->srcpool->pool = pool;
    pool = NULL;
    def->srcpool->volume = volume;
    volume = NULL;

    ret = 0;

cleanup:
    VIR_FREE(pool);
    VIR_FREE(volume);
4722
    VIR_FREE(mode);
4723 4724 4725
    return ret;
}

4726 4727
#define VENDOR_LEN  8
#define PRODUCT_LEN 16
4728

4729 4730 4731 4732
/* Parse the XML definition for a disk
 * @param node XML nodeset to parse for disk definition
 */
static virDomainDiskDefPtr
4733
virDomainDiskDefParseXML(virDomainXMLOptionPtr xmlopt,
4734
                         xmlNodePtr node,
L
Lei Li 已提交
4735
                         xmlXPathContextPtr ctxt,
4736
                         virHashTablePtr bootHash,
4737 4738
                         virSecurityLabelDefPtr* vmSeclabels,
                         int nvmSeclabels,
E
Eric Blake 已提交
4739
                         unsigned int flags)
4740
{
4741
    virDomainDiskDefPtr def;
4742
    xmlNodePtr sourceNode = NULL;
4743
    xmlNodePtr cur, child;
L
Lei Li 已提交
4744
    xmlNodePtr save_ctxt = ctxt->node;
4745 4746
    char *type = NULL;
    char *device = NULL;
4747
    char *snapshot = NULL;
4748
    char *rawio = NULL;
O
Osier Yang 已提交
4749
    char *sgio = NULL;
4750 4751 4752 4753
    char *driverName = NULL;
    char *driverType = NULL;
    char *source = NULL;
    char *target = NULL;
M
MORITA Kazutaka 已提交
4754
    char *protocol = NULL;
4755
    char *protocol_transport = NULL;
J
J.B. Joret 已提交
4756
    char *trans = NULL;
M
MORITA Kazutaka 已提交
4757 4758
    virDomainDiskHostDefPtr hosts = NULL;
    int nhosts = 0;
4759
    char *bus = NULL;
4760
    char *cachetag = NULL;
4761
    char *error_policy = NULL;
4762
    char *rerror_policy = NULL;
M
Matthias Dahl 已提交
4763
    char *iotag = NULL;
4764
    char *ioeventfd = NULL;
4765
    char *event_idx = NULL;
O
Osier Yang 已提交
4766
    char *copy_on_read = NULL;
4767 4768 4769
    char *mirror = NULL;
    char *mirrorFormat = NULL;
    bool mirroring = false;
4770
    char *devaddr = NULL;
4771
    virStorageEncryptionPtr encryption = NULL;
4772
    char *serial = NULL;
4773
    char *startupPolicy = NULL;
4774 4775 4776 4777
    char *authUsername = NULL;
    char *authUsage = NULL;
    char *authUUID = NULL;
    char *usageType = NULL;
4778
    char *tray = NULL;
4779
    char *removable = NULL;
4780 4781
    char *logical_block_size = NULL;
    char *physical_block_size = NULL;
O
Osier Yang 已提交
4782
    char *wwn = NULL;
4783 4784
    char *vendor = NULL;
    char *product = NULL;
O
Osier Yang 已提交
4785
    char *discard = NULL;
4786 4787
    int expected_secret_usage = -1;
    int auth_secret_usage = -1;
4788

4789
    if (VIR_ALLOC(def) < 0)
4790 4791
        return NULL;

J
J.B. Joret 已提交
4792 4793 4794 4795 4796
    def->geometry.cylinders = 0;
    def->geometry.heads = 0;
    def->geometry.sectors = 0;
    def->geometry.trans = VIR_DOMAIN_DISK_TRANS_DEFAULT;

V
Viktor Mihajlovski 已提交
4797 4798
    def->blockio.logical_block_size = 0;
    def->blockio.physical_block_size = 0;
4799

L
Lei Li 已提交
4800 4801
    ctxt->node = node;

4802 4803 4804
    type = virXMLPropString(node, "type");
    if (type) {
        if ((def->type = virDomainDiskTypeFromString(type)) < 0) {
4805 4806
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown disk type '%s'"), type);
4807 4808 4809 4810 4811 4812
            goto error;
        }
    } else {
        def->type = VIR_DOMAIN_DISK_TYPE_FILE;
    }

4813 4814
    snapshot = virXMLPropString(node, "snapshot");

4815
    rawio = virXMLPropString(node, "rawio");
O
Osier Yang 已提交
4816
    sgio = virXMLPropString(node, "sgio");
4817

4818 4819 4820
    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
4821
            if (!source && !hosts && !def->srcpool &&
E
Eric Blake 已提交
4822
                xmlStrEqual(cur->name, BAD_CAST "source")) {
4823 4824
                sourceNode = cur;

4825 4826
                switch (def->type) {
                case VIR_DOMAIN_DISK_TYPE_FILE:
4827
                    source = virXMLPropString(cur, "file");
4828 4829
                    break;
                case VIR_DOMAIN_DISK_TYPE_BLOCK:
4830
                    source = virXMLPropString(cur, "dev");
4831 4832 4833 4834
                    break;
                case VIR_DOMAIN_DISK_TYPE_DIR:
                    source = virXMLPropString(cur, "dir");
                    break;
M
MORITA Kazutaka 已提交
4835 4836 4837
                case VIR_DOMAIN_DISK_TYPE_NETWORK:
                    protocol = virXMLPropString(cur, "protocol");
                    if (protocol == NULL) {
4838 4839
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       "%s", _("missing protocol type"));
M
MORITA Kazutaka 已提交
4840 4841 4842 4843
                        goto error;
                    }
                    def->protocol = virDomainDiskProtocolTypeFromString(protocol);
                    if (def->protocol < 0) {
4844 4845 4846
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("unknown protocol type '%s'"),
                                       protocol);
M
MORITA Kazutaka 已提交
4847 4848
                        goto error;
                    }
4849 4850 4851 4852 4853
                    if (def->protocol == VIR_DOMAIN_DISK_PROTOCOL_ISCSI) {
                        expected_secret_usage = VIR_SECRET_USAGE_TYPE_ISCSI;
                    } else if (def->protocol == VIR_DOMAIN_DISK_PROTOCOL_RBD) {
                        expected_secret_usage = VIR_SECRET_USAGE_TYPE_CEPH;
                    }
4854 4855
                    if (!(source = virXMLPropString(cur, "name")) &&
                        def->protocol != VIR_DOMAIN_DISK_PROTOCOL_NBD) {
4856
                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4857
                                       _("missing name for disk source"));
4858 4859
                        goto error;
                    }
4860 4861 4862 4863
                    child = cur->children;
                    while (child != NULL) {
                        if (child->type == XML_ELEMENT_NODE &&
                            xmlStrEqual(child->name, BAD_CAST "host")) {
4864
                            if (VIR_REALLOC_N(hosts, nhosts + 1) < 0)
M
MORITA Kazutaka 已提交
4865 4866 4867
                                goto error;
                            hosts[nhosts].name = NULL;
                            hosts[nhosts].port = NULL;
4868 4869
                            hosts[nhosts].transport = VIR_DOMAIN_DISK_PROTO_TRANS_TCP;
                            hosts[nhosts].socket = NULL;
M
MORITA Kazutaka 已提交
4870 4871
                            nhosts++;

4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887
                            /* transport can be tcp (default), unix or rdma.  */
                            protocol_transport = virXMLPropString(child, "transport");
                            if (protocol_transport != NULL) {
                                hosts[nhosts - 1].transport = virDomainDiskProtocolTransportTypeFromString(protocol_transport);
                                if (hosts[nhosts - 1].transport < 0) {
                                    virReportError(VIR_ERR_XML_ERROR,
                                                   _("unknown protocol transport type '%s'"),
                                                   protocol_transport);
                                    goto error;
                                }
                            }
                            hosts[nhosts - 1].socket = virXMLPropString(child, "socket");
                            if (hosts[nhosts - 1].transport == VIR_DOMAIN_DISK_PROTO_TRANS_UNIX &&
                                hosts[nhosts - 1].socket == NULL) {
                                virReportError(VIR_ERR_XML_ERROR,
                                               "%s", _("missing socket for unix transport"));
M
MORITA Kazutaka 已提交
4888 4889
                                goto error;
                            }
4890 4891 4892 4893 4894
                            if (hosts[nhosts - 1].transport != VIR_DOMAIN_DISK_PROTO_TRANS_UNIX &&
                                hosts[nhosts - 1].socket != NULL) {
                                virReportError(VIR_ERR_XML_ERROR,
                                               _("transport %s does not support socket attribute"),
                                               protocol_transport);
M
MORITA Kazutaka 已提交
4895 4896
                                goto error;
                            }
4897 4898 4899 4900 4901 4902 4903 4904 4905 4906
                            VIR_FREE(protocol_transport);
                            if (hosts[nhosts - 1].transport != VIR_DOMAIN_DISK_PROTO_TRANS_UNIX) {
                                hosts[nhosts - 1].name = virXMLPropString(child, "name");
                                if (!hosts[nhosts - 1].name) {
                                    virReportError(VIR_ERR_XML_ERROR,
                                                   "%s", _("missing name for host"));
                                    goto error;
                                }
                                hosts[nhosts - 1].port = virXMLPropString(child, "port");
                            }
M
MORITA Kazutaka 已提交
4907
                        }
4908
                        child = child->next;
M
MORITA Kazutaka 已提交
4909 4910
                    }
                    break;
4911 4912 4913 4914
                case VIR_DOMAIN_DISK_TYPE_VOLUME:
                    if (virDomainDiskSourcePoolDefParse(cur, def) < 0)
                        goto error;
                    break;
4915
                default:
4916 4917 4918
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("unexpected disk type %s"),
                                   virDomainDiskTypeToString(def->type));
4919 4920
                    goto error;
                }
4921

4922 4923
                startupPolicy = virXMLPropString(cur, "startupPolicy");

4924 4925
                /* People sometimes pass a bogus '' source path
                   when they mean to omit the source element
M
Martin Kletzander 已提交
4926
                   completely (e.g. CDROM without media). This is
4927
                   just a little compatibility check to help
4928 4929 4930
                   those broken apps */
                if (source && STREQ(source, ""))
                    VIR_FREE(source);
E
Eric Blake 已提交
4931 4932
            } else if (!target &&
                       xmlStrEqual(cur->name, BAD_CAST "target")) {
4933 4934
                target = virXMLPropString(cur, "dev");
                bus = virXMLPropString(cur, "bus");
4935
                tray = virXMLPropString(cur, "tray");
4936
                removable = virXMLPropString(cur, "removable");
4937 4938 4939 4940 4941 4942

                /* HACK: Work around for compat with Xen
                 * driver in previous libvirt releases */
                if (target &&
                    STRPREFIX(target, "ioemu:"))
                    memmove(target, target+6, strlen(target)-5);
J
J.B. Joret 已提交
4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971
            } 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) {
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("invalid translation value '%s'"),
                                       trans);
                        goto error;
                    }
                }
V
Viktor Mihajlovski 已提交
4972
            } else if (xmlStrEqual(cur->name, BAD_CAST "blockio")) {
4973 4974 4975 4976
                logical_block_size =
                    virXMLPropString(cur, "logical_block_size");
                if (logical_block_size &&
                    virStrToLong_ui(logical_block_size, NULL, 0,
V
Viktor Mihajlovski 已提交
4977
                                    &def->blockio.logical_block_size) < 0) {
4978 4979 4980 4981 4982 4983 4984 4985 4986
                    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 已提交
4987
                                    &def->blockio.physical_block_size) < 0) {
4988 4989 4990 4991 4992
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("invalid physical block size '%s'"),
                                   physical_block_size);
                    goto error;
                }
E
Eric Blake 已提交
4993 4994
            } else if (!driverName &&
                       xmlStrEqual(cur->name, BAD_CAST "driver")) {
4995 4996
                driverName = virXMLPropString(cur, "name");
                driverType = virXMLPropString(cur, "type");
4997 4998 4999 5000 5001 5002
                if (STREQ_NULLABLE(driverType, "aio")) {
                    /* In-place conversion to "raw", for Xen back-compat */
                    driverType[0] = 'r';
                    driverType[1] = 'a';
                    driverType[2] = 'w';
                }
5003
                cachetag = virXMLPropString(cur, "cache");
5004
                error_policy = virXMLPropString(cur, "error_policy");
5005
                rerror_policy = virXMLPropString(cur, "rerror_policy");
M
Matthias Dahl 已提交
5006
                iotag = virXMLPropString(cur, "io");
5007
                ioeventfd = virXMLPropString(cur, "ioeventfd");
5008
                event_idx = virXMLPropString(cur, "event_idx");
O
Osier Yang 已提交
5009
                copy_on_read = virXMLPropString(cur, "copy_on_read");
O
Osier Yang 已提交
5010
                discard = virXMLPropString(cur, "discard");
5011 5012 5013 5014 5015
            } else if (!mirror && xmlStrEqual(cur->name, BAD_CAST "mirror") &&
                       !(flags & VIR_DOMAIN_XML_INACTIVE)) {
                char *ready;
                mirror = virXMLPropString(cur, "file");
                if (!mirror) {
5016 5017
                    virReportError(VIR_ERR_XML_ERROR, "%s",
                                   _("mirror requires file name"));
5018 5019 5020 5021 5022 5023 5024 5025
                    goto error;
                }
                mirrorFormat = virXMLPropString(cur, "format");
                ready = virXMLPropString(cur, "ready");
                if (ready) {
                    mirroring = true;
                    VIR_FREE(ready);
                }
5026 5027 5028
            } else if (xmlStrEqual(cur->name, BAD_CAST "auth")) {
                authUsername = virXMLPropString(cur, "username");
                if (authUsername == NULL) {
5029
                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5030
                                   _("missing username for auth"));
5031 5032 5033 5034 5035 5036 5037 5038 5039 5040
                    goto error;
                }

                def->auth.secretType = VIR_DOMAIN_DISK_SECRET_TYPE_NONE;
                child = cur->children;
                while (child != NULL) {
                    if (child->type == XML_ELEMENT_NODE &&
                        xmlStrEqual(child->name, BAD_CAST "secret")) {
                        usageType = virXMLPropString(child, "type");
                        if (usageType == NULL) {
5041
                            virReportError(VIR_ERR_XML_ERROR, "%s",
5042
                                           _("missing type for secret"));
5043 5044
                            goto error;
                        }
5045 5046 5047
                        auth_secret_usage =
                            virSecretUsageTypeTypeFromString(usageType);
                        if (auth_secret_usage < 0) {
5048 5049 5050
                            virReportError(VIR_ERR_XML_ERROR,
                                           _("invalid secret type %s"),
                                           usageType);
5051 5052 5053 5054 5055 5056 5057
                            goto error;
                        }

                        authUUID = virXMLPropString(child, "uuid");
                        authUsage = virXMLPropString(child, "usage");

                        if (authUUID != NULL && authUsage != NULL) {
5058
                            virReportError(VIR_ERR_XML_ERROR, "%s",
5059
                                           _("only one of uuid and usage can be specified"));
5060 5061
                            goto error;
                        }
5062 5063 5064 5065 5066 5067 5068 5069

                        if (!authUUID && !authUsage) {
                            virReportError(VIR_ERR_XML_ERROR, "%s",
                                           _("either uuid or usage should be "
                                             "specified for a secret"));
                            goto error;
                        }

5070 5071 5072 5073
                        if (authUUID != NULL) {
                            def->auth.secretType = VIR_DOMAIN_DISK_SECRET_TYPE_UUID;
                            if (virUUIDParse(authUUID,
                                             def->auth.secret.uuid) < 0) {
5074 5075 5076
                                virReportError(VIR_ERR_XML_ERROR,
                                               _("malformed uuid %s"),
                                               authUUID);
5077 5078 5079 5080 5081 5082 5083 5084 5085 5086
                                goto error;
                            }
                        } else if (authUsage != NULL) {
                            def->auth.secretType = VIR_DOMAIN_DISK_SECRET_TYPE_USAGE;
                            def->auth.secret.usage = authUsage;
                            authUsage = NULL;
                        }
                    }
                    child = child->next;
                }
L
Lei Li 已提交
5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120 5121 5122 5123 5124 5125 5126 5127
            } else if (xmlStrEqual(cur->name, BAD_CAST "iotune")) {
                if (virXPathULongLong("string(./iotune/total_bytes_sec)",
                                      ctxt,
                                      &def->blkdeviotune.total_bytes_sec) < 0) {
                    def->blkdeviotune.total_bytes_sec = 0;
                }

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

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

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

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

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

                if ((def->blkdeviotune.total_bytes_sec &&
                     def->blkdeviotune.read_bytes_sec) ||
                    (def->blkdeviotune.total_bytes_sec &&
                     def->blkdeviotune.write_bytes_sec)) {
5128
                    virReportError(VIR_ERR_XML_ERROR, "%s",
5129 5130
                                   _("total and read/write bytes_sec "
                                     "cannot be set at the same time"));
L
Lei Li 已提交
5131 5132 5133 5134 5135 5136 5137
                    goto error;
                }

                if ((def->blkdeviotune.total_iops_sec &&
                     def->blkdeviotune.read_iops_sec) ||
                    (def->blkdeviotune.total_iops_sec &&
                     def->blkdeviotune.write_iops_sec)) {
5138
                    virReportError(VIR_ERR_XML_ERROR, "%s",
5139 5140
                                   _("total and read/write iops_sec "
                                     "cannot be set at the same time"));
L
Lei Li 已提交
5141 5142
                    goto error;
                }
5143
            } else if (xmlStrEqual(cur->name, BAD_CAST "readonly")) {
5144
                def->readonly = true;
5145
            } else if (xmlStrEqual(cur->name, BAD_CAST "shareable")) {
5146
                def->shared = true;
5147
            } else if (xmlStrEqual(cur->name, BAD_CAST "transient")) {
5148
                def->transient = true;
5149 5150
            } else if ((flags & VIR_DOMAIN_XML_INTERNAL_STATUS) &&
                       xmlStrEqual(cur->name, BAD_CAST "state")) {
5151
                /* Legacy back-compat. Don't add any more attributes here */
5152
                devaddr = virXMLPropString(cur, "devaddr");
5153 5154
            } else if (encryption == NULL &&
                       xmlStrEqual(cur->name, BAD_CAST "encryption")) {
5155
                encryption = virStorageEncryptionParseNode(node->doc,
5156 5157 5158
                                                           cur);
                if (encryption == NULL)
                    goto error;
E
Eric Blake 已提交
5159 5160
            } else if (!serial &&
                       xmlStrEqual(cur->name, BAD_CAST "serial")) {
5161
                serial = (char *)xmlNodeGetContent(cur);
O
Osier Yang 已提交
5162 5163 5164 5165 5166 5167
            } else if (!wwn &&
                       xmlStrEqual(cur->name, BAD_CAST "wwn")) {
                wwn = (char *)xmlNodeGetContent(cur);

                if (!virValidateWWN(wwn))
                    goto error;
5168 5169 5170 5171 5172 5173 5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 5186
            } 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 已提交
5187
                if (strlen(product) > PRODUCT_LEN) {
5188 5189 5190 5191 5192 5193 5194 5195 5196 5197
                    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;
                }
5198
            } else if (xmlStrEqual(cur->name, BAD_CAST "boot")) {
5199
                /* boot is parsed as part of virDomainDeviceInfoParseXML */
5200 5201 5202 5203 5204
            }
        }
        cur = cur->next;
    }

5205 5206 5207 5208 5209 5210 5211
    if (auth_secret_usage != -1 && auth_secret_usage != expected_secret_usage) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("invalid secret type '%s'"),
                       virSecretUsageTypeTypeToString(auth_secret_usage));
        goto error;
    }

5212 5213 5214
    device = virXMLPropString(node, "device");
    if (device) {
        if ((def->device = virDomainDiskDeviceTypeFromString(device)) < 0) {
5215 5216
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown disk device '%s'"), device);
5217 5218 5219 5220 5221 5222 5223
            goto error;
        }
    } else {
        def->device = VIR_DOMAIN_DISK_DEVICE_DISK;
    }

    /* Only CDROM and Floppy devices are allowed missing source path
5224 5225
     * to indicate no media present. LUN is for raw access CD-ROMs
     * that are not attached to a physical device presently */
5226
    if (source == NULL && hosts == NULL && !def->srcpool &&
5227
        def->device != VIR_DOMAIN_DISK_DEVICE_CDROM &&
5228
        def->device != VIR_DOMAIN_DISK_DEVICE_LUN &&
5229
        def->device != VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
5230 5231
        virReportError(VIR_ERR_NO_SOURCE,
                       target ? "%s" : NULL, target);
5232 5233 5234
        goto error;
    }

5235 5236 5237 5238
    /* If source is present, check for an optional seclabel override.  */
    if (sourceNode) {
        xmlNodePtr saved_node = ctxt->node;
        ctxt->node = sourceNode;
5239 5240 5241
        if (virSecurityDeviceLabelDefParseXML(&def->seclabels,
                                              &def->nseclabels,
                                              vmSeclabels,
5242
                                              nvmSeclabels,
5243 5244
                                              ctxt,
                                              flags) < 0)
5245 5246 5247 5248
            goto error;
        ctxt->node = saved_node;
    }

5249
    if (target == NULL) {
5250 5251 5252
        if (def->srcpool) {
            char *tmp;
            if (virAsprintf(&tmp, "pool = '%s', volume = '%s'",
5253
                def->srcpool->pool, def->srcpool->volume) < 0)
5254 5255 5256 5257 5258 5259 5260
                goto error;

            virReportError(VIR_ERR_NO_TARGET, "%s", tmp);
            VIR_FREE(tmp);
        } else {
            virReportError(VIR_ERR_NO_TARGET, source ? "%s" : NULL, source);
        }
5261 5262 5263 5264 5265
        goto error;
    }

    if (def->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY &&
        !STRPREFIX(target, "fd")) {
5266 5267
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Invalid floppy device name: %s"), target);
5268 5269 5270 5271 5272
        goto error;
    }

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

5275 5276
    if ((def->device == VIR_DOMAIN_DISK_DEVICE_DISK ||
         def->device == VIR_DOMAIN_DISK_DEVICE_LUN) &&
5277 5278 5279
        !STRPREFIX((const char *)target, "hd") &&
        !STRPREFIX((const char *)target, "sd") &&
        !STRPREFIX((const char *)target, "vd") &&
5280 5281
        !STRPREFIX((const char *)target, "xvd") &&
        !STRPREFIX((const char *)target, "ubd")) {
5282 5283
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Invalid harddisk device name: %s"), target);
5284 5285 5286
        goto error;
    }

5287
    if (snapshot) {
E
Eric Blake 已提交
5288
        def->snapshot = virDomainSnapshotLocationTypeFromString(snapshot);
5289
        if (def->snapshot <= 0) {
5290 5291 5292
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown disk snapshot setting '%s'"),
                           snapshot);
5293 5294 5295
            goto error;
        }
    } else if (def->readonly) {
E
Eric Blake 已提交
5296
        def->snapshot = VIR_DOMAIN_SNAPSHOT_LOCATION_NONE;
5297 5298
    }

O
Osier Yang 已提交
5299 5300 5301 5302 5303 5304 5305 5306
    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;
    }

5307 5308
    if (rawio) {
        def->rawio_specified = true;
O
Osier Yang 已提交
5309 5310 5311 5312
        if (STREQ(rawio, "yes")) {
            def->rawio = 1;
        } else if (STREQ(rawio, "no")) {
            def->rawio = 0;
5313
        } else {
O
Osier Yang 已提交
5314 5315 5316 5317 5318 5319 5320 5321
            virReportError(VIR_ERR_XML_ERROR,
                           _("unknown disk rawio setting '%s'"),
                           rawio);
            goto error;
        }
    }

    if (sgio) {
5322
        if ((def->sgio = virDomainDeviceSGIOTypeFromString(sgio)) <= 0) {
O
Osier Yang 已提交
5323 5324
            virReportError(VIR_ERR_XML_ERROR,
                           _("unknown disk sgio mode '%s'"), sgio);
5325 5326 5327 5328
            goto error;
        }
    }

5329 5330
    if (bus) {
        if ((def->bus = virDomainDiskBusTypeFromString(bus)) < 0) {
5331 5332
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown disk bus type '%s'"), bus);
5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346
            goto error;
        }
    } else {
        if (def->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
            def->bus = VIR_DOMAIN_DISK_BUS_FDC;
        } else {
            if (STRPREFIX(target, "hd"))
                def->bus = VIR_DOMAIN_DISK_BUS_IDE;
            else if (STRPREFIX(target, "sd"))
                def->bus = VIR_DOMAIN_DISK_BUS_SCSI;
            else if (STRPREFIX(target, "vd"))
                def->bus = VIR_DOMAIN_DISK_BUS_VIRTIO;
            else if (STRPREFIX(target, "xvd"))
                def->bus = VIR_DOMAIN_DISK_BUS_XEN;
5347 5348
            else if (STRPREFIX(target, "ubd"))
                def->bus = VIR_DOMAIN_DISK_BUS_UML;
5349 5350 5351 5352 5353
            else
                def->bus = VIR_DOMAIN_DISK_BUS_IDE;
        }
    }

5354 5355
    if (tray) {
        if ((def->tray_status = virDomainDiskTrayTypeFromString(tray)) < 0) {
5356 5357
            virReportError(VIR_ERR_XML_ERROR,
                           _("unknown disk tray status '%s'"), tray);
5358 5359 5360 5361 5362
            goto error;
        }

        if (def->device != VIR_DOMAIN_DISK_DEVICE_FLOPPY &&
            def->device != VIR_DOMAIN_DISK_DEVICE_CDROM) {
5363 5364
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("tray is only valid for cdrom and floppy"));
5365 5366 5367 5368 5369 5370 5371 5372
            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;
    }

5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 5390
    if (removable) {
        if ((def->removable = virDomainFeatureStateTypeFromString(removable)) < 0) {
            virReportError(VIR_ERR_XML_ERROR,
                           _("unknown disk removable status '%s'"), removable);
            goto error;
        }

        if (def->bus != VIR_DOMAIN_DISK_BUS_USB) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("removable is only valid for usb disks"));
            goto error;
        }
    } else {
        if (def->bus == VIR_DOMAIN_DISK_BUS_USB) {
            def->removable = VIR_DOMAIN_FEATURE_STATE_DEFAULT;
        }
    }

5391 5392
    if (def->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY &&
        def->bus != VIR_DOMAIN_DISK_BUS_FDC) {
5393 5394
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Invalid bus type '%s' for floppy disk"), bus);
5395 5396 5397 5398
        goto error;
    }
    if (def->device != VIR_DOMAIN_DISK_DEVICE_FLOPPY &&
        def->bus == VIR_DOMAIN_DISK_BUS_FDC) {
5399 5400
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Invalid bus type '%s' for disk"), bus);
5401 5402 5403
        goto error;
    }

5404 5405
    if (cachetag &&
        (def->cachemode = virDomainDiskCacheTypeFromString(cachetag)) < 0) {
5406 5407
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown disk cache mode '%s'"), cachetag);
5408 5409 5410
        goto error;
    }

5411
    if (error_policy &&
5412
        (def->error_policy = virDomainDiskErrorPolicyTypeFromString(error_policy)) <= 0) {
5413 5414
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown disk error policy '%s'"), error_policy);
5415 5416 5417
        goto error;
    }

5418 5419 5420 5421
    if (rerror_policy &&
        (((def->rerror_policy
           = virDomainDiskErrorPolicyTypeFromString(rerror_policy)) <= 0) ||
         (def->rerror_policy == VIR_DOMAIN_DISK_ERROR_POLICY_ENOSPACE))) {
5422 5423 5424
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown disk read error policy '%s'"),
                       rerror_policy);
5425 5426 5427
        goto error;
    }

M
Matthias Dahl 已提交
5428 5429 5430
    if (iotag) {
        if ((def->iomode = virDomainDiskIoTypeFromString(iotag)) < 0 ||
            def->iomode == VIR_DOMAIN_DISK_IO_DEFAULT) {
5431 5432
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown disk io mode '%s'"), iotag);
M
Matthias Dahl 已提交
5433 5434 5435 5436
            goto error;
        }
    }

5437
    if (ioeventfd) {
5438 5439
        int val;

5440
        if (def->bus != VIR_DOMAIN_DISK_BUS_VIRTIO) {
5441
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
5442 5443
                           _("disk ioeventfd mode supported "
                             "only for virtio bus"));
5444 5445 5446
            goto error;
        }

5447
        if ((val = virDomainIoEventFdTypeFromString(ioeventfd)) <= 0) {
5448 5449 5450
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown disk ioeventfd mode '%s'"),
                           ioeventfd);
5451 5452
            goto error;
        }
5453
        def->ioeventfd = val;
5454 5455
    }

5456 5457
    if (event_idx) {
        if (def->bus != VIR_DOMAIN_DISK_BUS_VIRTIO) {
5458
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
5459 5460
                           _("disk event_idx mode supported "
                             "only for virtio bus"));
5461 5462 5463 5464 5465
            goto error;
        }

        int idx;
        if ((idx = virDomainVirtioEventIdxTypeFromString(event_idx)) <= 0) {
5466 5467 5468
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown disk event_idx mode '%s'"),
                           event_idx);
5469 5470 5471 5472 5473
            goto error;
        }
        def->event_idx = idx;
    }

O
Osier Yang 已提交
5474 5475 5476
    if (copy_on_read) {
        int cor;
        if ((cor = virDomainDiskCopyOnReadTypeFromString(copy_on_read)) <= 0) {
5477 5478 5479
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown disk copy_on_read mode '%s'"),
                           copy_on_read);
O
Osier Yang 已提交
5480 5481 5482 5483 5484
            goto error;
        }
        def->copy_on_read = cor;
    }

O
Osier Yang 已提交
5485 5486 5487 5488 5489 5490 5491 5492
    if (discard) {
        if ((def->discard = virDomainDiskDiscardTypeFromString(discard)) <= 0) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown disk discard mode '%s'"), discard);
            goto error;
        }
    }

5493
    if (devaddr) {
5494 5495
        if (virDomainParseLegacyDeviceAddress(devaddr,
                                              &def->info.addr.pci) < 0) {
5496 5497 5498
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unable to parse devaddr parameter '%s'"),
                           devaddr);
5499 5500 5501 5502
            goto error;
        }
        def->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
    } else {
5503
        if (virDomainDeviceInfoParseXML(node, bootHash, &def->info,
5504
                                        flags | VIR_DOMAIN_XML_INTERNAL_ALLOW_BOOT) < 0)
5505
            goto error;
5506 5507
    }

5508
    if (startupPolicy) {
5509
        int val;
5510

5511
        if ((val = virDomainStartupPolicyTypeFromString(startupPolicy)) <= 0) {
5512 5513 5514
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown startupPolicy value '%s'"),
                           startupPolicy);
5515 5516 5517
            goto error;
        }

5518 5519 5520 5521
        if (def->type == VIR_DOMAIN_DISK_TYPE_NETWORK) {
            virReportError(VIR_ERR_XML_ERROR,
                           _("Setting disk %s is not allowed for "
                             "disk of network type"),
5522
                           startupPolicy);
5523 5524
            goto error;
        }
5525 5526 5527 5528 5529 5530 5531 5532 5533

        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;
        }
5534
        def->startupPolicy = val;
5535 5536
    }

5537 5538 5539 5540
    def->src = source;
    source = NULL;
    def->dst = target;
    target = NULL;
M
MORITA Kazutaka 已提交
5541 5542 5543 5544
    def->hosts = hosts;
    hosts = NULL;
    def->nhosts = nhosts;
    nhosts = 0;
5545 5546
    def->auth.username = authUsername;
    authUsername = NULL;
5547 5548
    def->driverName = driverName;
    driverName = NULL;
5549 5550 5551
    def->mirror = mirror;
    mirror = NULL;
    def->mirroring = mirroring;
5552 5553
    def->encryption = encryption;
    encryption = NULL;
5554 5555
    def->serial = serial;
    serial = NULL;
O
Osier Yang 已提交
5556 5557
    def->wwn = wwn;
    wwn = NULL;
5558 5559 5560 5561
    def->vendor = vendor;
    vendor = NULL;
    def->product = product;
    product = NULL;
5562

5563 5564 5565 5566 5567 5568 5569 5570 5571
    if (driverType) {
        def->format = virStorageFileFormatTypeFromString(driverType);
        if (def->format <= 0) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown driver format value '%s'"),
                           driverType);
            goto error;
        }
    }
5572

5573 5574 5575 5576 5577 5578 5579 5580 5581
    if (mirrorFormat) {
        def->mirrorFormat = virStorageFileFormatTypeFromString(mirrorFormat);
        if (def->mirrorFormat <= 0) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown mirror format value '%s'"),
                           driverType);
            goto error;
        }
    }
5582

5583
    if (def->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE
5584
        && virDomainDiskDefAssignAddress(xmlopt, def) < 0)
5585
        goto error;
5586

5587 5588 5589
cleanup:
    VIR_FREE(bus);
    VIR_FREE(type);
5590
    VIR_FREE(snapshot);
5591
    VIR_FREE(rawio);
O
Osier Yang 已提交
5592
    VIR_FREE(sgio);
5593 5594
    VIR_FREE(target);
    VIR_FREE(source);
5595
    VIR_FREE(tray);
5596
    VIR_FREE(removable);
J
J.B. Joret 已提交
5597
    VIR_FREE(trans);
M
MORITA Kazutaka 已提交
5598
    while (nhosts > 0) {
5599
        virDomainDiskHostDefFree(&hosts[nhosts - 1]);
M
MORITA Kazutaka 已提交
5600 5601 5602 5603
        nhosts--;
    }
    VIR_FREE(hosts);
    VIR_FREE(protocol);
5604
    VIR_FREE(protocol_transport);
5605
    VIR_FREE(device);
5606 5607 5608 5609
    VIR_FREE(authUsername);
    VIR_FREE(usageType);
    VIR_FREE(authUUID);
    VIR_FREE(authUsage);
5610 5611
    VIR_FREE(driverType);
    VIR_FREE(driverName);
5612 5613
    VIR_FREE(mirror);
    VIR_FREE(mirrorFormat);
5614
    VIR_FREE(cachetag);
5615
    VIR_FREE(error_policy);
5616
    VIR_FREE(rerror_policy);
M
Matthias Dahl 已提交
5617
    VIR_FREE(iotag);
5618
    VIR_FREE(ioeventfd);
5619
    VIR_FREE(event_idx);
O
Osier Yang 已提交
5620
    VIR_FREE(copy_on_read);
O
Osier Yang 已提交
5621
    VIR_FREE(discard);
5622
    VIR_FREE(devaddr);
5623
    VIR_FREE(serial);
5624
    virStorageEncryptionFree(encryption);
5625
    VIR_FREE(startupPolicy);
5626 5627
    VIR_FREE(logical_block_size);
    VIR_FREE(physical_block_size);
O
Osier Yang 已提交
5628
    VIR_FREE(wwn);
5629 5630
    VIR_FREE(vendor);
    VIR_FREE(product);
5631

L
Lei Li 已提交
5632
    ctxt->node = save_ctxt;
5633 5634
    return def;

5635
error:
5636 5637 5638 5639 5640 5641
    virDomainDiskDefFree(def);
    def = NULL;
    goto cleanup;
}


5642 5643 5644 5645 5646 5647 5648 5649 5650 5651 5652 5653 5654 5655 5656 5657 5658 5659 5660 5661 5662 5663 5664 5665 5666 5667 5668 5669 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694
/* Parse a value located at XPATH within CTXT, and store the
 * result into val.  If REQUIRED, then the value must exist;
 * otherwise, the value is optional.  The value is in bytes.
 * Return 1 on success, 0 if the value was not present and
 * is not REQUIRED, -1 on failure after issuing error. */
static int
virDomainParseScaledValue(const char *xpath,
                          xmlXPathContextPtr ctxt,
                          unsigned long long *val,
                          unsigned long long scale,
                          unsigned long long max,
                          bool required)
{
    char *xpath_full = NULL;
    char *unit = NULL;
    int ret = -1;
    unsigned long long bytes;

    *val = 0;
    if (virAsprintf(&xpath_full, "string(%s)", xpath) < 0)
        goto cleanup;
    ret = virXPathULongLong(xpath_full, ctxt, &bytes);
    if (ret < 0) {
        if (ret == -2)
            virReportError(VIR_ERR_XML_ERROR,
                           _("could not parse element %s"),
                           xpath);
        else if (required)
            virReportError(VIR_ERR_XML_ERROR,
                           _("missing element %s"),
                           xpath);
        else
            ret = 0;
        goto cleanup;
    }
    VIR_FREE(xpath_full);

    if (virAsprintf(&xpath_full, "string(%s/@unit)", xpath) < 0)
        goto cleanup;
    unit = virXPathString(xpath_full, ctxt);

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

    *val = bytes;
    ret = 1;
cleanup:
    VIR_FREE(xpath_full);
    VIR_FREE(unit);
    return ret;
}


5695 5696 5697 5698 5699 5700
static int
virDomainControllerModelTypeFromString(const virDomainControllerDefPtr def,
                                       const char *model)
{
    if (def->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI)
        return virDomainControllerModelSCSITypeFromString(model);
5701 5702
    else if (def->type == VIR_DOMAIN_CONTROLLER_TYPE_USB)
        return virDomainControllerModelUSBTypeFromString(model);
J
Ján Tomko 已提交
5703 5704
    else if (def->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI)
        return virDomainControllerModelPCITypeFromString(model);
5705 5706 5707 5708

    return -1;
}

5709 5710 5711 5712
/* Parse the XML definition for a controller
 * @param node XML nodeset to parse for controller definition
 */
static virDomainControllerDefPtr
5713
virDomainControllerDefParseXML(xmlNodePtr node,
5714
                               xmlXPathContextPtr ctxt,
E
Eric Blake 已提交
5715
                               unsigned int flags)
5716 5717
{
    virDomainControllerDefPtr def;
5718
    xmlNodePtr cur = NULL;
5719 5720
    char *type = NULL;
    char *idx = NULL;
5721
    char *model = NULL;
5722
    char *queues = NULL;
5723
    xmlNodePtr saved = ctxt->node;
5724
    int rc;
5725 5726

    ctxt->node = node;
5727

5728
    if (VIR_ALLOC(def) < 0)
5729 5730 5731 5732
        return NULL;

    type = virXMLPropString(node, "type");
    if (type) {
5733
        if ((def->type = virDomainControllerTypeFromString(type)) < 0) {
5734 5735
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unknown controller type '%s'"), type);
5736 5737 5738 5739 5740 5741
            goto error;
        }
    }

    idx = virXMLPropString(node, "index");
    if (idx) {
5742 5743
        if (virStrToLong_ui(idx, NULL, 10, &def->idx) < 0 ||
            def->idx > INT_MAX) {
5744 5745
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Cannot parse controller index %s"), idx);
5746 5747 5748 5749
            goto error;
        }
    }

5750 5751
    model = virXMLPropString(node, "model");
    if (model) {
5752
        if ((def->model = virDomainControllerModelTypeFromString(def, model)) < 0) {
5753 5754
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unknown model type '%s'"), model);
5755 5756 5757 5758 5759 5760
            goto error;
        }
    } else {
        def->model = -1;
    }

5761 5762 5763 5764 5765
    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
            if (xmlStrEqual(cur->name, BAD_CAST "driver"))
                queues = virXMLPropString(cur, "queues");
5766
        }
5767 5768 5769 5770 5771 5772 5773
        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;
5774 5775
    }

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

5779 5780 5781 5782 5783 5784 5785
    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) {
5786 5787
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Invalid ports: %s"), ports);
5788 5789 5790 5791 5792 5793 5794 5795 5796 5797 5798 5799 5800
                VIR_FREE(ports);
                goto error;
            }
        } else {
            def->opts.vioserial.ports = -1;
        }
        VIR_FREE(ports);

        char *vectors = virXMLPropString(node, "vectors");
        if (vectors) {
            int r = virStrToLong_i(vectors, NULL, 10,
                                   &def->opts.vioserial.vectors);
            if (r != 0 || def->opts.vioserial.vectors < 0) {
5801 5802
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Invalid vectors: %s"), vectors);
5803 5804 5805 5806 5807 5808 5809 5810 5811
                VIR_FREE(vectors);
                goto error;
            }
        } else {
            def->opts.vioserial.vectors = -1;
        }
        VIR_FREE(vectors);
        break;
    }
5812 5813 5814 5815 5816 5817 5818 5819 5820 5821 5822 5823 5824 5825 5826 5827 5828 5829 5830 5831 5832 5833
    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 已提交
5834 5835 5836
    case VIR_DOMAIN_CONTROLLER_TYPE_PCI:
        switch (def->model) {
        case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT:
5837 5838
        case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT: {
            unsigned long long bytes;
J
Ján Tomko 已提交
5839 5840
            if (def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
                virReportError(VIR_ERR_XML_ERROR, "%s",
L
Laine Stump 已提交
5841
                               _("pci-root and pcie-root controllers should not "
J
Ján Tomko 已提交
5842 5843 5844
                                 "have an address"));
                goto error;
            }
5845 5846
            if (def->idx != 0) {
                virReportError(VIR_ERR_XML_ERROR, "%s",
L
Laine Stump 已提交
5847 5848
                               _("pci-root and pcie-root controllers "
                                 "should have index 0"));
5849 5850
                goto error;
            }
5851 5852 5853 5854
            if ((rc = virDomainParseScaledValue("./pcihole64", ctxt,
                                                &bytes, 1024,
                                                1024ULL * ULONG_MAX, false)) < 0)
                goto error;
5855

5856 5857 5858 5859
            if (rc == 1)
                def->opts.pciopts.pcihole64 = true;
            def->opts.pciopts.pcihole64size = VIR_DIV_UP(bytes, 1024);
        }
J
Ján Tomko 已提交
5860
        }
5861 5862 5863 5864 5865

    default:
        break;
    }

5866
    if (def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
5867
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO &&
5868
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW &&
5869
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390 &&
5870
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO &&
5871
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
5872 5873
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Controllers must use the 'pci' address type"));
5874 5875 5876 5877
        goto error;
    }

cleanup:
5878
    ctxt->node = saved;
5879 5880
    VIR_FREE(type);
    VIR_FREE(idx);
5881
    VIR_FREE(model);
5882
    VIR_FREE(queues);
5883 5884 5885 5886 5887 5888 5889 5890 5891

    return def;

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

5892

5893 5894 5895 5896 5897 5898 5899 5900
void
virDomainNetGenerateMAC(virDomainXMLOptionPtr xmlopt,
                        virMacAddrPtr mac)
{
    virMacAddrGenerate(xmlopt->config.macPrefix, mac);
}


5901 5902 5903 5904
/* Parse the XML definition for a disk
 * @param node XML nodeset to parse for disk definition
 */
static virDomainFSDefPtr
5905
virDomainFSDefParseXML(xmlNodePtr node,
5906
                       xmlXPathContextPtr ctxt,
E
Eric Blake 已提交
5907
                       unsigned int flags) {
5908
    virDomainFSDefPtr def;
5909
    xmlNodePtr cur, save_node = ctxt->node;
5910
    char *type = NULL;
5911
    char *fsdriver = NULL;
5912 5913
    char *source = NULL;
    char *target = NULL;
5914
    char *format = NULL;
5915
    char *accessmode = NULL;
5916
    char *wrpolicy = NULL;
5917 5918
    char *usage = NULL;
    char *unit = NULL;
5919

5920 5921
    ctxt->node = node;

5922
    if (VIR_ALLOC(def) < 0)
5923 5924 5925 5926 5927
        return NULL;

    type = virXMLPropString(node, "type");
    if (type) {
        if ((def->type = virDomainFSTypeFromString(type)) < 0) {
5928 5929
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown filesystem type '%s'"), type);
5930 5931 5932 5933 5934 5935
            goto error;
        }
    } else {
        def->type = VIR_DOMAIN_FS_TYPE_MOUNT;
    }

5936 5937 5938
    accessmode = virXMLPropString(node, "accessmode");
    if (accessmode) {
        if ((def->accessmode = virDomainFSAccessModeTypeFromString(accessmode)) < 0) {
5939 5940
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown accessmode '%s'"), accessmode);
5941 5942 5943 5944 5945 5946
            goto error;
        }
    } else {
        def->accessmode = VIR_DOMAIN_FS_ACCESSMODE_PASSTHROUGH;
    }

5947 5948
    if (virDomainParseScaledValue("./space_hard_limit[1]", ctxt,
                                  &def->space_hard_limit, 1,
5949
                                  ULLONG_MAX, false) < 0)
5950 5951 5952 5953
        goto error;

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

5957 5958 5959
    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
E
Eric Blake 已提交
5960 5961
            if (!source &&
                xmlStrEqual(cur->name, BAD_CAST "source")) {
5962

5963 5964
                if (def->type == VIR_DOMAIN_FS_TYPE_MOUNT ||
                    def->type == VIR_DOMAIN_FS_TYPE_BIND)
5965 5966 5967 5968 5969 5970 5971
                    source = virXMLPropString(cur, "dir");
                else if (def->type == VIR_DOMAIN_FS_TYPE_FILE)
                    source = virXMLPropString(cur, "file");
                else if (def->type == VIR_DOMAIN_FS_TYPE_BLOCK)
                    source = virXMLPropString(cur, "dev");
                else if (def->type == VIR_DOMAIN_FS_TYPE_TEMPLATE)
                    source = virXMLPropString(cur, "name");
5972 5973 5974 5975
                else if (def->type == VIR_DOMAIN_FS_TYPE_RAM) {
                    usage = virXMLPropString(cur, "usage");
                    unit = virXMLPropString(cur, "unit");
                }
E
Eric Blake 已提交
5976 5977
            } else if (!target &&
                       xmlStrEqual(cur->name, BAD_CAST "target")) {
5978 5979
                target = virXMLPropString(cur, "dir");
            } else if (xmlStrEqual(cur->name, BAD_CAST "readonly")) {
5980
                def->readonly = true;
5981 5982 5983 5984 5985 5986 5987
            } 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");
5988 5989 5990 5991 5992
            }
        }
        cur = cur->next;
    }

5993 5994
    if (fsdriver) {
        if ((def->fsdriver = virDomainFSDriverTypeTypeFromString(fsdriver)) <= 0) {
5995
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
5996
                           _("unknown fs driver type '%s'"), fsdriver);
5997 5998 5999 6000
            goto error;
        }
    }

6001 6002 6003 6004 6005 6006 6007 6008
    if (format) {
        if ((def->format = virStorageFileFormatTypeFromString(format)) <= 0) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown driver format value '%s'"), format);
            goto error;
        }
    }

6009 6010
    if (wrpolicy) {
        if ((def->wrpolicy = virDomainFSWrpolicyTypeFromString(wrpolicy)) <= 0) {
6011 6012
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown filesystem write policy '%s'"), wrpolicy);
6013 6014 6015 6016 6017 6018
            goto error;
        }
    } else {
        def->wrpolicy = VIR_DOMAIN_FS_WRPOLICY_DEFAULT;
    }

6019 6020
    if (source == NULL &&
        def->type != VIR_DOMAIN_FS_TYPE_RAM) {
6021 6022
        virReportError(VIR_ERR_NO_SOURCE,
                       target ? "%s" : NULL, target);
6023 6024 6025 6026
        goto error;
    }

    if (target == NULL) {
6027 6028
        virReportError(VIR_ERR_NO_TARGET,
                       source ? "%s" : NULL, source);
6029 6030 6031
        goto error;
    }

6032 6033
    if (def->type == VIR_DOMAIN_FS_TYPE_RAM) {
        if (!usage) {
6034 6035
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("missing 'usage' attribute for RAM filesystem"));
6036 6037 6038
            goto error;
        }
        if (virStrToLong_ull(usage, NULL, 10, &def->usage) < 0) {
6039 6040 6041
            virReportError(VIR_ERR_XML_ERROR,
                           _("cannot parse usage '%s' for RAM filesystem"),
                           usage);
6042 6043 6044 6045
            goto error;
        }
        if (unit &&
            virScaleInteger(&def->usage, unit,
6046
                            1024, ULLONG_MAX) < 0)
6047 6048 6049
            goto error;
    }

6050 6051 6052 6053 6054
    def->src = source;
    source = NULL;
    def->dst = target;
    target = NULL;

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

6058
cleanup:
6059
    ctxt->node = save_node;
6060
    VIR_FREE(type);
6061
    VIR_FREE(fsdriver);
6062 6063
    VIR_FREE(target);
    VIR_FREE(source);
6064
    VIR_FREE(accessmode);
6065
    VIR_FREE(wrpolicy);
6066 6067
    VIR_FREE(usage);
    VIR_FREE(unit);
6068
    VIR_FREE(format);
6069 6070 6071 6072 6073 6074 6075 6076 6077

    return def;

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

6078 6079 6080
static int
virDomainActualNetDefParseXML(xmlNodePtr node,
                              xmlXPathContextPtr ctxt,
6081 6082 6083
                              virDomainNetDefPtr parent,
                              virDomainActualNetDefPtr *def,
                              unsigned int flags)
6084 6085 6086 6087
{
    virDomainActualNetDefPtr actual = NULL;
    int ret = -1;
    xmlNodePtr save_ctxt = ctxt->node;
6088
    xmlNodePtr bandwidth_node = NULL;
6089
    xmlNodePtr vlanNode;
6090
    xmlNodePtr virtPortNode;
6091 6092
    char *type = NULL;
    char *mode = NULL;
6093
    char *addrtype = NULL;
6094

6095
    if (VIR_ALLOC(actual) < 0)
6096 6097 6098 6099 6100 6101
        return -1;

    ctxt->node = node;

    type = virXMLPropString(node, "type");
    if (!type) {
6102 6103
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("missing type attribute in interface's <actual> element"));
6104 6105 6106
        goto error;
    }
    if ((actual->type = virDomainNetTypeFromString(type)) < 0) {
6107 6108
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown type '%s' in interface's <actual> element"), type);
6109 6110 6111
        goto error;
    }
    if (actual->type != VIR_DOMAIN_NET_TYPE_BRIDGE &&
6112
        actual->type != VIR_DOMAIN_NET_TYPE_DIRECT &&
6113
        actual->type != VIR_DOMAIN_NET_TYPE_HOSTDEV &&
6114
        actual->type != VIR_DOMAIN_NET_TYPE_NETWORK) {
6115 6116 6117
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unsupported type '%s' in interface's <actual> element"),
                       type);
6118 6119 6120
        goto error;
    }

6121 6122 6123 6124 6125
    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) {
6126 6127 6128
            /* the virtualport in <actual> should always already
             * have an instanceid/interfaceid if its required,
             * so don't let the parser generate one */
6129
            if (!(actual->virtPortProfile
6130 6131 6132
                  = virNetDevVPortProfileParse(virtPortNode,
                                               VIR_VPORT_XML_REQUIRE_ALL_ATTRIBUTES |
                                               VIR_VPORT_XML_REQUIRE_TYPE))) {
6133 6134 6135 6136 6137 6138
                goto error;
            }
        } else {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("<virtualport> element unsupported for type='%s'"
                             " in interface's <actual> element"), type);
A
Ansis Atteka 已提交
6139
            goto error;
6140 6141
        }
    }
6142

6143
    if (actual->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
6144 6145 6146 6147 6148
        actual->data.direct.linkdev = virXPathString("string(./source[1]/@dev)", ctxt);

        mode = virXPathString("string(./source[1]/@mode)", ctxt);
        if (mode) {
            int m;
6149
            if ((m = virNetDevMacVLanModeTypeFromString(mode)) < 0) {
6150
                virReportError(VIR_ERR_INTERNAL_ERROR,
J
Ján Tomko 已提交
6151
                               _("Unknown mode '%s' in interface <actual> element"),
6152
                               mode);
6153 6154 6155 6156
                goto error;
            }
            actual->data.direct.mode = m;
        }
6157 6158 6159 6160 6161 6162 6163 6164 6165 6166 6167 6168
    } 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 已提交
6169
        if (!addrtype && virXPathNode("./source/vendor", ctxt) &&
6170
            VIR_STRDUP(addrtype, "usb") < 0)
6171
            goto error;
6172 6173 6174
        hostdev->mode = VIR_DOMAIN_HOSTDEV_MODE_SUBSYS;
        if (virDomainHostdevDefParseXMLSubsys(node, ctxt, addrtype,
                                              hostdev, flags) < 0) {
6175 6176
            goto error;
        }
6177 6178 6179 6180 6181 6182 6183 6184 6185 6186 6187
    } 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);
6188 6189
    }

6190 6191
    bandwidth_node = virXPathNode("./bandwidth", ctxt);
    if (bandwidth_node &&
6192 6193
        !(actual->bandwidth = virNetDevBandwidthParse(bandwidth_node,
                                                      actual->type)))
6194 6195
        goto error;

6196 6197 6198 6199
    vlanNode = virXPathNode("./vlan", ctxt);
    if (vlanNode && virNetDevVlanParse(vlanNode, ctxt, &actual->vlan) < 0)
       goto error;

6200 6201 6202 6203 6204 6205
    *def = actual;
    actual = NULL;
    ret = 0;
error:
    VIR_FREE(type);
    VIR_FREE(mode);
6206
    VIR_FREE(addrtype);
6207 6208 6209 6210 6211
    virDomainActualNetDefFree(actual);

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

E
Eric Blake 已提交
6213 6214 6215
#define NET_MODEL_CHARS \
    "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ091234567890_-"

6216 6217 6218 6219
/* Parse the XML definition for a network interface
 * @param node XML nodeset to parse for net definition
 * @return 0 on success, -1 on failure
 */
6220
static virDomainNetDefPtr
6221
virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt,
6222
                        xmlNodePtr node,
6223
                        xmlXPathContextPtr ctxt,
6224
                        virHashTablePtr bootHash,
E
Eric Blake 已提交
6225
                        unsigned int flags)
6226
{
6227
    virDomainNetDefPtr def;
6228
    virDomainHostdevDefPtr hostdev;
6229 6230 6231 6232
    xmlNodePtr cur;
    char *macaddr = NULL;
    char *type = NULL;
    char *network = NULL;
6233
    char *portgroup = NULL;
6234 6235 6236 6237 6238 6239 6240
    char *bridge = NULL;
    char *dev = NULL;
    char *ifname = NULL;
    char *script = NULL;
    char *address = NULL;
    char *port = NULL;
    char *model = NULL;
6241
    char *backend = NULL;
6242
    char *txmode = NULL;
6243
    char *ioeventfd = NULL;
6244
    char *event_idx = NULL;
6245
    char *queues = NULL;
6246
    char *filter = NULL;
D
Daniel Veillard 已提交
6247
    char *internal = NULL;
6248
    char *devaddr = NULL;
6249
    char *mode = NULL;
6250
    char *linkstate = NULL;
6251
    char *addrtype = NULL;
6252
    virNWFilterHashTablePtr filterparams = NULL;
6253
    virDomainActualNetDefPtr actual = NULL;
6254 6255
    xmlNodePtr oldnode = ctxt->node;
    int ret;
6256

6257
    if (VIR_ALLOC(def) < 0)
6258 6259
        return NULL;

6260 6261
    ctxt->node = node;

6262 6263
    type = virXMLPropString(node, "type");
    if (type != NULL) {
S
Stefan Berger 已提交
6264
        if ((int)(def->type = virDomainNetTypeFromString(type)) < 0) {
6265 6266
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown interface type '%s'"), type);
6267 6268 6269 6270 6271 6272 6273 6274 6275
            goto error;
        }
    } else {
        def->type = VIR_DOMAIN_NET_TYPE_USER;
    }

    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
E
Eric Blake 已提交
6276
            if (!macaddr && xmlStrEqual(cur->name, BAD_CAST "mac")) {
6277
                macaddr = virXMLPropString(cur, "address");
E
Eric Blake 已提交
6278 6279 6280
            } else if (!network &&
                       def->type == VIR_DOMAIN_NET_TYPE_NETWORK &&
                       xmlStrEqual(cur->name, BAD_CAST "source")) {
6281
                network = virXMLPropString(cur, "network");
6282
                portgroup = virXMLPropString(cur, "portgroup");
E
Eric Blake 已提交
6283 6284 6285
            } else if (!internal &&
                       def->type == VIR_DOMAIN_NET_TYPE_INTERNAL &&
                       xmlStrEqual(cur->name, BAD_CAST "source")) {
D
Daniel Veillard 已提交
6286
                internal = virXMLPropString(cur, "name");
G
Guannan Ren 已提交
6287
            } else if (!bridge &&
E
Eric Blake 已提交
6288 6289
                       def->type == VIR_DOMAIN_NET_TYPE_BRIDGE &&
                       xmlStrEqual(cur->name, BAD_CAST "source")) {
6290
                bridge = virXMLPropString(cur, "bridge");
E
Eric Blake 已提交
6291
            } else if (!dev &&
6292 6293
                       (def->type == VIR_DOMAIN_NET_TYPE_ETHERNET ||
                        def->type == VIR_DOMAIN_NET_TYPE_DIRECT) &&
6294
                       xmlStrEqual(cur->name, BAD_CAST "source")) {
6295 6296
                dev  = virXMLPropString(cur, "dev");
                mode = virXMLPropString(cur, "mode");
6297 6298
            } else if (!def->virtPortProfile
                       && xmlStrEqual(cur->name, BAD_CAST "virtualport")) {
6299
                if (def->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
6300
                    if (!(def->virtPortProfile
6301 6302 6303 6304 6305 6306 6307 6308 6309 6310 6311 6312
                          = 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))) {
6313 6314 6315 6316 6317 6318
                        goto error;
                    }
                } else {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("<virtualport> element unsupported for"
                                     " <interface type='%s'>"), type);
6319
                    goto error;
6320
                }
G
Guannan Ren 已提交
6321
            } else if (!address &&
E
Eric Blake 已提交
6322 6323 6324 6325
                       (def->type == VIR_DOMAIN_NET_TYPE_SERVER ||
                        def->type == VIR_DOMAIN_NET_TYPE_CLIENT ||
                        def->type == VIR_DOMAIN_NET_TYPE_MCAST) &&
                       xmlStrEqual(cur->name, BAD_CAST "source")) {
6326 6327
                address = virXMLPropString(cur, "address");
                port = virXMLPropString(cur, "port");
E
Eric Blake 已提交
6328
            } else if (!address &&
6329 6330
                       (def->type == VIR_DOMAIN_NET_TYPE_ETHERNET ||
                        def->type == VIR_DOMAIN_NET_TYPE_BRIDGE) &&
E
Eric Blake 已提交
6331
                       xmlStrEqual(cur->name, BAD_CAST "ip")) {
6332
                address = virXMLPropString(cur, "address");
E
Eric Blake 已提交
6333
            } else if (!ifname &&
6334 6335
                       xmlStrEqual(cur->name, BAD_CAST "target")) {
                ifname = virXMLPropString(cur, "dev");
E
Eric Blake 已提交
6336 6337 6338
                if (ifname &&
                    (flags & VIR_DOMAIN_XML_INACTIVE) &&
                    STRPREFIX(ifname, VIR_NET_GENERATED_PREFIX)) {
6339 6340 6341
                    /* An auto-generated target name, blank it out */
                    VIR_FREE(ifname);
                }
E
Eric Blake 已提交
6342
            } else if (!linkstate &&
6343 6344
                       xmlStrEqual(cur->name, BAD_CAST "link")) {
                linkstate = virXMLPropString(cur, "state");
E
Eric Blake 已提交
6345
            } else if (!script &&
6346 6347
                       xmlStrEqual(cur->name, BAD_CAST "script")) {
                script = virXMLPropString(cur, "path");
6348
            } else if (xmlStrEqual(cur->name, BAD_CAST "model")) {
6349
                model = virXMLPropString(cur, "type");
6350
            } else if (xmlStrEqual(cur->name, BAD_CAST "driver")) {
6351
                backend = virXMLPropString(cur, "name");
6352
                txmode = virXMLPropString(cur, "txmode");
6353
                ioeventfd = virXMLPropString(cur, "ioeventfd");
6354
                event_idx = virXMLPropString(cur, "event_idx");
6355
                queues = virXMLPropString(cur, "queues");
6356
            } else if (xmlStrEqual(cur->name, BAD_CAST "filterref")) {
6357 6358 6359 6360 6361 6362
                if (filter) {
                    virReportError(VIR_ERR_XML_ERROR, "%s",
                                   _("Invalid specification of multiple <filterref>s "
                                     "in a single <interface>"));
                    goto error;
                }
6363
                filter = virXMLPropString(cur, "filter");
6364
                virNWFilterHashTableFree(filterparams);
6365
                filterparams = virNWFilterParseParamAttributes(cur);
6366 6367
            } else if ((flags & VIR_DOMAIN_XML_INTERNAL_STATUS) &&
                       xmlStrEqual(cur->name, BAD_CAST "state")) {
6368
                /* Legacy back-compat. Don't add any more attributes here */
6369
                devaddr = virXMLPropString(cur, "devaddr");
6370
            } else if (xmlStrEqual(cur->name, BAD_CAST "boot")) {
6371
                /* boot is parsed as part of virDomainDeviceInfoParseXML */
E
Eric Blake 已提交
6372
            } else if (!actual &&
6373
                       (flags & VIR_DOMAIN_XML_INTERNAL_ACTUAL_NET) &&
E
Eric Blake 已提交
6374
                       def->type == VIR_DOMAIN_NET_TYPE_NETWORK &&
6375
                       xmlStrEqual(cur->name, BAD_CAST "actual")) {
6376 6377
                if (virDomainActualNetDefParseXML(cur, ctxt, def,
                                                  &actual, flags) < 0) {
6378
                    goto error;
6379
                }
6380
            } else if (xmlStrEqual(cur->name, BAD_CAST "bandwidth")) {
6381 6382
                if (!(def->bandwidth = virNetDevBandwidthParse(cur,
                                                               def->type)))
6383
                    goto error;
6384 6385 6386
            } else if (xmlStrEqual(cur->name, BAD_CAST "vlan")) {
                if (virNetDevVlanParse(cur, ctxt, &def->vlan) < 0)
                    goto error;
6387 6388 6389 6390 6391 6392
            }
        }
        cur = cur->next;
    }

    if (macaddr) {
6393
        if (virMacAddrParse((const char *)macaddr, &def->mac) < 0) {
6394 6395 6396
            virReportError(VIR_ERR_XML_ERROR,
                           _("unable to parse mac address '%s'"),
                           (const char *)macaddr);
6397 6398
            goto error;
        }
6399
        if (virMacAddrIsMulticast(&def->mac)) {
6400 6401 6402
            virReportError(VIR_ERR_XML_ERROR,
                           _("expected unicast mac address, found multicast '%s'"),
                           (const char *)macaddr);
6403 6404
            goto error;
        }
6405
    } else {
6406
        virDomainNetGenerateMAC(xmlopt, &def->mac);
6407 6408
    }

6409
    if (devaddr) {
6410 6411
        if (virDomainParseLegacyDeviceAddress(devaddr,
                                              &def->info.addr.pci) < 0) {
6412 6413 6414
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unable to parse devaddr parameter '%s'"),
                           devaddr);
6415 6416 6417 6418
            goto error;
        }
        def->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
    } else {
6419
        if (virDomainDeviceInfoParseXML(node, bootHash, &def->info,
6420 6421
                                        flags | VIR_DOMAIN_XML_INTERNAL_ALLOW_BOOT
                                        | VIR_DOMAIN_XML_INTERNAL_ALLOW_ROM) < 0)
6422 6423 6424 6425 6426 6427
            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 &&
6428
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO &&
6429
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW &&
6430
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390 &&
6431
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO &&
6432
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
6433 6434
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Network interfaces must use 'pci' address type"));
6435 6436 6437
        goto error;
    }

6438 6439 6440
    switch (def->type) {
    case VIR_DOMAIN_NET_TYPE_NETWORK:
        if (network == NULL) {
6441 6442 6443
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("No <source> 'network' attribute "
                             "specified with <interface type='network'/>"));
6444 6445 6446 6447
            goto error;
        }
        def->data.network.name = network;
        network = NULL;
6448 6449 6450 6451
        def->data.network.portgroup = portgroup;
        portgroup = NULL;
        def->data.network.actual = actual;
        actual = NULL;
6452 6453 6454 6455 6456 6457 6458 6459 6460 6461 6462 6463 6464 6465 6466
        break;

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

    case VIR_DOMAIN_NET_TYPE_BRIDGE:
        if (bridge == NULL) {
6467 6468 6469
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("No <source> 'bridge' attribute "
                             "specified with <interface type='bridge'/>"));
6470 6471 6472 6473
            goto error;
        }
        def->data.bridge.brname = bridge;
        bridge = NULL;
6474 6475 6476 6477
        if (address != NULL) {
            def->data.bridge.ipaddr = address;
            address = NULL;
        }
6478 6479 6480 6481 6482 6483
        break;

    case VIR_DOMAIN_NET_TYPE_CLIENT:
    case VIR_DOMAIN_NET_TYPE_SERVER:
    case VIR_DOMAIN_NET_TYPE_MCAST:
        if (port == NULL) {
6484 6485 6486
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("No <source> 'port' attribute "
                             "specified with socket interface"));
6487 6488 6489
            goto error;
        }
        if (virStrToLong_i(port, NULL, 10, &def->data.socket.port) < 0) {
6490 6491 6492
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Cannot parse <source> 'port' attribute "
                             "with socket interface"));
6493 6494 6495 6496 6497 6498
            goto error;
        }

        if (address == NULL) {
            if (def->type == VIR_DOMAIN_NET_TYPE_CLIENT ||
                def->type == VIR_DOMAIN_NET_TYPE_MCAST) {
6499 6500 6501
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("No <source> 'address' attribute "
                                 "specified with socket interface"));
6502 6503 6504 6505 6506 6507
                goto error;
            }
        } else {
            def->data.socket.address = address;
            address = NULL;
        }
6508 6509
        break;

D
Daniel Veillard 已提交
6510 6511
    case VIR_DOMAIN_NET_TYPE_INTERNAL:
        if (internal == NULL) {
6512 6513 6514
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("No <source> 'name' attribute specified "
                             "with <interface type='internal'/>"));
D
Daniel Veillard 已提交
6515 6516 6517 6518 6519
            goto error;
        }
        def->data.internal.name = internal;
        internal = NULL;
        break;
6520 6521 6522

    case VIR_DOMAIN_NET_TYPE_DIRECT:
        if (dev == NULL) {
6523 6524 6525
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("No <source> 'dev' attribute specified "
                             "with <interface type='direct'/>"));
6526 6527 6528 6529 6530
            goto error;
        }

        if (mode != NULL) {
            int m;
6531
            if ((m = virNetDevMacVLanModeTypeFromString(mode)) < 0) {
6532
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
J
Ján Tomko 已提交
6533
                               _("Unknown mode has been specified"));
6534 6535 6536
                goto error;
            }
            def->data.direct.mode = m;
E
Eric Blake 已提交
6537
        } else {
6538
            def->data.direct.mode = VIR_NETDEV_MACVLAN_MODE_VEPA;
E
Eric Blake 已提交
6539
        }
6540 6541 6542 6543

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

E
Eric Blake 已提交
6544
        if (flags & VIR_DOMAIN_XML_INACTIVE)
6545
            VIR_FREE(ifname);
6546

6547
        break;
S
Stefan Berger 已提交
6548

6549 6550 6551 6552 6553 6554 6555 6556 6557 6558 6559
    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 已提交
6560
        if (!addrtype && virXPathNode("./source/vendor", ctxt) &&
6561
            VIR_STRDUP(addrtype, "usb") < 0)
6562
            goto error;
6563 6564 6565
        hostdev->mode = VIR_DOMAIN_HOSTDEV_MODE_SUBSYS;
        if (virDomainHostdevDefParseXMLSubsys(node, ctxt, addrtype,
                                              hostdev, flags) < 0) {
6566 6567 6568 6569
            goto error;
        }
        break;

S
Stefan Berger 已提交
6570 6571 6572
    case VIR_DOMAIN_NET_TYPE_USER:
    case VIR_DOMAIN_NET_TYPE_LAST:
        break;
6573 6574
    }

6575 6576 6577 6578
    if (script != NULL) {
        def->script = script;
        script = NULL;
    }
6579 6580 6581 6582 6583 6584 6585 6586 6587
    if (ifname != NULL) {
        def->ifname = ifname;
        ifname = NULL;
    }

    /* NIC model (see -net nic,model=?).  We only check that it looks
     * reasonable, not that it is a supported NIC type.  FWIW kvm
     * supports these types as of April 2008:
     * i82551 i82557b i82559er ne2k_pci pcnet rtl8139 e1000 virtio
E
Eric Blake 已提交
6588
     * QEMU PPC64 supports spapr-vlan
6589 6590
     */
    if (model != NULL) {
E
Eric Blake 已提交
6591
        if (strspn(model, NET_MODEL_CHARS) < strlen(model)) {
6592 6593
            virReportError(VIR_ERR_INVALID_ARG, "%s",
                           _("Model name contains invalid characters"));
E
Eric Blake 已提交
6594
            goto error;
6595 6596 6597 6598 6599
        }
        def->model = model;
        model = NULL;
    }

6600 6601 6602
    if (def->model && STREQ(def->model, "virtio")) {
        if (backend != NULL) {
            int name;
E
Eric Blake 已提交
6603 6604
            if ((name = virDomainNetBackendTypeFromString(backend)) < 0 ||
                name == VIR_DOMAIN_NET_BACKEND_TYPE_DEFAULT) {
6605 6606 6607 6608
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Unknown interface <driver name='%s'> "
                                 "has been specified"),
                               backend);
6609 6610 6611
                goto error;
            }
            def->driver.virtio.name = name;
6612
        }
6613 6614
        if (txmode != NULL) {
            int m;
E
Eric Blake 已提交
6615 6616
            if ((m = virDomainNetVirtioTxModeTypeFromString(txmode)) < 0 ||
                m == VIR_DOMAIN_NET_VIRTIO_TX_MODE_DEFAULT) {
6617 6618 6619 6620
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Unknown interface <driver txmode='%s'> "
                                 "has been specified"),
                               txmode);
6621 6622 6623 6624
                goto error;
            }
            def->driver.virtio.txmode = m;
        }
6625
        if (ioeventfd) {
6626 6627
            int val;
            if ((val = virDomainIoEventFdTypeFromString(ioeventfd)) <= 0) {
6628 6629 6630
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("unknown interface ioeventfd mode '%s'"),
                               ioeventfd);
6631 6632
                goto error;
            }
6633
            def->driver.virtio.ioeventfd = val;
6634
        }
6635 6636 6637
        if (event_idx) {
            int idx;
            if ((idx = virDomainVirtioEventIdxTypeFromString(event_idx)) <= 0) {
6638 6639 6640
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("unknown interface event_idx mode '%s'"),
                               event_idx);
6641 6642 6643 6644
                goto error;
            }
            def->driver.virtio.event_idx = idx;
        }
6645 6646 6647 6648 6649 6650 6651 6652 6653 6654
        if (queues) {
            unsigned int q;
            if (virStrToLong_ui(queues, NULL, 10, &q) < 0) {
                virReportError(VIR_ERR_XML_DETAIL,
                               _("'queues' attribute must be positive number: %s"),
                               queues);
                goto error;
            }
            def->driver.virtio.queues = q;
        }
6655
    }
6656

6657 6658 6659
    def->linkstate = VIR_DOMAIN_NET_INTERFACE_LINK_STATE_DEFAULT;
    if (linkstate != NULL) {
        if ((def->linkstate = virDomainNetInterfaceLinkStateTypeFromString(linkstate)) <= 0) {
6660 6661 6662
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown interface link state '%s'"),
                           linkstate);
6663 6664 6665 6666
            goto error;
        }
    }

6667 6668 6669 6670 6671 6672 6673 6674 6675 6676 6677 6678 6679 6680 6681
    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;
        }
    }

6682 6683 6684 6685
    ret = virXPathULong("string(./tune/sndbuf)", ctxt, &def->tune.sndbuf);
    if (ret >= 0) {
        def->tune.sndbuf_specified = true;
    } else if (ret == -2) {
6686 6687
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("sndbuf must be a positive integer"));
6688 6689 6690
        goto error;
    }

6691
cleanup:
6692
    ctxt->node = oldnode;
6693 6694
    VIR_FREE(macaddr);
    VIR_FREE(network);
6695
    VIR_FREE(portgroup);
6696 6697 6698 6699
    VIR_FREE(address);
    VIR_FREE(port);
    VIR_FREE(ifname);
    VIR_FREE(dev);
6700
    virDomainActualNetDefFree(actual);
6701 6702 6703
    VIR_FREE(script);
    VIR_FREE(bridge);
    VIR_FREE(model);
6704
    VIR_FREE(backend);
6705
    VIR_FREE(txmode);
6706
    VIR_FREE(ioeventfd);
6707
    VIR_FREE(event_idx);
6708
    VIR_FREE(queues);
6709
    VIR_FREE(filter);
6710
    VIR_FREE(type);
D
Daniel Veillard 已提交
6711
    VIR_FREE(internal);
6712
    VIR_FREE(devaddr);
S
Stefan Berger 已提交
6713
    VIR_FREE(mode);
6714
    VIR_FREE(linkstate);
6715
    VIR_FREE(addrtype);
6716
    virNWFilterHashTableFree(filterparams);
6717 6718 6719 6720 6721 6722 6723 6724 6725

    return def;

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

6726
static int
6727 6728
virDomainChrDefaultTargetType(int devtype) {
    switch ((enum virDomainChrDeviceType) devtype) {
6729
    case VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL:
6730 6731 6732
        virReportError(VIR_ERR_XML_ERROR,
                       _("target type must be specified for %s device"),
                       virDomainChrDeviceTypeToString(devtype));
6733
        return -1;
6734 6735

    case VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE:
6736
        return VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_NONE;
6737

6738
    case VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL:
6739
        return VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_ISA;
G
Guannan Ren 已提交
6740

6741
    case VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL:
6742
    case VIR_DOMAIN_CHR_DEVICE_TYPE_LAST:
6743 6744 6745 6746
        /* No target type yet*/
        break;
    }

6747
    return 0;
6748 6749 6750
}

static int
6751
virDomainChrTargetTypeFromString(virDomainChrDefPtr def,
6752
                                 int devtype,
6753 6754 6755 6756
                                 const char *targetType)
{
    int ret = -1;

6757 6758
    if (!targetType)
        return virDomainChrDefaultTargetType(devtype);
6759

6760
    switch ((enum virDomainChrDeviceType) devtype) {
6761
    case VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL:
6762
        ret = virDomainChrChannelTargetTypeFromString(targetType);
6763 6764
        break;

6765
    case VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE:
6766
        ret = virDomainChrConsoleTargetTypeFromString(targetType);
C
Cole Robinson 已提交
6767
        break;
6768

6769
    case VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL:
6770
        ret = virDomainChrSerialTargetTypeFromString(targetType);
G
Guannan Ren 已提交
6771 6772
        break;

6773
    case VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL:
6774
    case VIR_DOMAIN_CHR_DEVICE_TYPE_LAST:
6775
        /* No target type yet*/
6776
        ret = 0;
6777 6778 6779
        break;
    }

G
Guannan Ren 已提交
6780 6781
    def->targetTypeAttr = true;

6782 6783 6784 6785
    return ret;
}

static int
6786
virDomainChrDefParseTargetXML(virDomainChrDefPtr def,
E
Eric Blake 已提交
6787
                              xmlNodePtr cur)
6788 6789 6790
{
    int ret = -1;
    unsigned int port;
6791 6792 6793
    char *targetType = virXMLPropString(cur, "type");
    char *addrStr = NULL;
    char *portStr = NULL;
6794 6795

    if ((def->targetType =
6796 6797
         virDomainChrTargetTypeFromString(def, def->deviceType,
                                          targetType)) < 0) {
6798 6799 6800
        virReportError(VIR_ERR_XML_ERROR,
                       _("unknown target type '%s' specified for character device"),
                       targetType);
6801 6802 6803 6804 6805 6806 6807 6808 6809 6810
        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");

6811
            if (VIR_ALLOC(def->target.addr) < 0)
6812 6813
                goto error;

6814
            if (addrStr == NULL) {
6815 6816 6817
                virReportError(VIR_ERR_XML_ERROR, "%s",
                               _("guestfwd channel does not "
                                 "define a target address"));
6818 6819 6820
                goto error;
            }

6821
            if (virSocketAddrParse(def->target.addr, addrStr, AF_UNSPEC) < 0)
6822 6823
                goto error;

6824
            if (def->target.addr->data.stor.ss_family != AF_INET) {
6825 6826 6827
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               "%s", _("guestfwd channel only supports "
                                       "IPv4 addresses"));
6828 6829 6830 6831
                goto error;
            }

            if (portStr == NULL) {
6832 6833 6834
                virReportError(VIR_ERR_XML_ERROR, "%s",
                               _("guestfwd channel does "
                                 "not define a target port"));
6835 6836 6837 6838
                goto error;
            }

            if (virStrToLong_ui(portStr, NULL, 10, &port) < 0) {
6839 6840 6841
                virReportError(VIR_ERR_XML_ERROR,
                               _("Invalid port number: %s"),
                               portStr);
6842 6843 6844
                goto error;
            }

6845
            virSocketAddrSetPort(def->target.addr, port);
6846 6847 6848 6849 6850 6851 6852 6853 6854 6855 6856
            break;

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

    default:
        portStr = virXMLPropString(cur, "port");
        if (portStr == NULL) {
6857 6858
            /* Set to negative value to indicate we should set it later */
            def->target.port = -1;
6859 6860 6861 6862
            break;
        }

        if (virStrToLong_ui(portStr, NULL, 10, &port) < 0) {
6863 6864 6865
            virReportError(VIR_ERR_XML_ERROR,
                           _("Invalid port number: %s"),
                           portStr);
6866 6867
            goto error;
        }
6868
        def->target.port = port;
6869 6870 6871 6872 6873 6874 6875 6876 6877 6878 6879 6880 6881
        break;
    }


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

    return ret;
}

6882 6883 6884 6885 6886 6887 6888
/* 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,
6889 6890 6891 6892 6893
                              xmlNodePtr cur, unsigned int flags,
                              virDomainChrDefPtr chr_def,
                              xmlXPathContextPtr ctxt,
                              virSecurityLabelDefPtr* vmSeclabels,
                              int nvmSeclabels)
6894
{
6895 6896 6897 6898 6899 6900 6901
    char *bindHost = NULL;
    char *bindService = NULL;
    char *connectHost = NULL;
    char *connectService = NULL;
    char *path = NULL;
    char *mode = NULL;
    char *protocol = NULL;
6902
    int remaining = 0;
6903 6904 6905 6906 6907 6908 6909 6910 6911 6912 6913 6914 6915

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

                switch (def->type) {
                case VIR_DOMAIN_CHR_TYPE_PTY:
                case VIR_DOMAIN_CHR_TYPE_DEV:
                case VIR_DOMAIN_CHR_TYPE_FILE:
                case VIR_DOMAIN_CHR_TYPE_PIPE:
                case VIR_DOMAIN_CHR_TYPE_UNIX:
6916 6917 6918 6919
                    /* PTY path is only parsed from live xml.  */
                    if (path == NULL &&
                        (def->type != VIR_DOMAIN_CHR_TYPE_PTY ||
                         !(flags & VIR_DOMAIN_XML_INACTIVE)))
6920 6921 6922 6923 6924 6925 6926 6927 6928 6929 6930 6931 6932
                        path = virXMLPropString(cur, "path");

                    break;

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

                        if (connectHost == NULL)
                            connectHost = virXMLPropString(cur, "host");
                        if (connectService == NULL)
                            connectService = virXMLPropString(cur, "service");
6933
                    } else if (STREQ((const char *)mode, "bind")) {
6934 6935 6936 6937
                        if (bindHost == NULL)
                            bindHost = virXMLPropString(cur, "host");
                        if (bindService == NULL)
                            bindService = virXMLPropString(cur, "service");
6938
                    } else {
6939 6940 6941
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("Unknown source mode '%s'"),
                                       mode);
6942
                        goto error;
6943 6944
                    }

6945
                    if (def->type == VIR_DOMAIN_CHR_TYPE_UDP)
6946 6947
                        VIR_FREE(mode);
                }
6948 6949 6950 6951 6952 6953 6954 6955 6956

                /* 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,
6957 6958
                                                          ctxt,
                                                          flags) < 0) {
6959 6960 6961 6962 6963
                        ctxt->node = saved_node;
                        goto error;
                    }
                    ctxt->node = saved_node;
                }
6964 6965 6966
            } else if (xmlStrEqual(cur->name, BAD_CAST "protocol")) {
                if (protocol == NULL)
                    protocol = virXMLPropString(cur, "type");
6967 6968
            } else {
                remaining++;
6969 6970 6971 6972 6973 6974 6975 6976 6977 6978 6979 6980 6981 6982 6983 6984 6985
            }
        }
        cur = cur->next;
    }

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

    case VIR_DOMAIN_CHR_TYPE_VC:
        break;

    case VIR_DOMAIN_CHR_TYPE_PTY:
    case VIR_DOMAIN_CHR_TYPE_DEV:
    case VIR_DOMAIN_CHR_TYPE_FILE:
    case VIR_DOMAIN_CHR_TYPE_PIPE:
6986 6987
        if (path == NULL &&
            def->type != VIR_DOMAIN_CHR_TYPE_PTY) {
6988 6989
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Missing source path attribute for char device"));
6990 6991 6992 6993 6994 6995 6996 6997
            goto error;
        }

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

    case VIR_DOMAIN_CHR_TYPE_STDIO:
6998
    case VIR_DOMAIN_CHR_TYPE_SPICEVMC:
6999 7000 7001 7002 7003 7004 7005
        /* Nada */
        break;

    case VIR_DOMAIN_CHR_TYPE_TCP:
        if (mode == NULL ||
            STREQ(mode, "connect")) {
            if (connectHost == NULL) {
7006 7007
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Missing source host attribute for char device"));
7008 7009 7010
                goto error;
            }
            if (connectService == NULL) {
7011 7012
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Missing source service attribute for char device"));
7013 7014 7015 7016 7017 7018 7019
                goto error;
            }

            def->data.tcp.host = connectHost;
            connectHost = NULL;
            def->data.tcp.service = connectService;
            connectService = NULL;
7020
            def->data.tcp.listen = false;
7021 7022
        } else {
            if (bindHost == NULL) {
7023 7024
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Missing source host attribute for char device"));
7025 7026 7027
                goto error;
            }
            if (bindService == NULL) {
7028 7029
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Missing source service attribute for char device"));
7030 7031 7032 7033 7034 7035 7036
                goto error;
            }

            def->data.tcp.host = bindHost;
            bindHost = NULL;
            def->data.tcp.service = bindService;
            bindService = NULL;
7037
            def->data.tcp.listen = true;
7038
        }
7039

7040
        if (protocol == NULL)
7041
            def->data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_RAW;
7042 7043
        else if ((def->data.tcp.protocol =
                  virDomainChrTcpProtocolTypeFromString(protocol)) < 0) {
7044 7045
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unknown protocol '%s'"), protocol);
7046 7047 7048
            goto error;
        }

7049 7050 7051 7052
        break;

    case VIR_DOMAIN_CHR_TYPE_UDP:
        if (connectService == NULL) {
7053 7054
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Missing source service attribute for char device"));
7055 7056 7057 7058 7059 7060 7061 7062 7063 7064 7065 7066 7067 7068 7069
            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:
7070 7071 7072
        /* path can be auto generated */
        if (!path &&
            chr_def->targetType != VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO) {
7073 7074
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Missing source path attribute for char device"));
7075 7076 7077
            goto error;
        }

7078
        def->data.nix.listen = mode != NULL && STRNEQ(mode, "connect");
7079 7080 7081 7082 7083 7084 7085 7086 7087 7088 7089 7090 7091 7092 7093

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

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

7094 7095 7096 7097 7098 7099 7100 7101
    return remaining;

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

M
Michal Novotny 已提交
7102 7103 7104 7105 7106 7107 7108
/* Create a new character device definition and set
 * default port.
 */
virDomainChrDefPtr
virDomainChrDefNew(void) {
    virDomainChrDefPtr def = NULL;

7109
    if (VIR_ALLOC(def) < 0)
M
Michal Novotny 已提交
7110 7111 7112 7113 7114 7115
        return NULL;

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

7116 7117 7118 7119 7120 7121 7122 7123 7124 7125 7126 7127 7128 7129 7130 7131 7132 7133 7134 7135 7136 7137 7138 7139 7140 7141 7142 7143 7144 7145 7146 7147 7148 7149 7150 7151 7152 7153 7154
/* Parse the XML definition for a character device
 * @param node XML nodeset to parse for net definition
 *
 * The XML we're dealing with looks like
 *
 * <serial type="pty">
 *   <source path="/dev/pts/3"/>
 *   <target port="1"/>
 * </serial>
 *
 * <serial type="dev">
 *   <source path="/dev/ttyS0"/>
 *   <target port="1"/>
 * </serial>
 *
 * <serial type="tcp">
 *   <source mode="connect" host="0.0.0.0" service="2445"/>
 *   <target port="1"/>
 * </serial>
 *
 * <serial type="tcp">
 *   <source mode="bind" host="0.0.0.0" service="2445"/>
 *   <target port="1"/>
 *   <protocol type='raw'/>
 * </serial>
 *
 * <serial type="udp">
 *   <source mode="bind" host="0.0.0.0" service="2445"/>
 *   <source mode="connect" host="0.0.0.0" service="2445"/>
 *   <target port="1"/>
 * </serial>
 *
 * <serial type="unix">
 *   <source mode="bind" path="/tmp/foo"/>
 *   <target port="1"/>
 * </serial>
 *
 */
static virDomainChrDefPtr
7155
virDomainChrDefParseXML(xmlXPathContextPtr ctxt,
7156
                        xmlNodePtr node,
7157 7158
                        virSecurityLabelDefPtr* vmSeclabels,
                        int nvmSeclabels,
E
Eric Blake 已提交
7159 7160
                        unsigned int flags)
{
7161 7162 7163 7164
    xmlNodePtr cur;
    char *type = NULL;
    const char *nodeName;
    virDomainChrDefPtr def;
7165
    bool seenTarget = false;
7166

M
Michal Novotny 已提交
7167
    if (!(def = virDomainChrDefNew()))
7168 7169 7170 7171 7172 7173
        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) {
7174 7175 7176
        virReportError(VIR_ERR_XML_ERROR,
                       _("unknown type presented to host for character device: %s"),
                       type);
7177 7178 7179 7180 7181
        goto error;
    }

    nodeName = (const char *) node->name;
    if ((def->deviceType = virDomainChrDeviceTypeFromString(nodeName)) < 0) {
7182 7183 7184
        virReportError(VIR_ERR_XML_ERROR,
                       _("unknown character device type: %s"),
                       nodeName);
7185 7186 7187
    }

    cur = node->children;
7188 7189 7190 7191 7192 7193
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
            if (xmlStrEqual(cur->name, BAD_CAST "target")) {
                seenTarget = true;
                if (virDomainChrDefParseTargetXML(def, cur) < 0) {
                    goto error;
7194 7195 7196
                }
            }
        }
7197
        cur = cur->next;
7198 7199
    }

7200
    if (!seenTarget &&
7201
        ((def->targetType = virDomainChrDefaultTargetType(def->deviceType)) < 0))
7202 7203
        goto cleanup;

7204 7205 7206 7207
    if (virDomainChrSourceDefParseXML(&def->source, node->children, flags, def,
                                      ctxt, vmSeclabels, nvmSeclabels) < 0)
        goto error;

E
Eric Blake 已提交
7208 7209
    if (def->source.type == VIR_DOMAIN_CHR_TYPE_SPICEVMC) {
        if (def->targetType != VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO) {
7210 7211 7212
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("spicevmc device type only supports "
                             "virtio"));
E
Eric Blake 已提交
7213 7214 7215 7216
            goto error;
        } else {
            def->source.data.spicevmc = VIR_DOMAIN_CHR_SPICEVMC_VDAGENT;
        }
7217 7218
    }

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

G
Guannan Ren 已提交
7222 7223 7224 7225 7226 7227 7228 7229 7230
    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;
    }

7231 7232 7233
cleanup:
    VIR_FREE(type);

7234 7235 7236 7237 7238 7239 7240 7241
    return def;

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

E
Eric Blake 已提交
7242 7243
static virDomainSmartcardDefPtr
virDomainSmartcardDefParseXML(xmlNodePtr node,
E
Eric Blake 已提交
7244
                              unsigned int flags)
E
Eric Blake 已提交
7245 7246 7247 7248 7249
{
    xmlNodePtr cur;
    char *mode = NULL;
    char *type = NULL;
    virDomainSmartcardDefPtr def;
7250
    size_t i;
E
Eric Blake 已提交
7251

7252
    if (VIR_ALLOC(def) < 0)
E
Eric Blake 已提交
7253 7254 7255 7256
        return NULL;

    mode = virXMLPropString(node, "mode");
    if (mode == NULL) {
7257 7258
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("missing smartcard device mode"));
E
Eric Blake 已提交
7259 7260 7261
        goto error;
    }
    if ((def->type = virDomainSmartcardTypeFromString(mode)) < 0) {
7262 7263 7264
        virReportError(VIR_ERR_XML_ERROR,
                       _("unknown smartcard device mode: %s"),
                       mode);
E
Eric Blake 已提交
7265 7266 7267 7268 7269 7270 7271 7272 7273 7274 7275 7276 7277 7278
        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) {
7279 7280 7281
                    virReportError(VIR_ERR_XML_ERROR, "%s",
                                   _("host-certificates mode needs "
                                     "exactly three certificates"));
E
Eric Blake 已提交
7282 7283 7284 7285 7286 7287 7288 7289 7290 7291 7292 7293 7294 7295 7296 7297 7298
                    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 != '/') {
7299 7300 7301
                    virReportError(VIR_ERR_XML_ERROR,
                                   _("expecting absolute path: %s"),
                                   def->data.cert.database);
E
Eric Blake 已提交
7302 7303 7304 7305 7306 7307
                    goto error;
                }
            }
            cur = cur->next;
        }
        if (i < 3) {
7308 7309 7310
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("host-certificates mode needs "
                             "exactly three certificates"));
E
Eric Blake 已提交
7311 7312 7313 7314 7315 7316 7317
            goto error;
        }
        break;

    case VIR_DOMAIN_SMARTCARD_TYPE_PASSTHROUGH:
        type = virXMLPropString(node, "type");
        if (type == NULL) {
7318 7319 7320
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("passthrough mode requires a character "
                             "device type attribute"));
E
Eric Blake 已提交
7321 7322 7323
            goto error;
        }
        if ((def->data.passthru.type = virDomainChrTypeFromString(type)) < 0) {
7324 7325 7326
            virReportError(VIR_ERR_XML_ERROR,
                           _("unknown type presented to host for "
                             "character device: %s"), type);
E
Eric Blake 已提交
7327 7328 7329 7330
            goto error;
        }

        cur = node->children;
7331 7332
        if (virDomainChrSourceDefParseXML(&def->data.passthru, cur, flags,
                                          NULL, NULL, NULL, 0) < 0)
E
Eric Blake 已提交
7333
            goto error;
7334 7335

        if (def->data.passthru.type == VIR_DOMAIN_CHR_TYPE_SPICEVMC) {
E
Eric Blake 已提交
7336 7337
            def->data.passthru.data.spicevmc
                = VIR_DOMAIN_CHR_SPICEVMC_SMARTCARD;
7338
        }
E
Eric Blake 已提交
7339

E
Eric Blake 已提交
7340 7341 7342
        break;

    default:
7343 7344
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("unknown smartcard mode"));
E
Eric Blake 已提交
7345 7346 7347
        goto error;
    }

7348
    if (virDomainDeviceInfoParseXML(node, NULL, &def->info, flags) < 0)
E
Eric Blake 已提交
7349 7350 7351
        goto error;
    if (def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCID) {
7352 7353
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Controllers must use the 'ccid' address type"));
E
Eric Blake 已提交
7354 7355 7356 7357 7358 7359 7360 7361 7362 7363 7364 7365 7366 7367 7368
        goto error;
    }

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

    return def;

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

7369 7370 7371 7372 7373 7374 7375 7376 7377 7378 7379 7380 7381 7382 7383 7384 7385 7386 7387 7388 7389 7390 7391 7392 7393
/* 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
virDomainTPMDefParseXML(const xmlNodePtr node,
                        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;

7394
    if (VIR_ALLOC(def) < 0)
7395 7396 7397 7398 7399 7400 7401 7402 7403 7404 7405 7406 7407 7408 7409 7410 7411 7412 7413 7414 7415 7416 7417
        return NULL;

    model = virXMLPropString(node, "model");
    if (model != NULL &&
        (int)(def->model = virDomainTPMModelTypeFromString(model)) < 0) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("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;
    }

7418 7419 7420 7421 7422 7423
    if (nbackends == 0) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("missing TPM device backend"));
        goto error;
    }

7424 7425 7426 7427 7428 7429 7430 7431 7432 7433 7434 7435 7436 7437 7438 7439
    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) {
        virReportError(VIR_ERR_XML_ERROR,
                       _("Unknown TPM backend type '%s'"),
                       backend);
        goto error;
    }

    switch (def->type) {
    case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH:
        path = virXPathString("string(./backend/device/@path)", ctxt);
7440
        if (!path && VIR_STRDUP(path, VIR_DOMAIN_TPM_DEFAULT_DEVICE) < 0)
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
            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;

cleanup:
    VIR_FREE(type);
    VIR_FREE(path);
    VIR_FREE(model);
    VIR_FREE(backend);
    VIR_FREE(backends);
    ctxt->node = save;
    return def;

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

7468
/* Parse the XML definition for an input device */
7469
static virDomainInputDefPtr
7470
virDomainInputDefParseXML(const char *ostype,
7471
                          xmlNodePtr node,
E
Eric Blake 已提交
7472 7473
                          unsigned int flags)
{
7474 7475 7476 7477
    virDomainInputDefPtr def;
    char *type = NULL;
    char *bus = NULL;

7478
    if (VIR_ALLOC(def) < 0)
7479 7480 7481 7482 7483 7484
        return NULL;

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

    if (!type) {
7485 7486
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing input device type"));
7487 7488 7489 7490
        goto error;
    }

    if ((def->type = virDomainInputTypeFromString(type)) < 0) {
7491 7492
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown input device type '%s'"), type);
7493 7494 7495 7496 7497
        goto error;
    }

    if (bus) {
        if ((def->bus = virDomainInputBusTypeFromString(bus)) < 0) {
7498 7499
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown input bus type '%s'"), bus);
7500 7501 7502 7503 7504 7505
            goto error;
        }

        if (STREQ(ostype, "hvm")) {
            if (def->bus == VIR_DOMAIN_INPUT_BUS_PS2 && /* Only allow mouse for ps2 */
                def->type != VIR_DOMAIN_INPUT_TYPE_MOUSE) {
7506 7507 7508
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("ps2 bus does not support %s input device"),
                               type);
7509 7510 7511
                goto error;
            }
            if (def->bus == VIR_DOMAIN_INPUT_BUS_XEN) {
7512 7513 7514
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unsupported input bus %s"),
                               bus);
7515 7516 7517 7518
                goto error;
            }
        } else {
            if (def->bus != VIR_DOMAIN_INPUT_BUS_XEN) {
7519 7520 7521
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unsupported input bus %s"),
                               bus);
7522 7523
            }
            if (def->type != VIR_DOMAIN_INPUT_TYPE_MOUSE) {
7524 7525 7526
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("xen bus does not support %s input device"),
                               type);
7527 7528 7529 7530 7531 7532 7533 7534 7535 7536 7537 7538 7539 7540
                goto error;
            }
        }
    } else {
        if (STREQ(ostype, "hvm")) {
            if (def->type == VIR_DOMAIN_INPUT_TYPE_MOUSE)
                def->bus = VIR_DOMAIN_INPUT_BUS_PS2;
            else
                def->bus = VIR_DOMAIN_INPUT_BUS_USB;
        } else {
            def->bus = VIR_DOMAIN_INPUT_BUS_XEN;
        }
    }

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

7544 7545 7546
    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) {
7547 7548
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Invalid address for a USB device"));
7549 7550 7551
        goto error;
    }

7552 7553 7554 7555 7556 7557 7558 7559 7560 7561 7562 7563 7564
cleanup:
    VIR_FREE(type);
    VIR_FREE(bus);

    return def;

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


E
Eric Blake 已提交
7565
/* Parse the XML definition for a hub device */
M
Marc-André Lureau 已提交
7566 7567 7568 7569 7570 7571
static virDomainHubDefPtr
virDomainHubDefParseXML(xmlNodePtr node, unsigned int flags)
{
    virDomainHubDefPtr def;
    char *type = NULL;

7572
    if (VIR_ALLOC(def) < 0)
M
Marc-André Lureau 已提交
7573 7574 7575 7576 7577
        return NULL;

    type = virXMLPropString(node, "type");

    if (!type) {
7578 7579
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing hub device type"));
M
Marc-André Lureau 已提交
7580 7581 7582 7583
        goto error;
    }

    if ((def->type = virDomainHubTypeFromString(type)) < 0) {
7584 7585
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown hub device type '%s'"), type);
M
Marc-André Lureau 已提交
7586 7587 7588
        goto error;
    }

7589
    if (virDomainDeviceInfoParseXML(node, NULL, &def->info, flags) < 0)
M
Marc-André Lureau 已提交
7590 7591 7592 7593 7594 7595 7596 7597 7598 7599 7600 7601 7602 7603
        goto error;

cleanup:
    VIR_FREE(type);

    return def;

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


7604 7605 7606
/* Parse the XML definition for a clock timer */
static virDomainTimerDefPtr
virDomainTimerDefParseXML(const xmlNodePtr node,
E
Eric Blake 已提交
7607
                          xmlXPathContextPtr ctxt)
7608 7609 7610 7611
{
    char *name = NULL;
    char *present = NULL;
    char *tickpolicy = NULL;
7612
    char *track = NULL;
7613 7614 7615 7616
    char *mode = NULL;

    virDomainTimerDefPtr def;
    xmlNodePtr oldnode = ctxt->node;
7617 7618
    xmlNodePtr catchup;
    int ret;
7619

7620
    if (VIR_ALLOC(def) < 0)
7621 7622 7623 7624 7625 7626
        return NULL;

    ctxt->node = node;

    name = virXMLPropString(node, "name");
    if (name == NULL) {
7627 7628
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing timer name"));
7629 7630 7631
        goto error;
    }
    if ((def->name = virDomainTimerNameTypeFromString(name)) < 0) {
7632 7633
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown timer name '%s'"), name);
7634 7635 7636 7637 7638 7639 7640 7641 7642 7643
        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 {
7644 7645
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown timer present value '%s'"), present);
7646 7647 7648 7649 7650 7651 7652 7653
            goto error;
        }
    }

    def->tickpolicy = -1;
    tickpolicy = virXMLPropString(node, "tickpolicy");
    if (tickpolicy != NULL) {
        if ((def->tickpolicy = virDomainTimerTickpolicyTypeFromString(tickpolicy)) < 0) {
7654 7655
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown timer tickpolicy '%s'"), tickpolicy);
7656 7657 7658 7659
            goto error;
        }
    }

7660 7661 7662 7663
    def->track = -1;
    track = virXMLPropString(node, "track");
    if (track != NULL) {
        if ((def->track = virDomainTimerTrackTypeFromString(track)) < 0) {
7664 7665
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown timer track '%s'"), track);
7666 7667 7668 7669
            goto error;
        }
    }

7670
    ret = virXPathULong("string(./frequency)", ctxt, &def->frequency);
7671 7672
    if (ret == -1) {
        def->frequency = 0;
7673
    } else if (ret < 0) {
7674 7675
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("invalid timer frequency"));
7676 7677 7678 7679 7680 7681 7682
        goto error;
    }

    def->mode = -1;
    mode = virXMLPropString(node, "mode");
    if (mode != NULL) {
        if ((def->mode = virDomainTimerModeTypeFromString(mode)) < 0) {
7683 7684
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown timer mode '%s'"), mode);
7685 7686 7687 7688
            goto error;
        }
    }

7689
    catchup = virXPathNode("./catchup", ctxt);
7690 7691 7692 7693 7694 7695
    if (catchup != NULL) {
        ret = virXPathULong("string(./catchup/@threshold)", ctxt,
                            &def->catchup.threshold);
        if (ret == -1) {
            def->catchup.threshold = 0;
        } else if (ret < 0) {
7696 7697
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("invalid catchup threshold"));
7698 7699 7700 7701 7702 7703 7704
            goto error;
        }

        ret = virXPathULong("string(./catchup/@slew)", ctxt, &def->catchup.slew);
        if (ret == -1) {
            def->catchup.slew = 0;
        } else if (ret < 0) {
7705 7706
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("invalid catchup slew"));
7707 7708 7709 7710 7711 7712 7713
            goto error;
        }

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

7720 7721 7722 7723
cleanup:
    VIR_FREE(name);
    VIR_FREE(present);
    VIR_FREE(tickpolicy);
7724
    VIR_FREE(track);
7725 7726 7727 7728 7729 7730 7731 7732 7733 7734
    VIR_FREE(mode);
    ctxt->node = oldnode;

    return def;

error:
    VIR_FREE(def);
    goto cleanup;
}

7735 7736

static int
7737 7738 7739
virDomainGraphicsAuthDefParseXML(xmlNodePtr node,
                                 virDomainGraphicsAuthDefPtr def,
                                 int type)
7740 7741
{
    char *validTo = NULL;
7742
    char *connected = virXMLPropString(node, "connected");
7743 7744 7745 7746 7747 7748 7749 7750 7751 7752 7753 7754 7755 7756 7757 7758 7759 7760 7761 7762 7763 7764 7765 7766

    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') {
7767 7768 7769
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot parse password validity time '%s', expect YYYY-MM-DDTHH:MM:SS"),
                           validTo);
7770 7771 7772 7773 7774 7775 7776 7777 7778 7779
            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);
7780
        def->expires = true;
7781 7782
    }

7783 7784 7785
    if (connected) {
        int action = virDomainGraphicsAuthConnectedTypeFromString(connected);
        if (action <= 0) {
7786 7787 7788
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown connected value %s"),
                           connected);
7789 7790 7791 7792 7793 7794 7795 7796
            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) {
7797 7798
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("VNC supports connected='keep' only"));
7799 7800 7801 7802 7803 7804
            return -1;
        }

        def->connected = action;
    }

7805 7806 7807
    return 0;
}

7808 7809 7810 7811 7812 7813 7814 7815 7816
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");
7817 7818
    char *fromConfig = virXMLPropString(node, "fromConfig");
    int tmp;
7819 7820

    if (!type) {
7821 7822
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("graphics listen type must be specified"));
7823 7824 7825 7826
        goto error;
    }

    if ((def->type = virDomainGraphicsListenTypeFromString(type)) < 0) {
7827 7828
        virReportError(VIR_ERR_XML_ERROR,
                       _("unknown graphics listen type '%s'"), type);
7829 7830 7831 7832 7833 7834 7835
        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 已提交
7836 7837
        (def->type == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS ||
         (def->type == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NETWORK &&
7838 7839 7840 7841 7842 7843 7844 7845
          !(flags & VIR_DOMAIN_XML_INACTIVE)))) {
        def->address = address;
        address = NULL;
    }

    if (network && network[0]) {
        if (def->type != VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NETWORK) {
            /* network='xxx' never makes sense with anything except
7846
             * type='network' */
7847 7848
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("network attribute not allowed when listen type is not network"));
7849 7850 7851 7852 7853 7854
            goto error;
        }
        def->network = network;
        network = NULL;
    }

7855 7856 7857 7858 7859 7860 7861 7862 7863 7864 7865
    if (fromConfig &&
        flags & VIR_DOMAIN_XML_INTERNAL_STATUS) {
        if (virStrToLong_i(fromConfig, NULL, 10, &tmp) < 0) {
            virReportError(VIR_ERR_XML_ERROR,
                           _("Invalid fromConfig value: %s"),
                           fromConfig);
            goto error;
        }
        def->fromConfig = tmp != 0;
    }

7866 7867 7868 7869 7870 7871 7872
    ret = 0;
error:
    if (ret < 0)
        virDomainGraphicsListenDefClear(def);
    VIR_FREE(type);
    VIR_FREE(address);
    VIR_FREE(network);
7873
    VIR_FREE(fromConfig);
7874 7875 7876
    return ret;
}

7877

7878 7879
/* Parse the XML definition for a graphics device */
static virDomainGraphicsDefPtr
7880 7881 7882
virDomainGraphicsDefParseXML(xmlNodePtr node,
                             xmlXPathContextPtr ctxt,
                             unsigned int flags)
E
Eric Blake 已提交
7883
{
7884 7885
    virDomainGraphicsDefPtr def;
    char *type = NULL;
7886 7887 7888 7889
    int nListens;
    xmlNodePtr *listenNodes = NULL;
    char *listenAddr = NULL;
    xmlNodePtr save = ctxt->node;
7890

7891
    if (VIR_ALLOC(def) < 0)
7892 7893
        return NULL;

7894 7895
    ctxt->node = node;

7896 7897 7898
    type = virXMLPropString(node, "type");

    if (!type) {
7899 7900
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing graphics device type"));
7901 7902 7903 7904
        goto error;
    }

    if ((def->type = virDomainGraphicsTypeFromString(type)) < 0) {
7905 7906
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown graphics device type '%s'"), type);
7907 7908 7909
        goto error;
    }

E
Eric Blake 已提交
7910 7911 7912
    if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC ||
        def->type == VIR_DOMAIN_GRAPHICS_TYPE_RDP ||
        def->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) {
7913 7914 7915 7916 7917 7918 7919

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

        if (nListens > 0) {
7920
            size_t i;
7921

7922
            if (VIR_ALLOC_N(def->listens, nListens) < 0)
7923 7924
                goto error;

7925 7926 7927
            for (i = 0; i < nListens; i++) {
                int ret = virDomainGraphicsListenDefParseXML(&def->listens[i],
                                                             listenNodes[i],
7928 7929 7930 7931 7932 7933 7934 7935 7936 7937 7938 7939 7940 7941 7942 7943 7944 7945 7946 7947 7948 7949 7950 7951 7952 7953 7954 7955 7956
                                                             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;
7957
                size_t i;
7958

7959 7960
                for (i = 0; i < nListens; i++) {
                    if (virDomainGraphicsListenGetType(def, i)
7961
                        == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS) {
7962
                        found = virDomainGraphicsListenGetAddress(def, i);
7963 7964 7965 7966 7967 7968 7969
                        if (STREQ_NULLABLE(found, listenAddr)) {
                            matched = true;
                        }
                        break;
                    }
                }
                if (!matched) {
7970 7971 7972 7973
                    virReportError(VIR_ERR_XML_ERROR,
                                   _("graphics listen attribute %s must match address "
                                     "attribute of first listen element (found %s)"),
                                   listenAddr, found ? found : "none");
7974 7975 7976 7977 7978 7979
                    goto error;
                }
            }
        }
    }

7980 7981
    if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
        char *port = virXMLPropString(node, "port");
M
Martin Kletzander 已提交
7982
        char *websocket = virXMLPropString(node, "websocket");
7983
        char *sharePolicy = virXMLPropString(node, "sharePolicy");
7984 7985 7986 7987
        char *autoport;

        if (port) {
            if (virStrToLong_i(port, NULL, 10, &def->data.vnc.port) < 0) {
7988 7989
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("cannot parse vnc port %s"), port);
7990 7991 7992 7993 7994 7995
                VIR_FREE(port);
                goto error;
            }
            VIR_FREE(port);
            /* Legacy compat syntax, used -1 for auto-port */
            if (def->data.vnc.port == -1) {
7996 7997
                if (flags & VIR_DOMAIN_XML_INACTIVE)
                    def->data.vnc.port = 0;
7998
                def->data.vnc.autoport = true;
7999 8000 8001
            }
        } else {
            def->data.vnc.port = 0;
8002
            def->data.vnc.autoport = true;
8003 8004 8005 8006
        }

        if ((autoport = virXMLPropString(node, "autoport")) != NULL) {
            if (STREQ(autoport, "yes")) {
8007 8008
                if (flags & VIR_DOMAIN_XML_INACTIVE)
                    def->data.vnc.port = 0;
8009
                def->data.vnc.autoport = true;
8010 8011 8012 8013
            }
            VIR_FREE(autoport);
        }

M
Martin Kletzander 已提交
8014 8015 8016 8017 8018 8019 8020 8021 8022 8023 8024 8025
        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);
        }

8026 8027 8028 8029 8030 8031 8032 8033 8034 8035 8036 8037 8038 8039 8040
        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);
        }

8041
        def->data.vnc.socket = virXMLPropString(node, "socket");
8042
        def->data.vnc.keymap = virXMLPropString(node, "keymap");
8043

8044 8045
        if (virDomainGraphicsAuthDefParseXML(node, &def->data.vnc.auth,
                                             def->type) < 0)
8046
            goto error;
8047
    } else if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) {
8048 8049 8050 8051
        char *fullscreen = virXMLPropString(node, "fullscreen");

        if (fullscreen != NULL) {
            if (STREQ(fullscreen, "yes")) {
8052
                def->data.sdl.fullscreen = true;
8053
            } else if (STREQ(fullscreen, "no")) {
8054
                def->data.sdl.fullscreen = false;
8055
            } else {
8056 8057
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unknown fullscreen value '%s'"), fullscreen);
8058 8059 8060 8061
                VIR_FREE(fullscreen);
                goto error;
            }
            VIR_FREE(fullscreen);
E
Eric Blake 已提交
8062
        } else {
8063
            def->data.sdl.fullscreen = false;
E
Eric Blake 已提交
8064
        }
8065 8066
        def->data.sdl.xauth = virXMLPropString(node, "xauth");
        def->data.sdl.display = virXMLPropString(node, "display");
8067 8068 8069 8070 8071 8072 8073 8074
    } 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) {
8075 8076
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("cannot parse rdp port %s"), port);
8077 8078 8079
                VIR_FREE(port);
                goto error;
            }
M
Michal Privoznik 已提交
8080 8081
            /* Legacy compat syntax, used -1 for auto-port */
            if (def->data.rdp.port == -1)
8082
                def->data.rdp.autoport = true;
M
Michal Privoznik 已提交
8083

8084 8085 8086
            VIR_FREE(port);
        } else {
            def->data.rdp.port = 0;
8087
            def->data.rdp.autoport = true;
8088 8089 8090
        }

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

8094 8095 8096
            VIR_FREE(autoport);
        }

M
Michal Privoznik 已提交
8097 8098 8099
        if (def->data.rdp.autoport && (flags & VIR_DOMAIN_XML_INACTIVE))
            def->data.rdp.port = 0;

8100 8101
        if ((replaceUser = virXMLPropString(node, "replaceUser")) != NULL) {
            if (STREQ(replaceUser, "yes")) {
8102
                def->data.rdp.replaceUser = true;
8103 8104 8105 8106 8107 8108
            }
            VIR_FREE(replaceUser);
        }

        if ((multiUser = virXMLPropString(node, "multiUser")) != NULL) {
            if (STREQ(multiUser, "yes")) {
8109
                def->data.rdp.multiUser = true;
8110 8111 8112 8113 8114 8115 8116 8117 8118
            }
            VIR_FREE(multiUser);
        }

    } else if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP) {
        char *fullscreen = virXMLPropString(node, "fullscreen");

        if (fullscreen != NULL) {
            if (STREQ(fullscreen, "yes")) {
8119
                def->data.desktop.fullscreen = true;
8120
            } else if (STREQ(fullscreen, "no")) {
8121
                def->data.desktop.fullscreen = false;
8122
            } else {
8123 8124
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unknown fullscreen value '%s'"), fullscreen);
8125 8126 8127 8128
                VIR_FREE(fullscreen);
                goto error;
            }
            VIR_FREE(fullscreen);
E
Eric Blake 已提交
8129
        } else {
8130
            def->data.desktop.fullscreen = false;
E
Eric Blake 已提交
8131
        }
8132 8133

        def->data.desktop.display = virXMLPropString(node, "display");
8134
    } else if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) {
8135
        xmlNodePtr cur;
8136 8137 8138
        char *port = virXMLPropString(node, "port");
        char *tlsPort;
        char *autoport;
8139 8140
        char *defaultMode;
        int defaultModeVal;
8141 8142 8143

        if (port) {
            if (virStrToLong_i(port, NULL, 10, &def->data.spice.port) < 0) {
8144 8145
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("cannot parse spice port %s"), port);
8146 8147 8148 8149 8150
                VIR_FREE(port);
                goto error;
            }
            VIR_FREE(port);
        } else {
8151
            def->data.spice.port = 0;
8152 8153 8154 8155 8156
        }

        tlsPort = virXMLPropString(node, "tlsPort");
        if (tlsPort) {
            if (virStrToLong_i(tlsPort, NULL, 10, &def->data.spice.tlsPort) < 0) {
8157 8158
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("cannot parse spice tlsPort %s"), tlsPort);
8159 8160 8161 8162 8163 8164 8165 8166 8167
                VIR_FREE(tlsPort);
                goto error;
            }
            VIR_FREE(tlsPort);
        } else {
            def->data.spice.tlsPort = 0;
        }

        if ((autoport = virXMLPropString(node, "autoport")) != NULL) {
M
Michal Privoznik 已提交
8168
            if (STREQ(autoport, "yes"))
8169
                def->data.spice.autoport = true;
8170 8171 8172
            VIR_FREE(autoport);
        }

8173 8174 8175 8176
        def->data.spice.defaultMode = VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_ANY;

        if ((defaultMode = virXMLPropString(node, "defaultMode")) != NULL) {
            if ((defaultModeVal = virDomainGraphicsSpiceChannelModeTypeFromString(defaultMode)) < 0) {
8177 8178 8179
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unknown default spice channel mode %s"),
                               defaultMode);
8180 8181 8182 8183 8184 8185 8186
                VIR_FREE(defaultMode);
                goto error;
            }
            def->data.spice.defaultMode = defaultModeVal;
            VIR_FREE(defaultMode);
        }

M
Michal Privoznik 已提交
8187 8188
        if (def->data.spice.port == -1 && def->data.spice.tlsPort == -1) {
            /* Legacy compat syntax, used -1 for auto-port */
8189
            def->data.spice.autoport = true;
M
Michal Privoznik 已提交
8190 8191 8192 8193 8194 8195 8196
        }

        if (def->data.spice.autoport && (flags & VIR_DOMAIN_XML_INACTIVE)) {
            def->data.spice.port = 0;
            def->data.spice.tlsPort = 0;
        }

8197
        def->data.spice.keymap = virXMLPropString(node, "keymap");
8198

8199 8200
        if (virDomainGraphicsAuthDefParseXML(node, &def->data.spice.auth,
                                             def->type) < 0)
8201
            goto error;
8202 8203 8204 8205 8206

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

                    if (!name || !mode) {
8213 8214
                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                       _("spice channel missing name/mode"));
E
Eric Blake 已提交
8215 8216
                        VIR_FREE(name);
                        VIR_FREE(mode);
8217 8218 8219 8220
                        goto error;
                    }

                    if ((nameval = virDomainGraphicsSpiceChannelNameTypeFromString(name)) < 0) {
8221 8222 8223
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("unknown spice channel name %s"),
                                       name);
E
Eric Blake 已提交
8224 8225
                        VIR_FREE(name);
                        VIR_FREE(mode);
8226 8227 8228
                        goto error;
                    }
                    if ((modeval = virDomainGraphicsSpiceChannelModeTypeFromString(mode)) < 0) {
8229 8230 8231
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("unknown spice channel mode %s"),
                                       mode);
E
Eric Blake 已提交
8232 8233
                        VIR_FREE(name);
                        VIR_FREE(mode);
8234 8235
                        goto error;
                    }
E
Eric Blake 已提交
8236 8237
                    VIR_FREE(name);
                    VIR_FREE(mode);
8238 8239

                    def->data.spice.channels[nameval] = modeval;
8240
                } else if (xmlStrEqual(cur->name, BAD_CAST "image")) {
8241
                    char *compression = virXMLPropString(cur, "compression");
8242 8243 8244
                    int compressionVal;

                    if (!compression) {
8245 8246
                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                       _("spice image missing compression"));
8247 8248 8249 8250 8251
                        goto error;
                    }

                    if ((compressionVal =
                         virDomainGraphicsSpiceImageCompressionTypeFromString(compression)) <= 0) {
8252 8253 8254
                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                       _("unknown spice image compression %s"),
                                       compression);
8255 8256 8257 8258 8259 8260 8261
                        VIR_FREE(compression);
                        goto error;
                    }
                    VIR_FREE(compression);

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

                    if (!compression) {
8266 8267
                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                       _("spice jpeg missing compression"));
8268 8269 8270 8271 8272
                        goto error;
                    }

                    if ((compressionVal =
                         virDomainGraphicsSpiceJpegCompressionTypeFromString(compression)) <= 0) {
8273 8274 8275
                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                       _("unknown spice jpeg compression %s"),
                                       compression);
8276 8277 8278 8279 8280 8281 8282
                        VIR_FREE(compression);
                        goto error;
                    }
                    VIR_FREE(compression);

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

                    if (!compression) {
8287 8288
                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                       _("spice zlib missing compression"));
8289 8290 8291 8292 8293
                        goto error;
                    }

                    if ((compressionVal =
                         virDomainGraphicsSpiceZlibCompressionTypeFromString(compression)) <= 0) {
8294 8295 8296
                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                       _("unknown spice zlib compression %s"),
                                       compression);
8297 8298 8299
                        VIR_FREE(compression);
                        goto error;
                    }
8300
                    VIR_FREE(compression);
8301 8302 8303

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

                    if (!compression) {
8308 8309
                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                       _("spice playback missing compression"));
8310 8311 8312 8313 8314
                        goto error;
                    }

                    if ((compressionVal =
                         virDomainGraphicsSpicePlaybackCompressionTypeFromString(compression)) <= 0) {
8315
                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
8316
                                       _("unknown spice playback compression"));
8317 8318 8319 8320 8321 8322 8323
                        VIR_FREE(compression);
                        goto error;

                    }
                    VIR_FREE(compression);

                    def->data.spice.playback = compressionVal;
8324
                } else if (xmlStrEqual(cur->name, BAD_CAST "streaming")) {
8325
                    char *mode = virXMLPropString(cur, "mode");
8326 8327 8328
                    int modeVal;

                    if (!mode) {
8329 8330
                        virReportError(VIR_ERR_XML_ERROR, "%s",
                                       _("spice streaming missing mode"));
8331 8332 8333 8334
                        goto error;
                    }
                    if ((modeVal =
                         virDomainGraphicsSpiceStreamingModeTypeFromString(mode)) <= 0) {
8335
                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
8336
                                       _("unknown spice streaming mode"));
8337 8338 8339 8340 8341 8342 8343
                        VIR_FREE(mode);
                        goto error;

                    }
                    VIR_FREE(mode);

                    def->data.spice.streaming = modeVal;
8344
                } else if (xmlStrEqual(cur->name, BAD_CAST "clipboard")) {
8345
                    char *copypaste = virXMLPropString(cur, "copypaste");
8346 8347 8348
                    int copypasteVal;

                    if (!copypaste) {
8349 8350
                        virReportError(VIR_ERR_XML_ERROR, "%s",
                                       _("spice clipboard missing copypaste"));
8351 8352 8353 8354 8355
                        goto error;
                    }

                    if ((copypasteVal =
                         virDomainGraphicsSpiceClipboardCopypasteTypeFromString(copypaste)) <= 0) {
8356 8357
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("unknown copypaste value '%s'"), copypaste);
8358 8359 8360 8361 8362 8363
                        VIR_FREE(copypaste);
                        goto error;
                    }
                    VIR_FREE(copypaste);

                    def->data.spice.copypaste = copypasteVal;
P
Peng Zhou 已提交
8364
                } else if (xmlStrEqual(cur->name, BAD_CAST "mouse")) {
8365
                    char *mode = virXMLPropString(cur, "mode");
P
Peng Zhou 已提交
8366 8367 8368
                    int modeVal;

                    if (!mode) {
8369 8370
                        virReportError(VIR_ERR_XML_ERROR, "%s",
                                       _("spice mouse missing mode"));
P
Peng Zhou 已提交
8371 8372 8373 8374
                        goto error;
                    }

                    if ((modeVal = virDomainGraphicsSpiceMouseModeTypeFromString(mode)) <= 0) {
8375 8376 8377
                        virReportError(VIR_ERR_XML_ERROR,
                                       _("unknown mouse mode value '%s'"),
                                       mode);
P
Peng Zhou 已提交
8378 8379 8380 8381 8382 8383
                        VIR_FREE(mode);
                        goto error;
                    }
                    VIR_FREE(mode);

                    def->data.spice.mousemode = modeVal;
8384 8385 8386 8387
                }
            }
            cur = cur->next;
        }
8388 8389 8390 8391
    }

cleanup:
    VIR_FREE(type);
8392 8393
    VIR_FREE(listenNodes);
    VIR_FREE(listenAddr);
8394

8395
    ctxt->node = save;
8396 8397 8398 8399 8400 8401 8402 8403 8404
    return def;

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


8405 8406 8407 8408 8409 8410
static virDomainSoundCodecDefPtr
virDomainSoundCodecDefParseXML(const xmlNodePtr node)
{
    char *type;
    virDomainSoundCodecDefPtr def;

8411
    if (VIR_ALLOC(def) < 0)
8412 8413 8414 8415
        return NULL;

    type = virXMLPropString(node, "type");
    if ((def->type = virDomainSoundCodecTypeFromString(type)) < 0) {
8416 8417
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown codec type '%s'"), type);
8418 8419 8420 8421 8422 8423 8424 8425 8426 8427 8428 8429 8430 8431 8432
        goto error;
    }

cleanup:
    VIR_FREE(type);

    return def;

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


8433
static virDomainSoundDefPtr
8434
virDomainSoundDefParseXML(const xmlNodePtr node,
8435
                          xmlXPathContextPtr ctxt,
E
Eric Blake 已提交
8436
                          unsigned int flags)
8437
{
8438 8439
    char *model;
    virDomainSoundDefPtr def;
8440
    xmlNodePtr save = ctxt->node;
8441

8442
    if (VIR_ALLOC(def) < 0)
8443 8444
        return NULL;

8445 8446
    ctxt->node = node;

8447 8448
    model = virXMLPropString(node, "model");
    if ((def->model = virDomainSoundModelTypeFromString(model)) < 0) {
8449 8450
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown sound model '%s'"), model);
8451 8452 8453
        goto error;
    }

8454 8455 8456 8457 8458 8459 8460 8461 8462 8463
    if (def->model == VIR_DOMAIN_SOUND_MODEL_ICH6) {
        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) {
8464
            size_t i;
8465 8466 8467 8468 8469 8470

            if (VIR_ALLOC_N(def->codecs, ncodecs) < 0) {
                VIR_FREE(codecNodes);
                goto error;
            }

8471 8472
            for (i = 0; i < ncodecs; i++) {
                virDomainSoundCodecDefPtr codec = virDomainSoundCodecDefParseXML(codecNodes[i]);
8473 8474 8475 8476 8477 8478 8479 8480 8481 8482
                if (codec == NULL)
                    goto error;

                codec->cad = def->ncodecs; /* that will do for now */
                def->codecs[def->ncodecs++] = codec;
            }
            VIR_FREE(codecNodes);
        }
    }

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

8486 8487 8488
cleanup:
    VIR_FREE(model);

8489
    ctxt->node = save;
8490 8491 8492 8493 8494 8495 8496 8497
    return def;

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

8498

R
Richard Jones 已提交
8499
static virDomainWatchdogDefPtr
8500
virDomainWatchdogDefParseXML(const xmlNodePtr node,
E
Eric Blake 已提交
8501
                             unsigned int flags)
8502
{
R
Richard Jones 已提交
8503 8504 8505 8506 8507

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

8508
    if (VIR_ALLOC(def) < 0)
R
Richard Jones 已提交
8509 8510
        return NULL;

8511
    model = virXMLPropString(node, "model");
R
Richard Jones 已提交
8512
    if (model == NULL) {
8513 8514
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("watchdog must contain model name"));
R
Richard Jones 已提交
8515 8516
        goto error;
    }
8517
    def->model = virDomainWatchdogModelTypeFromString(model);
R
Richard Jones 已提交
8518
    if (def->model < 0) {
8519 8520
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown watchdog model '%s'"), model);
R
Richard Jones 已提交
8521 8522 8523
        goto error;
    }

8524
    action = virXMLPropString(node, "action");
R
Richard Jones 已提交
8525 8526 8527
    if (action == NULL)
        def->action = VIR_DOMAIN_WATCHDOG_ACTION_RESET;
    else {
8528
        def->action = virDomainWatchdogActionTypeFromString(action);
R
Richard Jones 已提交
8529
        if (def->action < 0) {
8530 8531
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown watchdog action '%s'"), action);
R
Richard Jones 已提交
8532 8533 8534 8535
            goto error;
        }
    }

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

R
Richard Jones 已提交
8539
cleanup:
8540 8541
    VIR_FREE(action);
    VIR_FREE(model);
R
Richard Jones 已提交
8542 8543 8544 8545

    return def;

error:
8546
    virDomainWatchdogDefFree(def);
R
Richard Jones 已提交
8547 8548 8549 8550 8551
    def = NULL;
    goto cleanup;
}


8552 8553 8554 8555 8556
static virDomainRNGDefPtr
virDomainRNGDefParseXML(const xmlNodePtr node,
                        xmlXPathContextPtr ctxt,
                        unsigned int flags)
{
8557 8558 8559
    char *model = NULL;
    char *backend = NULL;
    char *type = NULL;
8560 8561 8562 8563 8564
    virDomainRNGDefPtr def;
    xmlNodePtr save = ctxt->node;
    xmlNodePtr *backends = NULL;
    int nbackends;

8565
    if (VIR_ALLOC(def) < 0)
8566 8567 8568 8569 8570 8571 8572 8573 8574 8575 8576 8577 8578 8579
        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) {
        virReportError(VIR_ERR_XML_ERROR, _("unknown RNG model '%s'"), model);
        goto error;
    }

    ctxt->node = node;

8580 8581 8582 8583 8584 8585 8586 8587 8588 8589 8590 8591 8592
    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;
    }

8593 8594 8595 8596 8597 8598 8599 8600 8601 8602 8603 8604 8605 8606 8607 8608 8609 8610 8611 8612 8613 8614 8615 8616
    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) {
        virReportError(VIR_ERR_XML_ERROR,
                       _("unknown RNG backend model '%s'"), backend);
        goto error;
    }

    switch ((enum virDomainRNGBackend) def->backend) {
    case VIR_DOMAIN_RNG_BACKEND_RANDOM:
        def->source.file = virXPathString("string(./backend)", ctxt);
8617 8618
        if (def->source.file &&
            STRNEQ(def->source.file, "/dev/random") &&
8619 8620 8621 8622 8623 8624
            STRNEQ(def->source.file, "/dev/hwrng")) {
            virReportError(VIR_ERR_XML_ERROR,
                           _("file '%s' is not a supported random source"),
                           def->source.file);
            goto error;
        }
8625 8626 8627 8628 8629 8630 8631 8632 8633
        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;
        }

8634
        if (VIR_ALLOC(def->source.chardev) < 0)
8635 8636 8637 8638 8639 8640 8641 8642 8643 8644 8645 8646 8647 8648 8649 8650 8651 8652 8653 8654 8655 8656 8657 8658 8659 8660 8661 8662 8663 8664 8665 8666 8667 8668 8669 8670 8671 8672
            goto error;

        def->source.chardev->type = virDomainChrTypeFromString(type);
        if (def->source.chardev->type < 0) {
            virReportError(VIR_ERR_XML_ERROR,
                           _("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;

cleanup:
    VIR_FREE(model);
    VIR_FREE(backend);
    VIR_FREE(type);
    VIR_FREE(backends);
    ctxt->node = save;
    return def;

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


8673 8674
static virDomainMemballoonDefPtr
virDomainMemballoonDefParseXML(const xmlNodePtr node,
8675
                               xmlXPathContextPtr ctxt,
E
Eric Blake 已提交
8676
                               unsigned int flags)
8677 8678 8679
{
    char *model;
    virDomainMemballoonDefPtr def;
8680
    xmlNodePtr save = ctxt->node;
8681

8682
    if (VIR_ALLOC(def) < 0)
8683 8684 8685
        return NULL;

    model = virXMLPropString(node, "model");
8686
    if (model == NULL) {
8687
        virReportError(VIR_ERR_XML_ERROR, "%s",
8688
                       _("balloon memory must contain model name"));
8689 8690
        goto error;
    }
8691

8692
    if ((def->model = virDomainMemballoonModelTypeFromString(model)) < 0) {
8693
        virReportError(VIR_ERR_XML_ERROR,
8694
                       _("unknown memory balloon model '%s'"), model);
8695 8696 8697
        goto error;
    }

8698 8699 8700 8701 8702 8703 8704
    ctxt->node = node;
    if (virXPathUInt("string(./stats/@period)", ctxt, &def->period) < -1) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("invalid statistics collection period"));
        goto error;
    }

8705
    if (virDomainDeviceInfoParseXML(node, NULL, &def->info, flags) < 0)
8706 8707 8708 8709 8710
        goto error;

cleanup:
    VIR_FREE(model);

8711
    ctxt->node = save;
8712 8713 8714 8715 8716 8717 8718 8719
    return def;

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

L
Li Zhang 已提交
8720 8721 8722 8723 8724 8725
static virDomainNVRAMDefPtr
virDomainNVRAMDefParseXML(const xmlNodePtr node,
                          unsigned int flags)
{
   virDomainNVRAMDefPtr def;

8726
    if (VIR_ALLOC(def) < 0)
L
Li Zhang 已提交
8727 8728 8729 8730 8731 8732 8733 8734 8735 8736 8737 8738
        return NULL;

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

    return def;

error:
    virDomainNVRAMDefFree(def);
    return NULL;
}

8739 8740
static virSysinfoDefPtr
virSysinfoParseXML(const xmlNodePtr node,
8741 8742 8743
                  xmlXPathContextPtr ctxt,
                  unsigned char *domUUID,
                  bool uuid_generated)
8744 8745 8746
{
    virSysinfoDefPtr def;
    char *type;
8747
    char *tmpUUID = NULL;
8748 8749

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

8755
    if (VIR_ALLOC(def) < 0)
8756
        return NULL;
8757 8758 8759

    type = virXMLPropString(node, "type");
    if (type == NULL) {
8760 8761
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("sysinfo must contain a type attribute"));
8762 8763
        goto error;
    }
8764
    if ((def->type = virSysinfoTypeFromString(type)) < 0) {
8765 8766
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown sysinfo type '%s'"), type);
8767 8768 8769 8770 8771 8772 8773 8774 8775 8776 8777
        goto error;
    }


    /* Extract BIOS related metadata */
    def->bios_vendor =
        virXPathString("string(bios/entry[@name='vendor'])", ctxt);
    def->bios_version =
        virXPathString("string(bios/entry[@name='version'])", ctxt);
    def->bios_date =
        virXPathString("string(bios/entry[@name='date'])", ctxt);
8778 8779 8780 8781 8782 8783 8784 8785 8786 8787 8788 8789 8790 8791 8792 8793 8794 8795 8796 8797 8798 8799 8800
    if (def->bios_date != NULL) {
        char *ptr;
        int month, day, year;

        /* Validate just the format of the date
         * Expect mm/dd/yyyy or mm/dd/yy,
         * where yy must be 00->99 and would be assumed to be 19xx
         * a yyyy date should be 1900 and beyond
         */
        if (virStrToLong_i(def->bios_date, &ptr, 10, &month) < 0 ||
            *ptr != '/' ||
            virStrToLong_i(ptr + 1, &ptr, 10, &day) < 0 ||
            *ptr != '/' ||
            virStrToLong_i(ptr + 1, &ptr, 10, &year) < 0 ||
            *ptr != '\0' ||
            (month < 1 || month > 12) ||
            (day < 1 || day > 31) ||
            (year < 0 || (year >= 100 && year < 1900))) {
            virReportError(VIR_ERR_XML_DETAIL, "%s",
                           _("Invalid BIOS 'date' format"));
            goto error;
        }
    }
8801 8802 8803 8804 8805 8806 8807 8808 8809 8810 8811 8812
    def->bios_release =
        virXPathString("string(bios/entry[@name='release'])", ctxt);

    /* Extract system related metadata */
    def->system_manufacturer =
        virXPathString("string(system/entry[@name='manufacturer'])", ctxt);
    def->system_product =
        virXPathString("string(system/entry[@name='product'])", ctxt);
    def->system_version =
        virXPathString("string(system/entry[@name='version'])", ctxt);
    def->system_serial =
        virXPathString("string(system/entry[@name='serial'])", ctxt);
8813 8814 8815 8816 8817 8818 8819 8820 8821 8822 8823 8824 8825 8826 8827 8828 8829 8830 8831 8832 8833 8834 8835 8836 8837 8838 8839
    tmpUUID = virXPathString("string(system/entry[@name='uuid'])", ctxt);
    if (tmpUUID) {
        unsigned char uuidbuf[VIR_UUID_BUFLEN];
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        if (virUUIDParse(tmpUUID, uuidbuf) < 0) {
            virReportError(VIR_ERR_XML_DETAIL,
                           "%s", _("malformed <sysinfo> uuid element"));
            goto error;
        }
        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 error;
        }
        /* Although we've validated the UUID as good, virUUIDParse() is
         * lax with respect to allowing extraneous "-" and " ", but the
         * underlying hypervisor may be less forgiving. Use virUUIDFormat()
         * to validate format in xml is right. If not, then format it
         * properly so that it's used correctly later.
         */
        virUUIDFormat(uuidbuf, uuidstr);
        if (VIR_STRDUP(def->system_uuid, uuidstr) < 0)
            goto error;
    }
8840 8841
    def->system_sku =
        virXPathString("string(system/entry[@name='sku'])", ctxt);
E
Eric Blake 已提交
8842 8843
    def->system_family =
        virXPathString("string(system/entry[@name='family'])", ctxt);
8844 8845 8846

cleanup:
    VIR_FREE(type);
8847
    VIR_FREE(tmpUUID);
8848
    return def;
8849 8850 8851 8852 8853 8854

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

8856 8857 8858 8859 8860
int
virDomainVideoDefaultRAM(virDomainDefPtr def,
                         int type)
{
    switch (type) {
J
Ján Tomko 已提交
8861
        /* Weird, QEMU defaults to 9 MB ??! */
8862 8863 8864 8865 8866
    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 已提交
8867 8868
        else if (def->virtType == VIR_DOMAIN_VIRT_VMWARE)
            return 4 * 1024;
8869 8870 8871 8872 8873 8874 8875 8876
        else
            return 9 * 1024;
        break;

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

8877 8878 8879 8880
    case VIR_DOMAIN_VIDEO_TYPE_QXL:
        /* QEMU use 64M as the minimal video video memory for qxl device */
        return 64 * 1024;

8881 8882 8883 8884 8885 8886 8887 8888 8889 8890 8891 8892 8893 8894 8895 8896 8897 8898 8899
    default:
        return 0;
    }
}


int
virDomainVideoDefaultType(virDomainDefPtr def)
{
    switch (def->virtType) {
    case VIR_DOMAIN_VIRT_TEST:
    case VIR_DOMAIN_VIRT_QEMU:
    case VIR_DOMAIN_VIRT_KQEMU:
    case VIR_DOMAIN_VIRT_KVM:
    case VIR_DOMAIN_VIRT_XEN:
        if (def->os.type &&
            (STREQ(def->os.type, "xen") ||
             STREQ(def->os.type, "linux")))
            return VIR_DOMAIN_VIDEO_TYPE_XEN;
8900 8901
        else if (def->os.arch == VIR_ARCH_PPC64)
            return VIR_DOMAIN_VIDEO_TYPE_VGA;
8902 8903 8904 8905 8906 8907
        else
            return VIR_DOMAIN_VIDEO_TYPE_CIRRUS;

    case VIR_DOMAIN_VIRT_VBOX:
        return VIR_DOMAIN_VIDEO_TYPE_VBOX;

M
Matthias Bolte 已提交
8908 8909 8910
    case VIR_DOMAIN_VIRT_VMWARE:
        return VIR_DOMAIN_VIDEO_TYPE_VMVGA;

8911 8912 8913 8914 8915
    default:
        return -1;
    }
}

8916
static virDomainVideoAccelDefPtr
8917
virDomainVideoAccelDefParseXML(const xmlNodePtr node) {
8918 8919 8920 8921 8922 8923 8924 8925
    xmlNodePtr cur;
    virDomainVideoAccelDefPtr def;
    char *support3d = NULL;
    char *support2d = NULL;

    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
E
Eric Blake 已提交
8926
            if (!support3d && !support2d &&
8927 8928 8929 8930 8931 8932 8933 8934
                xmlStrEqual(cur->name, BAD_CAST "acceleration")) {
                support3d = virXMLPropString(cur, "accel3d");
                support2d = virXMLPropString(cur, "accel2d");
            }
        }
        cur = cur->next;
    }

E
Eric Blake 已提交
8935
    if (!support3d && !support2d)
8936
        return NULL;
8937

8938
    if (VIR_ALLOC(def) < 0)
8939 8940 8941 8942
        return NULL;

    if (support3d) {
        if (STREQ(support3d, "yes"))
8943
            def->support3d = true;
8944
        else
8945
            def->support3d = false;
8946 8947 8948 8949 8950
        VIR_FREE(support3d);
    }

    if (support2d) {
        if (STREQ(support2d, "yes"))
8951
            def->support2d = true;
8952
        else
8953
            def->support2d = false;
8954 8955 8956 8957 8958 8959
        VIR_FREE(support2d);
    }

    return def;
}

8960
static virDomainVideoDefPtr
8961
virDomainVideoDefParseXML(const xmlNodePtr node,
8962
                          virDomainDefPtr dom,
E
Eric Blake 已提交
8963 8964
                          unsigned int flags)
{
8965 8966 8967 8968 8969
    virDomainVideoDefPtr def;
    xmlNodePtr cur;
    char *type = NULL;
    char *heads = NULL;
    char *vram = NULL;
8970
    char *ram = NULL;
8971
    char *primary = NULL;
8972

8973
    if (VIR_ALLOC(def) < 0)
8974 8975 8976 8977 8978
        return NULL;

    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
8979
            if (!type && !vram && !ram && !heads &&
8980 8981
                xmlStrEqual(cur->name, BAD_CAST "model")) {
                type = virXMLPropString(cur, "type");
8982
                ram = virXMLPropString(cur, "ram");
8983 8984
                vram = virXMLPropString(cur, "vram");
                heads = virXMLPropString(cur, "heads");
8985

8986
                if ((primary = virXMLPropString(cur, "primary")) != NULL) {
8987 8988
                    if (STREQ(primary, "yes"))
                        def->primary = 1;
8989 8990
                    VIR_FREE(primary);
                }
8991

8992
                def->accel = virDomainVideoAccelDefParseXML(cur);
8993 8994 8995 8996 8997 8998 8999
            }
        }
        cur = cur->next;
    }

    if (type) {
        if ((def->type = virDomainVideoTypeFromString(type)) < 0) {
9000 9001
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown video model '%s'"), type);
9002 9003 9004 9005
            goto error;
        }
    } else {
        if ((def->type = virDomainVideoDefaultType(dom)) < 0) {
9006 9007
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("missing video model and cannot determine default"));
9008 9009 9010 9011
            goto error;
        }
    }

9012 9013 9014 9015 9016 9017 9018 9019 9020 9021 9022 9023 9024 9025 9026
    if (ram) {
        if (def->type != VIR_DOMAIN_VIDEO_TYPE_QXL) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("ram attribute only supported for type of qxl"));
            goto error;
        }
        if (virStrToLong_ui(ram, NULL, 10, &def->ram) < 0) {
            virReportError(VIR_ERR_XML_ERROR,
                           _("cannot parse video ram '%s'"), ram);
            goto error;
        }
    } else if (def->type == VIR_DOMAIN_VIDEO_TYPE_QXL) {
        def->ram = virDomainVideoDefaultRAM(dom, def->type);
    }

9027 9028
    if (vram) {
        if (virStrToLong_ui(vram, NULL, 10, &def->vram) < 0) {
9029
            virReportError(VIR_ERR_XML_ERROR,
9030
                           _("cannot parse video ram '%s'"), vram);
9031 9032 9033 9034 9035 9036 9037 9038
            goto error;
        }
    } else {
        def->vram = virDomainVideoDefaultRAM(dom, def->type);
    }

    if (heads) {
        if (virStrToLong_ui(heads, NULL, 10, &def->heads) < 0) {
9039 9040
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot parse video heads '%s'"), heads);
9041 9042 9043 9044 9045 9046
            goto error;
        }
    } else {
        def->heads = 1;
    }

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

9050
    VIR_FREE(type);
9051
    VIR_FREE(ram);
9052 9053 9054 9055 9056 9057 9058 9059
    VIR_FREE(vram);
    VIR_FREE(heads);

    return def;

error:
    virDomainVideoDefFree(def);
    VIR_FREE(type);
9060
    VIR_FREE(ram);
9061 9062 9063 9064 9065
    VIR_FREE(vram);
    VIR_FREE(heads);
    return NULL;
}

9066
static virDomainHostdevDefPtr
9067 9068 9069
virDomainHostdevDefParseXML(virDomainXMLOptionPtr xmlopt,
                            virDomainDefPtr vmdef,
                            const xmlNodePtr node,
9070
                            xmlXPathContextPtr ctxt,
9071
                            virHashTablePtr bootHash,
E
Eric Blake 已提交
9072
                            unsigned int flags)
9073
{
9074
    virDomainHostdevDefPtr def;
9075 9076 9077
    xmlNodePtr save = ctxt->node;
    char *mode = virXMLPropString(node, "mode");
    char *type = virXMLPropString(node, "type");
9078

9079
    ctxt->node = node;
9080

9081
    if (!(def = virDomainHostdevDefAlloc()))
9082 9083
        goto error;

9084 9085 9086 9087 9088 9089 9090 9091 9092 9093 9094 9095 9096 9097 9098 9099
    if (mode) {
        if ((def->mode = virDomainHostdevModeTypeFromString(mode)) < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("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;
9100 9101 9102 9103 9104
    case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
        /* parse managed/mode/type, and the <source> element */
        if (virDomainHostdevDefParseXMLCaps(node, ctxt, type, def) < 0)
            goto error;
        break;
9105 9106 9107
    default:
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unexpected hostdev mode %d"), def->mode);
9108
        goto error;
9109
    }
9110

9111
    if (def->info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
9112
        if (virDomainDeviceInfoParseXML(node, bootHash, def->info,
9113 9114
                                        flags  | VIR_DOMAIN_XML_INTERNAL_ALLOW_BOOT
                                        | VIR_DOMAIN_XML_INTERNAL_ALLOW_ROM) < 0)
9115 9116 9117 9118 9119 9120
            goto error;
    }

    if (def->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
        switch (def->source.subsys.type) {
        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
9121 9122
            if (def->info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
                def->info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
9123 9124
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("PCI host devices must use 'pci' address type"));
9125 9126 9127
                goto error;
            }
            break;
H
Han Cheng 已提交
9128
        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
9129 9130 9131
            if (def->info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
                virDomainHostdevAssignAddress(xmlopt, vmdef, def) < 0) {

H
Han Cheng 已提交
9132 9133 9134 9135
                virReportError(VIR_ERR_XML_ERROR, "%s",
                               _("SCSI host devices must have address specified"));
                goto error;
            }
O
Osier Yang 已提交
9136 9137 9138

            if (virXPathBoolean("boolean(./readonly)", ctxt))
                def->readonly = true;
9139 9140
            if (virXPathBoolean("boolean(./shareable)", ctxt))
                def->shareable = true;
H
Han Cheng 已提交
9141
            break;
9142 9143 9144
        }
    }

9145 9146 9147
cleanup:
    VIR_FREE(type);
    VIR_FREE(mode);
9148
    ctxt->node = save;
9149 9150 9151 9152 9153 9154 9155 9156
    return def;

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

9157

9158 9159
static virDomainRedirdevDefPtr
virDomainRedirdevDefParseXML(const xmlNodePtr node,
9160
                             virHashTablePtr bootHash,
9161 9162 9163 9164 9165
                             unsigned int flags)
{
    xmlNodePtr cur;
    virDomainRedirdevDefPtr def;
    char *bus, *type = NULL;
9166
    int remaining;
9167

9168
    if (VIR_ALLOC(def) < 0)
9169 9170 9171 9172 9173
        return NULL;

    bus = virXMLPropString(node, "bus");
    if (bus) {
        if ((def->bus = virDomainRedirdevBusTypeFromString(bus)) < 0) {
9174 9175
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown redirdev bus '%s'"), bus);
9176 9177 9178 9179 9180 9181 9182 9183 9184
            goto error;
        }
    } else {
        def->bus = VIR_DOMAIN_REDIRDEV_BUS_USB;
    }

    type = virXMLPropString(node, "type");
    if (type) {
        if ((def->source.chr.type = virDomainChrTypeFromString(type)) < 0) {
9185 9186
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown redirdev character device type '%s'"), type);
9187 9188 9189
            goto error;
        }
    } else {
9190 9191
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing type in redirdev"));
9192 9193 9194 9195
        goto error;
    }

    cur = node->children;
9196 9197 9198 9199 9200 9201 9202
    /* 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;
9203

9204 9205 9206 9207
    if (def->source.chr.type == VIR_DOMAIN_CHR_TYPE_SPICEVMC) {
        def->source.chr.data.spicevmc = VIR_DOMAIN_CHR_SPICEVMC_USBREDIR;
    }

9208
    if (virDomainDeviceInfoParseXML(node, bootHash, &def->info,
9209
                                    flags | VIR_DOMAIN_XML_INTERNAL_ALLOW_BOOT) < 0)
9210 9211 9212 9213 9214
        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) {
9215 9216
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Invalid address for a USB device"));
9217 9218 9219 9220
        goto error;
    }


9221 9222 9223 9224 9225 9226 9227 9228 9229 9230 9231
cleanup:
    VIR_FREE(bus);
    VIR_FREE(type);
    return def;

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

9232 9233 9234 9235 9236 9237 9238 9239 9240 9241 9242 9243 9244 9245 9246 9247 9248 9249 9250 9251 9252
/*
 * This is the helper function to convert USB version from a
 * format of JJ.MN to a format of 0xJJMN where JJ is the major
 * version number, M is the minor version number and N is the
 * sub minor version number.
 * e.g. USB 2.0 is reported as 0x0200,
 *      USB 1.1 as 0x0110 and USB 1.0 as 0x0100.
 */
static int
virDomainRedirFilterUsbVersionHelper(const char *version,
                                     virDomainRedirFilterUsbDevDefPtr def)
{
    char *version_copy = NULL;
    char *temp = NULL;
    int ret = -1;
    size_t len;
    size_t fraction_len;
    unsigned int major;
    unsigned int minor;
    unsigned int hex;

9253
    if (VIR_STRDUP(version_copy, version) < 0)
9254 9255 9256 9257 9258 9259 9260 9261 9262 9263 9264 9265 9266 9267 9268 9269 9270 9271 9272 9273 9274 9275 9276 9277 9278 9279 9280 9281 9282 9283 9284 9285 9286 9287 9288 9289 9290 9291 9292 9293 9294 9295 9296 9297 9298 9299 9300 9301 9302
        return -1;

    len = strlen(version_copy);
    /*
     * The valid format of version is like 01.10, 1.10, 1.1, etc.
     */
    if (len > 5 ||
        !(temp = strchr(version_copy, '.')) ||
        temp - version_copy < 1 ||
        temp - version_copy > 2 ||
        !(fraction_len = strlen(temp + 1)) ||
        fraction_len > 2) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Incorrect USB version format %s"), version);
        goto cleanup;
    }

    *temp = '\0';
    temp++;

    if ((virStrToLong_ui(version_copy, NULL, 0, &major)) < 0 ||
        (virStrToLong_ui(temp, NULL, 0, &minor)) < 0) {
        virReportError(VIR_ERR_XML_ERROR,
                       _("Cannot parse USB version %s"), version);
        goto cleanup;
    }

    hex = (major / 10) << 12 | (major % 10) << 8;
    if (fraction_len == 1)
        hex |= (minor % 10) << 4;
    else
        hex |= (minor / 10) << 4 | (minor % 10) << 0;

    def->version = hex;
    ret = 0;

cleanup:
    VIR_FREE(version_copy);
    return ret;
}

static virDomainRedirFilterUsbDevDefPtr
virDomainRedirFilterUsbDevDefParseXML(const xmlNodePtr node)
{
    char *class;
    char *vendor = NULL, *product = NULL;
    char *version = NULL, *allow = NULL;
    virDomainRedirFilterUsbDevDefPtr def;

9303
    if (VIR_ALLOC(def) < 0)
9304 9305 9306 9307 9308 9309 9310 9311 9312 9313 9314 9315 9316 9317 9318 9319 9320 9321 9322 9323 9324 9325 9326 9327 9328 9329 9330 9331 9332 9333 9334 9335 9336 9337 9338 9339 9340 9341 9342 9343 9344 9345 9346 9347 9348 9349 9350 9351 9352 9353 9354 9355 9356 9357
        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;
        else if ((virDomainRedirFilterUsbVersionHelper(version, def)) < 0)
            goto error;
    } else {
        def->version = -1;
    }

    allow = virXMLPropString(node, "allow");
    if (allow) {
        if (STREQ(allow, "yes"))
9358
            def->allow = true;
9359
        else if (STREQ(allow, "no"))
9360
            def->allow = false;
9361 9362 9363 9364 9365 9366 9367 9368 9369 9370 9371 9372 9373 9374 9375 9376 9377 9378 9379 9380 9381 9382 9383 9384 9385 9386 9387 9388 9389 9390 9391 9392 9393 9394 9395 9396
        else {
            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;
    }

cleanup:
    VIR_FREE(class);
    VIR_FREE(vendor);
    VIR_FREE(product);
    VIR_FREE(version);
    VIR_FREE(allow);
    return def;

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

static virDomainRedirFilterDefPtr
virDomainRedirFilterDefParseXML(const xmlNodePtr node,
                                xmlXPathContextPtr ctxt)
{
    int n;
    size_t i;
    xmlNodePtr *nodes = NULL;
    xmlNodePtr save = ctxt->node;
    virDomainRedirFilterDefPtr def = NULL;

    if (VIR_ALLOC(def) < 0)
9397
        goto error;
9398 9399 9400 9401 9402 9403 9404

    ctxt->node = node;
    if ((n = virXPathNodeSet("./usbdev", ctxt, &nodes)) < 0) {
        goto error;
    }

    if (n && VIR_ALLOC_N(def->usbdevs, n) < 0)
9405
        goto error;
9406 9407 9408 9409 9410 9411 9412 9413 9414 9415 9416 9417 9418 9419 9420 9421 9422 9423 9424 9425

    for (i = 0; i < n; i++) {
        virDomainRedirFilterUsbDevDefPtr usbdev =
            virDomainRedirFilterUsbDevDefParseXML(nodes[i]);

        if (!usbdev)
            goto error;
        def->usbdevs[def->nusbdevs++] = usbdev;
    }
    VIR_FREE(nodes);

    ctxt->node = save;
    return def;

error:
    VIR_FREE(nodes);
    virDomainRedirFilterDefFree(def);
    return NULL;
}

9426 9427 9428 9429 9430 9431 9432
static int
virDomainEventActionParseXML(xmlXPathContextPtr ctxt,
                             const char *name,
                             const char *xpath,
                             int *val,
                             int defaultVal,
                             virEventActionFromStringFunc convFunc)
9433
{
9434
    char *tmp = virXPathString(xpath, ctxt);
9435 9436 9437
    if (tmp == NULL) {
        *val = defaultVal;
    } else {
9438
        *val = convFunc(tmp);
9439
        if (*val < 0) {
9440
            virReportError(VIR_ERR_INTERNAL_ERROR,
9441
                           _("unknown %s action: %s"), name, tmp);
9442 9443 9444 9445 9446 9447 9448 9449
            VIR_FREE(tmp);
            return -1;
        }
        VIR_FREE(tmp);
    }
    return 0;
}

9450 9451 9452 9453 9454 9455 9456 9457 9458 9459 9460 9461 9462 9463 9464 9465 9466 9467 9468 9469 9470 9471
static int
virDomainPMStateParseXML(xmlXPathContextPtr ctxt,
                         const char *xpath,
                         int *val)
{
    int ret = -1;
    char *tmp = virXPathString(xpath, ctxt);
    if (tmp) {
        *val = virDomainPMStateTypeFromString(tmp);
        if (*val < 0) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown PM state value %s"), tmp);
            goto cleanup;
        }
    }

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

9472
virDomainDeviceDefPtr
9473
virDomainDeviceDefParse(const char *xmlStr,
9474
                        virDomainDefPtr def,
9475 9476
                        virCapsPtr caps,
                        virDomainXMLOptionPtr xmlopt,
9477
                        unsigned int flags)
9478 9479 9480
{
    xmlDocPtr xml;
    xmlNodePtr node;
9481
    xmlXPathContextPtr ctxt = NULL;
9482 9483
    virDomainDeviceDefPtr dev = NULL;

9484
    if (!(xml = virXMLParseStringCtxt(xmlStr, _("(device_definition)"), &ctxt)))
9485
        goto error;
9486

9487
    node = ctxt->node;
9488

9489
    if (VIR_ALLOC(dev) < 0)
9490 9491
        goto error;

9492 9493 9494 9495 9496 9497 9498 9499 9500 9501 9502 9503 9504 9505 9506 9507 9508 9509
    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 {
            virReportError(VIR_ERR_XML_ERROR,
                           _("unknown device type '%s'"),
                           node->name);
            goto error;
        }
    }

    switch ((virDomainDeviceType) dev->type) {
    case VIR_DOMAIN_DEVICE_DISK:
9510
        if (!(dev->data.disk = virDomainDiskDefParseXML(xmlopt, node, ctxt,
9511 9512
                                                        NULL, def->seclabels,
                                                        def->nseclabels,
9513
                                                        flags)))
9514
            goto error;
9515 9516
        break;
    case VIR_DOMAIN_DEVICE_LEASE:
9517 9518
        if (!(dev->data.lease = virDomainLeaseDefParseXML(node)))
            goto error;
9519 9520
        break;
    case VIR_DOMAIN_DEVICE_FS:
9521
        if (!(dev->data.fs = virDomainFSDefParseXML(node, ctxt, flags)))
9522
            goto error;
9523 9524
        break;
    case VIR_DOMAIN_DEVICE_NET:
9525
        if (!(dev->data.net = virDomainNetDefParseXML(xmlopt, node, ctxt,
9526
                                                      NULL, flags)))
9527
            goto error;
9528 9529
        break;
    case VIR_DOMAIN_DEVICE_INPUT:
9530
        if (!(dev->data.input = virDomainInputDefParseXML(def->os.type,
9531
                                                          node, flags)))
9532
            goto error;
9533 9534
        break;
    case VIR_DOMAIN_DEVICE_SOUND:
9535
        if (!(dev->data.sound = virDomainSoundDefParseXML(node, ctxt, flags)))
9536
            goto error;
9537 9538
        break;
    case VIR_DOMAIN_DEVICE_WATCHDOG:
9539
        if (!(dev->data.watchdog = virDomainWatchdogDefParseXML(node, flags)))
R
Richard Jones 已提交
9540
            goto error;
9541 9542
        break;
    case VIR_DOMAIN_DEVICE_VIDEO:
9543
        if (!(dev->data.video = virDomainVideoDefParseXML(node, def, flags)))
9544
            goto error;
9545 9546
        break;
    case VIR_DOMAIN_DEVICE_HOSTDEV:
9547 9548
        if (!(dev->data.hostdev = virDomainHostdevDefParseXML(xmlopt, def, node,
                                                              ctxt, NULL, flags)))
9549
            goto error;
9550 9551
        break;
    case VIR_DOMAIN_DEVICE_CONTROLLER:
9552 9553
        if (!(dev->data.controller = virDomainControllerDefParseXML(node, ctxt,
                                                                    flags)))
9554
            goto error;
9555 9556
        break;
    case VIR_DOMAIN_DEVICE_GRAPHICS:
9557
        if (!(dev->data.graphics = virDomainGraphicsDefParseXML(node, ctxt, flags)))
9558
            goto error;
9559 9560
        break;
    case VIR_DOMAIN_DEVICE_HUB:
M
Marc-André Lureau 已提交
9561 9562
        if (!(dev->data.hub = virDomainHubDefParseXML(node, flags)))
            goto error;
9563 9564
        break;
    case VIR_DOMAIN_DEVICE_REDIRDEV:
9565
        if (!(dev->data.redirdev = virDomainRedirdevDefParseXML(node, NULL, flags)))
9566
            goto error;
9567 9568
        break;
    case VIR_DOMAIN_DEVICE_RNG:
9569 9570
        if (!(dev->data.rng = virDomainRNGDefParseXML(node, ctxt, flags)))
            goto error;
9571 9572
        break;
    case VIR_DOMAIN_DEVICE_CHR:
9573 9574 9575 9576 9577 9578
        if (!(dev->data.chr = virDomainChrDefParseXML(ctxt,
                                                      node,
                                                      def->seclabels,
                                                      def->nseclabels,
                                                      flags)))
            goto error;
9579 9580
        break;
    case VIR_DOMAIN_DEVICE_SMARTCARD:
9581 9582
        if (!(dev->data.smartcard = virDomainSmartcardDefParseXML(node, flags)))
            goto error;
9583 9584
        break;
    case VIR_DOMAIN_DEVICE_MEMBALLOON:
9585 9586 9587
        if (!(dev->data.memballoon = virDomainMemballoonDefParseXML(node,
                                                                    ctxt,
                                                                    flags)))
9588
            goto error;
9589 9590
        break;
    case VIR_DOMAIN_DEVICE_NVRAM:
9591 9592
        if (!(dev->data.nvram = virDomainNVRAMDefParseXML(node, flags)))
            goto error;
9593 9594 9595 9596
        break;
    case VIR_DOMAIN_DEVICE_NONE:
    case VIR_DOMAIN_DEVICE_LAST:
        break;
9597 9598
    }

9599 9600 9601 9602
    /* callback to fill driver specific device aspects */
    if (virDomainDeviceDefPostParse(dev, def,  caps, xmlopt) < 0)
        goto error;

9603
cleanup:
9604
    xmlFreeDoc(xml);
9605
    xmlXPathFreeContext(ctxt);
9606 9607
    return dev;

9608
error:
9609
    VIR_FREE(dev);
9610
    goto cleanup;
9611
}
M
Matthias Bolte 已提交
9612 9613


9614 9615 9616 9617 9618 9619 9620 9621 9622 9623 9624 9625 9626
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 已提交
9627 9628 9629
    case VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL:
        type = virDomainChrSerialTargetTypeToString(targetType);
        break;
9630 9631 9632 9633 9634 9635 9636
    default:
        break;
    }

    return type;
}

L
Laine Stump 已提交
9637 9638 9639 9640 9641 9642 9643 9644 9645
int
virDomainHostdevInsert(virDomainDefPtr def, virDomainHostdevDefPtr hostdev)
{
    if (VIR_REALLOC_N(def->hostdevs, def->nhostdevs + 1) < 0)
        return -1;
    def->hostdevs[def->nhostdevs++]  = hostdev;
    return 0;
}

9646
virDomainHostdevDefPtr
L
Laine Stump 已提交
9647 9648
virDomainHostdevRemove(virDomainDefPtr def, size_t i)
{
9649 9650
    virDomainHostdevDefPtr hostdev = def->hostdevs[i];

L
Laine Stump 已提交
9651 9652 9653 9654 9655 9656 9657 9658 9659 9660 9661 9662 9663
    if (def->nhostdevs > 1) {
        memmove(def->hostdevs + i,
                def->hostdevs + i + 1,
                sizeof(*def->hostdevs) *
                (def->nhostdevs - (i + 1)));
        def->nhostdevs--;
        if (VIR_REALLOC_N(def->hostdevs, def->nhostdevs) < 0) {
            /* ignore, harmless */
        }
    } else {
        VIR_FREE(def->hostdevs);
        def->nhostdevs = 0;
    }
9664
    return hostdev;
L
Laine Stump 已提交
9665 9666
}

9667 9668 9669 9670 9671

static int
virDomainHostdevMatchSubsysUSB(virDomainHostdevDefPtr a,
                               virDomainHostdevDefPtr b)
{
9672
    if (a->source.subsys.u.usb.bus && a->source.subsys.u.usb.device) {
9673 9674 9675 9676 9677 9678 9679 9680 9681 9682 9683 9684 9685 9686 9687 9688 9689
        /* specified by bus location on host */
        if (a->source.subsys.u.usb.bus == b->source.subsys.u.usb.bus &&
            a->source.subsys.u.usb.device == b->source.subsys.u.usb.device)
            return 1;
    } else {
        /* specified by product & vendor id */
        if (a->source.subsys.u.usb.product == b->source.subsys.u.usb.product &&
            a->source.subsys.u.usb.vendor == b->source.subsys.u.usb.vendor)
            return 1;
    }
    return 0;
}

static int
virDomainHostdevMatchSubsysPCI(virDomainHostdevDefPtr a,
                               virDomainHostdevDefPtr b)
{
9690 9691 9692 9693
    if (a->source.subsys.u.pci.addr.domain == b->source.subsys.u.pci.addr.domain &&
        a->source.subsys.u.pci.addr.bus == b->source.subsys.u.pci.addr.bus &&
        a->source.subsys.u.pci.addr.slot == b->source.subsys.u.pci.addr.slot &&
        a->source.subsys.u.pci.addr.function == b->source.subsys.u.pci.addr.function)
9694 9695 9696 9697
        return 1;
    return 0;
}

H
Han Cheng 已提交
9698 9699 9700 9701 9702 9703 9704 9705 9706 9707 9708
static int
virDomainHostdevMatchSubsysSCSI(virDomainHostdevDefPtr a,
                                virDomainHostdevDefPtr b)
{
    if (STREQ(a->source.subsys.u.scsi.adapter, b->source.subsys.u.scsi.adapter) &&
        a->source.subsys.u.scsi.bus == b->source.subsys.u.scsi.bus &&
        a->source.subsys.u.scsi.target == b->source.subsys.u.scsi.target &&
        a->source.subsys.u.scsi.unit == b->source.subsys.u.scsi.unit)
        return 1;
    return 0;
}
9709 9710 9711 9712 9713 9714 9715 9716 9717 9718 9719 9720 9721

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 已提交
9722 9723
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
        return virDomainHostdevMatchSubsysSCSI(a, b);
9724 9725 9726 9727 9728
    }
    return 0;
}


9729 9730 9731 9732 9733 9734 9735 9736 9737 9738 9739 9740 9741 9742 9743 9744 9745
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);
}

9746 9747 9748 9749 9750 9751 9752 9753
static int
virDomainHostdevMatchCapsNet(virDomainHostdevDefPtr a,
                              virDomainHostdevDefPtr b)
{
    return STREQ_NULLABLE(a->source.caps.u.net.iface,
                          b->source.caps.u.net.iface);
}

9754 9755 9756 9757 9758 9759 9760 9761 9762 9763 9764 9765 9766

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);
9767 9768
    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_NET:
        return virDomainHostdevMatchCapsNet(a, b);
9769 9770 9771 9772 9773
    }
    return 0;
}


9774 9775 9776 9777 9778 9779 9780 9781 9782 9783
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);
9784 9785
    case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
        return virDomainHostdevMatchCaps(a, b);
9786 9787 9788 9789
    }
    return 0;
}

L
Laine Stump 已提交
9790 9791 9792 9793 9794 9795 9796 9797 9798 9799 9800
/* 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;
9801
    size_t i;
L
Laine Stump 已提交
9802 9803 9804 9805 9806

    if (!found)
        found = &local_found;
    *found = NULL;

9807
    for (i = 0; i < def->nhostdevs; i++) {
9808 9809
        if (virDomainHostdevMatch(match, def->hostdevs[i])) {
            *found = def->hostdevs[i];
L
Laine Stump 已提交
9810 9811 9812 9813 9814 9815
            break;
        }
    }
    return *found ? i : -1;
}

9816 9817 9818
int
virDomainDiskIndexByName(virDomainDefPtr def, const char *name,
                         bool allow_ambiguous)
9819 9820
{
    virDomainDiskDefPtr vdisk;
9821
    size_t i;
9822
    int candidate = -1;
9823

9824 9825 9826 9827
    /* 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.  */
9828 9829
    for (i = 0; i < def->ndisks; i++) {
        vdisk = def->disks[i];
9830 9831 9832 9833 9834 9835 9836 9837 9838 9839 9840
        if (*name != '/') {
            if (STREQ(vdisk->dst, name))
                return i;
        } else if (vdisk->src &&
                   STREQ(vdisk->src, name)) {
            if (allow_ambiguous)
                return i;
            if (candidate >= 0)
                return -1;
            candidate = i;
        }
9841
    }
9842 9843 9844 9845 9846 9847 9848 9849 9850
    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)
{
9851
    int idx = virDomainDiskIndexByName(def, name, true);
9852

9853
    return idx < 0 ? NULL : def->disks[idx]->src;
9854 9855
}

9856 9857
int virDomainDiskInsert(virDomainDefPtr def,
                        virDomainDiskDefPtr disk)
9858 9859
{

9860 9861 9862 9863 9864 9865
    if (VIR_REALLOC_N(def->disks, def->ndisks+1) < 0)
        return -1;

    virDomainDiskInsertPreAlloced(def, disk);

    return 0;
9866 9867
}

9868 9869 9870
void virDomainDiskInsertPreAlloced(virDomainDefPtr def,
                                   virDomainDiskDefPtr disk)
{
9871
    int idx;
9872 9873 9874 9875 9876 9877 9878 9879
    /* 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
     */
9880
    for (idx = (def->ndisks - 1); idx >= 0; idx--) {
9881 9882
        /* If bus matches and current disk is after
         * new disk, then new disk should go here */
9883 9884
        if (def->disks[idx]->bus == disk->bus &&
            (virDiskNameToIndex(def->disks[idx]->dst) >
9885
             virDiskNameToIndex(disk->dst))) {
9886 9887
            insertAt = idx;
        } else if (def->disks[idx]->bus == disk->bus &&
9888 9889 9890 9891
                   insertAt == -1) {
            /* Last disk with match bus is before the
             * new disk, then put new disk just after
             */
9892
            insertAt = idx + 1;
9893 9894 9895 9896 9897 9898 9899 9900 9901 9902 9903 9904 9905 9906 9907 9908 9909
        }
    }

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

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

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


9910 9911
virDomainDiskDefPtr
virDomainDiskRemove(virDomainDefPtr def, size_t i)
9912
{
9913
    virDomainDiskDefPtr disk = def->disks[i];
9914

9915 9916 9917 9918 9919 9920 9921 9922 9923 9924 9925 9926 9927
    if (def->ndisks > 1) {
        memmove(def->disks + i,
                def->disks + i + 1,
                sizeof(*def->disks) *
                (def->ndisks - (i + 1)));
        def->ndisks--;
        if (VIR_REALLOC_N(def->disks, def->ndisks) < 0) {
            /* ignore, harmless */
        }
    } else {
        VIR_FREE(def->disks);
        def->ndisks = 0;
    }
9928
    return disk;
9929 9930
}

9931 9932
virDomainDiskDefPtr
virDomainDiskRemoveByName(virDomainDefPtr def, const char *name)
9933
{
9934 9935
    int idx = virDomainDiskIndexByName(def, name, false);
    if (idx < 0)
9936
        return NULL;
9937
    return virDomainDiskRemove(def, idx);
9938 9939
}

E
Eric Blake 已提交
9940 9941 9942 9943 9944
/* Return true if VM has at least one disk involved in a current block
 * copy job (that is, with a <mirror> element in the disk xml).  */
bool
virDomainHasDiskMirror(virDomainObjPtr vm)
{
9945
    size_t i;
E
Eric Blake 已提交
9946 9947 9948 9949 9950 9951
    for (i = 0; i < vm->def->ndisks; i++)
        if (vm->def->disks[i]->mirror)
            return true;
    return false;
}

9952 9953 9954 9955 9956 9957
int virDomainNetInsert(virDomainDefPtr def, virDomainNetDefPtr net)
{
    if (VIR_REALLOC_N(def->nets, def->nnets + 1) < 0)
        return -1;
    def->nets[def->nnets]  = net;
    def->nnets++;
9958 9959 9960 9961
    if (net->type == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
        /* hostdev net devices must also exist in the hostdevs array */
        return virDomainHostdevInsert(def, &net->data.hostdev.def);
    }
9962 9963 9964
    return 0;
}

9965 9966 9967 9968 9969 9970 9971 9972 9973
/* virDomainNetFindIdx: search according to mac address and guest side
 *                      PCI address (if specified)
 *
 * Return: index of match if unique match found
 *         -1 if not found
 *         -2 if multiple matches
 */
int
virDomainNetFindIdx(virDomainDefPtr def, virDomainNetDefPtr net)
9974
{
9975 9976
    size_t i;
    int matchidx = -1;
9977 9978
    bool PCIAddrSpecified = virDomainDeviceAddressIsValid(&net->info,
                                                          VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI);
9979

9980 9981
    for (i = 0; i < def->nnets; i++) {
        if (virMacAddrCmp(&def->nets[i]->mac, &net->mac))
9982 9983 9984 9985 9986 9987 9988 9989 9990 9991 9992 9993 9994
            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.
             */
            matchidx = -2; /* indicates "multiple matches" to caller */
            break;
        }
        if (PCIAddrSpecified) {
9995
            if (virDevicePCIAddressEqual(&def->nets[i]->info.addr.pci,
9996 9997 9998 9999
                                         &net->info.addr.pci)) {
                /* exit early if the pci address was specified and
                 * it matches, as this guarantees no duplicates.
                 */
10000
                matchidx = i;
10001 10002 10003 10004
                break;
            }
        } else {
            /* no PCI address given, so there may be multiple matches */
10005
            matchidx = i;
10006 10007 10008
        }
    }
    return matchidx;
10009 10010
}

10011

10012 10013 10014 10015
void
virDomainNetRemoveHostdev(virDomainDefPtr def,
                          virDomainNetDefPtr net)
{
10016 10017 10018 10019 10020 10021
    /* 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;
10022

10023
    if (hostdev) {
10024 10025 10026
        for (i = 0; i < def->nhostdevs; i++) {
            if (def->hostdevs[i] == hostdev) {
                virDomainHostdevRemove(def, i);
10027 10028 10029 10030
                break;
            }
        }
    }
10031 10032 10033 10034 10035 10036 10037 10038 10039 10040
}


virDomainNetDefPtr
virDomainNetRemove(virDomainDefPtr def, size_t i)
{
    virDomainNetDefPtr net = def->nets[i];

    virDomainNetRemoveHostdev(def, net);

10041 10042 10043 10044 10045 10046 10047 10048 10049 10050 10051 10052
    if (def->nnets > 1) {
        memmove(def->nets + i,
                def->nets + i + 1,
                sizeof(*def->nets) * (def->nnets - (i + 1)));
        def->nnets--;
        if (VIR_REALLOC_N(def->nets, def->nnets) < 0) {
            /* ignore harmless */
        }
    } else {
        VIR_FREE(def->nets);
        def->nnets = 0;
    }
10053
    return net;
10054 10055
}

10056 10057 10058 10059 10060 10061 10062 10063 10064 10065 10066 10067 10068 10069 10070
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)
{
10071
    int idx;
10072 10073 10074 10075 10076 10077 10078 10079
    /* Tenatively plan to insert controller at the end. */
    int insertAt = -1;

    /* Then work backwards looking for controllers of
     * the same type. If we find a controller with a
     * index greater than the new one, insert at
     * that position
     */
10080
    for (idx = (def->ncontrollers - 1); idx >= 0; idx--) {
10081 10082
        /* If bus matches and current controller is after
         * new controller, then new controller should go here */
10083 10084 10085 10086
        if (def->controllers[idx]->type == controller->type &&
            def->controllers[idx]->idx > controller->idx) {
            insertAt = idx;
        } else if (def->controllers[idx]->type == controller->type &&
10087 10088 10089 10090
                   insertAt == -1) {
            /* Last controller with match bus is before the
             * new controller, then put new controller just after
             */
10091
            insertAt = idx + 1;
10092 10093 10094 10095 10096 10097 10098 10099 10100 10101 10102 10103 10104 10105 10106 10107
        }
    }

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

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

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

10108 10109 10110 10111
int
virDomainControllerFind(virDomainDefPtr def,
                        int type, int idx)
{
10112
    size_t i;
10113

10114
    for (i = 0; i < def->ncontrollers; i++) {
10115 10116 10117 10118 10119 10120 10121 10122 10123 10124 10125 10126 10127 10128 10129 10130 10131 10132 10133 10134 10135 10136 10137 10138 10139 10140 10141 10142 10143 10144
        if ((def->controllers[i]->type == type) &&
            (def->controllers[i]->idx == idx)) {
            return i;
        }
    }

    return -1;
}

virDomainControllerDefPtr
virDomainControllerRemove(virDomainDefPtr def, size_t i)
{
    virDomainControllerDefPtr controller = def->controllers[i];

    if (def->ncontrollers > 1) {
        memmove(def->controllers + i,
                def->controllers + i + 1,
                sizeof(*def->controllers) *
                (def->ncontrollers - (i + 1)));
        def->ncontrollers--;
        if (VIR_REALLOC_N(def->controllers, def->ncontrollers) < 0) {
            /* ignore, harmless */
        }
    } else {
        VIR_FREE(def->controllers);
        def->ncontrollers = 0;
    }

    return controller;
}
10145

10146 10147 10148 10149
int virDomainLeaseIndex(virDomainDefPtr def,
                        virDomainLeaseDefPtr lease)
{
    virDomainLeaseDefPtr vlease;
10150
    size_t i;
10151 10152 10153 10154 10155 10156 10157 10158 10159 10160 10161 10162 10163 10164 10165 10166 10167 10168 10169

    for (i = 0; i < def->nleases; i++) {
        vlease = def->leases[i];
        /* Either both must have lockspaces present which  match.. */
        if (vlease->lockspace && lease->lockspace &&
            STRNEQ(vlease->lockspace, lease->lockspace))
            continue;
        /* ...or neither must have a lockspace present */
        if (vlease->lockspace || lease->lockspace)
            continue;
        if (STREQ(vlease->key, lease->key))
            return i;
    }
    return -1;
}


int virDomainLeaseInsertPreAlloc(virDomainDefPtr def)
{
10170
    return VIR_EXPAND_N(def->leases, def->nleases, 1);
10171 10172 10173 10174 10175 10176 10177 10178 10179 10180 10181 10182 10183 10184 10185 10186 10187 10188 10189 10190 10191 10192 10193
}

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


10194 10195
virDomainLeaseDefPtr
virDomainLeaseRemoveAt(virDomainDefPtr def, size_t i)
10196
{
10197 10198 10199

    virDomainLeaseDefPtr lease = def->leases[i];

10200 10201 10202 10203 10204 10205 10206 10207 10208 10209
    if (def->nleases > 1) {
        memmove(def->leases + i,
                def->leases + i + 1,
                sizeof(*def->leases) *
                (def->nleases - (i + 1)));
        VIR_SHRINK_N(def->leases, def->nleases, 1);
    } else {
        VIR_FREE(def->leases);
        def->nleases = 0;
    }
10210
    return lease;
10211 10212 10213
}


10214 10215 10216
virDomainLeaseDefPtr
virDomainLeaseRemove(virDomainDefPtr def,
                     virDomainLeaseDefPtr lease)
10217
{
10218 10219
    int idx = virDomainLeaseIndex(def, lease);
    if (idx < 0)
10220
        return NULL;
10221
    return virDomainLeaseRemoveAt(def, idx);
10222 10223
}

10224
bool
10225 10226 10227 10228 10229 10230 10231 10232 10233 10234 10235 10236 10237 10238 10239 10240 10241 10242 10243 10244 10245 10246 10247 10248 10249 10250 10251 10252 10253 10254 10255 10256 10257 10258 10259 10260 10261 10262 10263 10264 10265 10266 10267 10268 10269 10270 10271 10272 10273 10274 10275 10276 10277 10278 10279 10280 10281 10282 10283 10284 10285 10286 10287 10288 10289 10290 10291 10292 10293 10294 10295 10296 10297 10298 10299 10300 10301 10302 10303 10304 10305 10306 10307 10308 10309 10310 10311 10312 10313 10314 10315
virDomainChrEquals(virDomainChrDefPtr src,
                   virDomainChrDefPtr tgt)
{
    if (!src || !tgt)
        return src == tgt;

    if (src->deviceType != tgt->deviceType ||
        !virDomainChrSourceDefIsEqual(&src->source, &tgt->source))
        return false;

    switch ((enum virDomainChrDeviceType) src->deviceType) {
    case VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL:
        if (src->targetType != tgt->targetType)
            return false;
        switch ((enum virDomainChrChannelTargetType) src->targetType) {
        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)
{
    virDomainChrDefPtr chr, **arrPtr;
    size_t i, *cntPtr;

    virDomainChrGetDomainPtrs(def, target, &arrPtr, &cntPtr);

    for (i = 0; i < *cntPtr; i++) {
        chr = (*arrPtr)[i];
        if (virDomainChrEquals(chr, target))
            return chr;
    }
    return NULL;
}

void
virDomainChrGetDomainPtrs(virDomainDefPtr vmdef,
                          virDomainChrDefPtr chr,
                          virDomainChrDefPtr ***arrPtr,
                          size_t **cntPtr)
{
    switch ((enum virDomainChrDeviceType) chr->deviceType) {
    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:
10316 10317
        *arrPtr = NULL;
        *cntPtr = NULL;
10318 10319 10320 10321 10322 10323 10324 10325 10326 10327 10328 10329 10330 10331 10332 10333 10334 10335 10336 10337 10338 10339 10340 10341 10342 10343 10344 10345 10346 10347 10348 10349 10350 10351 10352 10353 10354 10355
        break;
    }
}

int
virDomainChrInsert(virDomainDefPtr vmdef,
                   virDomainChrDefPtr chr)
{
    virDomainChrDefPtr **arrPtr;
    size_t *cntPtr;

    virDomainChrGetDomainPtrs(vmdef, chr, &arrPtr, &cntPtr);

    return VIR_APPEND_ELEMENT(*arrPtr, *cntPtr, chr);
}

virDomainChrDefPtr
virDomainChrRemove(virDomainDefPtr vmdef,
                   virDomainChrDefPtr chr)
{
    virDomainChrDefPtr ret, **arrPtr;
    size_t i, *cntPtr;

    virDomainChrGetDomainPtrs(vmdef, chr, &arrPtr, &cntPtr);

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

10357 10358 10359 10360
char *
virDomainDefGetDefaultEmulator(virDomainDefPtr def,
                               virCapsPtr caps)
{
10361 10362 10363 10364 10365 10366
    const char *type;
    const char *emulator;
    char *retemu;

    type = virDomainVirtTypeToString(def->virtType);
    if (!type) {
10367 10368
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("unknown virt type"));
10369 10370 10371 10372 10373 10374 10375 10376 10377
        return NULL;
    }

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

    if (!emulator) {
10378
        virReportError(VIR_ERR_INTERNAL_ERROR,
10379 10380
                       _("no emulator for domain %s os type %s "
                         "on architecture %s"),
10381
                       type, def->os.type, virArchToString(def->os.arch));
10382 10383 10384
        return NULL;
    }

10385
    ignore_value(VIR_STRDUP(retemu, emulator));
10386 10387 10388
    return retemu;
}

10389 10390
static int
virDomainDefParseBootXML(xmlXPathContextPtr ctxt,
10391
                         virDomainDefPtr def)
10392 10393
{
    xmlNodePtr *nodes = NULL;
10394 10395
    size_t i;
    int n;
M
Martin Kletzander 已提交
10396
    char *tmp = NULL;
10397
    int ret = -1;
M
Michal Privoznik 已提交
10398
    unsigned long deviceBoot, serialPorts;
10399 10400

    if (virXPathULong("count(./devices/disk[boot]"
10401
                      "|./devices/interface[boot]"
10402 10403
                      "|./devices/hostdev[boot]"
                      "|./devices/redirdev[boot])", ctxt, &deviceBoot) < 0) {
10404 10405
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("cannot count boot devices"));
10406 10407
        goto cleanup;
    }
10408 10409 10410 10411 10412 10413

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

10414
    if (n > 0 && deviceBoot) {
10415 10416 10417
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("per-device boot elements cannot be used"
                         " together with os/boot elements"));
10418 10419 10420
        goto cleanup;
    }

10421
    for (i = 0; i < n && i < VIR_DOMAIN_BOOT_LAST; i++) {
10422 10423 10424
        int val;
        char *dev = virXMLPropString(nodes[i], "dev");
        if (!dev) {
10425 10426
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("missing boot device"));
10427 10428 10429
            goto cleanup;
        }
        if ((val = virDomainBootTypeFromString(dev)) < 0) {
10430 10431 10432
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown boot device '%s'"),
                           dev);
10433 10434 10435 10436 10437 10438
            VIR_FREE(dev);
            goto cleanup;
        }
        VIR_FREE(dev);
        def->os.bootDevs[def->os.nBootDevs++] = val;
    }
10439
    if (def->os.nBootDevs == 0 && !deviceBoot) {
10440 10441 10442 10443
        def->os.nBootDevs = 1;
        def->os.bootDevs[0] = VIR_DOMAIN_BOOT_DISK;
    }

M
Martin Kletzander 已提交
10444 10445 10446
    tmp = virXPathString("string(./os/bootmenu[1]/@enable)", ctxt);
    if (tmp) {
        def->os.bootmenu = virDomainBootMenuTypeFromString(tmp);
10447 10448 10449 10450 10451
        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 已提交
10452
                     tmp);
10453
            def->os.bootmenu = VIR_DOMAIN_BOOT_MENU_DISABLED;
10454
        }
M
Martin Kletzander 已提交
10455
        VIR_FREE(tmp);
10456 10457
    }

M
Martin Kletzander 已提交
10458 10459 10460
    tmp = virXPathString("string(./os/bios[1]/@useserial)", ctxt);
    if (tmp) {
        if (STREQ(tmp, "yes")) {
M
Michal Privoznik 已提交
10461 10462
            if (virXPathULong("count(./devices/serial)",
                              ctxt, &serialPorts) < 0) {
10463 10464 10465
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                               _("need at least one serial port "
                                 "for useserial"));
M
Michal Privoznik 已提交
10466 10467 10468 10469 10470 10471
                goto cleanup;
            }
            def->os.bios.useserial = VIR_DOMAIN_BIOS_USESERIAL_YES;
        } else {
            def->os.bios.useserial = VIR_DOMAIN_BIOS_USESERIAL_NO;
        }
M
Martin Kletzander 已提交
10472
        VIR_FREE(tmp);
M
Michal Privoznik 已提交
10473 10474
    }

10475 10476 10477 10478 10479 10480 10481 10482 10483 10484 10485 10486 10487 10488
    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;
    }

10489 10490 10491
    ret = 0;

cleanup:
10492
    VIR_FREE(tmp);
10493 10494 10495 10496
    VIR_FREE(nodes);
    return ret;
}

10497

G
Gao feng 已提交
10498 10499 10500 10501 10502 10503 10504 10505 10506 10507 10508 10509 10510
static int virDomainIdMapEntrySort(const void *a, const void *b)
{
    const virDomainIdMapEntryPtr entrya = (const virDomainIdMapEntryPtr) a;
    const virDomainIdMapEntryPtr entryb = (const virDomainIdMapEntryPtr) b;

    if (entrya->start > entryb->start)
        return 1;
    else if (entrya->start < entryb->start)
        return -1;
    else
        return 0;
}

10511 10512 10513 10514 10515 10516 10517 10518 10519 10520 10521 10522 10523 10524 10525 10526
/* 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,
                          const xmlNodePtr *node,
                          size_t num)
{
    size_t i;
    virDomainIdMapEntryPtr idmap = NULL;
    xmlNodePtr save_ctxt = ctxt->node;

10527
    if (VIR_ALLOC_N(idmap, num) < 0)
10528 10529 10530 10531 10532 10533 10534 10535 10536 10537 10538 10539
        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) {
            VIR_FREE(idmap);
            goto cleanup;
        }
    }

G
Gao feng 已提交
10540 10541 10542 10543 10544 10545 10546 10547 10548 10549 10550
    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;
    }

10551 10552 10553 10554 10555 10556
cleanup:
    ctxt->node = save_ctxt;
    return idmap;
}


10557 10558 10559 10560 10561 10562 10563 10564 10565 10566 10567 10568 10569
/* Parse the XML definition for a vcpupin or emulatorpin.
 *
 * vcpupin has the form of
 *
 *   <vcpupin vcpu='0' cpuset='0'/>
 *
 * and emulatorpin has the form of
 *
 *   <emulatorpin cpuset='0'/>
 *
 * A vcpuid of -1 is valid and only valid for emulatorpin. So callers
 * have to check the returned cpuid for validity.
 */
E
Eric Blake 已提交
10570 10571
static virDomainVcpuPinDefPtr
virDomainVcpuPinDefParseXML(const xmlNodePtr node,
10572
                            xmlXPathContextPtr ctxt,
10573 10574
                            int maxvcpus,
                            int emulator)
10575
{
E
Eric Blake 已提交
10576
    virDomainVcpuPinDefPtr def;
10577
    xmlNodePtr oldnode = ctxt->node;
10578
    int vcpuid = -1;
10579 10580 10581
    char *tmp = NULL;
    int ret;

10582
    if (VIR_ALLOC(def) < 0)
10583 10584 10585 10586
        return NULL;

    ctxt->node = node;

10587 10588 10589 10590 10591 10592 10593 10594 10595 10596 10597
    if (emulator == 0) {
        ret = virXPathInt("string(./@vcpu)", ctxt, &vcpuid);
        if ((ret == -2) || (vcpuid < -1)) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("vcpu id must be an unsigned integer or -1"));
            goto error;
        } else if (vcpuid == -1) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("vcpu id value -1 is not allowed for vcpupin"));
            goto error;
        }
10598 10599 10600
    }

    if (vcpuid >= maxvcpus) {
10601 10602
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("vcpu id must be less than maxvcpus"));
10603 10604 10605 10606 10607 10608 10609 10610 10611 10612 10613
        goto error;
    }

    def->vcpuid = vcpuid;

    tmp = virXMLPropString(node, "cpuset");

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

H
Hu Tao 已提交
10614 10615
        if (virBitmapParse(set, 0, &def->cpumask,
                           cpumasklen) < 0)
10616 10617 10618
           goto error;
        VIR_FREE(tmp);
    } else {
10619 10620
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing cpuset for vcpupin"));
10621 10622 10623 10624 10625 10626 10627 10628 10629 10630 10631 10632
        goto error;
    }

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

error:
    VIR_FREE(def);
    goto cleanup;
}

10633 10634 10635 10636 10637 10638 10639 10640
/*
 * Return the vcpupin related with the vcpu id on SUCCESS, or
 * NULL on failure.
 */
virDomainVcpuPinDefPtr
virDomainLookupVcpuPin(virDomainDefPtr def,
                       int vcpuid)
{
10641
    size_t i;
10642 10643 10644 10645 10646 10647 10648 10649 10650 10651 10652 10653

    if (!def->cputune.vcpupin)
        return NULL;

    for (i = 0; i < def->cputune.nvcpupin; i++) {
        if (def->cputune.vcpupin[i]->vcpuid == vcpuid)
            return def->cputune.vcpupin[i];
    }

    return NULL;
}

10654
int
10655 10656 10657 10658
virDomainDefMaybeAddController(virDomainDefPtr def,
                               int type,
                               int idx,
                               int model)
10659
{
10660
    size_t i;
10661 10662
    virDomainControllerDefPtr cont;

10663
    for (i = 0; i < def->ncontrollers; i++) {
10664 10665
        if (def->controllers[i]->type == type &&
            def->controllers[i]->idx == idx)
10666
            return 0;
10667 10668
    }

10669
    if (VIR_ALLOC(cont) < 0)
10670 10671 10672 10673
        return -1;

    cont->type = type;
    cont->idx = idx;
10674
    cont->model = model;
10675 10676 10677 10678 10679 10680

    if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL) {
        cont->opts.vioserial.ports = -1;
        cont->opts.vioserial.vectors = -1;
    }

10681
    if (VIR_APPEND_ELEMENT(def->controllers, def->ncontrollers, cont) < 0) {
10682 10683 10684 10685 10686 10687 10688
        VIR_FREE(cont);
        return -1;
    }

    return 0;
}

E
Eric Blake 已提交
10689 10690 10691 10692 10693 10694 10695 10696 10697 10698

/* Parse a memory element located at XPATH within CTXT, and store the
 * result into MEM.  If REQUIRED, then the value must exist;
 * otherwise, the value is optional.  The value is in blocks of 1024.
 * Return 0 on success, -1 on failure after issuing error.  */
static int
virDomainParseMemory(const char *xpath, xmlXPathContextPtr ctxt,
                     unsigned long long *mem, bool required)
{
    int ret = -1;
10699
    unsigned long long bytes, max;
E
Eric Blake 已提交
10700 10701 10702 10703 10704 10705 10706

    /* On 32-bit machines, our bound is 0xffffffff * KiB. On 64-bit
     * machines, our bound is off_t (2^63).  */
    if (sizeof(unsigned long) < sizeof(long long))
        max = 1024ull * ULONG_MAX;
    else
        max = LLONG_MAX;
10707 10708 10709

    ret = virDomainParseScaledValue(xpath, ctxt, &bytes, 1024, max, required);
    if (ret < 0)
E
Eric Blake 已提交
10710 10711 10712 10713 10714 10715 10716 10717 10718 10719
        goto cleanup;

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


10720 10721 10722 10723 10724 10725 10726 10727 10728
static virDomainResourceDefPtr
virDomainResourceDefParse(xmlNodePtr node,
                          xmlXPathContextPtr ctxt)
{
    virDomainResourceDefPtr def = NULL;
    xmlNodePtr tmp = ctxt->node;

    ctxt->node = node;

10729
    if (VIR_ALLOC(def) < 0)
10730 10731 10732 10733 10734 10735 10736 10737 10738 10739 10740 10741 10742 10743 10744 10745 10746 10747
        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;

error:
    ctxt->node = tmp;
    virDomainResourceDefFree(def);
    return NULL;
}

10748 10749 10750 10751
static int
virDomainDefMaybeAddHostdevSCSIcontroller(virDomainDefPtr def)
{
    /* Look for any hostdev scsi dev */
10752
    size_t i;
10753 10754 10755 10756 10757 10758 10759 10760 10761 10762 10763 10764
    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;
        }
    }

10765 10766 10767
    if (maxController == -1)
        return 0;

10768 10769 10770 10771 10772 10773 10774
    for (i = 0; i <= maxController; i++) {
        if (virDomainDefMaybeAddController(def, VIR_DOMAIN_CONTROLLER_TYPE_SCSI, i, -1) < 0)
            return -1;
    }

    return 0;
}
10775

10776
static virDomainDefPtr
10777
virDomainDefParseXML(xmlDocPtr xml,
10778 10779
                     xmlNodePtr root,
                     xmlXPathContextPtr ctxt,
10780 10781
                     virCapsPtr caps,
                     virDomainXMLOptionPtr xmlopt,
10782 10783
                     unsigned int expectedVirtTypes,
                     unsigned int flags)
10784 10785 10786
{
    xmlNodePtr *nodes = NULL, node = NULL;
    char *tmp = NULL;
10787 10788
    size_t i;
    int n;
10789
    long id = -1;
10790
    virDomainDefPtr def;
E
Eric Blake 已提交
10791
    unsigned long count;
10792
    bool uuid_generated = false;
10793
    virHashTablePtr bootHash = NULL;
O
Osier Yang 已提交
10794
    xmlNodePtr cur;
10795 10796
    bool usb_none = false;
    bool usb_other = false;
10797
    bool usb_master = false;
10798
    bool primaryVideo = false;
10799

10800
    if (VIR_ALLOC(def) < 0)
10801
        return NULL;
10802 10803

    if (!(flags & VIR_DOMAIN_XML_INACTIVE))
E
Eric Blake 已提交
10804
        if (virXPathLong("string(./@id)", ctxt, &id) < 0)
10805 10806
            id = -1;
    def->id = (int)id;
10807

10808
    /* Find out what type of virtualization to use */
10809
    if (!(tmp = virXPathString("string(./@type)", ctxt))) {
10810 10811
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing domain type attribute"));
10812 10813 10814 10815
        goto error;
    }

    if ((def->virtType = virDomainVirtTypeFromString(tmp)) < 0) {
10816 10817
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("invalid domain type %s"), tmp);
10818 10819 10820 10821
        goto error;
    }
    VIR_FREE(tmp);

M
Matthias Bolte 已提交
10822 10823
    if ((expectedVirtTypes & (1 << def->virtType)) == 0) {
        if (count_one_bits(expectedVirtTypes) == 1) {
10824 10825 10826 10827
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected domain type %s, expecting %s"),
                           virDomainVirtTypeToString(def->virtType),
                           virDomainVirtTypeToString(ffs(expectedVirtTypes) - 1));
M
Matthias Bolte 已提交
10828 10829 10830 10831 10832 10833 10834 10835 10836 10837 10838 10839 10840 10841 10842 10843 10844 10845 10846 10847 10848
        } else {
            virBuffer buffer = VIR_BUFFER_INITIALIZER;
            char *string;

            for (i = 0; i < VIR_DOMAIN_VIRT_LAST; ++i) {
                if ((expectedVirtTypes & (1 << i)) != 0) {
                    if (virBufferUse(&buffer) > 0)
                        virBufferAddLit(&buffer, ", ");

                    virBufferAdd(&buffer, virDomainVirtTypeToString(i), -1);
                }
            }

            if (virBufferError(&buffer)) {
                virReportOOMError();
                virBufferFreeAndReset(&buffer);
                goto error;
            }

            string = virBufferContentAndReset(&buffer);

10849 10850 10851 10852 10853
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected domain type %s, "
                             "expecting one of these: %s"),
                           virDomainVirtTypeToString(def->virtType),
                           string);
M
Matthias Bolte 已提交
10854 10855 10856 10857 10858 10859 10860

            VIR_FREE(string);
        }

        goto error;
    }

10861
    /* Extract domain name */
10862
    if (!(def->name = virXPathString("string(./name[1])", ctxt))) {
10863
        virReportError(VIR_ERR_NO_NAME, NULL);
10864 10865 10866
        goto error;
    }

10867 10868 10869
    /* 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. */
10870
    tmp = virXPathString("string(./uuid[1])", ctxt);
10871
    if (!tmp) {
10872
        if (virUUIDGenerate(def->uuid)) {
10873 10874
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("Failed to generate UUID"));
10875 10876
            goto error;
        }
10877
        uuid_generated = true;
10878 10879
    } else {
        if (virUUIDParse(tmp, def->uuid) < 0) {
10880 10881
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("malformed uuid element"));
10882 10883 10884 10885 10886
            goto error;
        }
        VIR_FREE(tmp);
    }

10887 10888 10889
    /* Extract short description of domain (title) */
    def->title = virXPathString("string(./title[1])", ctxt);
    if (def->title && strchr(def->title, '\n')) {
10890 10891
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Domain title can't contain newlines"));
10892 10893 10894
        goto error;
    }

10895
    /* Extract documentation if present */
10896
    def->description = virXPathString("string(./description[1])", ctxt);
10897

E
Eric Blake 已提交
10898 10899
    /* analysis of security label, done early even though we format it
     * late, so devices can refer to this for defaults */
10900
    if (virSecurityLabelDefsParseXML(def, ctxt, caps, flags) == -1)
E
Eric Blake 已提交
10901 10902
        goto error;

10903
    /* Extract domain memory */
E
Eric Blake 已提交
10904 10905
    if (virDomainParseMemory("./memory[1]", ctxt,
                             &def->mem.max_balloon, true) < 0)
10906 10907
        goto error;

E
Eric Blake 已提交
10908 10909 10910
    if (virDomainParseMemory("./currentMemory[1]", ctxt,
                             &def->mem.cur_balloon, false) < 0)
        goto error;
10911

10912
    /* and info about it */
10913 10914 10915 10916 10917
    if ((tmp = virXPathString("string(./memory[1]/@dumpCore)", ctxt)) &&
        (def->mem.dump_core = virDomainMemDumpTypeFromString(tmp)) <= 0) {
        virReportError(VIR_ERR_XML_ERROR,
                       _("Invalid memory core dump attribute value '%s'"), tmp);
        goto error;
10918
    }
10919
    VIR_FREE(tmp);
10920

10921
    if (def->mem.cur_balloon > def->mem.max_balloon) {
10922
        /* Older libvirt could get into this situation due to
10923
         * rounding; if the discrepancy is less than 4MiB, we silently
10924
         * round down, otherwise we flag the issue.  */
10925 10926
        if (VIR_DIV_UP(def->mem.cur_balloon, 4096) >
            VIR_DIV_UP(def->mem.max_balloon, 4096)) {
10927 10928 10929 10930
            virReportError(VIR_ERR_XML_ERROR,
                           _("current memory '%lluk' exceeds "
                             "maximum '%lluk'"),
                           def->mem.cur_balloon, def->mem.max_balloon);
10931 10932 10933 10934 10935 10936
            goto error;
        } else {
            VIR_DEBUG("Truncating current %lluk to maximum %lluk",
                      def->mem.cur_balloon, def->mem.max_balloon);
            def->mem.cur_balloon = def->mem.max_balloon;
        }
E
Eric Blake 已提交
10937 10938
    } else if (def->mem.cur_balloon == 0) {
        def->mem.cur_balloon = def->mem.max_balloon;
10939 10940
    }

10941
    if ((node = virXPathNode("./memoryBacking/hugepages", ctxt)))
10942
        def->mem.hugepage_backed = true;
10943

10944 10945 10946
    if ((node = virXPathNode("./memoryBacking/nosharepages", ctxt)))
        def->mem.nosharepages = true;

10947 10948 10949
    if (virXPathBoolean("boolean(./memoryBacking/locked)", ctxt))
        def->mem.locked = true;

10950 10951 10952 10953 10954
    /* Extract blkio cgroup tunables */
    if (virXPathUInt("string(./blkiotune/weight)", ctxt,
                     &def->blkio.weight) < 0)
        def->blkio.weight = 0;

10955
    if ((n = virXPathNodeSet("./blkiotune/device", ctxt, &nodes)) < 0) {
10956 10957
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("cannot extract blkiotune nodes"));
10958 10959 10960
        goto error;
    }
    if (n && VIR_ALLOC_N(def->blkio.devices, n) < 0)
10961
        goto error;
10962 10963

    for (i = 0; i < n; i++) {
10964
        size_t j;
10965 10966 10967 10968
        if (virDomainBlkioDeviceWeightParseXML(nodes[i],
                                               &def->blkio.devices[i]) < 0)
            goto error;
        def->blkio.ndevices++;
10969 10970 10971
        for (j = 0; j < i; j++) {
            if (STREQ(def->blkio.devices[j].path,
                      def->blkio.devices[i].path)) {
10972 10973 10974
                virReportError(VIR_ERR_XML_ERROR,
                               _("duplicate device weight path '%s'"),
                               def->blkio.devices[i].path);
10975 10976 10977
                goto error;
            }
        }
10978 10979 10980
    }
    VIR_FREE(nodes);

10981
    /* Extract other memory tunables */
E
Eric Blake 已提交
10982 10983 10984
    if (virDomainParseMemory("./memtune/hard_limit[1]", ctxt,
                             &def->mem.hard_limit, false) < 0)
        goto error;
10985

E
Eric Blake 已提交
10986 10987 10988
    if (virDomainParseMemory("./memtune/soft_limit[1]", ctxt,
                             &def->mem.soft_limit, false) < 0)
        goto error;
10989

E
Eric Blake 已提交
10990 10991 10992
    if (virDomainParseMemory("./memtune/min_guarantee[1]", ctxt,
                             &def->mem.min_guarantee, false) < 0)
        goto error;
10993

E
Eric Blake 已提交
10994 10995 10996
    if (virDomainParseMemory("./memtune/swap_hard_limit[1]", ctxt,
                             &def->mem.swap_hard_limit, false) < 0)
        goto error;
10997

E
Eric Blake 已提交
10998 10999
    n = virXPathULong("string(./vcpu[1])", ctxt, &count);
    if (n == -2) {
11000 11001
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("maximum vcpus must be an integer"));
E
Eric Blake 已提交
11002 11003 11004 11005 11006
        goto error;
    } else if (n < 0) {
        def->maxvcpus = 1;
    } else {
        def->maxvcpus = count;
11007
        if (count == 0 || (unsigned short) count != count) {
11008
            virReportError(VIR_ERR_XML_ERROR,
11009
                           _("invalid maximum number of vCPUs '%lu'"), count);
E
Eric Blake 已提交
11010 11011 11012 11013 11014 11015
            goto error;
        }
    }

    n = virXPathULong("string(./vcpu[1]/@current)", ctxt, &count);
    if (n == -2) {
11016 11017
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("current vcpus must be an integer"));
E
Eric Blake 已提交
11018 11019 11020 11021 11022
        goto error;
    } else if (n < 0) {
        def->vcpus = def->maxvcpus;
    } else {
        def->vcpus = count;
11023
        if (count == 0 || (unsigned short) count != count) {
11024
            virReportError(VIR_ERR_XML_ERROR,
11025
                           _("invalid current number of vCPUs '%lu'"), count);
E
Eric Blake 已提交
11026 11027
            goto error;
        }
11028 11029

        if (def->maxvcpus < count) {
11030
            virReportError(VIR_ERR_INTERNAL_ERROR,
11031 11032
                           _("maxvcpus must not be less than current vcpus "
                             "(%d < %lu)"),
11033
                           def->maxvcpus, count);
11034 11035
            goto error;
        }
E
Eric Blake 已提交
11036
    }
11037

O
Osier Yang 已提交
11038 11039 11040 11041
    tmp = virXPathString("string(./vcpu[1]/@placement)", ctxt);
    if (tmp) {
        if ((def->placement_mode =
             virDomainCpuPlacementModeTypeFromString(tmp)) < 0) {
11042 11043 11044
             virReportError(VIR_ERR_XML_ERROR,
                            _("Unsupported CPU placement mode '%s'"),
                            tmp);
O
Osier Yang 已提交
11045 11046 11047 11048
             goto error;
        }
        VIR_FREE(tmp);
    } else {
11049
        def->placement_mode = VIR_DOMAIN_CPU_PLACEMENT_MODE_STATIC;
O
Osier Yang 已提交
11050 11051
    }

11052
    if (def->placement_mode != VIR_DOMAIN_CPU_PLACEMENT_MODE_AUTO) {
11053 11054
        tmp = virXPathString("string(./vcpu[1]/@cpuset)", ctxt);
        if (tmp) {
H
Hu Tao 已提交
11055
            if (virBitmapParse(tmp, 0, &def->cpumask,
11056
                               VIR_DOMAIN_CPUMASK_LEN) < 0)
11057
                goto error;
11058
            VIR_FREE(tmp);
11059 11060 11061
        }
    }

11062 11063
    /* Extract cpu tunables. */
    if (virXPathULong("string(./cputune/shares[1])", ctxt,
11064 11065 11066 11067 11068
                      &def->cputune.shares) < -1) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("can't parse cputune shares value"));
        goto error;
    }
11069

11070
    if (virXPathULongLong("string(./cputune/period[1])", ctxt,
11071 11072 11073 11074 11075
                          &def->cputune.period) < -1) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("can't parse cputune period value"));
        goto error;
    }
11076

11077 11078 11079 11080 11081 11082 11083 11084
    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;
    }

11085
    if (virXPathLongLong("string(./cputune/quota[1])", ctxt,
11086 11087 11088 11089 11090
                         &def->cputune.quota) < -1) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("can't parse cputune quota value"));
        goto error;
    }
11091

11092 11093
    if (def->cputune.quota > 0 &&
        (def->cputune.quota < 1000 ||
E
Eric Blake 已提交
11094
         def->cputune.quota > 18446744073709551LL)) {
11095 11096 11097 11098 11099 11100
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Value of cputune quota must be in range "
                         "[1000, 18446744073709551]"));
        goto error;
    }

11101
    if (virXPathULongLong("string(./cputune/emulator_period[1])", ctxt,
11102 11103 11104 11105 11106
                          &def->cputune.emulator_period) < -1) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("can't parse cputune emulator period value"));
        goto error;
    }
11107

11108 11109 11110 11111 11112 11113 11114 11115 11116
    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;
    }

11117
    if (virXPathLongLong("string(./cputune/emulator_quota[1])", ctxt,
11118 11119 11120
                         &def->cputune.emulator_quota) < -1) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("can't parse cputune emulator quota value"));
11121 11122 11123
        goto error;
    }

11124 11125
    if (def->cputune.emulator_quota > 0 &&
        (def->cputune.emulator_quota < 1000 ||
E
Eric Blake 已提交
11126
         def->cputune.emulator_quota > 18446744073709551LL)) {
11127 11128 11129 11130 11131 11132
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Value of cputune emulator_quota must be in range "
                         "[1000, 18446744073709551]"));
        goto error;
    }

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

11136
    if (n && VIR_ALLOC_N(def->cputune.vcpupin, n) < 0)
11137
        goto error;
11138 11139

    if (n > def->maxvcpus) {
11140 11141
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("vcpupin nodes must be less than maxvcpus"));
11142 11143 11144
        goto error;
    }

11145
    for (i = 0; i < n; i++) {
E
Eric Blake 已提交
11146
        virDomainVcpuPinDefPtr vcpupin = NULL;
11147
        vcpupin = virDomainVcpuPinDefParseXML(nodes[i], ctxt, def->maxvcpus, 0);
11148 11149 11150 11151

        if (!vcpupin)
            goto error;

E
Eric Blake 已提交
11152
        if (virDomainVcpuPinIsDuplicate(def->cputune.vcpupin,
11153 11154
                                        def->cputune.nvcpupin,
                                        vcpupin->vcpuid)) {
11155 11156
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("duplicate vcpupin for same vcpu"));
11157 11158 11159 11160
            VIR_FREE(vcpupin);
            goto error;
        }

11161 11162 11163 11164 11165 11166 11167 11168 11169
        if (vcpupin->vcpuid >= def->vcpus)
            /* To avoid the regression when daemon loading
             * domain confs, we can't simply error out if
             * <vcpupin> nodes greater than current vcpus,
             * ignoring them instead.
             */
            VIR_WARN("Ignore vcpupin for not onlined vcpus");
        else
            def->cputune.vcpupin[def->cputune.nvcpupin++] = vcpupin;
11170 11171 11172
    }
    VIR_FREE(nodes);

11173 11174 11175 11176
    /* Initialize the pinning policy for vcpus which doesn't has
     * the policy specified explicitly as def->cpuset.
     */
    if (def->cpumask) {
11177
        if (VIR_REALLOC_N(def->cputune.vcpupin, def->vcpus) < 0)
11178
            goto error;
11179 11180

        for (i = 0; i < def->vcpus; i++) {
11181 11182 11183 11184
            if (virDomainVcpuPinIsDuplicate(def->cputune.vcpupin,
                                            def->cputune.nvcpupin,
                                            i))
                continue;
11185

11186
            virDomainVcpuPinDefPtr vcpupin = NULL;
11187

11188
            if (VIR_ALLOC(vcpupin) < 0)
11189 11190 11191 11192 11193 11194
                goto error;

            vcpupin->cpumask = virBitmapNew(VIR_DOMAIN_CPUMASK_LEN);
            virBitmapCopy(vcpupin->cpumask, def->cpumask);
            vcpupin->vcpuid = i;
            def->cputune.vcpupin[def->cputune.nvcpupin++] = vcpupin;
11195 11196 11197
        }
    }

T
Tang Chen 已提交
11198 11199 11200 11201 11202 11203
    if ((n = virXPathNodeSet("./cputune/emulatorpin", ctxt, &nodes)) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("cannot extract emulatorpin nodes"));
        goto error;
    }

11204 11205 11206 11207
    /* Ignore emulatorpin if <vcpu> placement is "auto", they
     * conflicts with each other, and <vcpu> placement can't be
     * simply ignored, as <numatune>'s placement defaults to it.
     */
T
Tang Chen 已提交
11208
    if (n) {
11209 11210 11211 11212 11213 11214 11215
        if (def->placement_mode != VIR_DOMAIN_CPU_PLACEMENT_MODE_AUTO) {
            if (n > 1) {
                virReportError(VIR_ERR_XML_ERROR, "%s",
                               _("only one emulatorpin is supported"));
                VIR_FREE(nodes);
                goto error;
            }
T
Tang Chen 已提交
11216

11217 11218
            def->cputune.emulatorpin = virDomainVcpuPinDefParseXML(nodes[0], ctxt,
                                                                   def->maxvcpus, 1);
T
Tang Chen 已提交
11219

11220 11221 11222 11223 11224
            if (!def->cputune.emulatorpin)
                goto error;
        } else {
            VIR_WARN("Ignore emulatorpin for <vcpu> placement is 'auto'");
        }
T
Tang Chen 已提交
11225 11226 11227
    }
    VIR_FREE(nodes);

11228
    /* Extract numatune if exists. */
O
Osier Yang 已提交
11229
    if ((n = virXPathNodeSet("./numatune", ctxt, &nodes)) < 0) {
11230 11231
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("cannot extract numatune nodes"));
11232 11233 11234
        goto error;
    }

O
Osier Yang 已提交
11235
    if (n > 1) {
11236 11237
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("only one numatune is supported"));
O
Osier Yang 已提交
11238 11239 11240 11241
        VIR_FREE(nodes);
        goto error;
    }

11242
    if (n) {
O
Osier Yang 已提交
11243 11244 11245
        cur = nodes[0]->children;
        while (cur != NULL) {
            if (cur->type == XML_ELEMENT_NODE) {
E
Eric Blake 已提交
11246
                if (xmlStrEqual(cur->name, BAD_CAST "memory")) {
11247 11248 11249
                    char *mode = NULL;
                    char *placement = NULL;
                    char *nodeset = NULL;
11250

11251 11252 11253 11254
                    mode = virXMLPropString(cur, "mode");
                    if (mode) {
                        if ((def->numatune.memory.mode =
                             virDomainNumatuneMemModeTypeFromString(mode)) < 0) {
11255 11256 11257 11258
                            virReportError(VIR_ERR_XML_ERROR,
                                           _("Unsupported NUMA memory "
                                             "tuning mode '%s'"),
                                           mode);
11259 11260 11261 11262 11263 11264 11265 11266 11267 11268
                            VIR_FREE(mode);
                            goto error;
                        }
                        VIR_FREE(mode);
                    } else {
                        def->numatune.memory.mode = VIR_DOMAIN_NUMATUNE_MEM_STRICT;
                    }

                    nodeset = virXMLPropString(cur, "nodeset");
                    if (nodeset) {
11269 11270 11271 11272
                        if (virBitmapParse(nodeset,
                                           0,
                                           &def->numatune.memory.nodemask,
                                           VIR_DOMAIN_CPUMASK_LEN) < 0) {
11273
                            VIR_FREE(nodeset);
O
Osier Yang 已提交
11274
                            goto error;
11275 11276
                        }
                        VIR_FREE(nodeset);
O
Osier Yang 已提交
11277 11278
                    }

11279 11280 11281 11282
                    placement = virXMLPropString(cur, "placement");
                    int placement_mode = 0;
                    if (placement) {
                        if ((placement_mode =
G
Gao feng 已提交
11283
                             virNumaTuneMemPlacementModeTypeFromString(placement)) < 0) {
11284 11285 11286
                            virReportError(VIR_ERR_XML_ERROR,
                                           _("Unsupported memory placement "
                                             "mode '%s'"), placement);
11287
                            VIR_FREE(placement);
O
Osier Yang 已提交
11288 11289
                            goto error;
                        }
11290 11291 11292
                        VIR_FREE(placement);
                    } else if (def->numatune.memory.nodemask) {
                        /* Defaults to "static" if nodeset is specified. */
G
Gao feng 已提交
11293
                        placement_mode = VIR_NUMA_TUNE_MEM_PLACEMENT_MODE_STATIC;
O
Osier Yang 已提交
11294
                    } else {
11295 11296 11297 11298
                        /* Defaults to "placement" of <vcpu> if nodeset is
                         * not specified.
                         */
                        if (def->placement_mode == VIR_DOMAIN_CPU_PLACEMENT_MODE_STATIC)
G
Gao feng 已提交
11299
                            placement_mode = VIR_NUMA_TUNE_MEM_PLACEMENT_MODE_STATIC;
11300
                        else
G
Gao feng 已提交
11301
                            placement_mode = VIR_NUMA_TUNE_MEM_PLACEMENT_MODE_AUTO;
O
Osier Yang 已提交
11302
                    }
11303

G
Gao feng 已提交
11304
                    if (placement_mode == VIR_NUMA_TUNE_MEM_PLACEMENT_MODE_STATIC &&
11305
                        !def->numatune.memory.nodemask) {
11306 11307 11308
                        virReportError(VIR_ERR_XML_ERROR, "%s",
                                       _("nodeset for NUMA memory tuning must be set "
                                         "if 'placement' is 'static'"));
11309 11310 11311 11312
                        goto error;
                    }

                    /* Ignore 'nodeset' if 'placement' is 'auto' finally */
11313
                    if (placement_mode == VIR_NUMA_TUNE_MEM_PLACEMENT_MODE_AUTO) {
11314
                        virBitmapFree(def->numatune.memory.nodemask);
11315 11316
                        def->numatune.memory.nodemask = NULL;
                    }
11317

11318 11319 11320
                    /* Copy 'placement' of <numatune> to <vcpu> if its 'placement'
                     * is not specified and 'placement' of <numatune> is specified.
                     */
G
Gao feng 已提交
11321
                    if (placement_mode == VIR_NUMA_TUNE_MEM_PLACEMENT_MODE_AUTO &&
11322 11323 11324
                        !def->cpumask)
                        def->placement_mode = VIR_DOMAIN_CPU_PLACEMENT_MODE_AUTO;

11325
                    def->numatune.memory.placement_mode = placement_mode;
O
Osier Yang 已提交
11326
                } else {
11327 11328 11329
                    virReportError(VIR_ERR_XML_ERROR,
                                   _("unsupported XML element %s"),
                                   (const char *)cur->name);
O
Osier Yang 已提交
11330 11331
                    goto error;
                }
11332
            }
O
Osier Yang 已提交
11333
            cur = cur->next;
11334
        }
11335 11336 11337 11338 11339
    } else {
        /* Defaults NUMA memory placement mode to 'auto' if no <numatune>
         * and 'placement' of <vcpu> is 'auto'.
         */
        if (def->placement_mode == VIR_DOMAIN_CPU_PLACEMENT_MODE_AUTO) {
G
Gao feng 已提交
11340
            def->numatune.memory.placement_mode = VIR_NUMA_TUNE_MEM_PLACEMENT_MODE_AUTO;
11341 11342
            def->numatune.memory.mode = VIR_DOMAIN_NUMATUNE_MEM_STRICT;
        }
11343
    }
O
Osier Yang 已提交
11344
    VIR_FREE(nodes);
11345

11346 11347 11348 11349 11350 11351 11352 11353 11354 11355 11356 11357 11358 11359 11360 11361 11362
    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);

11363
    if ((n = virXPathNodeSet("./features/*", ctxt, &nodes)) < 0)
11364
        goto error;
11365

11366
    for (i = 0; i < n; i++) {
11367 11368 11369 11370 11371 11372 11373 11374 11375 11376 11377 11378 11379 11380 11381 11382 11383
        int val = virDomainFeatureTypeFromString((const char *)nodes[i]->name);
        if (val < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected feature %s"),
                           nodes[i]->name);
            goto error;
        }
        def->features |= (1 << val);
        if (val == VIR_DOMAIN_FEATURE_APIC) {
            tmp = virXPathString("string(./features/apic/@eoi)", ctxt);
            if (tmp) {
                int eoi;
                if ((eoi = virDomainFeatureStateTypeFromString(tmp)) <= 0) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("unknown value for attribute eoi: %s"),
                                   tmp);
                    goto error;
11384
                }
11385 11386
                def->apic_eoi = eoi;
                VIR_FREE(tmp);
11387
            }
11388 11389
        }
    }
11390
    VIR_FREE(nodes);
11391

11392 11393 11394 11395 11396 11397 11398 11399 11400 11401 11402 11403 11404 11405 11406 11407 11408 11409 11410 11411
    if (def->features & (1 << VIR_DOMAIN_FEATURE_HYPERV)) {
        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) {
                virReportError(VIR_ERR_XML_ERROR,
                               _("unsupported HyperV Enlightenment feature: %s"),
                               nodes[i]->name);
                goto error;
            }

            ctxt->node = nodes[i];

            switch ((enum virDomainHyperv) feature) {
                case VIR_DOMAIN_HYPERV_RELAXED:
11412
                case VIR_DOMAIN_HYPERV_VAPIC:
11413 11414 11415 11416 11417 11418 11419 11420 11421 11422 11423 11424 11425 11426 11427 11428
                    if (!(tmp = virXPathString("string(./@state)", ctxt))) {
                        virReportError(VIR_ERR_XML_ERROR,
                                       _("missing 'state' attribute for "
                                         "HyperV Enlightenment feature '%s'"),
                                       nodes[i]->name);
                        goto error;
                    }

                    if ((value = virDomainFeatureStateTypeFromString(tmp)) < 0) {
                        virReportError(VIR_ERR_XML_ERROR,
                                       _("invalid value of state argument "
                                         "for HyperV Enlightenment feature '%s'"),
                                       nodes[i]->name);
                        goto error;
                    }

11429
                    VIR_FREE(tmp);
11430 11431 11432
                    def->hyperv_features[feature] = value;
                    break;

11433 11434 11435 11436 11437 11438 11439 11440 11441 11442 11443 11444 11445 11446 11447 11448 11449 11450
                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;
                    }

                    if ((value = virDomainFeatureStateTypeFromString(tmp)) < 0) {
                        virReportError(VIR_ERR_XML_ERROR,
                                       _("invalid value of state argument "
                                         "for HyperV Enlightenment feature '%s'"),
                                       nodes[i]->name);
                        goto error;
                    }

                    VIR_FREE(tmp);
11451 11452 11453 11454 11455 11456 11457
                    if (value == VIR_DOMAIN_FEATURE_STATE_ON) {
                        if (virXPathUInt("string(./@retries)", ctxt,
                                     &def->hyperv_spinlocks) < 0) {
                            virReportError(VIR_ERR_XML_ERROR, "%s",
                                           _("invalid HyperV spinlock retry count"));
                            goto error;
                        }
11458

11459 11460 11461 11462 11463 11464
                        if (def->hyperv_spinlocks < 0xFFF) {
                            virReportError(VIR_ERR_XML_ERROR, "%s",
                                           _("HyperV spinlock retry count must be "
                                             "at least 4095"));
                            goto error;
                        }
11465 11466 11467 11468
                    }
                    def->hyperv_features[feature] = value;
                    break;

11469 11470 11471 11472 11473 11474 11475 11476
                case VIR_DOMAIN_HYPERV_LAST:
                    break;
            }
        }
        VIR_FREE(nodes);
        ctxt->node = node;
    }

11477 11478 11479 11480 11481
    if (virDomainEventActionParseXML(ctxt, "on_reboot",
                                     "string(./on_reboot[1])",
                                     &def->onReboot,
                                     VIR_DOMAIN_LIFECYCLE_RESTART,
                                     virDomainLifecycleTypeFromString) < 0)
11482 11483
        goto error;

11484 11485 11486 11487 11488
    if (virDomainEventActionParseXML(ctxt, "on_poweroff",
                                     "string(./on_poweroff[1])",
                                     &def->onPoweroff,
                                     VIR_DOMAIN_LIFECYCLE_DESTROY,
                                     virDomainLifecycleTypeFromString) < 0)
11489 11490
        goto error;

11491 11492 11493 11494 11495
    if (virDomainEventActionParseXML(ctxt, "on_crash",
                                     "string(./on_crash[1])",
                                     &def->onCrash,
                                     VIR_DOMAIN_LIFECYCLE_CRASH_DESTROY,
                                     virDomainLifecycleCrashTypeFromString) < 0)
11496 11497
        goto error;

11498 11499 11500 11501 11502 11503 11504
    if (virDomainEventActionParseXML(ctxt, "on_lockfailure",
                                     "string(./on_lockfailure[1])",
                                     &def->onLockFailure,
                                     VIR_DOMAIN_LOCK_FAILURE_DEFAULT,
                                     virDomainLockFailureTypeFromString) < 0)
        goto error;

11505 11506 11507 11508 11509 11510 11511 11512 11513 11514
    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;

11515 11516 11517 11518 11519
    if ((tmp = virXPathString("string(./clock/@offset)", ctxt)) &&
        (def->clock.offset = virDomainClockOffsetTypeFromString(tmp)) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown clock offset '%s'"), tmp);
        goto error;
11520
    }
11521 11522
    VIR_FREE(tmp);

11523
    switch (def->clock.offset) {
11524 11525 11526 11527 11528 11529 11530
    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 {
11531 11532
                if (virStrToLong_ll(tmp, NULL, 10,
                                    &def->clock.data.variable.adjustment) < 0) {
11533 11534 11535
                    virReportError(VIR_ERR_XML_ERROR,
                                   _("unknown clock adjustment '%s'"),
                                   tmp);
11536 11537 11538 11539 11540 11541 11542 11543 11544 11545 11546 11547 11548 11549 11550 11551 11552 11553
                    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;

11554 11555
    case VIR_DOMAIN_CLOCK_OFFSET_VARIABLE:
        if (virXPathLongLong("number(./clock/@adjustment)", ctxt,
11556 11557 11558 11559 11560
                             &def->clock.data.variable.adjustment) < 0)
            def->clock.data.variable.adjustment = 0;
        tmp = virXPathString("string(./clock/@basis)", ctxt);
        if (tmp) {
            if ((def->clock.data.variable.basis = virDomainClockBasisTypeFromString(tmp)) < 0) {
11561 11562
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unknown clock basis '%s'"), tmp);
11563 11564 11565 11566 11567 11568
                goto error;
            }
            VIR_FREE(tmp);
        } else {
            def->clock.data.variable.basis = VIR_DOMAIN_CLOCK_BASIS_UTC;
        }
11569 11570 11571 11572 11573
        break;

    case VIR_DOMAIN_CLOCK_OFFSET_TIMEZONE:
        def->clock.data.timezone = virXPathString("string(./clock/@timezone)", ctxt);
        if (!def->clock.data.timezone) {
11574 11575
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("missing 'timezone' attribute for clock with offset='timezone'"));
11576 11577
            goto error;
        }
11578 11579
        break;
    }
11580

11581 11582 11583 11584 11585 11586 11587 11588 11589 11590
    if (def->clock.offset == VIR_DOMAIN_CLOCK_OFFSET_VARIABLE &&
        flags & VIR_DOMAIN_XML_INTERNAL_BASEDATE) {
        if (virXPathULongLong("number(./clock/@basedate)", ctxt,
                              &def->clock.data.variable.basedate) < 0) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("invalid basedate"));
            goto error;
        }
    }

11591
    if ((n = virXPathNodeSet("./clock/timer", ctxt, &nodes)) < 0)
11592
        goto error;
11593

11594
    if (n && VIR_ALLOC_N(def->clock.timers, n) < 0)
11595
        goto error;
11596

11597
    for (i = 0; i < n; i++) {
11598
        virDomainTimerDefPtr timer = virDomainTimerDefParseXML(nodes[i],
E
Eric Blake 已提交
11599
                                                               ctxt);
11600 11601 11602 11603 11604 11605 11606
        if (!timer)
            goto error;

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

11607 11608
    def->os.bootloader = virXPathString("string(./bootloader)", ctxt);
    def->os.bootloaderArgs = virXPathString("string(./bootloader_args)", ctxt);
11609

11610
    def->os.type = virXPathString("string(./os/type[1])", ctxt);
11611 11612
    if (!def->os.type) {
        if (def->os.bootloader) {
11613 11614
            if (VIR_STRDUP(def->os.type, "xen") < 0)
                goto error;
11615
        } else {
11616 11617
            virReportError(VIR_ERR_OS_TYPE,
                           "%s", _("no OS type"));
11618 11619 11620 11621 11622 11623 11624 11625 11626 11627 11628
            goto error;
        }
    }
    /*
     * HACK: For xen driver we previously used bogus 'linux' as the
     * os type for paravirt, whereas capabilities declare it to
     * be 'xen'. So we accept the former and convert
     */
    if (STREQ(def->os.type, "linux") &&
        def->virtType == VIR_DOMAIN_VIRT_XEN) {
        VIR_FREE(def->os.type);
11629 11630
        if (VIR_STRDUP(def->os.type, "xen") < 0)
            goto error;
11631 11632 11633
    }

    if (!virCapabilitiesSupportsGuestOSType(caps, def->os.type)) {
11634 11635
        virReportError(VIR_ERR_OS_TYPE,
                       "%s", def->os.type);
11636 11637 11638
        goto error;
    }

11639 11640
    tmp = virXPathString("string(./os/type[1]/@arch)", ctxt);
    if (tmp) {
11641 11642
        def->os.arch = virArchFromString(tmp);
        if (!def->os.arch) {
11643 11644 11645 11646 11647 11648 11649
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unknown architecture %s"),
                           tmp);
            goto error;
        }
        VIR_FREE(tmp);

11650
        if (!virCapabilitiesSupportsGuestArch(caps, def->os.arch)) {
11651 11652
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("No guest options available for arch '%s'"),
11653
                           virArchToString(def->os.arch));
11654 11655 11656 11657 11658 11659
            goto error;
        }

        if (!virCapabilitiesSupportsGuestOSTypeArch(caps,
                                                    def->os.type,
                                                    def->os.arch)) {
11660 11661
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("No os type '%s' available for arch '%s'"),
11662
                           def->os.type, virArchToString(def->os.arch));
11663 11664 11665
            goto error;
        }
    } else {
11666 11667 11668 11669 11670
        def->os.arch =
            virCapabilitiesDefaultGuestArch(caps,
                                            def->os.type,
                                            virDomainVirtTypeToString(def->virtType));
        if (!def->os.arch) {
11671 11672 11673
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("no supported architecture for os type '%s'"),
                           def->os.type);
11674 11675 11676 11677
            goto error;
        }
    }

11678
    def->os.machine = virXPathString("string(./os/type[1]/@machine)", ctxt);
11679 11680 11681
    if (!def->os.machine) {
        const char *defaultMachine = virCapabilitiesDefaultGuestMachine(caps,
                                                                        def->os.type,
11682 11683
                                                                        def->os.arch,
                                                                        virDomainVirtTypeToString(def->virtType));
11684 11685
        if (VIR_STRDUP(def->os.machine, defaultMachine) < 0)
            goto error;
11686 11687
    }

11688 11689 11690 11691 11692 11693 11694 11695 11696 11697
    /*
     * Booting options for different OS types....
     *
     *   - A bootloader (and optional kernel+initrd)  (xen)
     *   - A kernel + initrd                          (xen)
     *   - A boot device (and optional kernel+initrd) (hvm)
     *   - An init script                             (exe)
     */

    if (STREQ(def->os.type, "exe")) {
11698
        def->os.init = virXPathString("string(./os/init[1])", ctxt);
11699
        def->os.cmdline = virXPathString("string(./os/cmdline[1])", ctxt);
11700 11701 11702 11703 11704 11705

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

        if (VIR_ALLOC_N(def->os.initargv, n+1) < 0)
11706
            goto error;
11707
        for (i = 0; i < n; i++) {
11708 11709
            if (!nodes[i]->children ||
                !nodes[i]->children->content) {
11710 11711
                virReportError(VIR_ERR_XML_ERROR, "%s",
                               _("No data supplied for <initarg> element"));
11712 11713
                goto error;
            }
11714 11715 11716
            if (VIR_STRDUP(def->os.initargv[i],
                           (const char*) nodes[i]->children->content) < 0)
                goto error;
11717 11718 11719
        }
        def->os.initargv[n] = NULL;
        VIR_FREE(nodes);
11720 11721 11722
    }

    if (STREQ(def->os.type, "xen") ||
11723 11724
        STREQ(def->os.type, "hvm") ||
        STREQ(def->os.type, "uml")) {
11725 11726 11727
        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);
11728
        def->os.dtb = virXPathString("string(./os/dtb[1])", ctxt);
11729 11730
        def->os.root = virXPathString("string(./os/root[1])", ctxt);
        def->os.loader = virXPathString("string(./os/loader[1])", ctxt);
11731
    }
11732

11733
    if (STREQ(def->os.type, "hvm")) {
11734 11735 11736
        if (virDomainDefParseBootXML(ctxt, def) < 0)
            goto error;
        if (!(bootHash = virHashCreate(5, NULL)))
11737
            goto error;
11738 11739
    }

11740
    def->emulator = virXPathString("string(./devices/emulator[1])", ctxt);
11741 11742

    /* analysis of the disk devices */
11743
    if ((n = virXPathNodeSet("./devices/disk", ctxt, &nodes)) < 0)
11744
        goto error;
11745

11746
    if (n && VIR_ALLOC_N(def->disks, n) < 0)
11747
        goto error;
11748

11749
    for (i = 0; i < n; i++) {
11750
        virDomainDiskDefPtr disk = virDomainDiskDefParseXML(xmlopt,
11751
                                                            nodes[i],
L
Lei Li 已提交
11752
                                                            ctxt,
11753
                                                            bootHash,
11754 11755
                                                            def->seclabels,
                                                            def->nseclabels,
11756
                                                            flags);
11757 11758 11759
        if (!disk)
            goto error;

11760
        virDomainDiskInsertPreAlloced(def, disk);
11761 11762 11763
    }
    VIR_FREE(nodes);

11764
    /* analysis of the controller devices */
11765
    if ((n = virXPathNodeSet("./devices/controller", ctxt, &nodes)) < 0)
11766
        goto error;
11767

11768
    if (n && VIR_ALLOC_N(def->controllers, n) < 0)
11769
        goto error;
11770

11771
    for (i = 0; i < n; i++) {
11772
        virDomainControllerDefPtr controller = virDomainControllerDefParseXML(nodes[i],
11773
                                                                              ctxt,
11774 11775 11776 11777
                                                                              flags);
        if (!controller)
            goto error;

11778 11779 11780 11781
        /* 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) {
11782
                    virDomainControllerDefFree(controller);
11783 11784 11785 11786 11787 11788 11789 11790
                    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) {
11791
                    virDomainControllerDefFree(controller);
11792 11793 11794 11795 11796 11797 11798
                    virReportError(VIR_ERR_XML_DETAIL, "%s",
                                   _("Can't add another USB controller: "
                                     "USB is disabled for this domain"));
                    goto error;
                }
                usb_other = true;
            }
11799 11800 11801

            if (controller->info.mastertype == VIR_DOMAIN_CONTROLLER_MASTER_NONE)
                usb_master = true;
11802 11803
        }

11804
        virDomainControllerInsertPreAlloced(def, controller);
11805 11806 11807
    }
    VIR_FREE(nodes);

11808 11809 11810 11811 11812 11813
    if (usb_other && !usb_master) {
        virReportError(VIR_ERR_XML_DETAIL, "%s",
                       _("No master USB controller specified"));
        goto error;
    }

11814 11815
    /* analysis of the resource leases */
    if ((n = virXPathNodeSet("./devices/lease", ctxt, &nodes)) < 0) {
11816 11817
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("cannot extract device leases"));
11818 11819 11820
        goto error;
    }
    if (n && VIR_ALLOC_N(def->leases, n) < 0)
11821
        goto error;
11822
    for (i = 0; i < n; i++) {
11823 11824 11825 11826 11827 11828 11829 11830
        virDomainLeaseDefPtr lease = virDomainLeaseDefParseXML(nodes[i]);
        if (!lease)
            goto error;

        def->leases[def->nleases++] = lease;
    }
    VIR_FREE(nodes);

11831
    /* analysis of the filesystems */
11832
    if ((n = virXPathNodeSet("./devices/filesystem", ctxt, &nodes)) < 0) {
11833 11834
        goto error;
    }
11835
    if (n && VIR_ALLOC_N(def->fss, n) < 0)
11836
        goto error;
11837
    for (i = 0; i < n; i++) {
11838
        virDomainFSDefPtr fs = virDomainFSDefParseXML(nodes[i], ctxt,
11839
                                                      flags);
11840 11841 11842
        if (!fs)
            goto error;

11843
        def->fss[def->nfss++] = fs;
11844 11845 11846
    }
    VIR_FREE(nodes);

11847
    /* analysis of the network devices */
11848
    if ((n = virXPathNodeSet("./devices/interface", ctxt, &nodes)) < 0) {
11849 11850
        goto error;
    }
11851
    if (n && VIR_ALLOC_N(def->nets, n) < 0)
11852
        goto error;
11853
    for (i = 0; i < n; i++) {
11854
        virDomainNetDefPtr net = virDomainNetDefParseXML(xmlopt,
11855
                                                         nodes[i],
11856
                                                         ctxt,
11857
                                                         bootHash,
11858
                                                         flags);
11859 11860 11861
        if (!net)
            goto error;

11862
        def->nets[def->nnets++] = net;
11863 11864

        /* <interface type='hostdev'> must also be in the hostdevs array */
E
Eric Blake 已提交
11865 11866
        if (net->type == VIR_DOMAIN_NET_TYPE_HOSTDEV &&
            virDomainHostdevInsert(def, &net->data.hostdev.def) < 0) {
11867
            goto error;
11868
        }
11869 11870 11871 11872
    }
    VIR_FREE(nodes);


E
Eric Blake 已提交
11873 11874 11875 11876 11877
    /* analysis of the smartcard devices */
    if ((n = virXPathNodeSet("./devices/smartcard", ctxt, &nodes)) < 0) {
        goto error;
    }
    if (n && VIR_ALLOC_N(def->smartcards, n) < 0)
11878
        goto error;
E
Eric Blake 已提交
11879

11880
    for (i = 0; i < n; i++) {
E
Eric Blake 已提交
11881 11882 11883 11884 11885 11886 11887 11888 11889 11890
        virDomainSmartcardDefPtr card = virDomainSmartcardDefParseXML(nodes[i],
                                                                      flags);
        if (!card)
            goto error;

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


11891
    /* analysis of the character devices */
11892
    if ((n = virXPathNodeSet("./devices/parallel", ctxt, &nodes)) < 0) {
11893 11894
        goto error;
    }
11895
    if (n && VIR_ALLOC_N(def->parallels, n) < 0)
11896
        goto error;
11897

11898
    for (i = 0; i < n; i++) {
11899
        virDomainChrDefPtr chr = virDomainChrDefParseXML(ctxt,
11900
                                                         nodes[i],
11901 11902
                                                         def->seclabels,
                                                         def->nseclabels,
11903
                                                         flags);
11904 11905 11906
        if (!chr)
            goto error;

11907 11908
        if (chr->target.port == -1) {
            int maxport = -1;
11909
            size_t j;
11910
            for (j = 0; j < i; j++) {
11911 11912 11913 11914 11915
                if (def->parallels[j]->target.port > maxport)
                    maxport = def->parallels[j]->target.port;
            }
            chr->target.port = maxport + 1;
        }
11916
        def->parallels[def->nparallels++] = chr;
11917 11918 11919
    }
    VIR_FREE(nodes);

11920
    if ((n = virXPathNodeSet("./devices/serial", ctxt, &nodes)) < 0)
11921
        goto error;
11922

11923
    if (n && VIR_ALLOC_N(def->serials, n) < 0)
11924
        goto error;
11925

11926
    for (i = 0; i < n; i++) {
11927
        virDomainChrDefPtr chr = virDomainChrDefParseXML(ctxt,
11928
                                                         nodes[i],
11929 11930
                                                         def->seclabels,
                                                         def->nseclabels,
11931
                                                         flags);
11932 11933 11934
        if (!chr)
            goto error;

11935 11936
        if (chr->target.port == -1) {
            int maxport = -1;
11937
            size_t j;
11938
            for (j = 0; j < i; j++) {
11939 11940 11941 11942 11943
                if (def->serials[j]->target.port > maxport)
                    maxport = def->serials[j]->target.port;
            }
            chr->target.port = maxport + 1;
        }
11944
        def->serials[def->nserials++] = chr;
11945 11946 11947
    }
    VIR_FREE(nodes);

11948
    if ((n = virXPathNodeSet("./devices/console", ctxt, &nodes)) < 0) {
11949 11950
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("cannot extract console devices"));
11951 11952 11953
        goto error;
    }
    if (n && VIR_ALLOC_N(def->consoles, n) < 0)
11954
        goto error;
11955

11956
    for (i = 0; i < n; i++) {
11957
        virDomainChrDefPtr chr = virDomainChrDefParseXML(ctxt,
11958
                                                         nodes[i],
11959 11960
                                                         def->seclabels,
                                                         def->nseclabels,
11961
                                                         flags);
11962 11963
        if (!chr)
            goto error;
11964

11965 11966
        chr->target.port = i;
        def->consoles[def->nconsoles++] = chr;
11967
    }
11968
    VIR_FREE(nodes);
11969

11970
    if ((n = virXPathNodeSet("./devices/channel", ctxt, &nodes)) < 0) {
11971 11972 11973
        goto error;
    }
    if (n && VIR_ALLOC_N(def->channels, n) < 0)
11974
        goto error;
11975

11976
    for (i = 0; i < n; i++) {
11977
        virDomainChrDefPtr chr = virDomainChrDefParseXML(ctxt,
11978
                                                         nodes[i],
11979 11980
                                                         def->seclabels,
                                                         def->nseclabels,
11981 11982 11983 11984 11985
                                                         flags);
        if (!chr)
            goto error;

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

11987 11988
        if (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL &&
            chr->targetType == VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO &&
11989 11990 11991
            chr->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
            chr->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL;

11992 11993
        if (chr->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL &&
            chr->info.addr.vioserial.port == 0) {
11994
            int maxport = 0;
11995
            size_t j;
11996
            for (j = 0; j < i; j++) {
11997 11998 11999 12000 12001 12002 12003 12004 12005
                virDomainChrDefPtr thischr = def->channels[j];
                if (thischr->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL &&
                    thischr->info.addr.vioserial.controller == chr->info.addr.vioserial.controller &&
                    thischr->info.addr.vioserial.bus == chr->info.addr.vioserial.bus &&
                    (int)thischr->info.addr.vioserial.port > maxport)
                    maxport = thischr->info.addr.vioserial.port;
            }
            chr->info.addr.vioserial.port = maxport + 1;
        }
12006 12007 12008
    }
    VIR_FREE(nodes);

12009 12010

    /* analysis of the input devices */
12011
    if ((n = virXPathNodeSet("./devices/input", ctxt, &nodes)) < 0) {
12012 12013
        goto error;
    }
12014
    if (n && VIR_ALLOC_N(def->inputs, n) < 0)
12015
        goto error;
12016

12017
    for (i = 0; i < n; i++) {
12018
        virDomainInputDefPtr input = virDomainInputDefParseXML(def->os.type,
12019 12020
                                                               nodes[i],
                                                               flags);
12021 12022 12023
        if (!input)
            goto error;

12024 12025
        /* Check if USB bus is required */
        if (input->bus == VIR_DOMAIN_INPUT_BUS_USB && usb_none) {
12026
            virDomainInputDefFree(input);
12027 12028 12029 12030 12031
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("Can't add USB input device. "
                             "USB bus is disabled"));
            goto error;
        }
12032 12033 12034 12035 12036 12037 12038 12039 12040 12041 12042 12043 12044 12045

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

12046
        def->inputs[def->ninputs++] = input;
12047 12048 12049
    }
    VIR_FREE(nodes);

12050
    /* analysis of the graphics devices */
12051
    if ((n = virXPathNodeSet("./devices/graphics", ctxt, &nodes)) < 0) {
12052 12053
        goto error;
    }
12054
    if (n && VIR_ALLOC_N(def->graphics, n) < 0)
12055
        goto error;
12056
    for (i = 0; i < n; i++) {
12057
        virDomainGraphicsDefPtr graphics = virDomainGraphicsDefParseXML(nodes[i],
12058
                                                                        ctxt,
12059
                                                                        flags);
12060 12061 12062
        if (!graphics)
            goto error;

12063
        def->graphics[def->ngraphics++] = graphics;
12064 12065 12066 12067
    }
    VIR_FREE(nodes);

    /* If graphics are enabled, there's an implicit PS2 mouse */
12068
    if (def->ngraphics > 0) {
12069 12070 12071
        virDomainInputDefPtr input;

        if (VIR_ALLOC(input) < 0) {
12072
            goto error;
12073 12074 12075 12076 12077 12078 12079 12080
        }
        if (STREQ(def->os.type, "hvm")) {
            input->type = VIR_DOMAIN_INPUT_TYPE_MOUSE;
            input->bus = VIR_DOMAIN_INPUT_BUS_PS2;
        } else {
            input->type = VIR_DOMAIN_INPUT_TYPE_MOUSE;
            input->bus = VIR_DOMAIN_INPUT_BUS_XEN;
        }
12081 12082 12083

        if (VIR_REALLOC_N(def->inputs, def->ninputs + 1) < 0) {
            virDomainInputDefFree(input);
12084
            goto error;
12085 12086 12087
        }
        def->inputs[def->ninputs] = input;
        def->ninputs++;
12088 12089 12090 12091
    }


    /* analysis of the sound devices */
12092
    if ((n = virXPathNodeSet("./devices/sound", ctxt, &nodes)) < 0) {
12093 12094
        goto error;
    }
12095
    if (n && VIR_ALLOC_N(def->sounds, n) < 0)
12096
        goto error;
12097
    for (i = 0; i < n; i++) {
12098
        virDomainSoundDefPtr sound = virDomainSoundDefParseXML(nodes[i],
12099
                                                               ctxt,
12100
                                                               flags);
12101 12102 12103
        if (!sound)
            goto error;

12104
        def->sounds[def->nsounds++] = sound;
12105 12106 12107
    }
    VIR_FREE(nodes);

12108
    /* analysis of the video devices */
12109
    if ((n = virXPathNodeSet("./devices/video", ctxt, &nodes)) < 0) {
12110 12111 12112
        goto error;
    }
    if (n && VIR_ALLOC_N(def->videos, n) < 0)
12113
        goto error;
12114
    for (i = 0; i < n; i++) {
12115 12116
        size_t j = def->nvideos;
        virDomainVideoDefPtr video = virDomainVideoDefParseXML(nodes[j],
12117 12118 12119 12120
                                                               def,
                                                               flags);
        if (!video)
            goto error;
12121 12122 12123

        if (video->primary) {
            if (primaryVideo) {
12124
                virDomainVideoDefFree(video);
12125 12126 12127 12128 12129
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                               _("Only one primary video device is supported"));
                goto error;
            }

12130
            j = 0;
12131 12132
            primaryVideo = true;
        }
12133
        if (VIR_INSERT_ELEMENT_INPLACE(def->videos,
12134
                                       j,
12135 12136
                                       def->nvideos,
                                       video) < 0) {
12137
            virDomainVideoDefFree(video);
12138
            goto error;
12139
        }
12140 12141 12142
    }
    VIR_FREE(nodes);

12143
    /* For backwards compatibility, if no <video> tag is set but there
12144 12145 12146 12147
     * is a <graphics> tag, then we add a single video tag */
    if (def->ngraphics && !def->nvideos) {
        virDomainVideoDefPtr video;
        if (VIR_ALLOC(video) < 0)
12148
            goto error;
12149 12150
        video->type = virDomainVideoDefaultType(def);
        if (video->type < 0) {
12151 12152
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("cannot determine default video type"));
12153 12154 12155 12156 12157 12158 12159
            VIR_FREE(video);
            goto error;
        }
        video->vram = virDomainVideoDefaultRAM(def, video->type);
        video->heads = 1;
        if (VIR_ALLOC_N(def->videos, 1) < 0) {
            virDomainVideoDefFree(video);
12160
            goto error;
12161 12162 12163 12164
        }
        def->videos[def->nvideos++] = video;
    }

12165
    /* analysis of the host devices */
12166
    if ((n = virXPathNodeSet("./devices/hostdev", ctxt, &nodes)) < 0) {
12167 12168
        goto error;
    }
12169
    if (n && VIR_REALLOC_N(def->hostdevs, def->nhostdevs + n) < 0)
12170
        goto error;
12171
    for (i = 0; i < n; i++) {
12172 12173
        virDomainHostdevDefPtr hostdev;

12174 12175
        hostdev = virDomainHostdevDefParseXML(xmlopt, def, nodes[i],
                                              ctxt, bootHash, flags);
12176 12177 12178
        if (!hostdev)
            goto error;

12179 12180 12181 12182 12183 12184 12185 12186
        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"));
            goto error;
        }

12187
        def->hostdevs[def->nhostdevs++] = hostdev;
12188 12189 12190

        if (virDomainDefMaybeAddHostdevSCSIcontroller(def) < 0)
            goto error;
12191 12192 12193
    }
    VIR_FREE(nodes);

R
Richard Jones 已提交
12194 12195
    /* analysis of the watchdog devices */
    def->watchdog = NULL;
12196
    if ((n = virXPathNodeSet("./devices/watchdog", ctxt, &nodes)) < 0) {
R
Richard Jones 已提交
12197 12198 12199
        goto error;
    }
    if (n > 1) {
12200 12201
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("only a single watchdog device is supported"));
R
Richard Jones 已提交
12202 12203 12204 12205
        goto error;
    }
    if (n > 0) {
        virDomainWatchdogDefPtr watchdog =
12206
            virDomainWatchdogDefParseXML(nodes[0], flags);
R
Richard Jones 已提交
12207 12208 12209 12210 12211 12212 12213
        if (!watchdog)
            goto error;

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

12214 12215 12216 12217 12218 12219
    /* analysis of the memballoon devices */
    def->memballoon = NULL;
    if ((n = virXPathNodeSet("./devices/memballoon", ctxt, &nodes)) < 0) {
        goto error;
    }
    if (n > 1) {
12220 12221
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("only a single memory balloon device is supported"));
12222 12223 12224 12225
        goto error;
    }
    if (n > 0) {
        virDomainMemballoonDefPtr memballoon =
12226
            virDomainMemballoonDefParseXML(nodes[0], ctxt, flags);
12227 12228 12229 12230 12231 12232 12233
        if (!memballoon)
            goto error;

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

12234 12235 12236 12237 12238 12239 12240 12241 12242 12243 12244 12245 12246 12247 12248
    /* Parse the RNG device */
    if ((n = virXPathNodeSet("./devices/rng", ctxt, &nodes)) < 0)
        goto error;

    if (n > 1) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("only a single RNG device is supported"));
        goto error;
    }

    if (n > 0) {
        if (!(def->rng = virDomainRNGDefParseXML(nodes[0], ctxt, flags)))
            goto error;
        VIR_FREE(nodes);
    }
12249 12250 12251 12252 12253 12254 12255 12256 12257 12258 12259 12260 12261 12262 12263 12264 12265
    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);
12266

L
Li Zhang 已提交
12267 12268 12269 12270 12271 12272 12273 12274 12275 12276 12277 12278 12279 12280 12281 12282 12283
    if ((n = virXPathNodeSet("./devices/nvram", ctxt, &nodes)) < 0) {
        goto error;
    }

    if (n > 1) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("only a single nvram device is supported"));
        goto error;
    } else if (n == 1) {
        virDomainNVRAMDefPtr nvram =
            virDomainNVRAMDefParseXML(nodes[0], flags);
        if (!nvram)
            goto error;
        def->nvram = nvram;
        VIR_FREE(nodes);
    }

M
Marc-André Lureau 已提交
12284 12285 12286 12287 12288
    /* analysis of the hub devices */
    if ((n = virXPathNodeSet("./devices/hub", ctxt, &nodes)) < 0) {
        goto error;
    }
    if (n && VIR_ALLOC_N(def->hubs, n) < 0)
12289
        goto error;
12290
    for (i = 0; i < n; i++) {
M
Marc-André Lureau 已提交
12291 12292 12293 12294
        virDomainHubDefPtr hub = virDomainHubDefParseXML(nodes[i], flags);
        if (!hub)
            goto error;

12295
        if (hub->type == VIR_DOMAIN_HUB_TYPE_USB && usb_none) {
12296
            virDomainHubDefFree(hub);
12297 12298 12299 12300 12301 12302
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("Can't add USB hub: "
                             "USB is disabled for this domain"));
            goto error;
        }

M
Marc-André Lureau 已提交
12303 12304 12305 12306
        def->hubs[def->nhubs++] = hub;
    }
    VIR_FREE(nodes);

12307 12308 12309 12310 12311
    /* analysis of the redirected devices */
    if ((n = virXPathNodeSet("./devices/redirdev", ctxt, &nodes)) < 0) {
        goto error;
    }
    if (n && VIR_ALLOC_N(def->redirdevs, n) < 0)
12312
        goto error;
12313
    for (i = 0; i < n; i++) {
12314
        virDomainRedirdevDefPtr redirdev = virDomainRedirdevDefParseXML(nodes[i],
12315
                                                                        bootHash,
12316 12317 12318 12319
                                                                        flags);
        if (!redirdev)
            goto error;

12320 12321 12322 12323 12324 12325 12326
        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"));
            goto error;
        }

12327 12328 12329 12330
        def->redirdevs[def->nredirdevs++] = redirdev;
    }
    VIR_FREE(nodes);

12331 12332 12333 12334 12335 12336 12337 12338 12339 12340 12341 12342 12343 12344 12345 12346 12347 12348 12349 12350
    /* analysis of the redirection filter rules */
    if ((n = virXPathNodeSet("./devices/redirfilter", ctxt, &nodes)) < 0) {
        goto error;
    }
    if (n > 1) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("only one set of redirection filter rule is supported"));
        goto error;
    }

    if (n) {
        virDomainRedirFilterDefPtr redirfilter =
            virDomainRedirFilterDefParseXML(nodes[0], ctxt);
        if (!redirfilter)
            goto error;

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

12351 12352 12353 12354 12355 12356 12357 12358 12359 12360 12361 12362 12363 12364 12365 12366 12367 12368 12369 12370 12371 12372 12373 12374 12375 12376 12377 12378 12379 12380 12381 12382
    /* 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;
    }

E
Eric Blake 已提交
12383
    /* analysis of cpu handling */
12384
    if ((node = virXPathNode("./cpu[1]", ctxt)) != NULL) {
12385 12386
        xmlNodePtr oldnode = ctxt->node;
        ctxt->node = node;
12387
        def->cpu = virCPUDefParseXML(node, ctxt, VIR_CPU_TYPE_GUEST);
12388 12389 12390 12391
        ctxt->node = oldnode;

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

12393 12394 12395
        if (def->cpu->sockets &&
            def->maxvcpus >
            def->cpu->sockets * def->cpu->cores * def->cpu->threads) {
12396 12397
            virReportError(VIR_ERR_XML_DETAIL, "%s",
                           _("Maximum CPUs greater than topology limit"));
12398 12399 12400
            goto error;
        }

12401
        if (def->cpu->cells_cpus > def->maxvcpus) {
12402 12403 12404
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Number of CPUs in <numa> exceeds the"
                             " <vcpu> count"));
12405 12406
            goto error;
        }
12407 12408
    }

12409 12410 12411
    if ((node = virXPathNode("./sysinfo[1]", ctxt)) != NULL) {
        xmlNodePtr oldnode = ctxt->node;
        ctxt->node = node;
12412 12413
        def->sysinfo = virSysinfoParseXML(node, ctxt,
                                          def->uuid, uuid_generated);
12414 12415 12416 12417 12418
        ctxt->node = oldnode;

        if (def->sysinfo == NULL)
            goto error;
    }
12419 12420

    if ((tmp = virXPathString("string(./os/smbios/@mode)", ctxt))) {
12421 12422 12423
        int mode;

        if ((mode = virDomainSmbiosModeTypeFromString(tmp)) < 0) {
12424 12425
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown smbios mode '%s'"), tmp);
12426 12427 12428 12429 12430
            goto error;
        }
        def->os.smbios_mode = mode;
        VIR_FREE(tmp);
    }
12431

12432
    /* Extract custom metadata */
12433
    if ((node = virXPathNode("./metadata[1]", ctxt)) != NULL)
12434 12435
        def->metadata = xmlCopyNode(node, 1);

12436 12437 12438
    /* we have to make a copy of all of the callback pointers here since
     * we won't have the virCaps structure available during free
     */
12439
    def->ns = xmlopt->ns;
12440

12441 12442 12443
    if (def->ns.parse &&
        (def->ns.parse)(xml, root, ctxt, &def->namespaceData) < 0)
        goto error;
12444

12445 12446 12447 12448
    /* callback to fill driver specific domain aspects */
    if (virDomainDefPostParse(def, caps, xmlopt) < 0)
        goto error;

12449 12450 12451 12452
    /* Auto-add any implied controllers which aren't present */
    if (virDomainDefAddImplicitControllers(def) < 0)
        goto error;

12453
    virHashFree(bootHash);
12454

12455 12456
    return def;

12457
error:
12458 12459
    VIR_FREE(tmp);
    VIR_FREE(nodes);
12460
    virHashFree(bootHash);
12461 12462 12463 12464
    virDomainDefFree(def);
    return NULL;
}

12465

12466
static virDomainObjPtr
12467
virDomainObjParseXML(xmlDocPtr xml,
12468
                     xmlXPathContextPtr ctxt,
12469 12470
                     virCapsPtr caps,
                     virDomainXMLOptionPtr xmlopt,
12471 12472
                     unsigned int expectedVirtTypes,
                     unsigned int flags)
12473 12474 12475 12476 12477 12478
{
    char *tmp = NULL;
    long val;
    xmlNodePtr config;
    xmlNodePtr oldnode;
    virDomainObjPtr obj;
12479
    xmlNodePtr *nodes = NULL;
12480 12481
    size_t i;
    int n;
J
Jiri Denemark 已提交
12482 12483
    int state;
    int reason = 0;
12484

12485
    if (!(obj = virDomainObjNew(xmlopt)))
12486 12487
        return NULL;

12488
    if (!(config = virXPathNode("./domain", ctxt))) {
12489 12490
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("no domain config"));
12491 12492 12493 12494 12495
        goto error;
    }

    oldnode = ctxt->node;
    ctxt->node = config;
12496 12497
    obj->def = virDomainDefParseXML(xml, config, ctxt, caps, xmlopt,
                                    expectedVirtTypes, flags);
12498 12499 12500 12501
    ctxt->node = oldnode;
    if (!obj->def)
        goto error;

12502
    if (!(tmp = virXPathString("string(./@state)", ctxt))) {
12503 12504
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("missing domain state"));
12505 12506
        goto error;
    }
J
Jiri Denemark 已提交
12507
    if ((state = virDomainStateTypeFromString(tmp)) < 0) {
12508 12509
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("invalid domain state '%s'"), tmp);
12510 12511 12512 12513 12514
        VIR_FREE(tmp);
        goto error;
    }
    VIR_FREE(tmp);

J
Jiri Denemark 已提交
12515 12516
    if ((tmp = virXPathString("string(./@reason)", ctxt))) {
        if ((reason = virDomainStateReasonFromString(state, tmp)) < 0) {
12517 12518
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("invalid domain state reason '%s'"), tmp);
J
Jiri Denemark 已提交
12519 12520 12521 12522 12523 12524 12525 12526
            VIR_FREE(tmp);
            goto error;
        }
        VIR_FREE(tmp);
    }

    virDomainObjSetState(obj, state, reason);

E
Eric Blake 已提交
12527
    if (virXPathLong("string(./@pid)", ctxt, &val) < 0) {
12528 12529
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("invalid pid"));
12530 12531 12532 12533
        goto error;
    }
    obj->pid = (pid_t)val;

12534 12535 12536
    if ((n = virXPathNodeSet("./taint", ctxt, &nodes)) < 0) {
        goto error;
    }
12537
    for (i = 0; i < n; i++) {
12538 12539 12540 12541
        char *str = virXMLPropString(nodes[i], "flag");
        if (str) {
            int flag = virDomainTaintTypeFromString(str);
            if (flag < 0) {
12542 12543
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Unknown taint flag %s"), str);
12544
                VIR_FREE(str);
12545 12546
                goto error;
            }
12547
            VIR_FREE(str);
12548 12549 12550 12551 12552
            virDomainObjTaint(obj, flag);
        }
    }
    VIR_FREE(nodes);

12553 12554
    if (xmlopt->privateData.parse &&
        ((xmlopt->privateData.parse)(ctxt, obj->privateData)) < 0)
12555
        goto error;
12556

12557 12558 12559
    return obj;

error:
12560
    virObjectUnref(obj);
12561
    VIR_FREE(nodes);
12562 12563 12564 12565
    return NULL;
}


J
Jiri Denemark 已提交
12566 12567 12568 12569
static virDomainDefPtr
virDomainDefParse(const char *xmlStr,
                  const char *filename,
                  virCapsPtr caps,
12570
                  virDomainXMLOptionPtr xmlopt,
M
Matthias Bolte 已提交
12571
                  unsigned int expectedVirtTypes,
E
Eric Blake 已提交
12572
                  unsigned int flags)
12573
{
J
Jiri Denemark 已提交
12574 12575
    xmlDocPtr xml;
    virDomainDefPtr def = NULL;
12576
    int keepBlanksDefault = xmlKeepBlanksDefault(0);
J
Jiri Denemark 已提交
12577

12578
    if ((xml = virXMLParse(filename, xmlStr, _("(domain_definition)")))) {
12579 12580
        def = virDomainDefParseNode(xml, xmlDocGetRootElement(xml), caps,
                                    xmlopt, expectedVirtTypes, flags);
J
Jiri Denemark 已提交
12581
        xmlFreeDoc(xml);
12582
    }
J
Jiri Denemark 已提交
12583

12584
    xmlKeepBlanksDefault(keepBlanksDefault);
J
Jiri Denemark 已提交
12585
    return def;
12586
}
12587

12588
virDomainDefPtr
12589 12590
virDomainDefParseString(const char *xmlStr,
                        virCapsPtr caps,
12591
                        virDomainXMLOptionPtr xmlopt,
12592 12593
                        unsigned int expectedVirtTypes,
                        unsigned int flags)
12594
{
12595
    return virDomainDefParse(xmlStr, NULL, caps, xmlopt,
12596
                             expectedVirtTypes, flags);
12597 12598
}

12599
virDomainDefPtr
12600 12601
virDomainDefParseFile(const char *filename,
                      virCapsPtr caps,
12602
                      virDomainXMLOptionPtr xmlopt,
12603 12604
                      unsigned int expectedVirtTypes,
                      unsigned int flags)
12605
{
12606
    return virDomainDefParse(NULL, filename, caps, xmlopt,
12607
                             expectedVirtTypes, flags);
12608 12609 12610
}


12611
virDomainDefPtr
12612
virDomainDefParseNode(xmlDocPtr xml,
12613
                      xmlNodePtr root,
12614 12615
                      virCapsPtr caps,
                      virDomainXMLOptionPtr xmlopt,
12616 12617
                      unsigned int expectedVirtTypes,
                      unsigned int flags)
12618 12619 12620 12621 12622
{
    xmlXPathContextPtr ctxt = NULL;
    virDomainDefPtr def = NULL;

    if (!xmlStrEqual(root->name, BAD_CAST "domain")) {
12623 12624 12625 12626
        virReportError(VIR_ERR_XML_ERROR,
                       _("unexpected root element <%s>, "
                         "expecting <domain>"),
                       root->name);
12627 12628 12629 12630 12631
        goto cleanup;
    }

    ctxt = xmlXPathNewContext(xml);
    if (ctxt == NULL) {
12632
        virReportOOMError();
12633 12634 12635 12636
        goto cleanup;
    }

    ctxt->node = root;
12637
    def = virDomainDefParseXML(xml, root, ctxt, caps, xmlopt,
12638
                               expectedVirtTypes, flags);
12639 12640 12641 12642 12643

cleanup:
    xmlXPathFreeContext(ctxt);
    return def;
}
12644 12645


H
Hu Tao 已提交
12646
static virDomainObjPtr
12647
virDomainObjParseNode(xmlDocPtr xml,
L
Laine Stump 已提交
12648
                      xmlNodePtr root,
12649 12650
                      virCapsPtr caps,
                      virDomainXMLOptionPtr xmlopt,
M
Matthias Bolte 已提交
12651
                      unsigned int expectedVirtTypes,
L
Laine Stump 已提交
12652
                      unsigned int flags)
12653 12654 12655 12656 12657
{
    xmlXPathContextPtr ctxt = NULL;
    virDomainObjPtr obj = NULL;

    if (!xmlStrEqual(root->name, BAD_CAST "domstatus")) {
12658 12659 12660 12661
        virReportError(VIR_ERR_XML_ERROR,
                       _("unexpected root element <%s>, "
                         "expecting <domstatus>"),
                       root->name);
12662 12663 12664
        goto cleanup;
    }

12665
    if (!(ctxt = xmlXPathNewContext(xml))) {
12666
        virReportOOMError();
12667 12668 12669 12670
        goto cleanup;
    }

    ctxt->node = root;
12671
    obj = virDomainObjParseXML(xml, ctxt, caps, xmlopt, expectedVirtTypes, flags);
12672 12673 12674 12675 12676 12677

cleanup:
    xmlXPathFreeContext(ctxt);
    return obj;
}

H
Hu Tao 已提交
12678

12679
static virDomainObjPtr
12680 12681
virDomainObjParseFile(const char *filename,
                      virCapsPtr caps,
12682
                      virDomainXMLOptionPtr xmlopt,
12683 12684
                      unsigned int expectedVirtTypes,
                      unsigned int flags)
H
Hu Tao 已提交
12685 12686 12687
{
    xmlDocPtr xml;
    virDomainObjPtr obj = NULL;
12688
    int keepBlanksDefault = xmlKeepBlanksDefault(0);
H
Hu Tao 已提交
12689 12690

    if ((xml = virXMLParseFile(filename))) {
12691 12692
        obj = virDomainObjParseNode(xml, xmlDocGetRootElement(xml),
                                    caps, xmlopt,
M
Matthias Bolte 已提交
12693
                                    expectedVirtTypes, flags);
H
Hu Tao 已提交
12694 12695 12696
        xmlFreeDoc(xml);
    }

12697
    xmlKeepBlanksDefault(keepBlanksDefault);
H
Hu Tao 已提交
12698 12699 12700 12701
    return obj;
}


12702 12703 12704
static bool
virDomainTimerDefCheckABIStability(virDomainTimerDefPtr src,
                                   virDomainTimerDefPtr dst)
12705 12706
{
    if (src->name != dst->name) {
12707 12708 12709 12710
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target timer %s does not match source %s"),
                       virDomainTimerNameTypeToString(dst->name),
                       virDomainTimerNameTypeToString(src->name));
12711
        return false;
12712 12713 12714
    }

    if (src->present != dst->present) {
12715 12716 12717
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target timer presence %d does not match source %d"),
                       dst->present, src->present);
12718
        return false;
12719 12720 12721 12722
    }

    if (src->name == VIR_DOMAIN_TIMER_NAME_TSC) {
        if (src->frequency != dst->frequency) {
12723 12724 12725
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Target TSC frequency %lu does not match source %lu"),
                           dst->frequency, src->frequency);
12726
            return false;
12727 12728 12729
        }

        if (src->mode != dst->mode) {
12730 12731 12732 12733
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Target TSC mode %s does not match source %s"),
                           virDomainTimerModeTypeToString(dst->mode),
                           virDomainTimerModeTypeToString(src->mode));
12734
            return false;
12735 12736 12737
        }
    }

12738
    return true;
12739 12740 12741
}


12742 12743 12744
static bool
virDomainDeviceInfoCheckABIStability(virDomainDeviceInfoPtr src,
                                     virDomainDeviceInfoPtr dst)
12745 12746
{
    if (src->type != dst->type) {
12747 12748 12749 12750
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target device address type %s does not match source %s"),
                       virDomainDeviceAddressTypeToString(dst->type),
                       virDomainDeviceAddressTypeToString(src->type));
12751
        return false;
12752 12753 12754 12755 12756 12757 12758 12759
    }

    switch (src->type) {
    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) {
12760
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
12761 12762
                           _("Target device PCI address %04x:%02x:%02x.%02x "
                             "does not match source %04x:%02x:%02x.%02x"),
12763 12764 12765 12766
                           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);
12767
            return false;
12768 12769 12770 12771 12772 12773 12774
        }
        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) {
12775
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
12776 12777
                           _("Target device drive address %d:%d:%d "
                             "does not match source %d:%d:%d"),
12778 12779 12780 12781
                           dst->addr.drive.controller, dst->addr.drive.bus,
                           dst->addr.drive.unit,
                           src->addr.drive.controller, src->addr.drive.bus,
                           src->addr.drive.unit);
12782
            return false;
12783 12784 12785 12786 12787 12788 12789
        }
        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) {
12790
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
12791 12792
                           _("Target device virtio serial address %d:%d:%d "
                             "does not match source %d:%d:%d"),
12793 12794 12795 12796
                           dst->addr.vioserial.controller, dst->addr.vioserial.bus,
                           dst->addr.vioserial.port,
                           src->addr.vioserial.controller, src->addr.vioserial.bus,
                           src->addr.vioserial.port);
12797
            return false;
12798 12799 12800 12801 12802 12803
        }
        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) {
12804
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
12805 12806
                           _("Target device ccid address %d:%d "
                             "does not match source %d:%d"),
12807 12808 12809 12810
                           dst->addr.ccid.controller,
                           dst->addr.ccid.slot,
                           src->addr.ccid.controller,
                           src->addr.ccid.slot);
12811
            return false;
12812 12813 12814 12815
        }
        break;
    }

12816
    return true;
12817 12818 12819
}


12820 12821 12822
static bool
virDomainDiskDefCheckABIStability(virDomainDiskDefPtr src,
                                  virDomainDiskDefPtr dst)
12823 12824
{
    if (src->device != dst->device) {
12825 12826 12827 12828
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target disk device %s does not match source %s"),
                       virDomainDiskDeviceTypeToString(dst->device),
                       virDomainDiskDeviceTypeToString(src->device));
12829
        return false;
12830 12831 12832
    }

    if (src->bus != dst->bus) {
12833 12834 12835 12836
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target disk bus %s does not match source %s"),
                       virDomainDiskBusTypeToString(dst->bus),
                       virDomainDiskBusTypeToString(src->bus));
12837
        return false;
12838 12839 12840
    }

    if (STRNEQ(src->dst, dst->dst)) {
12841 12842 12843
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target disk %s does not match source %s"),
                       dst->dst, src->dst);
12844
        return false;
12845 12846 12847
    }

    if (STRNEQ_NULLABLE(src->serial, dst->serial)) {
12848 12849 12850
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target disk serial %s does not match source %s"),
                       NULLSTR(dst->serial), NULLSTR(src->serial));
12851
        return false;
12852 12853 12854
    }

    if (src->readonly != dst->readonly || src->shared != dst->shared) {
12855 12856
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Target disk access mode does not match source"));
12857
        return false;
12858 12859 12860
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
12861
        return false;
12862

12863
    return true;
12864 12865 12866
}


12867 12868 12869
static bool
virDomainControllerDefCheckABIStability(virDomainControllerDefPtr src,
                                        virDomainControllerDefPtr dst)
12870 12871
{
    if (src->type != dst->type) {
12872 12873 12874 12875
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target controller type %s does not match source %s"),
                       virDomainControllerTypeToString(dst->type),
                       virDomainControllerTypeToString(src->type));
12876
        return false;
12877 12878 12879
    }

    if (src->idx != dst->idx) {
12880 12881 12882
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target controller index %d does not match source %d"),
                       dst->idx, src->idx);
12883
        return false;
12884 12885 12886
    }

    if (src->model != dst->model) {
12887 12888 12889
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target controller model %d does not match source %d"),
                       dst->model, src->model);
12890
        return false;
12891 12892 12893 12894
    }

    if (src->type == VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL) {
        if (src->opts.vioserial.ports != dst->opts.vioserial.ports) {
12895 12896 12897
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Target controller ports %d does not match source %d"),
                           dst->opts.vioserial.ports, src->opts.vioserial.ports);
12898
            return false;
12899 12900 12901
        }

        if (src->opts.vioserial.vectors != dst->opts.vioserial.vectors) {
12902 12903 12904
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Target controller vectors %d does not match source %d"),
                           dst->opts.vioserial.vectors, src->opts.vioserial.vectors);
12905
            return false;
12906 12907 12908 12909
        }
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
12910
        return false;
12911

12912
    return true;
12913 12914 12915
}


12916 12917 12918
static bool
virDomainFsDefCheckABIStability(virDomainFSDefPtr src,
                                virDomainFSDefPtr dst)
12919 12920
{
    if (STRNEQ(src->dst, dst->dst)) {
12921 12922 12923
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target filesystem guest target %s does not match source %s"),
                       dst->dst, src->dst);
12924
        return false;
12925 12926 12927
    }

    if (src->readonly != dst->readonly) {
12928 12929
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Target filesystem access mode does not match source"));
12930
        return false;
12931 12932 12933
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
12934
        return false;
12935

12936
    return true;
12937 12938 12939
}


12940 12941 12942
static bool
virDomainNetDefCheckABIStability(virDomainNetDefPtr src,
                                 virDomainNetDefPtr dst)
12943
{
12944 12945 12946
    char srcmac[VIR_MAC_STRING_BUFLEN];
    char dstmac[VIR_MAC_STRING_BUFLEN];

12947
    if (virMacAddrCmp(&src->mac, &dst->mac) != 0) {
12948
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
12949 12950 12951 12952
                       _("Target network card mac %s"
                         " does not match source %s"),
                       virMacAddrFormat(&dst->mac, dstmac),
                       virMacAddrFormat(&src->mac, srcmac));
12953
        return false;
12954 12955 12956
    }

    if (STRNEQ_NULLABLE(src->model, dst->model)) {
12957 12958 12959
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target network card model %s does not match source %s"),
                       NULLSTR(dst->model), NULLSTR(src->model));
12960
        return false;
12961 12962 12963
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
12964
        return false;
12965

12966
    return true;
12967 12968 12969
}


12970 12971 12972
static bool
virDomainInputDefCheckABIStability(virDomainInputDefPtr src,
                                   virDomainInputDefPtr dst)
12973 12974
{
    if (src->type != dst->type) {
12975 12976 12977 12978
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target input device type %s does not match source %s"),
                       virDomainInputTypeToString(dst->type),
                       virDomainInputTypeToString(src->type));
12979
        return false;
12980 12981 12982
    }

    if (src->bus != dst->bus) {
12983 12984 12985 12986
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target input device bus %s does not match source %s"),
                       virDomainInputBusTypeToString(dst->bus),
                       virDomainInputBusTypeToString(src->bus));
12987
        return false;
12988 12989 12990
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
12991
        return false;
12992

12993
    return true;
12994 12995 12996
}


12997 12998 12999
static bool
virDomainSoundDefCheckABIStability(virDomainSoundDefPtr src,
                                   virDomainSoundDefPtr dst)
13000 13001
{
    if (src->model != dst->model) {
13002 13003 13004 13005
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target sound card model %s does not match source %s"),
                       virDomainSoundModelTypeToString(dst->model),
                       virDomainSoundModelTypeToString(src->model));
13006
        return false;
13007 13008 13009
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
13010
        return false;
13011

13012
    return true;
13013 13014 13015
}


13016 13017 13018
static bool
virDomainVideoDefCheckABIStability(virDomainVideoDefPtr src,
                                   virDomainVideoDefPtr dst)
13019 13020
{
    if (src->type != dst->type) {
13021 13022 13023 13024
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target video card model %s does not match source %s"),
                       virDomainVideoTypeToString(dst->type),
                       virDomainVideoTypeToString(src->type));
13025
        return false;
13026 13027 13028
    }

    if (src->vram != dst->vram) {
13029 13030 13031
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target video card vram %u does not match source %u"),
                       dst->vram, src->vram);
13032
        return false;
13033 13034 13035
    }

    if (src->heads != dst->heads) {
13036 13037 13038
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target video card heads %u does not match source %u"),
                       dst->heads, src->heads);
13039
        return false;
13040 13041 13042 13043
    }

    if ((src->accel && !dst->accel) ||
        (!src->accel && dst->accel)) {
13044 13045
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Target video card acceleration does not match source"));
13046
        return false;
13047 13048 13049 13050
    }

    if (src->accel) {
        if (src->accel->support2d != dst->accel->support2d) {
13051 13052 13053
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Target video card 2d accel %u does not match source %u"),
                           dst->accel->support2d, src->accel->support2d);
13054
            return false;
13055 13056 13057
        }

        if (src->accel->support3d != dst->accel->support3d) {
13058 13059 13060
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Target video card 3d accel %u does not match source %u"),
                           dst->accel->support3d, src->accel->support3d);
13061
            return false;
13062 13063 13064 13065
        }
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
13066
        return false;
13067

13068
    return true;
13069 13070 13071
}


13072 13073 13074
static bool
virDomainHostdevDefCheckABIStability(virDomainHostdevDefPtr src,
                                     virDomainHostdevDefPtr dst)
13075 13076
{
    if (src->mode != dst->mode) {
13077 13078 13079 13080
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target host device mode %s does not match source %s"),
                       virDomainHostdevModeTypeToString(dst->mode),
                       virDomainHostdevModeTypeToString(src->mode));
13081
        return false;
13082 13083
    }

13084 13085 13086 13087 13088 13089 13090
    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;
13091 13092
    }

13093
    if (!virDomainDeviceInfoCheckABIStability(src->info, dst->info))
13094
        return false;
13095

13096
    return true;
13097 13098 13099
}


13100 13101 13102
static bool
virDomainSmartcardDefCheckABIStability(virDomainSmartcardDefPtr src,
                                       virDomainSmartcardDefPtr dst)
13103 13104
{
    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
13105
        return false;
13106

13107
    return true;
13108 13109 13110
}


13111 13112 13113
static bool
virDomainSerialDefCheckABIStability(virDomainChrDefPtr src,
                                    virDomainChrDefPtr dst)
13114 13115
{
    if (src->target.port != dst->target.port) {
13116 13117 13118
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target serial port %d does not match source %d"),
                       dst->target.port, src->target.port);
13119
        return false;
13120 13121 13122
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
13123
        return false;
13124

13125
    return true;
13126 13127 13128
}


13129 13130 13131
static bool
virDomainParallelDefCheckABIStability(virDomainChrDefPtr src,
                                      virDomainChrDefPtr dst)
13132 13133
{
    if (src->target.port != dst->target.port) {
13134
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
13135
                       _("Target parallel port %d does not match source %d"),
13136
                       dst->target.port, src->target.port);
13137
        return false;
13138 13139 13140
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
13141
        return false;
13142

13143
    return true;
13144 13145 13146
}


13147 13148 13149
static bool
virDomainChannelDefCheckABIStability(virDomainChrDefPtr src,
                                     virDomainChrDefPtr dst)
13150 13151
{
    if (src->targetType != dst->targetType) {
13152 13153 13154 13155
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target channel type %s does not match source %s"),
                       virDomainChrChannelTargetTypeToString(dst->targetType),
                       virDomainChrChannelTargetTypeToString(src->targetType));
13156
        return false;
13157 13158 13159 13160
    }

    switch (src->targetType) {
    case VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO:
13161
        if (STRNEQ_NULLABLE(src->target.name, dst->target.name)) {
13162 13163 13164
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Target channel name %s does not match source %s"),
                           NULLSTR(dst->target.name), NULLSTR(src->target.name));
13165
            return false;
13166
        }
13167 13168 13169 13170 13171 13172 13173
        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"));
13174
            return false;
13175
        }
13176 13177
        break;
    case VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_GUESTFWD:
E
Eric Blake 已提交
13178 13179
        if (memcmp(src->target.addr, dst->target.addr,
                   sizeof(*src->target.addr)) != 0) {
13180 13181
            char *saddr = virSocketAddrFormatFull(src->target.addr, true, ":");
            char *daddr = virSocketAddrFormatFull(dst->target.addr, true, ":");
13182 13183 13184
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Target channel addr %s does not match source %s"),
                           NULLSTR(daddr), NULLSTR(saddr));
13185 13186
            VIR_FREE(saddr);
            VIR_FREE(daddr);
13187
            return false;
13188 13189 13190 13191 13192
        }
        break;
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
13193
        return false;
13194

13195
    return true;
13196 13197 13198
}


13199 13200 13201
static bool
virDomainConsoleDefCheckABIStability(virDomainChrDefPtr src,
                                     virDomainChrDefPtr dst)
13202 13203
{
    if (src->targetType != dst->targetType) {
13204 13205 13206 13207
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target console type %s does not match source %s"),
                       virDomainChrConsoleTargetTypeToString(dst->targetType),
                       virDomainChrConsoleTargetTypeToString(src->targetType));
13208
        return false;
13209 13210 13211
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
13212
        return false;
13213

13214
    return true;
13215 13216 13217
}


13218 13219 13220
static bool
virDomainWatchdogDefCheckABIStability(virDomainWatchdogDefPtr src,
                                      virDomainWatchdogDefPtr dst)
13221 13222
{
    if (src->model != dst->model) {
13223 13224 13225 13226
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target watchdog model %s does not match source %s"),
                       virDomainWatchdogModelTypeToString(dst->model),
                       virDomainWatchdogModelTypeToString(src->model));
13227
        return false;
13228 13229 13230
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
13231
        return false;
13232

13233
    return true;
13234 13235 13236
}


13237 13238 13239
static bool
virDomainMemballoonDefCheckABIStability(virDomainMemballoonDefPtr src,
                                        virDomainMemballoonDefPtr dst)
13240 13241
{
    if (src->model != dst->model) {
13242 13243 13244 13245
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target balloon model %s does not match source %s"),
                       virDomainMemballoonModelTypeToString(dst->model),
                       virDomainMemballoonModelTypeToString(src->model));
13246
        return false;
13247 13248 13249
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
13250
        return false;
13251

13252
    return true;
13253 13254 13255
}


13256 13257 13258 13259 13260 13261 13262 13263 13264 13265 13266 13267 13268 13269 13270 13271 13272 13273 13274 13275 13276 13277 13278 13279 13280 13281 13282 13283 13284 13285
static bool
virDomainRNGDefCheckABIStability(virDomainRNGDefPtr src,
                                 virDomainRNGDefPtr dst)
{
    if (!src && !dst)
        return true;

    if (!src || !dst) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target domain RNG device count '%d' "
                         "does not match source count '%d'"),
                       src ? 1 : 0, dst ? 1 : 0);
        return false;
    }

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


13286 13287 13288
static bool
virDomainHubDefCheckABIStability(virDomainHubDefPtr src,
                                 virDomainHubDefPtr dst)
M
Marc-André Lureau 已提交
13289 13290
{
    if (src->type != dst->type) {
13291 13292 13293 13294
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target hub device type %s does not match source %s"),
                       virDomainHubTypeToString(dst->type),
                       virDomainHubTypeToString(src->type));
13295
        return false;
M
Marc-André Lureau 已提交
13296 13297 13298
    }

    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
13299
        return false;
M
Marc-André Lureau 已提交
13300

13301
    return true;
M
Marc-André Lureau 已提交
13302 13303
}

13304 13305 13306 13307
static bool
virDomainRedirFilterDefCheckABIStability(virDomainRedirFilterDefPtr src,
                                         virDomainRedirFilterDefPtr dst)
{
13308
    size_t i;
13309 13310 13311 13312 13313 13314

    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);
13315
        return false;
13316 13317 13318 13319 13320 13321 13322 13323
    }

    for (i = 0; i < src->nusbdevs; i++) {
        virDomainRedirFilterUsbDevDefPtr srcUsbDev = src->usbdevs[i];
        virDomainRedirFilterUsbDevDefPtr dstUsbDev = dst->usbdevs[i];
        if (srcUsbDev->usbClass != dstUsbDev->usbClass) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           "%s", _("Target USB Class code does not match source"));
13324
            return false;
13325 13326 13327 13328 13329
        }

        if (srcUsbDev->vendor != dstUsbDev->vendor) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           "%s", _("Target USB vendor ID does not match source"));
13330
            return false;
13331 13332 13333 13334 13335
        }

        if (srcUsbDev->product != dstUsbDev->product) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           "%s", _("Target USB product ID does not match source"));
13336
            return false;
13337 13338 13339 13340 13341
        }

        if (srcUsbDev->version != dstUsbDev->version) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           "%s", _("Target USB version does not match source"));
13342
            return false;
13343 13344 13345 13346 13347 13348 13349
        }

        if (srcUsbDev->allow != dstUsbDev->allow) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Target USB allow '%s' does not match source '%s'"),
                             dstUsbDev->allow ? "yes" : "no",
                             srcUsbDev->allow ? "yes" : "no");
13350
            return false;
13351 13352 13353
        }
    }

13354
    return true;
13355
}
M
Marc-André Lureau 已提交
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 13386 13387 13388 13389 13390 13391 13392 13393 13394 13395 13396 13397 13398 13399 13400 13401 13402 13403 13404 13405 13406 13407 13408 13409 13410 13411 13412 13413 13414 13415 13416 13417 13418 13419 13420 13421 13422

static bool
virDomainDefFeaturesCheckABIStability(virDomainDefPtr src,
                                      virDomainDefPtr dst)
{
    size_t i;

    /* basic check */
    if (src->features != dst->features) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target domain features %d does not match source %d"),
                       dst->features, src->features);
        return false;
    }

    /* APIC EOI */
    if (src->apic_eoi != dst->apic_eoi) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("State of APIC EOI differs: "
                         "source: '%s', destination: '%s'"),
                       virDomainFeatureStateTypeToString(src->apic_eoi),
                       virDomainFeatureStateTypeToString(dst->apic_eoi));
        return false;
    }

    /* hyperv */
    if (src->features & (1 << VIR_DOMAIN_FEATURE_HYPERV)) {
        for (i = 0; i < VIR_DOMAIN_HYPERV_LAST; i++) {
            switch ((enum virDomainHyperv) i) {
            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),
                                   virDomainFeatureStateTypeToString(src->hyperv_features[i]),
                                   virDomainFeatureStateTypeToString(dst->hyperv_features[i]));
                    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;

            case VIR_DOMAIN_HYPERV_LAST:
                break;
            }
        }
    }

    return true;
}


13423 13424 13425 13426
/* 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
 */
13427 13428 13429
bool
virDomainDefCheckABIStability(virDomainDefPtr src,
                              virDomainDefPtr dst)
13430
{
13431
    size_t i;
13432 13433

    if (src->virtType != dst->virtType) {
13434 13435 13436 13437
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target domain virt type %s does not match source %s"),
                       virDomainVirtTypeToString(dst->virtType),
                       virDomainVirtTypeToString(src->virtType));
13438
        return false;
13439 13440 13441 13442 13443 13444 13445
    }

    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);
13446 13447 13448
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target domain uuid %s does not match source %s"),
                       uuiddst, uuidsrc);
13449
        return false;
13450 13451
    }

13452 13453 13454 13455 13456 13457 13458 13459 13460 13461 13462
    /* 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
     */
    if (STRNEQ(src->name, dst->name)) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target domain name '%s' does not match source '%s'"),
                       dst->name, src->name);
        return false;
    }

13463
    if (src->mem.max_balloon != dst->mem.max_balloon) {
13464 13465 13466
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target domain max memory %lld does not match source %lld"),
                       dst->mem.max_balloon, src->mem.max_balloon);
13467
        return false;
13468 13469
    }
    if (src->mem.cur_balloon != dst->mem.cur_balloon) {
13470 13471 13472
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target domain current memory %lld does not match source %lld"),
                       dst->mem.cur_balloon, src->mem.cur_balloon);
13473
        return false;
13474 13475
    }
    if (src->mem.hugepage_backed != dst->mem.hugepage_backed) {
13476 13477 13478 13479
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target domain huge page backing %d does not match source %d"),
                       dst->mem.hugepage_backed,
                       src->mem.hugepage_backed);
13480
        return false;
13481 13482
    }

13483
    if (src->vcpus != dst->vcpus) {
13484
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
13485
                       _("Target domain vCPU count %d does not match source %d"),
13486
                       dst->vcpus, src->vcpus);
13487
        return false;
13488 13489
    }
    if (src->maxvcpus != dst->maxvcpus) {
13490
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
13491
                       _("Target domain vCPU max %d does not match source %d"),
13492
                       dst->maxvcpus, src->maxvcpus);
13493
        return false;
13494 13495 13496
    }

    if (STRNEQ(src->os.type, dst->os.type)) {
13497 13498 13499
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target domain OS type %s does not match source %s"),
                       dst->os.type, src->os.type);
13500
        return false;
13501
    }
13502
    if (src->os.arch != dst->os.arch){
13503 13504
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target domain architecture %s does not match source %s"),
13505 13506
                       virArchToString(dst->os.arch),
                       virArchToString(src->os.arch));
13507
        return false;
13508 13509
    }
    if (STRNEQ(src->os.machine, dst->os.machine)) {
13510 13511 13512
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Target domain OS type %s does not match source %s"),
                       dst->os.machine, src->os.machine);
13513
        return false;
13514 13515 13516
    }

    if (src->os.smbios_mode != dst->os.smbios_mode) {
13517 13518 13519 13520
        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));
13521
        return false;
13522 13523
    }

13524
    if (!virDomainDefFeaturesCheckABIStability(src, dst))
13525
        return false;
13526 13527

    if (src->clock.ntimers != dst->clock.ntimers) {
13528 13529
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Target domain timers do not match source"));
13530
        return false;
13531 13532
    }

13533
    for (i = 0; i < src->clock.ntimers; i++) {
13534 13535 13536
        if (!virDomainTimerDefCheckABIStability(src->clock.timers[i],
                                                dst->clock.timers[i]))
            return false;
13537 13538 13539
    }

    if (!virCPUDefIsEqual(src->cpu, dst->cpu))
13540
        return false;
13541 13542

    if (!virSysinfoIsEqual(src->sysinfo, dst->sysinfo))
13543
        return false;
13544 13545

    if (src->ndisks != dst->ndisks) {
13546
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
13547
                       _("Target domain disk count %zu does not match source %zu"),
13548
                       dst->ndisks, src->ndisks);
13549
        return false;
13550 13551
    }

13552
    for (i = 0; i < src->ndisks; i++)
13553
        if (!virDomainDiskDefCheckABIStability(src->disks[i], dst->disks[i]))
13554
            return false;
13555 13556

    if (src->ncontrollers != dst->ncontrollers) {
13557
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
13558
                       _("Target domain controller count %zu "
13559
                         "does not match source %zu"),
13560
                       dst->ncontrollers, src->ncontrollers);
13561
        return false;
13562 13563
    }

13564
    for (i = 0; i < src->ncontrollers; i++)
13565 13566 13567
        if (!virDomainControllerDefCheckABIStability(src->controllers[i],
                                                     dst->controllers[i]))
            return false;
13568 13569

    if (src->nfss != dst->nfss) {
13570
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
13571 13572
                       _("Target domain filesystem count %zu "
                         "does not match source %zu"),
13573
                       dst->nfss, src->nfss);
13574
        return false;
13575 13576
    }

13577
    for (i = 0; i < src->nfss; i++)
13578
        if (!virDomainFsDefCheckABIStability(src->fss[i], dst->fss[i]))
13579
            return false;
13580 13581

    if (src->nnets != dst->nnets) {
13582
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
13583 13584
                       _("Target domain net card count %zu "
                         "does not match source %zu"),
13585
                       dst->nnets, src->nnets);
13586
        return false;
13587 13588
    }

13589
    for (i = 0; i < src->nnets; i++)
13590
        if (!virDomainNetDefCheckABIStability(src->nets[i], dst->nets[i]))
13591
            return false;
13592 13593

    if (src->ninputs != dst->ninputs) {
13594
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
13595 13596
                       _("Target domain input device count %zu "
                         "does not match source %zu"),
13597
                       dst->ninputs, src->ninputs);
13598
        return false;
13599 13600
    }

13601
    for (i = 0; i < src->ninputs; i++)
13602
        if (!virDomainInputDefCheckABIStability(src->inputs[i], dst->inputs[i]))
13603
            return false;
13604 13605

    if (src->nsounds != dst->nsounds) {
13606
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
13607 13608
                       _("Target domain sound card count %zu "
                         "does not match source %zu"),
13609
                       dst->nsounds, src->nsounds);
13610
        return false;
13611 13612
    }

13613
    for (i = 0; i < src->nsounds; i++)
13614
        if (!virDomainSoundDefCheckABIStability(src->sounds[i], dst->sounds[i]))
13615
            return false;
13616 13617

    if (src->nvideos != dst->nvideos) {
13618
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
13619 13620
                       _("Target domain video card count %zu "
                         "does not match source %zu"),
13621
                       dst->nvideos, src->nvideos);
13622
        return false;
13623 13624
    }

13625
    for (i = 0; i < src->nvideos; i++)
13626
        if (!virDomainVideoDefCheckABIStability(src->videos[i], dst->videos[i]))
13627
            return false;
13628 13629

    if (src->nhostdevs != dst->nhostdevs) {
13630
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
13631 13632
                       _("Target domain host device count %zu "
                         "does not match source %zu"),
13633
                       dst->nhostdevs, src->nhostdevs);
13634
        return false;
13635 13636
    }

13637
    for (i = 0; i < src->nhostdevs; i++)
13638 13639 13640
        if (!virDomainHostdevDefCheckABIStability(src->hostdevs[i],
                                                  dst->hostdevs[i]))
            return false;
13641 13642

    if (src->nsmartcards != dst->nsmartcards) {
13643
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
13644 13645
                       _("Target domain smartcard count %zu "
                         "does not match source %zu"),
13646
                       dst->nsmartcards, src->nsmartcards);
13647
        return false;
13648 13649
    }

13650
    for (i = 0; i < src->nsmartcards; i++)
13651 13652 13653
        if (!virDomainSmartcardDefCheckABIStability(src->smartcards[i],
                                                    dst->smartcards[i]))
            return false;
13654 13655

    if (src->nserials != dst->nserials) {
13656
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
13657 13658
                       _("Target domain serial port count %zu "
                         "does not match source %zu"),
13659
                       dst->nserials, src->nserials);
13660
        return false;
13661 13662
    }

13663
    for (i = 0; i < src->nserials; i++)
13664 13665 13666
        if (!virDomainSerialDefCheckABIStability(src->serials[i],
                                                 dst->serials[i]))
            return false;
13667 13668

    if (src->nparallels != dst->nparallels) {
13669
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
13670 13671
                       _("Target domain parallel port count %zu "
                         "does not match source %zu"),
13672
                       dst->nparallels, src->nparallels);
13673
        return false;
13674 13675
    }

13676
    for (i = 0; i < src->nparallels; i++)
13677 13678 13679
        if (!virDomainParallelDefCheckABIStability(src->parallels[i],
                                                   dst->parallels[i]))
            return false;
13680 13681

    if (src->nchannels != dst->nchannels) {
13682
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
13683 13684
                       _("Target domain channel count %zu "
                         "does not match source %zu"),
13685
                       dst->nchannels, src->nchannels);
13686
        return false;
13687 13688
    }

13689
    for (i = 0; i < src->nchannels; i++)
13690 13691 13692
        if (!virDomainChannelDefCheckABIStability(src->channels[i],
                                                  dst->channels[i]))
            return false;
13693

13694
    if (src->nconsoles != dst->nconsoles) {
13695
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
13696 13697
                       _("Target domain console count %zu "
                         "does not match source %zu"),
13698
                       dst->nconsoles, src->nconsoles);
13699
        return false;
13700 13701
    }

13702
    for (i = 0; i < src->nconsoles; i++)
13703 13704 13705
        if (!virDomainConsoleDefCheckABIStability(src->consoles[i],
                                                  dst->consoles[i]))
            return false;
13706

M
Marc-André Lureau 已提交
13707
    if (src->nhubs != dst->nhubs) {
13708
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
13709 13710
                       _("Target domain hub device count %zu "
                         "does not match source %zu"),
13711
                       dst->nhubs, src->nhubs);
13712
        return false;
M
Marc-André Lureau 已提交
13713 13714
    }

13715
    for (i = 0; i < src->nhubs; i++)
M
Marc-André Lureau 已提交
13716
        if (!virDomainHubDefCheckABIStability(src->hubs[i], dst->hubs[i]))
13717
            return false;
M
Marc-André Lureau 已提交
13718

13719 13720 13721
    if ((!src->redirfilter && dst->redirfilter) ||
        (src->redirfilter && !dst->redirfilter)) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
13722 13723
                       _("Target domain USB redirection filter count %d "
                         "does not match source %d"),
13724
                       dst->redirfilter ? 1 : 0, src->redirfilter ? 1 : 0);
13725
        return false;
13726 13727 13728
    }

    if (src->redirfilter &&
13729 13730 13731
        !virDomainRedirFilterDefCheckABIStability(src->redirfilter,
                                                  dst->redirfilter))
        return false;
13732 13733 13734

    if ((!src->watchdog && dst->watchdog) ||
        (src->watchdog && !dst->watchdog)) {
13735
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
13736 13737
                       _("Target domain watchdog count %d "
                         "does not match source %d"),
13738
                       dst->watchdog ? 1 : 0, src->watchdog ? 1 : 0);
13739
        return false;
13740 13741 13742 13743
    }

    if (src->watchdog &&
        !virDomainWatchdogDefCheckABIStability(src->watchdog, dst->watchdog))
13744
        return false;
13745 13746 13747

    if ((!src->memballoon && dst->memballoon) ||
        (src->memballoon && !dst->memballoon)) {
13748
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
13749 13750
                       _("Target domain memory balloon count %d "
                         "does not match source %d"),
13751
                       dst->memballoon ? 1 : 0, src->memballoon ? 1 : 0);
13752
        return false;
13753 13754 13755
    }

    if (src->memballoon &&
13756 13757 13758
        !virDomainMemballoonDefCheckABIStability(src->memballoon,
                                                 dst->memballoon))
        return false;
13759

13760 13761 13762
    if (!virDomainRNGDefCheckABIStability(src->rng, dst->rng))
        return false;

13763
    return true;
13764 13765 13766
}


13767 13768 13769 13770
static int
virDomainDefAddDiskControllersForType(virDomainDefPtr def,
                                      int controllerType,
                                      int diskBus)
13771
{
13772
    size_t i;
13773 13774
    int maxController = -1;

13775
    for (i = 0; i < def->ndisks; i++) {
13776 13777 13778 13779 13780 13781 13782 13783 13784 13785
        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;
    }

13786 13787 13788
    if (maxController == -1)
        return 0;

13789
    for (i = 0; i <= maxController; i++) {
13790
        if (virDomainDefMaybeAddController(def, controllerType, i, -1) < 0)
13791 13792 13793 13794 13795 13796 13797
            return -1;
    }

    return 0;
}


13798 13799
static int
virDomainDefMaybeAddVirtioSerialController(virDomainDefPtr def)
13800
{
C
Cole Robinson 已提交
13801
    /* Look for any virtio serial or virtio console devs */
13802
    size_t i;
13803

13804
    for (i = 0; i < def->nchannels; i++) {
13805 13806
        virDomainChrDefPtr channel = def->channels[i];

13807
        if (channel->targetType == VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO) {
13808 13809 13810 13811
            int idx = 0;
            if (channel->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL)
                idx = channel->info.addr.vioserial.controller;

13812
            if (virDomainDefMaybeAddController(def,
13813
                VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL, idx, -1) < 0)
13814 13815 13816 13817
                return -1;
        }
    }

13818
    for (i = 0; i < def->nconsoles; i++) {
13819
        virDomainChrDefPtr console = def->consoles[i];
C
Cole Robinson 已提交
13820 13821 13822 13823 13824 13825 13826 13827

        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,
13828
                VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL, idx, -1) < 0)
C
Cole Robinson 已提交
13829 13830 13831 13832
                return -1;
        }
    }

13833 13834 13835 13836
    return 0;
}


E
Eric Blake 已提交
13837 13838 13839 13840
static int
virDomainDefMaybeAddSmartcardController(virDomainDefPtr def)
{
    /* Look for any smartcard devs */
13841
    size_t i;
E
Eric Blake 已提交
13842

13843
    for (i = 0; i < def->nsmartcards; i++) {
E
Eric Blake 已提交
13844 13845 13846 13847 13848 13849 13850
        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) {
13851
            size_t j;
E
Eric Blake 已提交
13852 13853 13854 13855 13856 13857 13858 13859 13860 13861 13862 13863 13864 13865 13866 13867
            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,
13868
                                           idx, -1) < 0)
E
Eric Blake 已提交
13869 13870 13871 13872 13873 13874
            return -1;
    }

    return 0;
}

13875
/*
13876
 * Based on the declared <address/> info for any devices,
13877
 * add necessary drive controllers which are not already present
13878 13879 13880
 * in the XML. This is for compat with existing apps which will
 * not know/care about <controller> info in the XML
 */
13881 13882
int
virDomainDefAddImplicitControllers(virDomainDefPtr def)
13883 13884 13885 13886 13887 13888 13889 13890 13891 13892 13893 13894 13895 13896 13897 13898
{
    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 已提交
13899 13900 13901 13902 13903
    if (virDomainDefAddDiskControllersForType(def,
                                              VIR_DOMAIN_CONTROLLER_TYPE_SATA,
                                              VIR_DOMAIN_DISK_BUS_SATA) < 0)
        return -1;

13904 13905 13906
    if (virDomainDefMaybeAddVirtioSerialController(def) < 0)
        return -1;

E
Eric Blake 已提交
13907 13908 13909
    if (virDomainDefMaybeAddSmartcardController(def) < 0)
        return -1;

H
Han Cheng 已提交
13910 13911 13912
    if (virDomainDefMaybeAddHostdevSCSIcontroller(def) < 0)
        return -1;

13913 13914 13915
    return 0;
}

13916 13917 13918
/* Check if vcpupin with same vcpuid already exists.
 * Return 1 if exists, 0 if not. */
int
E
Eric Blake 已提交
13919
virDomainVcpuPinIsDuplicate(virDomainVcpuPinDefPtr *def,
13920 13921 13922
                            int nvcpupin,
                            int vcpu)
{
13923
    size_t i;
13924 13925 13926 13927 13928 13929 13930 13931 13932 13933 13934 13935

    if (!def || !nvcpupin)
        return 0;

    for (i = 0; i < nvcpupin; i++) {
        if (def[i]->vcpuid == vcpu)
            return 1;
    }

    return 0;
}

E
Eric Blake 已提交
13936 13937
virDomainVcpuPinDefPtr
virDomainVcpuPinFindByVcpu(virDomainVcpuPinDefPtr *def,
13938 13939 13940
                           int nvcpupin,
                           int vcpu)
{
13941
    size_t i;
13942 13943 13944 13945 13946 13947 13948 13949 13950 13951 13952 13953

    if (!def || !nvcpupin)
        return NULL;

    for (i = 0; i < nvcpupin; i++) {
        if (def[i]->vcpuid == vcpu)
            return def[i];
    }

    return NULL;
}

13954 13955 13956 13957 13958 13959
int
virDomainVcpuPinAdd(virDomainVcpuPinDefPtr **vcpupin_list,
                    int *nvcpupin,
                    unsigned char *cpumap,
                    int maplen,
                    int vcpu)
13960 13961 13962
{
    virDomainVcpuPinDefPtr vcpupin = NULL;

H
Hu Tao 已提交
13963 13964
    if (!vcpupin_list)
        return -1;
13965

13966
    vcpupin = virDomainVcpuPinFindByVcpu(*vcpupin_list,
H
Hu Tao 已提交
13967 13968 13969
                                         *nvcpupin,
                                         vcpu);
    if (vcpupin) {
13970
        vcpupin->vcpuid = vcpu;
H
Hu Tao 已提交
13971 13972
        virBitmapFree(vcpupin->cpumask);
        vcpupin->cpumask = virBitmapNewData(cpumap, maplen);
13973
        if (!vcpupin->cpumask)
H
Hu Tao 已提交
13974
            return -1;
13975

H
Hu Tao 已提交
13976 13977
        return 0;
    }
13978

H
Hu Tao 已提交
13979
    /* No existing vcpupin matches vcpu, adding a new one */
13980

13981
    if (VIR_ALLOC(vcpupin) < 0)
13982
        goto error;
13983

H
Hu Tao 已提交
13984
    vcpupin->vcpuid = vcpu;
H
Hu Tao 已提交
13985
    vcpupin->cpumask = virBitmapNewData(cpumap, maplen);
13986
    if (!vcpupin->cpumask)
13987
        goto error;
13988

13989
    if (VIR_REALLOC_N(*vcpupin_list, *nvcpupin + 1) < 0)
13990
        goto error;
H
Hu Tao 已提交
13991

13992
    (*vcpupin_list)[(*nvcpupin)++] = vcpupin;
H
Hu Tao 已提交
13993 13994

    return 0;
13995

13996
error:
G
Guido Günther 已提交
13997
    virDomainVcpuPinDefFree(vcpupin);
13998
    return -1;
13999 14000
}

14001
int
E
Eric Blake 已提交
14002
virDomainVcpuPinDel(virDomainDefPtr def, int vcpu)
14003 14004 14005
{
    int n;
    bool deleted = false;
E
Eric Blake 已提交
14006
    virDomainVcpuPinDefPtr *vcpupin_list = def->cputune.vcpupin;
14007 14008 14009 14010 14011 14012 14013 14014

    /* No vcpupin exists yet */
    if (!def->cputune.nvcpupin) {
        return 0;
    }

    for (n = 0; n < def->cputune.nvcpupin; n++) {
        if (vcpupin_list[n]->vcpuid == vcpu) {
14015
            virBitmapFree(vcpupin_list[n]->cpumask);
14016 14017 14018
            VIR_FREE(vcpupin_list[n]);
            memmove(&vcpupin_list[n],
                    &vcpupin_list[n+1],
E
Eric Blake 已提交
14019
                    (def->cputune.nvcpupin - n - 1) * sizeof(virDomainVcpuPinDef *));
14020 14021 14022 14023 14024 14025 14026 14027 14028
            deleted = true;
            break;
        }
    }

    if (!deleted)
        return 0;

    if (--def->cputune.nvcpupin == 0) {
14029
        VIR_FREE(def->cputune.vcpupin);
14030
    } else {
14031
        if (VIR_REALLOC_N(def->cputune.vcpupin, def->cputune.nvcpupin) < 0)
14032 14033 14034 14035 14036 14037
            return -1;
    }

    return 0;
}

14038 14039 14040 14041 14042 14043 14044 14045 14046
int
virDomainEmulatorPinAdd(virDomainDefPtr def,
                        unsigned char *cpumap,
                        int maplen)
{
    virDomainVcpuPinDefPtr emulatorpin = NULL;

    if (!def->cputune.emulatorpin) {
        /* No emulatorpin exists yet. */
14047
        if (VIR_ALLOC(emulatorpin) < 0)
H
Hu Tao 已提交
14048
            return -1;
14049 14050

        emulatorpin->vcpuid = -1;
H
Hu Tao 已提交
14051 14052 14053 14054
        emulatorpin->cpumask = virBitmapNewData(cpumap, maplen);
        if (!emulatorpin->cpumask)
            return -1;

14055 14056 14057 14058 14059
        def->cputune.emulatorpin = emulatorpin;
    } else {
        /* Since there is only 1 emulatorpin for each vm,
         * juest replace the old one.
         */
H
Hu Tao 已提交
14060 14061 14062 14063
        virBitmapFree(def->cputune.emulatorpin->cpumask);
        def->cputune.emulatorpin->cpumask = virBitmapNewData(cpumap, maplen);
        if (!def->cputune.emulatorpin->cpumask)
            return -1;
14064 14065 14066 14067 14068 14069 14070 14071 14072 14073 14074 14075
    }

    return 0;
}

int
virDomainEmulatorPinDel(virDomainDefPtr def)
{
    if (!def->cputune.emulatorpin) {
        return 0;
    }

H
Hu Tao 已提交
14076
    virDomainVcpuPinDefFree(def->cputune.emulatorpin);
14077 14078 14079 14080 14081
    def->cputune.emulatorpin = NULL;

    return 0;
}

14082
static int
14083 14084 14085 14086
virDomainEventActionDefFormat(virBufferPtr buf,
                              int type,
                              const char *name,
                              virEventActionToStringFunc convFunc)
14087
{
14088
    const char *typeStr = convFunc(type);
14089
    if (!typeStr) {
14090
        virReportError(VIR_ERR_INTERNAL_ERROR,
14091
                       _("unexpected %s action: %d"), name, type);
14092 14093 14094
        return -1;
    }

14095
    virBufferAsprintf(buf, "  <%s>%s</%s>\n", name, typeStr, name);
14096 14097 14098 14099 14100

    return 0;
}


14101 14102
static void
virSecurityLabelDefFormat(virBufferPtr buf, virSecurityLabelDefPtr def)
14103 14104 14105 14106
{
    const char *sectype = virDomainSeclabelTypeToString(def->type);

    if (!sectype)
14107 14108 14109 14110 14111
        return;

    if (def->type == VIR_DOMAIN_SECLABEL_DEFAULT)
        return;

14112 14113 14114 14115 14116 14117
    /* To avoid backward compatibility issues, suppress DAC labels that are
     * automatically generated.
     */
    if (STREQ_NULLABLE(def->model, "dac") && def->implicit)
        return;

14118 14119 14120
    virBufferAsprintf(buf, "<seclabel type='%s'",
                      sectype);

14121
    if (def->model && STRNEQ(def->model, "none"))
14122 14123
        virBufferEscapeString(buf, " model='%s'", def->model);

14124 14125 14126 14127 14128
    if (def->type == VIR_DOMAIN_SECLABEL_NONE) {
        virBufferAddLit(buf, "/>\n");
        return;
    }

14129 14130 14131
    virBufferAsprintf(buf, " relabel='%s'",
                      def->norelabel ? "no" : "yes");

14132 14133
    if (def->label || def->imagelabel || def->baselabel) {
        virBufferAddLit(buf, ">\n");
14134

14135 14136 14137 14138 14139 14140 14141 14142 14143
        virBufferEscapeString(buf, "  <label>%s</label>\n",
                              def->label);
        if (!def->norelabel)
            virBufferEscapeString(buf, "  <imagelabel>%s</imagelabel>\n",
                                  def->imagelabel);
        if (def->type == VIR_DOMAIN_SECLABEL_DYNAMIC)
            virBufferEscapeString(buf, "  <baselabel>%s</baselabel>\n",
                                  def->baselabel);
        virBufferAddLit(buf, "</seclabel>\n");
14144 14145
    } else {
        virBufferAddLit(buf, "/>\n");
14146 14147 14148 14149
    }
}


14150 14151
static void
virSecurityDeviceLabelDefFormat(virBufferPtr buf,
14152 14153
                                virSecurityDeviceLabelDefPtr def,
                                unsigned int flags)
14154
{
14155 14156 14157 14158 14159
    /* For offline output, skip elements that allow labels but have no
     * label specified (possible if labelskip was ignored on input).  */
    if ((flags & VIR_DOMAIN_XML_INACTIVE) && !def->label && !def->norelabel)
        return;

14160
    virBufferAddLit(buf, "<seclabel");
14161 14162 14163 14164

    if (def->model)
        virBufferAsprintf(buf, " model='%s'", def->model);

14165 14166 14167 14168
    if (def->labelskip)
        virBufferAddLit(buf, " labelskip='yes'");
    else
        virBufferAsprintf(buf, " relabel='%s'", def->norelabel ? "no" : "yes");
14169

14170 14171 14172 14173 14174 14175 14176 14177 14178 14179 14180
    if (def->label) {
        virBufferAddLit(buf, ">\n");
        virBufferEscapeString(buf, "  <label>%s</label>\n",
                              def->label);
        virBufferAddLit(buf, "</seclabel>\n");
    } else {
        virBufferAddLit(buf, "/>\n");
    }
}


14181 14182 14183 14184 14185 14186 14187 14188 14189 14190 14191 14192 14193 14194 14195 14196
static int
virDomainLeaseDefFormat(virBufferPtr buf,
                        virDomainLeaseDefPtr def)
{
    virBufferAddLit(buf, "    <lease>\n");
    virBufferEscapeString(buf, "      <lockspace>%s</lockspace>\n", def->lockspace);
    virBufferEscapeString(buf, "      <key>%s</key>\n", def->key);
    virBufferEscapeString(buf, "      <target path='%s'", def->path);
    if (def->offset)
        virBufferAsprintf(buf, " offset='%llu'", def->offset);
    virBufferAddLit(buf, "/>\n");
    virBufferAddLit(buf, "    </lease>\n");

    return 0;
}

14197 14198 14199
static void
virDomainDiskGeometryDefFormat(virBufferPtr buf,
                               virDomainDiskDefPtr def)
J
J.B. Joret 已提交
14200 14201 14202 14203 14204 14205 14206 14207 14208 14209 14210 14211 14212 14213 14214 14215 14216 14217 14218
{
    const char *trans =
        virDomainDiskGeometryTransTypeToString(def->geometry.trans);

    if (def->geometry.cylinders > 0 &&
        def->geometry.heads > 0 &&
        def->geometry.sectors > 0) {
        virBufferAsprintf(buf,
                          "      <geometry cyls='%u' heads='%u' secs='%u'",
                          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");
    }
}
14219

14220 14221 14222
static void
virDomainDiskBlockIoDefFormat(virBufferPtr buf,
                              virDomainDiskDefPtr def)
14223
{
V
Viktor Mihajlovski 已提交
14224 14225 14226 14227
    if (def->blockio.logical_block_size > 0 ||
        def->blockio.physical_block_size > 0) {
        virBufferAddLit(buf,"      <blockio");
        if (def->blockio.logical_block_size > 0) {
14228 14229
            virBufferAsprintf(buf,
                              " logical_block_size='%u'",
V
Viktor Mihajlovski 已提交
14230
                              def->blockio.logical_block_size);
14231
        }
V
Viktor Mihajlovski 已提交
14232
        if (def->blockio.physical_block_size > 0) {
14233 14234
            virBufferAsprintf(buf,
                              " physical_block_size='%u'",
V
Viktor Mihajlovski 已提交
14235
                              def->blockio.physical_block_size);
14236 14237 14238 14239 14240
        }
        virBufferAddLit(buf, "/>\n");
    }
}

14241 14242
static int
virDomainDiskSourceDefFormat(virBufferPtr buf,
14243 14244
                             virDomainDiskDefPtr def,
                             unsigned int flags)
14245 14246 14247 14248
{
    int n;
    const char *startupPolicy = virDomainStartupPolicyTypeToString(def->startupPolicy);

14249
    if (def->src || def->nhosts > 0 || def->srcpool ||
14250 14251 14252 14253 14254 14255 14256 14257 14258 14259 14260 14261 14262
        def->startupPolicy) {
        switch (def->type) {
        case VIR_DOMAIN_DISK_TYPE_FILE:
            virBufferAddLit(buf,"      <source");
            if (def->src)
                virBufferEscapeString(buf, " file='%s'", def->src);
            if (def->startupPolicy)
                virBufferEscapeString(buf, " startupPolicy='%s'",
                                      startupPolicy);
            if (def->nseclabels) {
                virBufferAddLit(buf, ">\n");
                virBufferAdjustIndent(buf, 8);
                for (n = 0; n < def->nseclabels; n++)
14263 14264
                    virSecurityDeviceLabelDefFormat(buf, def->seclabels[n],
                                                    flags);
14265 14266 14267 14268 14269 14270 14271
                virBufferAdjustIndent(buf, -8);
                virBufferAddLit(buf, "      </source>\n");
            } else {
                virBufferAddLit(buf, "/>\n");
            }
            break;
        case VIR_DOMAIN_DISK_TYPE_BLOCK:
14272 14273
            virBufferAddLit(buf, "      <source");
            virBufferEscapeString(buf, " dev='%s'", def->src);
14274 14275 14276
            if (def->startupPolicy)
                virBufferEscapeString(buf, " startupPolicy='%s'",
                                      startupPolicy);
14277 14278 14279 14280
            if (def->nseclabels) {
                virBufferAddLit(buf, ">\n");
                virBufferAdjustIndent(buf, 8);
                for (n = 0; n < def->nseclabels; n++)
14281 14282
                    virSecurityDeviceLabelDefFormat(buf, def->seclabels[n],
                                                    flags);
14283 14284 14285 14286 14287 14288 14289
                virBufferAdjustIndent(buf, -8);
                virBufferAddLit(buf, "      </source>\n");
            } else {
                virBufferAddLit(buf, "/>\n");
            }
            break;
        case VIR_DOMAIN_DISK_TYPE_DIR:
14290
            virBufferEscapeString(buf, "      <source dir='%s'",
14291
                                  def->src);
14292 14293 14294 14295
            if (def->startupPolicy)
                virBufferEscapeString(buf, " startupPolicy='%s'",
                                      startupPolicy);
            virBufferAddLit(buf, "/>\n");
14296 14297 14298 14299 14300 14301 14302 14303 14304 14305
            break;
        case VIR_DOMAIN_DISK_TYPE_NETWORK:
            virBufferAsprintf(buf, "      <source protocol='%s'",
                              virDomainDiskProtocolTypeToString(def->protocol));
            if (def->src) {
                virBufferEscapeString(buf, " name='%s'", def->src);
            }
            if (def->nhosts == 0) {
                virBufferAddLit(buf, "/>\n");
            } else {
14306
                size_t i;
14307 14308 14309 14310 14311 14312 14313 14314 14315 14316 14317 14318 14319 14320 14321 14322 14323 14324 14325 14326 14327 14328 14329

                virBufferAddLit(buf, ">\n");
                for (i = 0; i < def->nhosts; i++) {
                    virBufferAddLit(buf, "        <host");
                    if (def->hosts[i].name) {
                        virBufferEscapeString(buf, " name='%s'", def->hosts[i].name);
                    }
                    if (def->hosts[i].port) {
                        virBufferEscapeString(buf, " port='%s'",
                                              def->hosts[i].port);
                    }
                    if (def->hosts[i].transport) {
                        virBufferAsprintf(buf, " transport='%s'",
                                          virDomainDiskProtocolTransportTypeToString(def->hosts[i].transport));
                    }
                    if (def->hosts[i].socket) {
                        virBufferEscapeString(buf, " socket='%s'", def->hosts[i].socket);
                    }
                    virBufferAddLit(buf, "/>\n");
                }
                virBufferAddLit(buf, "      </source>\n");
            }
            break;
14330
        case VIR_DOMAIN_DISK_TYPE_VOLUME:
14331 14332
            virBufferAddLit(buf, "      <source");

14333
            if (def->srcpool) {
14334
                virBufferAsprintf(buf, " pool='%s' volume='%s'",
14335
                                  def->srcpool->pool, def->srcpool->volume);
14336 14337 14338 14339
                if (def->srcpool->mode)
                    virBufferAsprintf(buf, " mode='%s'",
                                      virDomainDiskSourcePoolModeTypeToString(def->srcpool->mode));
            }
14340
            if (def->startupPolicy)
14341 14342 14343 14344 14345 14346
                virBufferEscapeString(buf, " startupPolicy='%s'", startupPolicy);

            if (def->nseclabels) {
                virBufferAddLit(buf, ">\n");
                virBufferAdjustIndent(buf, 8);
                for (n = 0; n < def->nseclabels; n++)
14347 14348
                    virSecurityDeviceLabelDefFormat(buf, def->seclabels[n],
                                                    flags);
14349 14350 14351
                virBufferAdjustIndent(buf, -8);
                virBufferAddLit(buf, "      </source>\n");
            } else {
14352
                virBufferAddLit(buf, "/>\n");
14353
            }
14354
            break;
14355 14356 14357 14358 14359 14360 14361 14362 14363 14364
        default:
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected disk type %s"),
                           virDomainDiskTypeToString(def->type));
            return -1;
        }
    }

    return 0;
}
J
J.B. Joret 已提交
14365

14366
static int
14367
virDomainDiskDefFormat(virBufferPtr buf,
D
Daniel P. Berrange 已提交
14368
                       virDomainDiskDefPtr def,
E
Eric Blake 已提交
14369
                       unsigned int flags)
14370 14371 14372 14373
{
    const char *type = virDomainDiskTypeToString(def->type);
    const char *device = virDomainDiskDeviceTypeToString(def->device);
    const char *bus = virDomainDiskBusTypeToString(def->bus);
14374
    const char *cachemode = virDomainDiskCacheTypeToString(def->cachemode);
14375
    const char *error_policy = virDomainDiskErrorPolicyTypeToString(def->error_policy);
14376
    const char *rerror_policy = virDomainDiskErrorPolicyTypeToString(def->rerror_policy);
M
Matthias Dahl 已提交
14377
    const char *iomode = virDomainDiskIoTypeToString(def->iomode);
14378
    const char *ioeventfd = virDomainIoEventFdTypeToString(def->ioeventfd);
14379
    const char *event_idx = virDomainVirtioEventIdxTypeToString(def->event_idx);
14380
    const char *copy_on_read = virDomainDiskCopyOnReadTypeToString(def->copy_on_read);
14381
    const char *sgio = virDomainDeviceSGIOTypeToString(def->sgio);
O
Osier Yang 已提交
14382
    const char *discard = virDomainDiskDiscardTypeToString(def->discard);
14383

14384 14385
    char uuidstr[VIR_UUID_STRING_BUFLEN];

14386
    if (!type) {
14387 14388
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected disk type %d"), def->type);
14389 14390 14391
        return -1;
    }
    if (!device) {
14392 14393
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected disk device %d"), def->device);
14394 14395 14396
        return -1;
    }
    if (!bus) {
14397 14398
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected disk bus %d"), def->bus);
14399 14400
        return -1;
    }
14401
    if (!cachemode) {
14402 14403
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected disk cache mode %d"), def->cachemode);
14404 14405
        return -1;
    }
M
Matthias Dahl 已提交
14406
    if (!iomode) {
14407 14408
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected disk io mode %d"), def->iomode);
M
Matthias Dahl 已提交
14409 14410
        return -1;
    }
O
Osier Yang 已提交
14411 14412 14413 14414 14415
    if (!sgio) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unexpected disk sgio mode '%d'"), def->sgio);
        return -1;
    }
14416

14417
    virBufferAsprintf(buf,
14418
                      "    <disk type='%s' device='%s'",
14419
                      type, device);
14420 14421 14422 14423 14424 14425 14426
    if (def->rawio_specified) {
        if (def->rawio == 1) {
            virBufferAddLit(buf, " rawio='yes'");
        } else if (def->rawio == 0) {
            virBufferAddLit(buf, " rawio='no'");
        }
    }
O
Osier Yang 已提交
14427 14428 14429 14430

    if (def->sgio)
        virBufferAsprintf(buf, " sgio='%s'", sgio);

14431
    if (def->snapshot &&
E
Eric Blake 已提交
14432
        !(def->snapshot == VIR_DOMAIN_SNAPSHOT_LOCATION_NONE && def->readonly))
14433
        virBufferAsprintf(buf, " snapshot='%s'",
E
Eric Blake 已提交
14434
                          virDomainSnapshotLocationTypeToString(def->snapshot));
14435
    virBufferAddLit(buf, ">\n");
14436

14437
    if (def->driverName || def->format > 0 || def->cachemode ||
O
Osier Yang 已提交
14438
        def->ioeventfd || def->event_idx || def->copy_on_read) {
14439
        virBufferAddLit(buf, "      <driver");
14440
        if (def->driverName)
14441
            virBufferAsprintf(buf, " name='%s'", def->driverName);
14442 14443 14444
        if (def->format > 0)
            virBufferAsprintf(buf, " type='%s'",
                              virStorageFileFormatTypeToString(def->format));
14445
        if (def->cachemode)
14446
            virBufferAsprintf(buf, " cache='%s'", cachemode);
14447
        if (def->error_policy)
14448
            virBufferAsprintf(buf, " error_policy='%s'", error_policy);
14449 14450
        if (def->rerror_policy)
            virBufferAsprintf(buf, " rerror_policy='%s'", rerror_policy);
M
Matthias Dahl 已提交
14451
        if (def->iomode)
14452
            virBufferAsprintf(buf, " io='%s'", iomode);
14453 14454
        if (def->ioeventfd)
            virBufferAsprintf(buf, " ioeventfd='%s'", ioeventfd);
14455 14456
        if (def->event_idx)
            virBufferAsprintf(buf, " event_idx='%s'", event_idx);
O
Osier Yang 已提交
14457 14458
        if (def->copy_on_read)
            virBufferAsprintf(buf, " copy_on_read='%s'", copy_on_read);
O
Osier Yang 已提交
14459 14460
        if (def->discard)
            virBufferAsprintf(buf, " discard='%s'", discard);
14461
        virBufferAddLit(buf, "/>\n");
14462 14463
    }

14464 14465 14466
    if (def->auth.username) {
        virBufferEscapeString(buf, "      <auth username='%s'>\n",
                              def->auth.username);
14467
        if (def->protocol == VIR_DOMAIN_DISK_PROTOCOL_ISCSI) {
14468
            virBufferAddLit(buf, "        <secret type='iscsi'");
14469
        } else if (def->protocol == VIR_DOMAIN_DISK_PROTOCOL_RBD) {
14470
            virBufferAddLit(buf, "        <secret type='ceph'");
14471 14472
        }

14473 14474
        if (def->auth.secretType == VIR_DOMAIN_DISK_SECRET_TYPE_UUID) {
            virUUIDFormat(def->auth.secret.uuid, uuidstr);
14475
            virBufferAsprintf(buf, " uuid='%s'/>\n", uuidstr);
14476 14477
        }
        if (def->auth.secretType == VIR_DOMAIN_DISK_SECRET_TYPE_USAGE) {
14478
            virBufferEscapeString(buf, " usage='%s'/>\n",
14479 14480 14481 14482 14483
                                  def->auth.secret.usage);
        }
        virBufferAddLit(buf, "      </auth>\n");
    }

14484
    if (virDomainDiskSourceDefFormat(buf, def, flags) < 0)
14485
        return -1;
J
J.B. Joret 已提交
14486
    virDomainDiskGeometryDefFormat(buf, def);
V
Viktor Mihajlovski 已提交
14487
    virDomainDiskBlockIoDefFormat(buf, def);
J
J.B. Joret 已提交
14488

14489 14490 14491 14492 14493 14494
    /* For now, mirroring is currently output-only: we only output it
     * for live domains, therefore we ignore it on input except for
     * the internal parse on libvirtd restart.  */
    if (def->mirror && !(flags & VIR_DOMAIN_XML_INACTIVE)) {
        virBufferEscapeString(buf, "      <mirror file='%s'", def->mirror);
        if (def->mirrorFormat)
14495 14496
            virBufferAsprintf(buf, " format='%s'",
                              virStorageFileFormatTypeToString(def->mirrorFormat));
14497 14498 14499 14500 14501
        if (def->mirroring)
            virBufferAddLit(buf, " ready='yes'");
        virBufferAddLit(buf, "/>\n");
    }

14502
    virBufferAsprintf(buf, "      <target dev='%s' bus='%s'",
14503
                      def->dst, bus);
14504 14505
    if ((def->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY ||
         def->device == VIR_DOMAIN_DISK_DEVICE_CDROM) &&
E
Eric Blake 已提交
14506
        def->tray_status != VIR_DOMAIN_DISK_TRAY_CLOSED)
14507
        virBufferAsprintf(buf, " tray='%s'",
14508
                          virDomainDiskTrayTypeToString(def->tray_status));
14509 14510 14511 14512 14513 14514
    if (def->bus == VIR_DOMAIN_DISK_BUS_USB &&
        def->removable != VIR_DOMAIN_FEATURE_STATE_DEFAULT) {
        virBufferAsprintf(buf, " removable='%s'",
                          virDomainFeatureStateTypeToString(def->removable));
    }
    virBufferAddLit(buf, "/>\n");
14515

L
Lei Li 已提交
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
    /*disk I/O throttling*/
    if (def->blkdeviotune.total_bytes_sec ||
        def->blkdeviotune.read_bytes_sec ||
        def->blkdeviotune.write_bytes_sec ||
        def->blkdeviotune.total_iops_sec ||
        def->blkdeviotune.read_iops_sec ||
        def->blkdeviotune.write_iops_sec) {
        virBufferAddLit(buf, "      <iotune>\n");
        if (def->blkdeviotune.total_bytes_sec) {
            virBufferAsprintf(buf, "        <total_bytes_sec>%llu</total_bytes_sec>\n",
                              def->blkdeviotune.total_bytes_sec);
        }

        if (def->blkdeviotune.read_bytes_sec) {
            virBufferAsprintf(buf, "        <read_bytes_sec>%llu</read_bytes_sec>\n",
                              def->blkdeviotune.read_bytes_sec);

        }

        if (def->blkdeviotune.write_bytes_sec) {
            virBufferAsprintf(buf, "        <write_bytes_sec>%llu</write_bytes_sec>\n",
                              def->blkdeviotune.write_bytes_sec);
        }

        if (def->blkdeviotune.total_iops_sec) {
            virBufferAsprintf(buf, "        <total_iops_sec>%llu</total_iops_sec>\n",
                              def->blkdeviotune.total_iops_sec);
        }

        if (def->blkdeviotune.read_iops_sec) {
14546
            virBufferAsprintf(buf, "        <read_iops_sec>%llu</read_iops_sec>\n",
L
Lei Li 已提交
14547 14548 14549 14550
                              def->blkdeviotune.read_iops_sec);
        }

        if (def->blkdeviotune.write_iops_sec) {
14551
            virBufferAsprintf(buf, "        <write_iops_sec>%llu</write_iops_sec>\n",
L
Lei Li 已提交
14552 14553 14554 14555 14556 14557
                              def->blkdeviotune.write_iops_sec);
        }

        virBufferAddLit(buf, "      </iotune>\n");
    }

14558 14559 14560 14561
    if (def->readonly)
        virBufferAddLit(buf, "      <readonly/>\n");
    if (def->shared)
        virBufferAddLit(buf, "      <shareable/>\n");
14562 14563
    if (def->transient)
        virBufferAddLit(buf, "      <transient/>\n");
14564
    virBufferEscapeString(buf, "      <serial>%s</serial>\n", def->serial);
O
Osier Yang 已提交
14565
    virBufferEscapeString(buf, "      <wwn>%s</wwn>\n", def->wwn);
14566 14567
    virBufferEscapeString(buf, "      <vendor>%s</vendor>\n", def->vendor);
    virBufferEscapeString(buf, "      <product>%s</product>\n", def->product);
14568 14569 14570 14571 14572 14573
    if (def->encryption) {
        virBufferAdjustIndent(buf, 6);
        if (virStorageEncryptionFormat(buf, def->encryption) < 0)
            return -1;
        virBufferAdjustIndent(buf, -6);
    }
14574

14575 14576
    if (virDomainDeviceInfoFormat(buf, &def->info,
                                  flags | VIR_DOMAIN_XML_INTERNAL_ALLOW_BOOT) < 0)
14577
        return -1;
14578

14579 14580 14581 14582 14583
    virBufferAddLit(buf, "    </disk>\n");

    return 0;
}

14584 14585 14586 14587 14588 14589
static const char *
virDomainControllerModelTypeToString(virDomainControllerDefPtr def,
                                     int model)
{
    if (def->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI)
        return virDomainControllerModelSCSITypeToString(model);
14590 14591
    else if (def->type == VIR_DOMAIN_CONTROLLER_TYPE_USB)
        return virDomainControllerModelUSBTypeToString(model);
J
Ján Tomko 已提交
14592 14593
    else if (def->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI)
        return virDomainControllerModelPCITypeToString(model);
14594 14595 14596 14597

    return NULL;
}

14598
static int
14599
virDomainControllerDefFormat(virBufferPtr buf,
D
Daniel P. Berrange 已提交
14600
                             virDomainControllerDefPtr def,
E
Eric Blake 已提交
14601
                             unsigned int flags)
14602 14603
{
    const char *type = virDomainControllerTypeToString(def->type);
14604
    const char *model = NULL;
14605
    bool pcihole64 = false;
14606 14607

    if (!type) {
14608 14609
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected controller type %d"), def->type);
14610 14611 14612
        return -1;
    }

14613
    if (def->model != -1) {
14614
        model = virDomainControllerModelTypeToString(def, def->model);
14615 14616

        if (!model) {
14617 14618
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected model type %d"), def->model);
14619 14620 14621 14622
            return -1;
        }
    }

14623
    virBufferAsprintf(buf,
14624
                      "    <controller type='%s' index='%u'",
14625 14626
                      type, def->idx);

14627 14628 14629 14630
    if (model) {
        virBufferEscapeString(buf, " model='%s'", model);
    }

14631 14632 14633
    switch (def->type) {
    case VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL:
        if (def->opts.vioserial.ports != -1) {
14634
            virBufferAsprintf(buf, " ports='%d'",
14635 14636 14637
                              def->opts.vioserial.ports);
        }
        if (def->opts.vioserial.vectors != -1) {
14638
            virBufferAsprintf(buf, " vectors='%d'",
14639 14640 14641 14642
                              def->opts.vioserial.vectors);
        }
        break;

14643 14644 14645 14646 14647
    case VIR_DOMAIN_CONTROLLER_TYPE_PCI:
        if (def->opts.pciopts.pcihole64)
            pcihole64 = true;
        break;

14648 14649 14650 14651
    default:
        break;
    }

14652 14653
    if (def->queues || virDomainDeviceInfoIsSet(&def->info, flags) ||
        pcihole64) {
14654
        virBufferAddLit(buf, ">\n");
14655 14656 14657 14658 14659 14660

        if (def->queues)
            virBufferAsprintf(buf, "      <driver queues='%u'/>\n", def->queues);

        if (virDomainDeviceInfoIsSet(&def->info, flags) &&
            virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
14661
            return -1;
14662

14663 14664 14665 14666 14667
        if (pcihole64) {
            virBufferAsprintf(buf, "      <pcihole64 unit='KiB'>%lu</"
                              "pcihole64>\n", def->opts.pciopts.pcihole64size);
        }

14668 14669 14670 14671 14672 14673 14674 14675
        virBufferAddLit(buf, "    </controller>\n");
    } else {
        virBufferAddLit(buf, "/>\n");
    }

    return 0;
}

14676 14677 14678 14679 14680

int
virDomainFSIndexByName(virDomainDefPtr def, const char *name)
{
    virDomainFSDefPtr fs;
14681
    size_t i;
14682 14683 14684 14685 14686 14687 14688 14689 14690 14691

    for (i = 0; i < def->nfss; i++) {
        fs = def->fss[i];
        if (STREQ(fs->dst, name))
            return i;
    }
    return -1;
}


14692
static int
14693
virDomainFSDefFormat(virBufferPtr buf,
14694
                     virDomainFSDefPtr def,
E
Eric Blake 已提交
14695
                     unsigned int flags)
14696 14697
{
    const char *type = virDomainFSTypeToString(def->type);
14698
    const char *accessmode = virDomainFSAccessModeTypeToString(def->accessmode);
14699
    const char *fsdriver = virDomainFSDriverTypeTypeToString(def->fsdriver);
14700
    const char *wrpolicy = virDomainFSWrpolicyTypeToString(def->wrpolicy);
14701 14702

    if (!type) {
14703 14704
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected filesystem type %d"), def->type);
14705 14706 14707
        return -1;
    }

14708
   if (!accessmode) {
14709 14710
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected accessmode %d"), def->accessmode);
14711 14712 14713 14714
        return -1;
    }


14715
    virBufferAsprintf(buf,
14716 14717
                      "    <filesystem type='%s' accessmode='%s'>\n",
                      type, accessmode);
14718

14719
    if (def->fsdriver) {
14720 14721
        virBufferAsprintf(buf, "      <driver type='%s'", fsdriver);

14722 14723 14724 14725
        if (def->format)
            virBufferAsprintf(buf, " format='%s'",
                              virStorageFileFormatTypeToString(def->format));

14726
        /* Don't generate anything if wrpolicy is set to default */
14727
        if (def->wrpolicy)
14728 14729 14730
            virBufferAsprintf(buf, " wrpolicy='%s'", wrpolicy);

        virBufferAddLit(buf, "/>\n");
14731 14732
    }

14733 14734
    switch (def->type) {
    case VIR_DOMAIN_FS_TYPE_MOUNT:
14735
    case VIR_DOMAIN_FS_TYPE_BIND:
14736 14737 14738
        virBufferEscapeString(buf, "      <source dir='%s'/>\n",
                              def->src);
        break;
14739

14740 14741 14742 14743
    case VIR_DOMAIN_FS_TYPE_BLOCK:
        virBufferEscapeString(buf, "      <source dev='%s'/>\n",
                              def->src);
        break;
14744

14745 14746 14747 14748
    case VIR_DOMAIN_FS_TYPE_FILE:
        virBufferEscapeString(buf, "      <source file='%s'/>\n",
                              def->src);
        break;
14749

14750 14751 14752 14753 14754 14755 14756 14757 14758
    case VIR_DOMAIN_FS_TYPE_TEMPLATE:
        virBufferEscapeString(buf, "      <source name='%s'/>\n",
                              def->src);
        break;

    case VIR_DOMAIN_FS_TYPE_RAM:
        virBufferAsprintf(buf, "      <source usage='%lld' units='KiB'/>\n",
                          def->usage / 1024);
        break;
14759 14760
    }

14761 14762
    virBufferEscapeString(buf, "      <target dir='%s'/>\n",
                          def->dst);
14763 14764 14765 14766

    if (def->readonly)
        virBufferAddLit(buf, "      <readonly/>\n");

14767 14768 14769
    if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
        return -1;

14770 14771 14772 14773 14774 14775 14776 14777

    if (def->space_hard_limit)
        virBufferAsprintf(buf, "      <space_hard_limit unit='bytes'>"
                          "%llu</space_hard_limit>\n", def->space_hard_limit);
    if (def->space_soft_limit) {
        virBufferAsprintf(buf, "      <space_soft_limit unit='bytes'>"
                          "%llu</space_soft_limit>\n", def->space_soft_limit);
    }
14778 14779 14780 14781 14782
    virBufferAddLit(buf, "    </filesystem>\n");

    return 0;
}

14783
static int
14784 14785 14786 14787
virDomainHostdevDefFormatSubsys(virBufferPtr buf,
                                virDomainHostdevDefPtr def,
                                unsigned int flags,
                                bool includeTypeInAddr)
14788
{
14789
    if (def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI &&
14790
        def->source.subsys.u.pci.backend != VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT) {
14791 14792 14793 14794 14795 14796 14797 14798 14799 14800 14801
        const char *backend = virDomainHostdevSubsysPciBackendTypeToString(def->source.subsys.u.pci.backend);

        if (!backend) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected pci hostdev driver name type %d"),
                           def->source.subsys.u.pci.backend);
            return -1;
        }
        virBufferAsprintf(buf, "<driver name='%s'/>\n", backend);
    }

14802 14803 14804 14805 14806 14807
    virBufferAddLit(buf, "<source");
    if (def->startupPolicy) {
        const char *policy;
        policy = virDomainStartupPolicyTypeToString(def->startupPolicy);
        virBufferAsprintf(buf, " startupPolicy='%s'", policy);
    }
14808 14809 14810
    if (def->source.subsys.u.usb.autoAddress &&
        (flags & VIR_DOMAIN_XML_MIGRATABLE))
        virBufferAddLit(buf, " autoAddress='yes'");
14811 14812 14813 14814 14815

    if (def->missing &&
        !(flags & VIR_DOMAIN_XML_INACTIVE))
        virBufferAddLit(buf, " missing='yes'");

14816 14817
    virBufferAddLit(buf, ">\n");

14818
    virBufferAdjustIndent(buf, 2);
14819 14820 14821 14822
    switch (def->source.subsys.type)
    {
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
        if (def->source.subsys.u.usb.vendor) {
14823
            virBufferAsprintf(buf, "<vendor id='0x%.4x'/>\n",
14824
                              def->source.subsys.u.usb.vendor);
14825
            virBufferAsprintf(buf, "<product id='0x%.4x'/>\n",
14826 14827 14828 14829
                              def->source.subsys.u.usb.product);
        }
        if (def->source.subsys.u.usb.bus ||
            def->source.subsys.u.usb.device) {
14830
            virBufferAsprintf(buf, "<address %sbus='%d' device='%d'/>\n",
14831 14832 14833 14834 14835 14836
                              includeTypeInAddr ? "type='usb' " : "",
                              def->source.subsys.u.usb.bus,
                              def->source.subsys.u.usb.device);
        }
        break;
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
14837
        if (virDevicePCIAddressFormat(buf,
14838
                                      def->source.subsys.u.pci.addr,
14839 14840 14841
                                      includeTypeInAddr) != 0)
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("PCI address Formatting failed"));
14842 14843 14844 14845 14846

        if ((flags & VIR_DOMAIN_XML_INTERNAL_PCI_ORIG_STATES) &&
            (def->origstates.states.pci.unbind_from_stub ||
             def->origstates.states.pci.remove_slot ||
             def->origstates.states.pci.reprobe)) {
14847
            virBufferAddLit(buf, "<origstates>\n");
14848
            if (def->origstates.states.pci.unbind_from_stub)
14849
                virBufferAddLit(buf, "  <unbind/>\n");
14850
            if (def->origstates.states.pci.remove_slot)
14851
                virBufferAddLit(buf, "  <removeslot/>\n");
14852
            if (def->origstates.states.pci.reprobe)
14853 14854
                virBufferAddLit(buf, "  <reprobe/>\n");
            virBufferAddLit(buf, "</origstates>\n");
14855 14856
        }
        break;
H
Han Cheng 已提交
14857 14858 14859 14860 14861 14862 14863 14864 14865
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
        virBufferAsprintf(buf, "<adapter name='%s'/>\n",
                          def->source.subsys.u.scsi.adapter);
        virBufferAsprintf(buf, "<address %sbus='%d' target='%d' unit='%d'/>\n",
                          includeTypeInAddr ? "type='scsi' " : "",
                          def->source.subsys.u.scsi.bus,
                          def->source.subsys.u.scsi.target,
                          def->source.subsys.u.scsi.unit);
        break;
14866
    default:
14867 14868 14869
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected hostdev type %d"),
                       def->source.subsys.type);
14870 14871 14872
        return -1;
    }

14873
    virBufferAdjustIndent(buf, -2);
14874 14875 14876 14877
    virBufferAddLit(buf, "</source>\n");
    return 0;
}

14878 14879 14880 14881 14882 14883 14884 14885 14886 14887 14888 14889 14890 14891 14892 14893 14894
static int
virDomainHostdevDefFormatCaps(virBufferPtr buf,
                              virDomainHostdevDefPtr def)
{
    virBufferAddLit(buf, "<source>\n");

    virBufferAdjustIndent(buf, 2);
    switch (def->source.caps.type)
    {
    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;
14895 14896 14897 14898
    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_NET:
        virBufferEscapeString(buf, "<interface>%s</interface>\n",
                              def->source.caps.u.net.iface);
        break;
14899 14900 14901 14902 14903 14904 14905 14906 14907 14908 14909 14910
    default:
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected hostdev type %d"),
                       def->source.caps.type);
        return -1;
    }

    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</source>\n");
    return 0;
}

14911 14912
static int
virDomainActualNetDefFormat(virBufferPtr buf,
14913 14914
                            virDomainActualNetDefPtr def,
                            unsigned int flags)
14915 14916 14917 14918 14919 14920 14921 14922 14923
{
    const char *type;
    const char *mode;

    if (!def)
        return 0;

    type = virDomainNetTypeToString(def->type);
    if (!type) {
14924 14925
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected net type %d"), def->type);
14926
        return -1;
14927 14928
    }

14929
    virBufferAsprintf(buf, "<actual type='%s'", type);
E
Eric Blake 已提交
14930
    if (def->type == VIR_DOMAIN_NET_TYPE_HOSTDEV &&
14931 14932
        def->data.hostdev.def.managed) {
        virBufferAddLit(buf, " managed='yes'");
14933
    }
14934
    virBufferAddLit(buf, ">\n");
14935

14936
    virBufferAdjustIndent(buf, 2);
14937 14938
    switch (def->type) {
    case VIR_DOMAIN_NET_TYPE_BRIDGE:
14939
        virBufferEscapeString(buf, "<source bridge='%s'/>\n",
14940
                              def->data.bridge.brname);
14941 14942 14943
        break;

    case VIR_DOMAIN_NET_TYPE_DIRECT:
14944
        virBufferAddLit(buf, "<source");
14945 14946 14947 14948
        if (def->data.direct.linkdev)
            virBufferEscapeString(buf, " dev='%s'",
                                  def->data.direct.linkdev);

14949
        mode = virNetDevMacVLanModeTypeToString(def->data.direct.mode);
14950
        if (!mode) {
14951 14952 14953
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected source mode %d"),
                           def->data.direct.mode);
14954
            return -1;
14955 14956 14957
        }
        virBufferAsprintf(buf, " mode='%s'/>\n", mode);
        break;
14958 14959

    case VIR_DOMAIN_NET_TYPE_HOSTDEV:
14960 14961
        if (virDomainHostdevDefFormatSubsys(buf, &def->data.hostdev.def,
                                            flags, true) < 0) {
14962 14963
            return -1;
        }
14964
        break;
14965 14966

    case VIR_DOMAIN_NET_TYPE_NETWORK:
14967 14968
        if (def->class_id)
            virBufferAsprintf(buf, "<class id='%u'/>", def->class_id);
14969 14970
        break;
    default:
14971 14972
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected net type %s"), type);
14973
        return -1;
14974
    }
14975

14976 14977
    if (virNetDevVlanFormat(&def->vlan, buf) < 0)
        return -1;
14978
    if (virNetDevVPortProfileFormat(def->virtPortProfile, buf) < 0)
14979
        return -1;
14980
    if (virNetDevBandwidthFormat(def->bandwidth, buf) < 0)
14981
        return -1;
14982

14983 14984
    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</actual>\n");
14985
    return 0;
14986 14987
}

14988
static int
14989
virDomainNetDefFormat(virBufferPtr buf,
14990
                      virDomainNetDefPtr def,
E
Eric Blake 已提交
14991
                      unsigned int flags)
14992 14993
{
    const char *type = virDomainNetTypeToString(def->type);
14994
    char macstr[VIR_MAC_STRING_BUFLEN];
14995 14996

    if (!type) {
14997 14998
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected net type %d"), def->type);
14999 15000 15001
        return -1;
    }

15002
    virBufferAsprintf(buf, "    <interface type='%s'", type);
E
Eric Blake 已提交
15003
    if (def->type == VIR_DOMAIN_NET_TYPE_HOSTDEV &&
15004 15005 15006 15007
        def->data.hostdev.def.managed) {
        virBufferAddLit(buf, " managed='yes'");
    }
    virBufferAddLit(buf, ">\n");
15008

15009
    virBufferAdjustIndent(buf, 6);
15010 15011
    virBufferAsprintf(buf, "<mac address='%s'/>\n",
                      virMacAddrFormat(&def->mac, macstr));
15012 15013 15014

    switch (def->type) {
    case VIR_DOMAIN_NET_TYPE_NETWORK:
15015
        virBufferEscapeString(buf, "<source network='%s'",
15016
                              def->data.network.name);
15017 15018
        virBufferEscapeString(buf, " portgroup='%s'",
                              def->data.network.portgroup);
15019 15020
        virBufferAddLit(buf, "/>\n");
        if ((flags & VIR_DOMAIN_XML_INTERNAL_ACTUAL_NET) &&
15021
            (virDomainActualNetDefFormat(buf, def->data.network.actual, flags) < 0))
15022
            return -1;
15023 15024 15025
        break;

    case VIR_DOMAIN_NET_TYPE_ETHERNET:
15026
        virBufferEscapeString(buf, "<source dev='%s'/>\n",
15027
                              def->data.ethernet.dev);
15028
        if (def->data.ethernet.ipaddr)
15029
            virBufferAsprintf(buf, "<ip address='%s'/>\n",
15030 15031 15032 15033
                              def->data.ethernet.ipaddr);
        break;

    case VIR_DOMAIN_NET_TYPE_BRIDGE:
15034
        virBufferEscapeString(buf, "<source bridge='%s'/>\n",
15035
                              def->data.bridge.brname);
15036 15037
        if (def->data.bridge.ipaddr) {
            virBufferAsprintf(buf, "<ip address='%s'/>\n",
15038
                              def->data.bridge.ipaddr);
15039
        }
15040 15041 15042 15043 15044
        break;

    case VIR_DOMAIN_NET_TYPE_SERVER:
    case VIR_DOMAIN_NET_TYPE_CLIENT:
    case VIR_DOMAIN_NET_TYPE_MCAST:
15045 15046
        if (def->data.socket.address) {
            virBufferAsprintf(buf, "<source address='%s' port='%d'/>\n",
15047
                              def->data.socket.address, def->data.socket.port);
15048 15049
        } else {
            virBufferAsprintf(buf, "<source port='%d'/>\n",
15050
                              def->data.socket.port);
15051
        }
15052
        break;
D
Daniel Veillard 已提交
15053 15054

    case VIR_DOMAIN_NET_TYPE_INTERNAL:
15055
        virBufferEscapeString(buf, "<source name='%s'/>\n",
D
Daniel Veillard 已提交
15056 15057 15058
                              def->data.internal.name);
        break;

15059
    case VIR_DOMAIN_NET_TYPE_DIRECT:
15060
        virBufferEscapeString(buf, "<source dev='%s'",
15061
                              def->data.direct.linkdev);
15062
        virBufferAsprintf(buf, " mode='%s'",
15063
                          virNetDevMacVLanModeTypeToString(def->data.direct.mode));
15064 15065
        virBufferAddLit(buf, "/>\n");
        break;
S
Stefan Berger 已提交
15066

15067
    case VIR_DOMAIN_NET_TYPE_HOSTDEV:
15068 15069
        if (virDomainHostdevDefFormatSubsys(buf, &def->data.hostdev.def,
                                            flags, true) < 0) {
15070 15071 15072 15073
            return -1;
        }
        break;

S
Stefan Berger 已提交
15074 15075 15076
    case VIR_DOMAIN_NET_TYPE_USER:
    case VIR_DOMAIN_NET_TYPE_LAST:
        break;
15077 15078
    }

15079 15080
    if (virNetDevVlanFormat(&def->vlan, buf) < 0)
        return -1;
15081
    if (virNetDevVPortProfileFormat(def->virtPortProfile, buf) < 0)
15082
        return -1;
15083
    virBufferEscapeString(buf, "<script path='%s'/>\n",
15084
                          def->script);
15085 15086 15087 15088
    if (def->ifname &&
        !((flags & VIR_DOMAIN_XML_INACTIVE) &&
          (STRPREFIX(def->ifname, VIR_NET_GENERATED_PREFIX)))) {
        /* Skip auto-generated target names for inactive config. */
15089
        virBufferEscapeString(buf, "<target dev='%s'/>\n", def->ifname);
15090
    }
15091
    if (def->model) {
15092
        virBufferEscapeString(buf, "<model type='%s'/>\n",
15093
                              def->model);
15094
        if (STREQ(def->model, "virtio") &&
15095
            (def->driver.virtio.name || def->driver.virtio.txmode)) {
15096
            virBufferAddLit(buf, "<driver");
15097
            if (def->driver.virtio.name) {
15098
                virBufferAsprintf(buf, " name='%s'",
15099 15100
                                  virDomainNetBackendTypeToString(def->driver.virtio.name));
            }
15101
            if (def->driver.virtio.txmode) {
15102
                virBufferAsprintf(buf, " txmode='%s'",
15103 15104
                                  virDomainNetVirtioTxModeTypeToString(def->driver.virtio.txmode));
            }
15105 15106 15107 15108
            if (def->driver.virtio.ioeventfd) {
                virBufferAsprintf(buf, " ioeventfd='%s'",
                                  virDomainIoEventFdTypeToString(def->driver.virtio.ioeventfd));
            }
15109 15110 15111 15112
            if (def->driver.virtio.event_idx) {
                virBufferAsprintf(buf, " event_idx='%s'",
                                  virDomainVirtioEventIdxTypeToString(def->driver.virtio.event_idx));
            }
15113 15114
            if (def->driver.virtio.queues)
                virBufferAsprintf(buf, " queues='%u'", def->driver.virtio.queues);
15115
            virBufferAddLit(buf, "/>\n");
15116 15117
        }
    }
15118
    if (def->filter) {
15119 15120 15121
        if (virNWFilterFormatParamAttributes(buf, def->filterparams,
                                             def->filter) < 0)
            return -1;
15122
    }
15123

15124
    if (def->tune.sndbuf_specified) {
15125 15126 15127
        virBufferAddLit(buf,   "<tune>\n");
        virBufferAsprintf(buf, "  <sndbuf>%lu</sndbuf>\n", def->tune.sndbuf);
        virBufferAddLit(buf,   "</tune>\n");
15128 15129
    }

15130 15131
    if (def->linkstate) {
        virBufferAsprintf(buf, "<link state='%s'/>\n",
15132
                          virDomainNetInterfaceLinkStateTypeToString(def->linkstate));
15133
    }
15134

15135
    if (virNetDevBandwidthFormat(def->bandwidth, buf) < 0)
15136
        return -1;
15137

15138
    virBufferAdjustIndent(buf, -6);
15139

15140
    if (virDomainDeviceInfoFormat(buf, &def->info,
15141 15142
                                  flags | VIR_DOMAIN_XML_INTERNAL_ALLOW_BOOT
                                  | VIR_DOMAIN_XML_INTERNAL_ALLOW_ROM) < 0)
15143 15144
        return -1;

15145 15146 15147 15148 15149 15150
    virBufferAddLit(buf, "    </interface>\n");

    return 0;
}


15151 15152
/* Assumes that "<device" has already been generated, and starts
 * output at " type='type'>". */
15153
static int
15154 15155 15156
virDomainChrSourceDefFormat(virBufferPtr buf,
                            virDomainChrSourceDefPtr def,
                            bool tty_compat,
E
Eric Blake 已提交
15157
                            unsigned int flags)
15158 15159
{
    const char *type = virDomainChrTypeToString(def->type);
15160

15161
    if (!type) {
15162 15163
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected char type %d"), def->type);
15164
        return -1;
15165 15166
    }

15167
    /* Compat with legacy <console tty='/dev/pts/5'/> syntax */
15168
    virBufferAsprintf(buf, " type='%s'", type);
15169
    if (tty_compat) {
C
Cole Robinson 已提交
15170
        virBufferEscapeString(buf, " tty='%s'",
15171 15172
                              def->data.file.path);
    }
C
Cole Robinson 已提交
15173
    virBufferAddLit(buf, ">\n");
15174 15175 15176 15177 15178

    switch (def->type) {
    case VIR_DOMAIN_CHR_TYPE_NULL:
    case VIR_DOMAIN_CHR_TYPE_VC:
    case VIR_DOMAIN_CHR_TYPE_STDIO:
15179
    case VIR_DOMAIN_CHR_TYPE_SPICEVMC:
15180 15181 15182 15183 15184 15185 15186 15187
        /* 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 ||
15188 15189
            (def->data.file.path &&
             !(flags & VIR_DOMAIN_XML_INACTIVE))) {
15190 15191 15192 15193 15194 15195 15196 15197
            virBufferEscapeString(buf, "      <source path='%s'/>\n",
                                  def->data.file.path);
        }
        break;

    case VIR_DOMAIN_CHR_TYPE_UDP:
        if (def->data.udp.bindService &&
            def->data.udp.bindHost) {
15198
            virBufferAsprintf(buf,
15199 15200
                              "      <source mode='bind' host='%s' "
                              "service='%s'/>\n",
15201 15202 15203
                              def->data.udp.bindHost,
                              def->data.udp.bindService);
        } else if (def->data.udp.bindHost) {
15204
            virBufferAsprintf(buf, "      <source mode='bind' host='%s'/>\n",
15205 15206
                              def->data.udp.bindHost);
        } else if (def->data.udp.bindService) {
15207
            virBufferAsprintf(buf, "      <source mode='bind' service='%s'/>\n",
15208 15209 15210 15211 15212
                              def->data.udp.bindService);
        }

        if (def->data.udp.connectService &&
            def->data.udp.connectHost) {
15213
            virBufferAsprintf(buf,
15214 15215
                              "      <source mode='connect' host='%s' "
                              "service='%s'/>\n",
15216 15217 15218
                              def->data.udp.connectHost,
                              def->data.udp.connectService);
        } else if (def->data.udp.connectHost) {
15219
            virBufferAsprintf(buf, "      <source mode='connect' host='%s'/>\n",
15220 15221
                              def->data.udp.connectHost);
        } else if (def->data.udp.connectService) {
15222
            virBufferAsprintf(buf,
15223
                              "      <source mode='connect' service='%s'/>\n",
15224 15225 15226 15227 15228
                              def->data.udp.connectService);
        }
        break;

    case VIR_DOMAIN_CHR_TYPE_TCP:
15229
        virBufferAsprintf(buf,
15230
                          "      <source mode='%s' host='%s' service='%s'/>\n",
15231 15232 15233
                          def->data.tcp.listen ? "bind" : "connect",
                          def->data.tcp.host,
                          def->data.tcp.service);
15234
        virBufferAsprintf(buf, "      <protocol type='%s'/>\n",
15235 15236
                          virDomainChrTcpProtocolTypeToString(
                              def->data.tcp.protocol));
15237 15238 15239
        break;

    case VIR_DOMAIN_CHR_TYPE_UNIX:
15240
        virBufferAsprintf(buf, "      <source mode='%s'",
15241
                          def->data.nix.listen ? "bind" : "connect");
15242 15243
        virBufferEscapeString(buf, " path='%s'", def->data.nix.path);
        virBufferAddLit(buf, "/>\n");
15244 15245 15246
        break;
    }

15247 15248 15249 15250 15251 15252
    return 0;
}

static int
virDomainChrDefFormat(virBufferPtr buf,
                      virDomainChrDefPtr def,
E
Eric Blake 已提交
15253
                      unsigned int flags)
15254 15255 15256 15257 15258
{
    const char *elementName = virDomainChrDeviceTypeToString(def->deviceType);
    const char *targetType = virDomainChrTargetTypeToString(def->deviceType,
                                                            def->targetType);
    bool tty_compat;
15259
    size_t n;
15260 15261 15262 15263

    int ret = 0;

    if (!elementName) {
15264 15265 15266
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected char device type %d"),
                       def->deviceType);
15267 15268 15269
        return -1;
    }

15270
    virBufferAsprintf(buf, "    <%s", elementName);
15271 15272 15273 15274 15275 15276 15277 15278
    tty_compat = (def->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE &&
                  def->target.port == 0 &&
                  def->source.type == VIR_DOMAIN_CHR_TYPE_PTY &&
                  !(flags & VIR_DOMAIN_XML_INACTIVE) &&
                  def->source.data.file.path);
    if (virDomainChrSourceDefFormat(buf, &def->source, tty_compat, flags) < 0)
        return -1;

15279
    /* Format <target> block */
15280
    switch (def->deviceType) {
15281 15282
    case VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL: {
        if (!targetType) {
15283 15284
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Could not format channel target type"));
15285 15286
            return -1;
        }
15287
        virBufferAsprintf(buf, "      <target type='%s'", targetType);
15288 15289 15290

        switch (def->targetType) {
        case VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_GUESTFWD: {
15291
            int port = virSocketAddrGetPort(def->target.addr);
15292
            if (port < 0) {
15293 15294
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Unable to format guestfwd port"));
15295 15296
                return -1;
            }
15297

15298
            char *addr = virSocketAddrFormat(def->target.addr);
15299
            if (addr == NULL)
15300
                return -1;
15301

15302
            virBufferAsprintf(buf, " address='%s' port='%d'",
15303 15304 15305
                              addr, port);
            VIR_FREE(addr);
            break;
15306 15307
        }

15308 15309 15310 15311 15312 15313 15314
        case VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO: {
            if (def->target.name) {
                virBufferEscapeString(buf, " name='%s'", def->target.name);
            }
            break;
        }

15315 15316 15317
        }
        virBufferAddLit(buf, "/>\n");
        break;
15318
    }
15319

15320
    case VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE:
15321
        virBufferAsprintf(buf,
15322 15323 15324 15325 15326 15327
                          "      <target type='%s' port='%d'/>\n",
                          virDomainChrTargetTypeToString(def->deviceType,
                                                         def->targetType),
                          def->target.port);
        break;

G
Guannan Ren 已提交
15328 15329 15330 15331 15332 15333 15334 15335 15336
    case VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL:
        if (def->targetTypeAttr) {
            virBufferAsprintf(buf,
                              "      <target type='%s' port='%d'/>\n",
                              virDomainChrTargetTypeToString(def->deviceType,
                                                             def->targetType),
                              def->target.port);
            break;
        }
15337
    default:
15338
        virBufferAsprintf(buf, "      <target port='%d'/>\n",
15339
                          def->target.port);
15340
        break;
15341
    }
15342

15343
    if (virDomainDeviceInfoIsSet(&def->info, flags)) {
15344 15345 15346
        if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
            return -1;
    }
15347

15348 15349 15350 15351
    /* Security label overrides, if any. */
    if (def->seclabels && def->nseclabels > 0) {
        virBufferAdjustIndent(buf, 2);
        for (n = 0; n < def->nseclabels; n++)
15352
            virSecurityDeviceLabelDefFormat(buf, def->seclabels[n], flags);
15353 15354 15355
        virBufferAdjustIndent(buf, -2);
    }

15356
    virBufferAsprintf(buf, "    </%s>\n", elementName);
15357

15358
    return ret;
15359 15360
}

E
Eric Blake 已提交
15361 15362 15363
static int
virDomainSmartcardDefFormat(virBufferPtr buf,
                            virDomainSmartcardDefPtr def,
E
Eric Blake 已提交
15364
                            unsigned int flags)
E
Eric Blake 已提交
15365 15366 15367 15368 15369
{
    const char *mode = virDomainSmartcardTypeToString(def->type);
    size_t i;

    if (!mode) {
15370 15371
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected smartcard type %d"), def->type);
E
Eric Blake 已提交
15372 15373 15374
        return -1;
    }

15375
    virBufferAsprintf(buf, "    <smartcard mode='%s'", mode);
E
Eric Blake 已提交
15376 15377
    switch (def->type) {
    case VIR_DOMAIN_SMARTCARD_TYPE_HOST:
15378
        if (!virDomainDeviceInfoIsSet(&def->info, flags)) {
E
Eric Blake 已提交
15379 15380 15381
            virBufferAddLit(buf, "/>\n");
            return 0;
        }
15382
        virBufferAddLit(buf, ">\n");
E
Eric Blake 已提交
15383 15384 15385 15386 15387 15388 15389
        break;

    case VIR_DOMAIN_SMARTCARD_TYPE_HOST_CERTIFICATES:
        virBufferAddLit(buf, ">\n");
        for (i = 0; i < VIR_DOMAIN_SMARTCARD_NUM_CERTIFICATES; i++)
            virBufferEscapeString(buf, "      <certificate>%s</certificate>\n",
                                  def->data.cert.file[i]);
15390 15391
        virBufferEscapeString(buf, "      <database>%s</database>\n",
                              def->data.cert.database);
E
Eric Blake 已提交
15392 15393 15394 15395 15396 15397 15398 15399 15400
        break;

    case VIR_DOMAIN_SMARTCARD_TYPE_PASSTHROUGH:
        if (virDomainChrSourceDefFormat(buf, &def->data.passthru, false,
                                        flags) < 0)
            return -1;
        break;

    default:
15401 15402
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected smartcard type %d"), def->type);
E
Eric Blake 已提交
15403 15404 15405 15406 15407 15408 15409 15410
        return -1;
    }
    if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
        return -1;
    virBufferAddLit(buf, "    </smartcard>\n");
    return 0;
}

15411 15412 15413 15414 15415 15416 15417
static int
virDomainSoundCodecDefFormat(virBufferPtr buf,
                             virDomainSoundCodecDefPtr def)
{
    const char *type = virDomainSoundCodecTypeToString(def->type);

    if (!type) {
15418 15419
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected codec type %d"), def->type);
15420 15421 15422 15423 15424 15425 15426 15427
        return -1;
    }

    virBufferAsprintf(buf, "      <codec type='%s'/>\n",  type);

    return 0;
}

15428 15429 15430 15431 15432 15433 15434 15435 15436 15437 15438 15439 15440 15441 15442 15443 15444 15445 15446 15447 15448 15449 15450 15451 15452 15453 15454 15455 15456 15457 15458 15459 15460
static int
virDomainTPMDefFormat(virBufferPtr buf,
                      virDomainTPMDefPtr def,
                      unsigned int flags)
{
    virBufferAsprintf(buf, "    <tpm model='%s'>\n",
                      virDomainTPMModelTypeToString(def->model));

    virBufferAsprintf(buf, "      <backend type='%s'>\n",
                      virDomainTPMBackendTypeToString(def->type));

    switch (def->type) {
    case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH:
        virBufferEscapeString(buf, "        <device path='%s'/>\n",
                              def->data.passthrough.source.data.file.path);
        break;
    case VIR_DOMAIN_TPM_TYPE_LAST:
        break;
    }

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

    if (virDomainDeviceInfoIsSet(&def->info, flags)) {
        if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
            return -1;
    }

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

    return 0;
}


15461
static int
15462
virDomainSoundDefFormat(virBufferPtr buf,
D
Daniel P. Berrange 已提交
15463
                        virDomainSoundDefPtr def,
E
Eric Blake 已提交
15464
                        unsigned int flags)
15465 15466
{
    const char *model = virDomainSoundModelTypeToString(def->model);
15467
    bool children = false;
15468
    size_t i;
15469 15470

    if (!model) {
15471 15472
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected sound model %d"), def->model);
15473 15474 15475
        return -1;
    }

15476
    virBufferAsprintf(buf, "    <sound model='%s'",  model);
15477

15478 15479 15480 15481 15482 15483 15484 15485
    for (i = 0; i < def->ncodecs; i++) {
        if (!children) {
            virBufferAddLit(buf, ">\n");
            children = true;
        }
        virDomainSoundCodecDefFormat(buf, def->codecs[i]);
    }

15486
    if (virDomainDeviceInfoIsSet(&def->info, flags)) {
15487 15488 15489 15490
        if (!children) {
            virBufferAddLit(buf, ">\n");
            children = true;
        }
D
Daniel P. Berrange 已提交
15491
        if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
15492
            return -1;
15493 15494 15495
    }

    if (children) {
15496 15497 15498 15499 15500
        virBufferAddLit(buf, "    </sound>\n");
    } else {
        virBufferAddLit(buf, "/>\n");
    }

15501 15502 15503
    return 0;
}

15504

15505 15506 15507
static int
virDomainMemballoonDefFormat(virBufferPtr buf,
                             virDomainMemballoonDefPtr def,
E
Eric Blake 已提交
15508
                             unsigned int flags)
15509 15510
{
    const char *model = virDomainMemballoonModelTypeToString(def->model);
15511
    bool noopts = true;
15512 15513

    if (!model) {
15514 15515
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected memballoon model %d"), def->model);
15516 15517 15518
        return -1;
    }

15519
    virBufferAsprintf(buf, "    <memballoon model='%s'", model);
15520

15521
    if (virDomainDeviceInfoIsSet(&def->info, flags)) {
15522 15523 15524
        virBufferAddLit(buf, ">\n");
        if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
            return -1;
15525
        noopts = false;
15526 15527
    }

15528 15529 15530 15531 15532 15533 15534 15535 15536 15537 15538 15539
    if (def->period) {
        if (noopts)
            virBufferAddLit(buf, ">\n");
        virBufferAsprintf(buf, "      <stats period='%u'/>\n", def->period);
        noopts = false;
    }

    if (noopts)
        virBufferAddLit(buf, "/>\n");
    else
        virBufferAddLit(buf, "    </memballoon>\n");

15540 15541 15542
    return 0;
}

L
Li Zhang 已提交
15543 15544 15545 15546 15547 15548 15549 15550 15551 15552 15553 15554 15555 15556 15557
static int
virDomainNVRAMDefFormat(virBufferPtr buf,
                        virDomainNVRAMDefPtr def,
                        unsigned int flags)
{
    virBufferAddLit(buf, "    <nvram>\n");
    if (virDomainDeviceInfoIsSet(&def->info, flags) &&
        virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
        return -1;

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

    return 0;
}

15558 15559 15560 15561
static int
virDomainSysinfoDefFormat(virBufferPtr buf,
                          virSysinfoDefPtr def)
{
15562 15563 15564 15565 15566
    int ret;
    virBufferAdjustIndent(buf, 2);
    ret = virSysinfoFormat(buf, def);
    virBufferAdjustIndent(buf, -2);
    return ret;
15567 15568
}

15569

R
Richard Jones 已提交
15570
static int
15571
virDomainWatchdogDefFormat(virBufferPtr buf,
D
Daniel P. Berrange 已提交
15572
                           virDomainWatchdogDefPtr def,
E
Eric Blake 已提交
15573
                           unsigned int flags)
R
Richard Jones 已提交
15574
{
15575 15576
    const char *model = virDomainWatchdogModelTypeToString(def->model);
    const char *action = virDomainWatchdogActionTypeToString(def->action);
R
Richard Jones 已提交
15577 15578

    if (!model) {
15579 15580
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected watchdog model %d"), def->model);
R
Richard Jones 已提交
15581 15582 15583 15584
        return -1;
    }

    if (!action) {
15585 15586
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected watchdog action %d"), def->action);
R
Richard Jones 已提交
15587 15588 15589
        return -1;
    }

15590
    virBufferAsprintf(buf, "    <watchdog model='%s' action='%s'",
R
Richard Jones 已提交
15591 15592
                      model, action);

15593
    if (virDomainDeviceInfoIsSet(&def->info, flags)) {
15594
        virBufferAddLit(buf, ">\n");
D
Daniel P. Berrange 已提交
15595
        if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
15596 15597 15598 15599 15600 15601
            return -1;
        virBufferAddLit(buf, "    </watchdog>\n");
    } else {
        virBufferAddLit(buf, "/>\n");
    }

R
Richard Jones 已提交
15602 15603 15604 15605
    return 0;
}


15606 15607 15608 15609 15610 15611 15612 15613 15614
static int
virDomainRNGDefFormat(virBufferPtr buf,
                      virDomainRNGDefPtr def,
                      unsigned int flags)
{
    const char *model = virDomainRNGModelTypeToString(def->model);
    const char *backend = virDomainRNGBackendTypeToString(def->backend);

    virBufferAsprintf(buf, "    <rng model='%s'>\n", model);
15615 15616 15617 15618 15619 15620
    if (def->rate) {
        virBufferAsprintf(buf, "      <rate bytes='%u'", def->rate);
        if (def->period)
            virBufferAsprintf(buf, " period='%u'", def->period);
        virBufferAddLit(buf, "/>\n");
    }
15621 15622 15623 15624 15625 15626 15627 15628 15629 15630 15631 15632 15633 15634 15635 15636 15637 15638 15639 15640 15641 15642 15643 15644 15645 15646 15647 15648 15649 15650 15651 15652 15653 15654 15655 15656 15657 15658 15659 15660 15661 15662 15663 15664 15665
    virBufferAsprintf(buf, "      <backend model='%s'", backend);

    switch ((enum virDomainRNGBackend) def->backend) {
    case VIR_DOMAIN_RNG_BACKEND_RANDOM:
        if (def->source.file)
            virBufferEscapeString(buf, ">%s</backend>\n", def->source.file);
        else
            virBufferAddLit(buf, "/>\n");

        break;

    case VIR_DOMAIN_RNG_BACKEND_EGD:
        virBufferAdjustIndent(buf, 2);
        if (virDomainChrSourceDefFormat(buf, def->source.chardev,
                                        false, flags) < 0)
            return -1;
        virBufferAdjustIndent(buf, -2);
        virBufferAddLit(buf, "      </backend>\n");

    case VIR_DOMAIN_RNG_BACKEND_LAST:
        break;
    }

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

    return 0;
}

void
virDomainRNGDefFree(virDomainRNGDefPtr def)
{
    if (!def)
        return;

    switch ((enum virDomainRNGBackend) def->backend) {
    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 已提交
15666
    virDomainDeviceInfoClear(&def->info);
15667 15668 15669
    VIR_FREE(def);
}

15670 15671 15672 15673
static void
virDomainVideoAccelDefFormat(virBufferPtr buf,
                             virDomainVideoAccelDefPtr def)
{
15674
    virBufferAsprintf(buf, "        <acceleration accel3d='%s'",
15675
                      def->support3d ? "yes" : "no");
15676
    virBufferAsprintf(buf, " accel2d='%s'",
15677 15678 15679 15680 15681
                      def->support2d ? "yes" : "no");
    virBufferAddLit(buf, "/>\n");
}


15682
static int
15683
virDomainVideoDefFormat(virBufferPtr buf,
D
Daniel P. Berrange 已提交
15684
                        virDomainVideoDefPtr def,
E
Eric Blake 已提交
15685
                        unsigned int flags)
15686 15687 15688 15689
{
    const char *model = virDomainVideoTypeToString(def->type);

    if (!model) {
15690 15691
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected video model %d"), def->type);
15692 15693 15694 15695
        return -1;
    }

    virBufferAddLit(buf, "    <video>\n");
15696
    virBufferAsprintf(buf, "      <model type='%s'",
15697
                      model);
15698 15699
    if (def->ram)
        virBufferAsprintf(buf, " ram='%u'", def->ram);
15700
    if (def->vram)
15701
        virBufferAsprintf(buf, " vram='%u'", def->vram);
15702
    if (def->heads)
15703
        virBufferAsprintf(buf, " heads='%u'", def->heads);
15704 15705
    if (def->primary)
        virBufferAddLit(buf, " primary='yes'");
15706 15707 15708 15709 15710 15711 15712 15713
    if (def->accel) {
        virBufferAddLit(buf, ">\n");
        virDomainVideoAccelDefFormat(buf, def->accel);
        virBufferAddLit(buf, "      </model>\n");
    } else {
        virBufferAddLit(buf, "/>\n");
    }

D
Daniel P. Berrange 已提交
15714
    if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
15715 15716
        return -1;

15717 15718 15719 15720 15721
    virBufferAddLit(buf, "    </video>\n");

    return 0;
}

15722
static int
15723
virDomainInputDefFormat(virBufferPtr buf,
15724
                        virDomainInputDefPtr def,
E
Eric Blake 已提交
15725
                        unsigned int flags)
15726 15727 15728 15729 15730
{
    const char *type = virDomainInputTypeToString(def->type);
    const char *bus = virDomainInputBusTypeToString(def->bus);

    if (!type) {
15731 15732
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected input type %d"), def->type);
15733 15734 15735
        return -1;
    }
    if (!bus) {
15736 15737
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected input bus type %d"), def->bus);
15738 15739 15740
        return -1;
    }

15741
    virBufferAsprintf(buf, "    <input type='%s' bus='%s'",
15742 15743
                      type, bus);

15744
    if (virDomainDeviceInfoIsSet(&def->info, flags)) {
15745 15746 15747 15748 15749 15750 15751 15752
        virBufferAddLit(buf, ">\n");
        if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
            return -1;
        virBufferAddLit(buf, "    </input>\n");
    } else {
        virBufferAddLit(buf, "/>\n");
    }

15753 15754 15755 15756
    return 0;
}


15757 15758 15759 15760 15761 15762 15763
static int
virDomainTimerDefFormat(virBufferPtr buf,
                        virDomainTimerDefPtr def)
{
    const char *name = virDomainTimerNameTypeToString(def->name);

    if (!name) {
15764 15765
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected timer name %d"), def->name);
15766 15767
        return -1;
    }
15768
    virBufferAsprintf(buf, "    <timer name='%s'", name);
15769 15770 15771 15772 15773 15774 15775 15776 15777 15778 15779

    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) {
15780 15781 15782
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected timer tickpolicy %d"),
                           def->tickpolicy);
15783 15784
            return -1;
        }
15785
        virBufferAsprintf(buf, " tickpolicy='%s'", tickpolicy);
15786 15787 15788 15789
    }

    if ((def->name == VIR_DOMAIN_TIMER_NAME_PLATFORM)
        || (def->name == VIR_DOMAIN_TIMER_NAME_RTC)) {
15790 15791 15792 15793
        if (def->track != -1) {
            const char *track
                = virDomainTimerTrackTypeToString(def->track);
            if (!track) {
15794 15795 15796
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unexpected timer track %d"),
                               def->track);
15797 15798
                return -1;
            }
15799
            virBufferAsprintf(buf, " track='%s'", track);
15800 15801 15802 15803 15804
        }
    }

    if (def->name == VIR_DOMAIN_TIMER_NAME_TSC) {
        if (def->frequency > 0) {
15805
            virBufferAsprintf(buf, " frequency='%lu'", def->frequency);
15806 15807 15808 15809 15810 15811
        }

        if (def->mode != -1) {
            const char *mode
                = virDomainTimerModeTypeToString(def->mode);
            if (!mode) {
15812 15813 15814
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unexpected timer mode %d"),
                               def->mode);
15815 15816
                return -1;
            }
15817
            virBufferAsprintf(buf, " mode='%s'", mode);
15818 15819 15820
        }
    }

E
Eric Blake 已提交
15821 15822
    if (def->catchup.threshold == 0 && def->catchup.slew == 0 &&
        def->catchup.limit == 0) {
15823 15824
        virBufferAddLit(buf, "/>\n");
    } else {
15825 15826
        virBufferAddLit(buf, ">\n");
        virBufferAddLit(buf, "      <catchup ");
15827
        if (def->catchup.threshold > 0) {
15828
            virBufferAsprintf(buf, " threshold='%lu'", def->catchup.threshold);
15829 15830
        }
        if (def->catchup.slew > 0) {
15831
            virBufferAsprintf(buf, " slew='%lu'", def->catchup.slew);
15832 15833
        }
        if (def->catchup.limit > 0) {
15834
            virBufferAsprintf(buf, " limit='%lu'", def->catchup.limit);
15835
        }
15836 15837
        virBufferAddLit(buf, "/>\n");
        virBufferAddLit(buf, "    </timer>\n");
15838
    }
15839 15840 15841 15842

    return 0;
}

15843 15844 15845 15846 15847 15848 15849 15850 15851 15852 15853 15854 15855 15856 15857 15858 15859
static void
virDomainGraphicsAuthDefFormatAttr(virBufferPtr buf,
                                   virDomainGraphicsAuthDefPtr def,
                                   unsigned int flags)
{
    if (!def->passwd)
        return;

    if (flags & VIR_DOMAIN_XML_SECURE)
        virBufferEscapeString(buf, " passwd='%s'",
                              def->passwd);

    if (def->expires) {
        char strbuf[100];
        struct tm tmbuf, *tm;
        tm = gmtime_r(&def->validTo, &tmbuf);
        strftime(strbuf, sizeof(strbuf), "%Y-%m-%dT%H:%M:%S", tm);
15860
        virBufferAsprintf(buf, " passwdValidTo='%s'", strbuf);
15861
    }
15862 15863 15864 15865

    if (def->connected)
        virBufferEscapeString(buf, " connected='%s'",
                              virDomainGraphicsAuthConnectedTypeToString(def->connected));
15866 15867
}

15868 15869 15870 15871 15872 15873

static void
virDomainGraphicsListenDefFormat(virBufferPtr buf,
                                 virDomainGraphicsListenDefPtr def,
                                 unsigned int flags)
{
15874 15875 15876 15877 15878
    /* If generating migratable XML, skip listen address
     * dragged in from config file */
    if ((flags & VIR_DOMAIN_XML_MIGRATABLE) && def->fromConfig)
        return;

15879 15880 15881 15882 15883 15884 15885 15886
    virBufferAddLit(buf, "      <listen");

    if (def->type) {
        virBufferAsprintf(buf, " type='%s'",
                          virDomainGraphicsListenTypeToString(def->type));
    }

    if (def->address &&
E
Eric Blake 已提交
15887 15888
        (def->type == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS ||
         (def->type == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NETWORK &&
15889 15890 15891 15892 15893 15894 15895 15896
          !(flags & VIR_DOMAIN_XML_INACTIVE)))) {
        /* address may also be set to show current status when type='network',
         * but we don't want to print that if INACTIVE data is requested. */
        virBufferAsprintf(buf, " address='%s'", def->address);
    }

    if (def->network &&
        (def->type == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NETWORK)) {
15897
        virBufferEscapeString(buf, " network='%s'", def->network);
15898 15899
    }

15900 15901 15902
    if (flags & VIR_DOMAIN_XML_INTERNAL_STATUS)
        virBufferAsprintf(buf, " fromConfig='%d'", def->fromConfig);

15903 15904 15905 15906
    virBufferAddLit(buf, "/>\n");
}


15907
static int
15908
virDomainGraphicsDefFormat(virBufferPtr buf,
15909
                           virDomainGraphicsDefPtr def,
E
Eric Blake 已提交
15910
                           unsigned int flags)
15911 15912
{
    const char *type = virDomainGraphicsTypeToString(def->type);
15913
    const char *listenAddr = NULL;
15914
    bool children = false;
15915
    size_t i;
15916 15917

    if (!type) {
15918 15919
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected net type %d"), def->type);
15920 15921 15922
        return -1;
    }

15923 15924 15925 15926 15927 15928
    /* find the first listen element of type='address' and duplicate
    * its address attribute as the listen attribute of
    * <graphics>. This is done to improve backward compatibility. */
    for (i = 0; i < def->nListens; i++) {
        if (virDomainGraphicsListenGetType(def, i)
            == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS) {
15929 15930 15931
            if (flags & VIR_DOMAIN_XML_MIGRATABLE &&
                def->listens[i].fromConfig)
                continue;
15932 15933 15934 15935 15936
            listenAddr = virDomainGraphicsListenGetAddress(def, i);
            break;
        }
    }

15937
    virBufferAsprintf(buf, "    <graphics type='%s'", type);
15938 15939 15940

    switch (def->type) {
    case VIR_DOMAIN_GRAPHICS_TYPE_VNC:
15941 15942
        if (def->data.vnc.socket) {
            if (def->data.vnc.socket)
15943
                virBufferAsprintf(buf, " socket='%s'",
15944 15945 15946 15947
                                  def->data.vnc.socket);
        } else {
            if (def->data.vnc.port &&
                (!def->data.vnc.autoport || !(flags & VIR_DOMAIN_XML_INACTIVE)))
15948
                virBufferAsprintf(buf, " port='%d'",
15949 15950 15951
                                  def->data.vnc.port);
            else if (def->data.vnc.autoport)
                virBufferAddLit(buf, " port='-1'");
15952

15953
            virBufferAsprintf(buf, " autoport='%s'",
15954
                              def->data.vnc.autoport ? "yes" : "no");
15955

M
Martin Kletzander 已提交
15956 15957 15958
            if (def->data.vnc.websocket)
                virBufferAsprintf(buf, " websocket='%d'", def->data.vnc.websocket);

15959 15960
            if (listenAddr)
                virBufferAsprintf(buf, " listen='%s'", listenAddr);
15961
        }
15962 15963 15964 15965 15966

        if (def->data.vnc.keymap)
            virBufferEscapeString(buf, " keymap='%s'",
                                  def->data.vnc.keymap);

15967 15968 15969 15970 15971
        if (def->data.vnc.sharePolicy)
            virBufferAsprintf(buf, " sharePolicy='%s'",
                              virDomainGraphicsVNCSharePolicyTypeToString(
                              def->data.vnc.sharePolicy));

15972
        virDomainGraphicsAuthDefFormatAttr(buf, &def->data.vnc.auth, flags);
15973 15974 15975 15976 15977 15978 15979 15980 15981 15982
        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);
15983 15984 15985
        if (def->data.sdl.fullscreen)
            virBufferAddLit(buf, " fullscreen='yes'");

15986
        break;
15987 15988 15989

    case VIR_DOMAIN_GRAPHICS_TYPE_RDP:
        if (def->data.rdp.port)
15990
            virBufferAsprintf(buf, " port='%d'",
15991 15992 15993 15994 15995
                              def->data.rdp.port);
        else if (def->data.rdp.autoport)
            virBufferAddLit(buf, " port='0'");

        if (def->data.rdp.autoport)
15996
            virBufferAddLit(buf, " autoport='yes'");
15997 15998

        if (def->data.rdp.replaceUser)
15999
            virBufferAddLit(buf, " replaceUser='yes'");
16000 16001

        if (def->data.rdp.multiUser)
16002
            virBufferAddLit(buf, " multiUser='yes'");
16003

16004 16005
        if (listenAddr)
            virBufferAsprintf(buf, " listen='%s'", listenAddr);
16006 16007 16008 16009 16010 16011 16012 16013 16014 16015 16016 16017 16018

        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;

16019 16020
    case VIR_DOMAIN_GRAPHICS_TYPE_SPICE:
        if (def->data.spice.port)
16021
            virBufferAsprintf(buf, " port='%d'",
16022 16023 16024
                              def->data.spice.port);

        if (def->data.spice.tlsPort)
16025
            virBufferAsprintf(buf, " tlsPort='%d'",
16026 16027
                              def->data.spice.tlsPort);

16028
        virBufferAsprintf(buf, " autoport='%s'",
16029 16030
                          def->data.spice.autoport ? "yes" : "no");

16031 16032
        if (listenAddr)
            virBufferAsprintf(buf, " listen='%s'", listenAddr);
16033 16034 16035 16036 16037

        if (def->data.spice.keymap)
            virBufferEscapeString(buf, " keymap='%s'",
                                  def->data.spice.keymap);

16038 16039 16040 16041
        if (def->data.spice.defaultMode != VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_ANY)
            virBufferAsprintf(buf, " defaultMode='%s'",
              virDomainGraphicsSpiceChannelModeTypeToString(def->data.spice.defaultMode));

16042
        virDomainGraphicsAuthDefFormatAttr(buf, &def->data.spice.auth, flags);
16043 16044
        break;

16045 16046
    }

16047 16048 16049 16050
    for (i = 0; i < def->nListens; i++) {
        if (virDomainGraphicsListenGetType(def, i)
            == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NONE)
            continue;
16051 16052 16053
        if (flags & VIR_DOMAIN_XML_MIGRATABLE &&
            def->listens[i].fromConfig)
            continue;
16054 16055
        if (!children) {
            virBufferAddLit(buf, ">\n");
16056
            children = true;
16057 16058 16059 16060
        }
        virDomainGraphicsListenDefFormat(buf, &def->listens[i], flags);
    }

16061
    if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) {
16062
        for (i = 0; i < VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_LAST; i++) {
16063 16064 16065 16066 16067 16068
            int mode = def->data.spice.channels[i];
            if (mode == VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_ANY)
                continue;

            if (!children) {
                virBufferAddLit(buf, ">\n");
16069
                children = true;
16070 16071
            }

16072
            virBufferAsprintf(buf, "      <channel name='%s' mode='%s'/>\n",
16073 16074 16075
                              virDomainGraphicsSpiceChannelNameTypeToString(i),
                              virDomainGraphicsSpiceChannelModeTypeToString(mode));
        }
16076 16077
        if (!children && (def->data.spice.image || def->data.spice.jpeg ||
                          def->data.spice.zlib || def->data.spice.playback ||
P
Peng Zhou 已提交
16078 16079
                          def->data.spice.streaming || def->data.spice.copypaste ||
                          def->data.spice.mousemode)) {
16080
            virBufferAddLit(buf, ">\n");
16081
            children = true;
16082
        }
16083
        if (def->data.spice.image)
16084
            virBufferAsprintf(buf, "      <image compression='%s'/>\n",
16085 16086
                              virDomainGraphicsSpiceImageCompressionTypeToString(def->data.spice.image));
        if (def->data.spice.jpeg)
16087
            virBufferAsprintf(buf, "      <jpeg compression='%s'/>\n",
16088 16089
                              virDomainGraphicsSpiceJpegCompressionTypeToString(def->data.spice.jpeg));
        if (def->data.spice.zlib)
16090
            virBufferAsprintf(buf, "      <zlib compression='%s'/>\n",
16091 16092
                              virDomainGraphicsSpiceZlibCompressionTypeToString(def->data.spice.zlib));
        if (def->data.spice.playback)
16093
            virBufferAsprintf(buf, "      <playback compression='%s'/>\n",
16094
                              virDomainGraphicsSpicePlaybackCompressionTypeToString(def->data.spice.playback));
16095 16096 16097
        if (def->data.spice.streaming)
            virBufferAsprintf(buf, "      <streaming mode='%s'/>\n",
                              virDomainGraphicsSpiceStreamingModeTypeToString(def->data.spice.streaming));
P
Peng Zhou 已提交
16098 16099 16100
        if (def->data.spice.mousemode)
            virBufferAsprintf(buf, "      <mouse mode='%s'/>\n",
                              virDomainGraphicsSpiceMouseModeTypeToString(def->data.spice.mousemode));
16101 16102 16103
        if (def->data.spice.copypaste)
            virBufferAsprintf(buf, "      <clipboard copypaste='%s'/>\n",
                              virDomainGraphicsSpiceClipboardCopypasteTypeToString(def->data.spice.copypaste));
16104 16105 16106 16107 16108 16109 16110
    }

    if (children) {
        virBufferAddLit(buf, "    </graphics>\n");
    } else {
        virBufferAddLit(buf, "/>\n");
    }
16111 16112 16113 16114

    return 0;
}

16115 16116

static int
16117
virDomainHostdevDefFormat(virBufferPtr buf,
D
Daniel P. Berrange 已提交
16118
                          virDomainHostdevDefPtr def,
E
Eric Blake 已提交
16119
                          unsigned int flags)
16120 16121 16122 16123
{
    const char *mode = virDomainHostdevModeTypeToString(def->mode);
    const char *type;

16124
    if (!mode) {
16125 16126
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected hostdev mode %d"), def->mode);
16127 16128 16129
        return -1;
    }

16130 16131 16132 16133 16134 16135 16136 16137 16138 16139
    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;
16140 16141 16142 16143 16144 16145 16146 16147 16148
    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;
16149
    default:
16150
        virReportError(VIR_ERR_INTERNAL_ERROR,
16151
                       _("unexpected hostdev mode %d"), def->mode);
16152 16153 16154
        return -1;
    }

16155 16156
    virBufferAsprintf(buf, "    <hostdev mode='%s' type='%s'",
                      mode, type);
O
Osier Yang 已提交
16157 16158
    if (def->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
        virBufferAsprintf(buf, " managed='%s'",
16159
                          def->managed ? "yes" : "no");
O
Osier Yang 已提交
16160 16161 16162 16163 16164 16165 16166 16167

        if (def->source.subsys.type ==
            VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI &&
            def->source.subsys.u.scsi.sgio)
            virBufferAsprintf(buf, " sgio='%s'",
                              virDomainDeviceSGIOTypeToString(def->source.subsys.u.scsi.sgio));
    }
    virBufferAddLit(buf, ">\n");
16168

16169
    virBufferAdjustIndent(buf, 6);
16170 16171 16172 16173 16174
    switch (def->mode) {
    case VIR_DOMAIN_HOSTDEV_MODE_SUBSYS:
        if (virDomainHostdevDefFormatSubsys(buf, def, flags, false) < 0)
            return -1;
        break;
16175 16176 16177 16178
    case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
        if (virDomainHostdevDefFormatCaps(buf, def) < 0)
            return -1;
        break;
16179
    }
O
Osier Yang 已提交
16180 16181 16182

    if (def->readonly)
        virBufferAddLit(buf, "<readonly/>\n");
16183 16184
    if (def->shareable)
        virBufferAddLit(buf, "<shareable/>\n");
16185
    virBufferAdjustIndent(buf, -6);
16186

16187
    if (virDomainDeviceInfoFormat(buf, def->info,
16188 16189
                                  flags | VIR_DOMAIN_XML_INTERNAL_ALLOW_BOOT
                                  | VIR_DOMAIN_XML_INTERNAL_ALLOW_ROM) < 0)
16190 16191
        return -1;

16192 16193 16194 16195 16196
    virBufferAddLit(buf, "    </hostdev>\n");

    return 0;
}

16197 16198 16199 16200 16201 16202 16203 16204 16205 16206 16207 16208
static int
virDomainRedirdevDefFormat(virBufferPtr buf,
                           virDomainRedirdevDefPtr def,
                           unsigned int flags)
{
    const char *bus;

    bus = virDomainRedirdevBusTypeToString(def->bus);

    virBufferAsprintf(buf, "    <redirdev bus='%s'", bus);
    if (virDomainChrSourceDefFormat(buf, &def->source.chr, false, flags) < 0)
        return -1;
16209 16210
    if (virDomainDeviceInfoFormat(buf, &def->info,
                                  flags | VIR_DOMAIN_XML_INTERNAL_ALLOW_BOOT) < 0)
16211
        return -1;
16212 16213 16214 16215
    virBufferAddLit(buf, "    </redirdev>\n");

    return 0;
}
16216

16217 16218 16219 16220 16221 16222 16223 16224 16225 16226 16227 16228 16229 16230 16231 16232 16233 16234 16235 16236 16237 16238 16239 16240 16241 16242 16243 16244 16245 16246 16247 16248 16249
static int
virDomainRedirFilterDefFormat(virBufferPtr buf,
                              virDomainRedirFilterDefPtr filter)
{
    size_t i;

    virBufferAddLit(buf, "    <redirfilter>\n");
    for (i = 0; i < filter->nusbdevs; i++) {
        virDomainRedirFilterUsbDevDefPtr usbdev = filter->usbdevs[i];
        virBufferAddLit(buf, "      <usbdev");
        if (usbdev->usbClass >= 0)
            virBufferAsprintf(buf, " class='0x%02X'", usbdev->usbClass);

        if (usbdev->vendor >= 0)
            virBufferAsprintf(buf, " vendor='0x%04X'", usbdev->vendor);

        if (usbdev->product >= 0)
            virBufferAsprintf(buf, " product='0x%04X'", usbdev->product);

        if (usbdev->version >= 0)
            virBufferAsprintf(buf, " version='%d.%d'",
                                 ((usbdev->version & 0xf000) >> 12) * 10 +
                                 ((usbdev->version & 0x0f00) >>  8),
                                 ((usbdev->version & 0x00f0) >>  4) * 10 +
                                 ((usbdev->version & 0x000f) >>  0));

        virBufferAsprintf(buf, " allow='%s'/>\n", usbdev->allow ? "yes" : "no");

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

M
Marc-André Lureau 已提交
16250 16251
static int
virDomainHubDefFormat(virBufferPtr buf,
16252 16253
                      virDomainHubDefPtr def,
                      unsigned int flags)
M
Marc-André Lureau 已提交
16254 16255 16256 16257
{
    const char *type = virDomainHubTypeToString(def->type);

    if (!type) {
16258 16259
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected hub type %d"), def->type);
M
Marc-André Lureau 已提交
16260 16261 16262 16263 16264 16265 16266 16267 16268 16269 16270 16271 16272 16273 16274 16275 16276
        return -1;
    }

    virBufferAsprintf(buf, "    <hub type='%s'", type);

    if (virDomainDeviceInfoIsSet(&def->info, flags)) {
        virBufferAddLit(buf, ">\n");
        if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
            return -1;
        virBufferAddLit(buf, "    </hub>\n");
    } else {
        virBufferAddLit(buf, "/>\n");
    }

    return 0;
}

16277 16278 16279 16280 16281 16282 16283 16284
/*
 * Return true if no <vcpupin> specified in domain XML
 * (I.e. all vcpus inherit the cpuset from "cpuset" of
 * <vcpu>). Or false otherwise.
 */
static bool
virDomainIsAllVcpupinInherited(virDomainDefPtr def)
{
16285
    size_t i;
16286 16287

    if (!def->cpumask) {
16288
        if (def->cputune.nvcpupin)
16289
            return false;
16290 16291
        else
            return true;
16292 16293 16294 16295 16296 16297 16298 16299 16300 16301
    } else {
        for (i = 0; i < def->cputune.nvcpupin; i++) {
            if (!virBitmapEqual(def->cputune.vcpupin[i]->cpumask,
                                def->cpumask))
                return false;
        }

        return true;
   }
}
M
Marc-André Lureau 已提交
16302

16303 16304 16305 16306 16307 16308 16309 16310 16311 16312 16313

static void
virDomainResourceDefFormat(virBufferPtr buf,
                           virDomainResourceDefPtr def)
{
    virBufferAddLit(buf, "  <resource>\n");
    virBufferEscapeString(buf, "    <partition>%s</partition>\n", def->partition);
    virBufferAddLit(buf, "  </resource>\n");
}


16314 16315 16316
#define DUMPXML_FLAGS                           \
    (VIR_DOMAIN_XML_SECURE |                    \
     VIR_DOMAIN_XML_INACTIVE |                  \
16317 16318
     VIR_DOMAIN_XML_UPDATE_CPU |                \
     VIR_DOMAIN_XML_MIGRATABLE)
16319

16320
verify(((VIR_DOMAIN_XML_INTERNAL_STATUS |
16321
         VIR_DOMAIN_XML_INTERNAL_ACTUAL_NET |
16322 16323
         VIR_DOMAIN_XML_INTERNAL_PCI_ORIG_STATES |
         VIR_DOMAIN_XML_INTERNAL_BASEDATE)
16324
        & DUMPXML_FLAGS) == 0);
16325

16326
/* This internal version can accept VIR_DOMAIN_XML_INTERNAL_*,
16327
 * whereas the public version cannot.  Also, it appends to an existing
16328 16329 16330
 * buffer (possibly with auto-indent), rather than flattening to string.
 * Return -1 on failure.  */
int
16331
virDomainDefFormatInternal(virDomainDefPtr def,
16332 16333
                           unsigned int flags,
                           virBufferPtr buf)
16334 16335 16336
{
    unsigned char *uuid;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
16337
    const char *type = NULL;
H
Hu Tao 已提交
16338
    int n;
16339
    size_t i;
16340
    bool blkio = false;
16341

16342 16343
    virCheckFlags(DUMPXML_FLAGS |
                  VIR_DOMAIN_XML_INTERNAL_STATUS |
16344
                  VIR_DOMAIN_XML_INTERNAL_ACTUAL_NET |
16345 16346
                  VIR_DOMAIN_XML_INTERNAL_PCI_ORIG_STATES |
                  VIR_DOMAIN_XML_INTERNAL_BASEDATE,
16347
                  -1);
16348

16349
    if (!(type = virDomainVirtTypeToString(def->virtType))) {
16350 16351
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected domain type %d"), def->virtType);
16352
        goto error;
16353 16354
    }

16355 16356 16357
    if (def->id == -1)
        flags |= VIR_DOMAIN_XML_INACTIVE;

16358
    virBufferAsprintf(buf, "<domain type='%s'", type);
16359
    if (!(flags & VIR_DOMAIN_XML_INACTIVE))
16360
        virBufferAsprintf(buf, " id='%d'", def->id);
16361
    if (def->namespaceData && def->ns.href)
16362 16363
        virBufferAsprintf(buf, " %s", (def->ns.href)());
    virBufferAddLit(buf, ">\n");
16364

16365
    virBufferEscapeString(buf, "  <name>%s</name>\n", def->name);
16366 16367 16368

    uuid = def->uuid;
    virUUIDFormat(uuid, uuidstr);
16369
    virBufferAsprintf(buf, "  <uuid>%s</uuid>\n", uuidstr);
16370

16371 16372
    virBufferEscapeString(buf, "  <title>%s</title>\n", def->title);

16373 16374
    virBufferEscapeString(buf, "  <description>%s</description>\n",
                          def->description);
16375

16376 16377 16378 16379 16380 16381 16382 16383 16384 16385 16386 16387 16388 16389 16390 16391
    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,
                        virBufferGetIndent(buf, false) / 2 + 1, 1) < 0) {
            xmlBufferFree(xmlbuf);
            xmlIndentTreeOutput = oldIndentTreeOutput;
16392
            goto error;
16393 16394 16395 16396 16397 16398
        }
        virBufferAsprintf(buf, "  %s\n", (char *) xmlBufferContent(xmlbuf));
        xmlBufferFree(xmlbuf);
        xmlIndentTreeOutput = oldIndentTreeOutput;
    }

16399 16400 16401 16402 16403
    virBufferAddLit(buf, "  <memory");
    if (def->mem.dump_core)
        virBufferAsprintf(buf, " dumpCore='%s'",
                          virDomainMemDumpTypeToString(def->mem.dump_core));
    virBufferAsprintf(buf, " unit='KiB'>%llu</memory>\n",
E
Eric Blake 已提交
16404
                      def->mem.max_balloon);
16405

16406
    virBufferAsprintf(buf, "  <currentMemory unit='KiB'>%llu</currentMemory>\n",
16407 16408
                      def->mem.cur_balloon);

16409 16410
    /* add blkiotune only if there are any */
    if (def->blkio.weight) {
16411 16412 16413 16414 16415 16416 16417 16418 16419 16420 16421
        blkio = true;
    } else {
        for (n = 0; n < def->blkio.ndevices; n++) {
            if (def->blkio.devices[n].weight) {
                blkio = true;
                break;
            }
        }
    }

    if (blkio) {
16422
        virBufferAddLit(buf, "  <blkiotune>\n");
16423 16424 16425 16426 16427 16428 16429 16430 16431 16432 16433 16434 16435 16436 16437 16438

        if (def->blkio.weight)
            virBufferAsprintf(buf, "    <weight>%u</weight>\n",
                              def->blkio.weight);

        for (n = 0; n < def->blkio.ndevices; n++) {
            if (def->blkio.devices[n].weight == 0)
                continue;
            virBufferAddLit(buf, "    <device>\n");
            virBufferEscapeString(buf, "      <path>%s</path>\n",
                                  def->blkio.devices[n].path);
            virBufferAsprintf(buf, "      <weight>%u</weight>\n",
                              def->blkio.devices[n].weight);
            virBufferAddLit(buf, "    </device>\n");
        }

16439
        virBufferAddLit(buf, "  </blkiotune>\n");
16440 16441
    }

16442
    /* add memtune only if there are any */
16443 16444
    if (def->mem.hard_limit || def->mem.soft_limit || def->mem.min_guarantee ||
        def->mem.swap_hard_limit)
16445
        virBufferAddLit(buf, "  <memtune>\n");
16446
    if (def->mem.hard_limit) {
E
Eric Blake 已提交
16447
        virBufferAsprintf(buf, "    <hard_limit unit='KiB'>"
16448
                          "%llu</hard_limit>\n", def->mem.hard_limit);
16449 16450
    }
    if (def->mem.soft_limit) {
E
Eric Blake 已提交
16451
        virBufferAsprintf(buf, "    <soft_limit unit='KiB'>"
16452
                          "%llu</soft_limit>\n", def->mem.soft_limit);
16453
    }
16454
    if (def->mem.min_guarantee) {
E
Eric Blake 已提交
16455
        virBufferAsprintf(buf, "    <min_guarantee unit='KiB'>"
16456
                          "%llu</min_guarantee>\n", def->mem.min_guarantee);
16457
    }
16458
    if (def->mem.swap_hard_limit) {
E
Eric Blake 已提交
16459
        virBufferAsprintf(buf, "    <swap_hard_limit unit='KiB'>"
16460
                          "%llu</swap_hard_limit>\n", def->mem.swap_hard_limit);
16461
    }
16462 16463
    if (def->mem.hard_limit || def->mem.soft_limit || def->mem.min_guarantee ||
        def->mem.swap_hard_limit)
16464
        virBufferAddLit(buf, "  </memtune>\n");
16465

16466
    if (def->mem.hugepage_backed || def->mem.nosharepages || def->mem.locked) {
16467
        virBufferAddLit(buf, "  <memoryBacking>\n");
16468 16469 16470 16471 16472 16473
        if (def->mem.hugepage_backed)
            virBufferAddLit(buf, "    <hugepages/>\n");
        if (def->mem.nosharepages)
            virBufferAddLit(buf, "    <nosharepages/>\n");
        if (def->mem.locked)
            virBufferAddLit(buf, "    <locked/>\n");
16474
        virBufferAddLit(buf, "  </memoryBacking>\n");
16475
    }
16476

16477
    virBufferAddLit(buf, "  <vcpu");
16478 16479
    virBufferAsprintf(buf, " placement='%s'",
                      virDomainCpuPlacementModeTypeToString(def->placement_mode));
H
Hu Tao 已提交
16480 16481

    if (def->cpumask && !virBitmapIsAllSet(def->cpumask)) {
16482
        char *cpumask = NULL;
H
Hu Tao 已提交
16483
        if ((cpumask = virBitmapFormat(def->cpumask)) == NULL)
16484
            goto error;
16485
        virBufferAsprintf(buf, " cpuset='%s'", cpumask);
16486 16487
        VIR_FREE(cpumask);
    }
E
Eric Blake 已提交
16488
    if (def->vcpus != def->maxvcpus)
16489 16490
        virBufferAsprintf(buf, " current='%u'", def->vcpus);
    virBufferAsprintf(buf, ">%u</vcpu>\n", def->maxvcpus);
16491

16492
    if (def->cputune.shares ||
16493
        (def->cputune.nvcpupin && !virDomainIsAllVcpupinInherited(def)) ||
T
Tang Chen 已提交
16494
        def->cputune.period || def->cputune.quota ||
16495 16496
        def->cputune.emulatorpin ||
        def->cputune.emulator_period || def->cputune.emulator_quota)
16497
        virBufferAddLit(buf, "  <cputune>\n");
16498 16499

    if (def->cputune.shares)
16500
        virBufferAsprintf(buf, "    <shares>%lu</shares>\n",
16501
                          def->cputune.shares);
16502
    if (def->cputune.period)
16503
        virBufferAsprintf(buf, "    <period>%llu</period>\n",
16504 16505
                          def->cputune.period);
    if (def->cputune.quota)
16506
        virBufferAsprintf(buf, "    <quota>%lld</quota>\n",
16507
                          def->cputune.quota);
16508 16509 16510 16511 16512 16513 16514 16515 16516 16517 16518

    if (def->cputune.emulator_period)
        virBufferAsprintf(buf, "    <emulator_period>%llu"
                          "</emulator_period>\n",
                          def->cputune.emulator_period);

    if (def->cputune.emulator_quota)
        virBufferAsprintf(buf, "    <emulator_quota>%lld"
                          "</emulator_quota>\n",
                          def->cputune.emulator_quota);

16519
    for (i = 0; i < def->cputune.nvcpupin; i++) {
P
Peter Krempa 已提交
16520 16521
        char *cpumask;
        /* Ignore the vcpupin which inherit from "cpuset of "<vcpu>." */
16522 16523 16524 16525
        if (def->cpumask &&
            virBitmapEqual(def->cpumask,
                           def->cputune.vcpupin[i]->cpumask))
            continue;
16526

16527 16528
        virBufferAsprintf(buf, "    <vcpupin vcpu='%u' ",
                          def->cputune.vcpupin[i]->vcpuid);
16529

P
Peter Krempa 已提交
16530
        if (!(cpumask = virBitmapFormat(def->cputune.vcpupin[i]->cpumask))) {
16531 16532
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("failed to format cpuset for vcpupin"));
16533
            goto error;
16534
        }
16535 16536 16537

        virBufferAsprintf(buf, "cpuset='%s'/>\n", cpumask);
        VIR_FREE(cpumask);
16538 16539
    }

T
Tang Chen 已提交
16540
    if (def->cputune.emulatorpin) {
P
Peter Krempa 已提交
16541
        char *cpumask;
16542
        virBufferAddLit(buf, "    <emulatorpin ");
T
Tang Chen 已提交
16543

P
Peter Krempa 已提交
16544
        if (!(cpumask = virBitmapFormat(def->cputune.emulatorpin->cpumask))) {
T
Tang Chen 已提交
16545 16546
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("failed to format cpuset for emulator"));
16547
                goto error;
T
Tang Chen 已提交
16548 16549 16550 16551 16552
        }

        virBufferAsprintf(buf, "cpuset='%s'/>\n", cpumask);
        VIR_FREE(cpumask);
    }
G
Guido Günther 已提交
16553
    if (def->cputune.shares ||
16554
        (def->cputune.nvcpupin && !virDomainIsAllVcpupinInherited(def)) ||
T
Tang Chen 已提交
16555
        def->cputune.period || def->cputune.quota ||
16556 16557
        def->cputune.emulatorpin ||
        def->cputune.emulator_period || def->cputune.emulator_quota)
16558
        virBufferAddLit(buf, "  </cputune>\n");
16559

16560 16561
    if (def->numatune.memory.nodemask ||
        def->numatune.memory.placement_mode) {
O
Osier Yang 已提交
16562
        virBufferAddLit(buf, "  <numatune>\n");
16563
        const char *mode;
16564
        char *nodemask = NULL;
16565
        const char *placement;
16566

16567
        mode = virDomainNumatuneMemModeTypeToString(def->numatune.memory.mode);
16568
        virBufferAsprintf(buf, "    <memory mode='%s' ", mode);
O
Osier Yang 已提交
16569

16570
        if (def->numatune.memory.placement_mode ==
G
Gao feng 已提交
16571
            VIR_NUMA_TUNE_MEM_PLACEMENT_MODE_STATIC) {
16572
            nodemask = virBitmapFormat(def->numatune.memory.nodemask);
16573
            if (nodemask == NULL) {
16574 16575 16576
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("failed to format nodeset for "
                                 "NUMA memory tuning"));
16577
                goto error;
16578 16579 16580 16581
            }
            virBufferAsprintf(buf, "nodeset='%s'/>\n", nodemask);
            VIR_FREE(nodemask);
        } else if (def->numatune.memory.placement_mode) {
G
Gao feng 已提交
16582
            placement = virNumaTuneMemPlacementModeTypeToString(def->numatune.memory.placement_mode);
16583 16584
            virBufferAsprintf(buf, "placement='%s'/>\n", placement);
        }
16585
        virBufferAddLit(buf, "  </numatune>\n");
16586
    }
16587

16588 16589 16590
    if (def->resource)
        virDomainResourceDefFormat(buf, def->resource);

16591
    if (def->sysinfo)
16592
        virDomainSysinfoDefFormat(buf, def->sysinfo);
16593

16594
    if (def->os.bootloader) {
16595
        virBufferEscapeString(buf, "  <bootloader>%s</bootloader>\n",
16596
                              def->os.bootloader);
16597 16598 16599
        virBufferEscapeString(buf,
                              "  <bootloader_args>%s</bootloader_args>\n",
                              def->os.bootloaderArgs);
16600 16601
    }

16602
    virBufferAddLit(buf, "  <os>\n");
16603

16604
    virBufferAddLit(buf, "    <type");
16605
    if (def->os.arch)
16606
        virBufferAsprintf(buf, " arch='%s'", virArchToString(def->os.arch));
16607
    if (def->os.machine)
16608
        virBufferAsprintf(buf, " machine='%s'", def->os.machine);
16609 16610 16611 16612 16613 16614 16615
    /*
     * HACK: For xen driver we previously used bogus 'linux' as the
     * os type for paravirt, whereas capabilities declare it to
     * be 'xen'. So we convert to the former for backcompat
     */
    if (def->virtType == VIR_DOMAIN_VIRT_XEN &&
        STREQ(def->os.type, "xen"))
16616
        virBufferAsprintf(buf, ">%s</type>\n", "linux");
16617
    else
16618
        virBufferAsprintf(buf, ">%s</type>\n", def->os.type);
16619

16620 16621
    virBufferEscapeString(buf, "    <init>%s</init>\n",
                          def->os.init);
16622
    for (i = 0; def->os.initargv && def->os.initargv[i]; i++)
16623 16624
        virBufferEscapeString(buf, "    <initarg>%s</initarg>\n",
                              def->os.initargv[i]);
16625 16626 16627 16628 16629 16630 16631 16632
    virBufferEscapeString(buf, "    <loader>%s</loader>\n",
                          def->os.loader);
    virBufferEscapeString(buf, "    <kernel>%s</kernel>\n",
                          def->os.kernel);
    virBufferEscapeString(buf, "    <initrd>%s</initrd>\n",
                          def->os.initrd);
    virBufferEscapeString(buf, "    <cmdline>%s</cmdline>\n",
                          def->os.cmdline);
16633 16634
    virBufferEscapeString(buf, "    <dtb>%s</dtb>\n",
                          def->os.dtb);
16635 16636
    virBufferEscapeString(buf, "    <root>%s</root>\n",
                          def->os.root);
16637 16638

    if (!def->os.bootloader) {
16639
        for (n = 0; n < def->os.nBootDevs; n++) {
16640 16641 16642
            const char *boottype =
                virDomainBootTypeToString(def->os.bootDevs[n]);
            if (!boottype) {
16643 16644 16645
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unexpected boot device type %d"),
                               def->os.bootDevs[n]);
16646
                goto error;
16647
            }
16648
            virBufferAsprintf(buf, "    <boot dev='%s'/>\n", boottype);
16649
        }
16650 16651 16652 16653 16654

        if (def->os.bootmenu != VIR_DOMAIN_BOOT_MENU_DEFAULT) {
            const char *enabled = (def->os.bootmenu ==
                                   VIR_DOMAIN_BOOT_MENU_ENABLED ? "yes"
                                                                : "no");
16655
            virBufferAsprintf(buf, "    <bootmenu enable='%s'/>\n", enabled);
16656
        }
M
Michal Privoznik 已提交
16657

16658 16659 16660 16661 16662 16663 16664 16665 16666 16667 16668
        if (def->os.bios.useserial || def->os.bios.rt_set) {
            virBufferAddLit(buf, "    <bios");
            if (def->os.bios.useserial)
                virBufferAsprintf(buf, " useserial='%s'",
                                  (def->os.bios.useserial ==
                                   VIR_DOMAIN_BIOS_USESERIAL_YES ? "yes"
                                                                   : "no"));
            if (def->os.bios.rt_set)
                virBufferAsprintf(buf, " rebootTimeout='%d'", def->os.bios.rt_delay);

            virBufferAddLit(buf, "/>\n");
M
Michal Privoznik 已提交
16669
        }
16670 16671
    }

16672 16673 16674 16675 16676
    if (def->os.smbios_mode) {
        const char *mode;

        mode = virDomainSmbiosModeTypeToString(def->os.smbios_mode);
        if (mode == NULL) {
16677 16678
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected smbios mode %d"), def->os.smbios_mode);
16679
            goto error;
16680
        }
16681
        virBufferAsprintf(buf, "    <smbios mode='%s'/>\n", mode);
16682 16683
    }

16684
    virBufferAddLit(buf, "  </os>\n");
16685

16686 16687 16688 16689 16690 16691 16692 16693 16694 16695 16696 16697 16698 16699 16700 16701 16702 16703 16704 16705 16706

    if (def->idmap.uidmap) {
        virBufferAddLit(buf, "  <idmap>\n");
        for (i = 0; i < def->idmap.nuidmap; i++) {
            virBufferAsprintf(buf,
                              "    <uid start='%u' target='%u' count='%u'/>\n",
                              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,
                              "    <gid start='%u' target='%u' count='%u'/>\n",
                              def->idmap.gidmap[i].start,
                              def->idmap.gidmap[i].target,
                              def->idmap.gidmap[i].count);
        }
        virBufferAddLit(buf, "  </idmap>\n");
    }


16707
    if (def->features) {
16708
        virBufferAddLit(buf, "  <features>\n");
16709
        for (i = 0; i < VIR_DOMAIN_FEATURE_LAST; i++) {
16710
            if (def->features & (1 << i) && i != VIR_DOMAIN_FEATURE_HYPERV) {
16711 16712
                const char *name = virDomainFeatureTypeToString(i);
                if (!name) {
16713
                    virReportError(VIR_ERR_INTERNAL_ERROR,
16714
                                   _("unexpected feature %zu"), i);
16715
                    goto error;
16716
                }
16717 16718 16719 16720
                virBufferAsprintf(buf, "    <%s", name);
                if (i == VIR_DOMAIN_FEATURE_APIC && def->apic_eoi) {
                    virBufferAsprintf(buf,
                                      " eoi='%s'",
16721
                                      virDomainFeatureStateTypeToString(def->apic_eoi));
16722
                }
16723
                virBufferAddLit(buf, "/>\n");
16724 16725
            }
        }
16726 16727 16728 16729 16730 16731

        if (def->features & (1 << VIR_DOMAIN_FEATURE_HYPERV)) {
            virBufferAddLit(buf, "    <hyperv>\n");
            for (i = 0; i < VIR_DOMAIN_HYPERV_LAST; i++) {
                switch ((enum virDomainHyperv) i) {
                case VIR_DOMAIN_HYPERV_RELAXED:
16732
                case VIR_DOMAIN_HYPERV_VAPIC:
16733 16734 16735
                    if (def->hyperv_features[i])
                        virBufferAsprintf(buf, "      <%s state='%s'/>\n",
                                          virDomainHypervTypeToString(i),
16736 16737 16738 16739 16740 16741 16742 16743 16744 16745 16746 16747 16748 16749 16750
                                          virDomainFeatureStateTypeToString(
                                              def->hyperv_features[i]));
                    break;

                case VIR_DOMAIN_HYPERV_SPINLOCKS:
                    if (def->hyperv_features[i] == 0)
                        break;

                    virBufferAsprintf(buf, "      <spinlocks state='%s'",
                                      virDomainFeatureStateTypeToString(
                                          def->hyperv_features[i]));
                    if (def->hyperv_features[i] == VIR_DOMAIN_FEATURE_STATE_ON)
                        virBufferAsprintf(buf, " retries='%d'",
                                          def->hyperv_spinlocks);
                    virBufferAddLit(buf, "/>\n");
16751 16752 16753 16754 16755 16756 16757 16758 16759
                    break;

                case VIR_DOMAIN_HYPERV_LAST:
                    break;
                }
            }
            virBufferAddLit(buf, "    </hyperv>\n");
        }

16760
        virBufferAddLit(buf, "  </features>\n");
16761 16762
    }

16763
    virBufferAdjustIndent(buf, 2);
16764
    if (virCPUDefFormatBufFull(buf, def->cpu, flags) < 0)
16765
        goto error;
16766
    virBufferAdjustIndent(buf, -2);
16767

16768
    virBufferAsprintf(buf, "  <clock offset='%s'",
16769
                      virDomainClockOffsetTypeToString(def->clock.offset));
16770
    switch (def->clock.offset) {
16771 16772 16773 16774 16775
    case VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME:
    case VIR_DOMAIN_CLOCK_OFFSET_UTC:
        if (def->clock.data.utc_reset)
            virBufferAddLit(buf, " adjustment='reset'");
        break;
16776
    case VIR_DOMAIN_CLOCK_OFFSET_VARIABLE:
16777 16778 16779
        virBufferAsprintf(buf, " adjustment='%lld' basis='%s'",
                          def->clock.data.variable.adjustment,
                          virDomainClockBasisTypeToString(def->clock.data.variable.basis));
16780 16781 16782 16783

        if (flags & VIR_DOMAIN_XML_INTERNAL_BASEDATE)
            virBufferAsprintf(buf, " basedate='%llu'",
                              def->clock.data.variable.basedate);
16784 16785
        break;
    case VIR_DOMAIN_CLOCK_OFFSET_TIMEZONE:
16786
        virBufferEscapeString(buf, " timezone='%s'", def->clock.data.timezone);
16787 16788
        break;
    }
16789
    if (def->clock.ntimers == 0) {
16790
        virBufferAddLit(buf, "/>\n");
16791
    } else {
16792
        virBufferAddLit(buf, ">\n");
16793
        for (n = 0; n < def->clock.ntimers; n++) {
16794
            if (virDomainTimerDefFormat(buf, def->clock.timers[n]) < 0)
16795
                goto error;
16796
        }
16797
        virBufferAddLit(buf, "  </clock>\n");
16798
    }
16799

16800 16801 16802
    if (virDomainEventActionDefFormat(buf, def->onPoweroff,
                                      "on_poweroff",
                                      virDomainLifecycleTypeToString) < 0)
16803
        goto error;
16804 16805 16806
    if (virDomainEventActionDefFormat(buf, def->onReboot,
                                      "on_reboot",
                                      virDomainLifecycleTypeToString) < 0)
16807
        goto error;
16808 16809 16810
    if (virDomainEventActionDefFormat(buf, def->onCrash,
                                      "on_crash",
                                      virDomainLifecycleCrashTypeToString) < 0)
16811
        goto error;
16812 16813 16814 16815
    if (def->onLockFailure != VIR_DOMAIN_LOCK_FAILURE_DEFAULT &&
        virDomainEventActionDefFormat(buf, def->onLockFailure,
                                      "on_lockfailure",
                                      virDomainLockFailureTypeToString) < 0)
16816
        goto error;
16817

16818 16819 16820 16821 16822 16823 16824 16825 16826 16827 16828 16829 16830
    if (def->pm.s3 || def->pm.s4) {
        virBufferAddLit(buf, "  <pm>\n");
        if (def->pm.s3) {
            virBufferAsprintf(buf, "    <suspend-to-mem enabled='%s'/>\n",
                              virDomainPMStateTypeToString(def->pm.s3));
        }
        if (def->pm.s4) {
            virBufferAsprintf(buf, "    <suspend-to-disk enabled='%s'/>\n",
                              virDomainPMStateTypeToString(def->pm.s4));
        }
        virBufferAddLit(buf, "  </pm>\n");
    }

16831
    virBufferAddLit(buf, "  <devices>\n");
16832

16833 16834
    virBufferEscapeString(buf, "    <emulator>%s</emulator>\n",
                          def->emulator);
16835

16836
    for (n = 0; n < def->ndisks; n++)
16837
        if (virDomainDiskDefFormat(buf, def->disks[n], flags) < 0)
16838
            goto error;
16839

16840
    for (n = 0; n < def->ncontrollers; n++)
16841
        if (virDomainControllerDefFormat(buf, def->controllers[n], flags) < 0)
16842
            goto error;
16843

16844
    for (n = 0; n < def->nleases; n++)
16845
        if (virDomainLeaseDefFormat(buf, def->leases[n]) < 0)
16846
            goto error;
16847

16848
    for (n = 0; n < def->nfss; n++)
16849
        if (virDomainFSDefFormat(buf, def->fss[n], flags) < 0)
16850
            goto error;
16851

16852
    for (n = 0; n < def->nnets; n++)
16853
        if (virDomainNetDefFormat(buf, def->nets[n], flags) < 0)
16854
            goto error;
16855

16856
    for (n = 0; n < def->nsmartcards; n++)
16857
        if (virDomainSmartcardDefFormat(buf, def->smartcards[n], flags) < 0)
16858
            goto error;
E
Eric Blake 已提交
16859

16860
    for (n = 0; n < def->nserials; n++)
16861
        if (virDomainChrDefFormat(buf, def->serials[n], flags) < 0)
16862
            goto error;
16863

16864
    for (n = 0; n < def->nparallels; n++)
16865
        if (virDomainChrDefFormat(buf, def->parallels[n], flags) < 0)
16866
            goto error;
16867

16868
    for (n = 0; n < def->nconsoles; n++) {
16869 16870 16871 16872 16873
        virDomainChrDef console;
        /* Back compat, ignore the console element for hvm guests
         * if it is type == serial
         */
        if (STREQ(def->os.type, "hvm") &&
16874 16875
            (def->consoles[n]->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL ||
             def->consoles[n]->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_NONE) &&
16876 16877 16878
            (n < def->nserials)) {
            memcpy(&console, def->serials[n], sizeof(console));
            console.deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE;
G
Guannan Ren 已提交
16879
            console.targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL;
16880 16881 16882 16883
        } else {
            memcpy(&console, def->consoles[n], sizeof(console));
        }
        if (virDomainChrDefFormat(buf, &console, flags) < 0)
16884
            goto error;
16885 16886 16887 16888
    }
    if (STREQ(def->os.type, "hvm") &&
        def->nconsoles == 0 &&
        def->nserials > 0) {
16889
        virDomainChrDef console;
16890
        memcpy(&console, def->serials[n], sizeof(console));
16891
        console.deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE;
16892
        console.targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL;
16893
        if (virDomainChrDefFormat(buf, &console, flags) < 0)
16894
            goto error;
16895 16896
    }

16897
    for (n = 0; n < def->nchannels; n++)
16898
        if (virDomainChrDefFormat(buf, def->channels[n], flags) < 0)
16899
            goto error;
16900

16901
    for (n = 0; n < def->ninputs; n++)
16902
        if (def->inputs[n]->bus == VIR_DOMAIN_INPUT_BUS_USB &&
16903
            virDomainInputDefFormat(buf, def->inputs[n], flags) < 0)
16904
            goto error;
16905

16906 16907 16908 16909 16910
    if (def->tpm) {
        if (virDomainTPMDefFormat(buf, def->tpm, flags) < 0)
            goto error;
    }

16911
    if (def->ngraphics > 0) {
16912 16913 16914 16915
        /* If graphics is enabled, add the implicit mouse */
        virDomainInputDef autoInput = {
            VIR_DOMAIN_INPUT_TYPE_MOUSE,
            STREQ(def->os.type, "hvm") ?
16916 16917
            VIR_DOMAIN_INPUT_BUS_PS2 : VIR_DOMAIN_INPUT_BUS_XEN,
            { .alias = NULL },
16918
        };
16919

16920
        if (virDomainInputDefFormat(buf, &autoInput, flags) < 0)
16921
            goto error;
16922

16923
        for (n = 0; n < def->ngraphics; n++)
16924
            if (virDomainGraphicsDefFormat(buf, def->graphics[n], flags) < 0)
16925
                goto error;
16926 16927
    }

16928
    for (n = 0; n < def->nsounds; n++)
16929
        if (virDomainSoundDefFormat(buf, def->sounds[n], flags) < 0)
16930
            goto error;
16931

16932
    for (n = 0; n < def->nvideos; n++)
16933
        if (virDomainVideoDefFormat(buf, def->videos[n], flags) < 0)
16934
            goto error;
16935

16936
    for (n = 0; n < def->nhostdevs; n++) {
16937 16938 16939 16940
        /* 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 已提交
16941 16942
        if (def->hostdevs[n]->parent.type == VIR_DOMAIN_DEVICE_NONE &&
            virDomainHostdevDefFormat(buf, def->hostdevs[n], flags) < 0) {
16943
            goto error;
16944 16945
        }
    }
16946

16947
    for (n = 0; n < def->nredirdevs; n++)
16948
        if (virDomainRedirdevDefFormat(buf, def->redirdevs[n], flags) < 0)
16949
            goto error;
16950

16951 16952 16953
    if (def->redirfilter)
        virDomainRedirFilterDefFormat(buf, def->redirfilter);

16954
    for (n = 0; n < def->nhubs; n++)
16955
        if (virDomainHubDefFormat(buf, def->hubs[n], flags) < 0)
16956
            goto error;
M
Marc-André Lureau 已提交
16957

R
Richard Jones 已提交
16958
    if (def->watchdog)
16959
        virDomainWatchdogDefFormat(buf, def->watchdog, flags);
R
Richard Jones 已提交
16960

16961
    if (def->memballoon)
16962
        virDomainMemballoonDefFormat(buf, def->memballoon, flags);
16963

16964 16965 16966
    if (def->rng)
        virDomainRNGDefFormat(buf, def->rng, flags);

L
Li Zhang 已提交
16967 16968 16969
    if (def->nvram)
        virDomainNVRAMDefFormat(buf, def->nvram, flags);

16970
    virBufferAddLit(buf, "  </devices>\n");
16971

16972 16973 16974 16975
    virBufferAdjustIndent(buf, 2);
    for (n = 0; n < def->nseclabels; n++)
        virSecurityLabelDefFormat(buf, def->seclabels[n]);
    virBufferAdjustIndent(buf, -2);
16976

16977
    if (def->namespaceData && def->ns.format) {
16978
        if ((def->ns.format)(buf, def->namespaceData) < 0)
16979
            goto error;
16980 16981
    }

16982
    virBufferAddLit(buf, "</domain>\n");
16983

16984
    if (virBufferError(buf))
16985 16986
        goto no_memory;

16987
    return 0;
16988 16989

 no_memory:
16990
    virReportOOMError();
16991
 error:
16992 16993
    virBufferFreeAndReset(buf);
    return -1;
16994 16995
}

16996 16997 16998
char *
virDomainDefFormat(virDomainDefPtr def, unsigned int flags)
{
16999 17000
    virBuffer buf = VIR_BUFFER_INITIALIZER;

17001
    virCheckFlags(DUMPXML_FLAGS, NULL);
17002 17003 17004 17005
    if (virDomainDefFormatInternal(def, flags, &buf) < 0)
        return NULL;

    return virBufferContentAndReset(&buf);
17006 17007
}

17008

17009
static char *
17010
virDomainObjFormat(virDomainXMLOptionPtr xmlopt,
17011 17012
                   virDomainObjPtr obj,
                   unsigned int flags)
17013 17014
{
    virBuffer buf = VIR_BUFFER_INITIALIZER;
J
Jiri Denemark 已提交
17015 17016
    int state;
    int reason;
17017
    size_t i;
17018

J
Jiri Denemark 已提交
17019
    state = virDomainObjGetState(obj, &reason);
17020
    virBufferAsprintf(&buf, "<domstatus state='%s' reason='%s' pid='%lld'>\n",
J
Jiri Denemark 已提交
17021 17022
                      virDomainStateTypeToString(state),
                      virDomainStateReasonToString(state, reason),
17023
                      (long long)obj->pid);
17024

17025
    for (i = 0; i < VIR_DOMAIN_TAINT_LAST; i++) {
17026 17027 17028 17029 17030
        if (obj->taint & (1 << i))
            virBufferAsprintf(&buf, "  <taint flag='%s'/>\n",
                              virDomainTaintTypeToString(i));
    }

17031 17032
    if (xmlopt->privateData.format &&
        ((xmlopt->privateData.format)(&buf, obj->privateData)) < 0)
17033
        goto error;
17034

17035
    virBufferAdjustIndent(&buf, 2);
17036
    if (virDomainDefFormatInternal(obj->def, flags, &buf) < 0)
17037
        goto error;
17038
    virBufferAdjustIndent(&buf, -2);
17039 17040 17041 17042 17043 17044 17045 17046 17047

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

    if (virBufferError(&buf))
        goto no_memory;

    return virBufferContentAndReset(&buf);

no_memory:
17048
    virReportOOMError();
17049
error:
17050
    virBufferFreeAndReset(&buf);
17051 17052 17053
    return NULL;
}

17054 17055 17056
static bool
virDomainDefHasUSB(virDomainDefPtr def)
{
17057
    size_t i;
17058 17059 17060 17061 17062 17063 17064 17065 17066 17067 17068 17069 17070 17071 17072 17073 17074 17075 17076 17077 17078 17079 17080 17081 17082 17083 17084 17085 17086 17087 17088 17089 17090 17091 17092 17093 17094 17095 17096 17097 17098 17099 17100 17101 17102 17103

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

int
virDomainDefCompatibleDevice(virDomainDefPtr def,
                             virDomainDeviceDefPtr dev)
{
    if (!virDomainDefHasUSB(def) &&
        virDomainDeviceIsUSB(dev)) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Device configuration is not compatible: "
                         "Domain has no USB bus support"));
        return -1;
    }

    return 0;
}

17104 17105 17106 17107
int
virDomainSaveXML(const char *configDir,
                 virDomainDefPtr def,
                 const char *xml)
17108
{
J
Ján Tomko 已提交
17109
    char uuidstr[VIR_UUID_STRING_BUFLEN];
17110
    char *configFile = NULL;
17111
    int ret = -1;
17112

17113
    if ((configFile = virDomainConfigFile(configDir, def->name)) == NULL)
17114 17115
        goto cleanup;

17116
    if (virFileMakePath(configDir) < 0) {
17117
        virReportSystemError(errno,
17118 17119
                             _("cannot create config directory '%s'"),
                             configDir);
17120 17121 17122
        goto cleanup;
    }

J
Ján Tomko 已提交
17123 17124 17125 17126
    virUUIDFormat(def->uuid, uuidstr);
    ret = virXMLSaveFile(configFile,
                         virXMLPickShellSafeComment(def->name, uuidstr), "edit",
                         xml);
17127

17128
 cleanup:
R
Ryota Ozaki 已提交
17129
    VIR_FREE(configFile);
17130 17131 17132
    return ret;
}

17133 17134 17135
int
virDomainSaveConfig(const char *configDir,
                    virDomainDefPtr def)
17136 17137 17138
{
    int ret = -1;
    char *xml;
17139

17140
    if (!(xml = virDomainDefFormat(def, VIR_DOMAIN_XML_WRITE_FLAGS)))
17141 17142
        goto cleanup;

17143
    if (virDomainSaveXML(configDir, def, xml))
17144 17145 17146 17147 17148
        goto cleanup;

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

17152
int
17153
virDomainSaveStatus(virDomainXMLOptionPtr xmlopt,
17154 17155
                    const char *statusDir,
                    virDomainObjPtr obj)
17156
{
17157 17158
    unsigned int flags = (VIR_DOMAIN_XML_SECURE |
                          VIR_DOMAIN_XML_INTERNAL_STATUS |
17159
                          VIR_DOMAIN_XML_INTERNAL_ACTUAL_NET |
17160 17161
                          VIR_DOMAIN_XML_INTERNAL_PCI_ORIG_STATES |
                          VIR_DOMAIN_XML_INTERNAL_BASEDATE);
17162

17163 17164 17165
    int ret = -1;
    char *xml;

17166
    if (!(xml = virDomainObjFormat(xmlopt, obj, flags)))
17167 17168
        goto cleanup;

17169
    if (virDomainSaveXML(statusDir, obj->def, xml))
17170 17171 17172 17173 17174 17175 17176 17177
        goto cleanup;

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

17178

17179 17180 17181
static virDomainObjPtr
virDomainObjListLoadConfig(virDomainObjListPtr doms,
                           virCapsPtr caps,
17182
                           virDomainXMLOptionPtr xmlopt,
17183 17184 17185 17186 17187 17188
                           const char *configDir,
                           const char *autostartDir,
                           const char *name,
                           unsigned int expectedVirtTypes,
                           virDomainLoadConfigNotify notify,
                           void *opaque)
17189 17190 17191 17192 17193
{
    char *configFile = NULL, *autostartLink = NULL;
    virDomainDefPtr def = NULL;
    virDomainObjPtr dom;
    int autostart;
17194
    virDomainDefPtr oldDef = NULL;
17195

17196
    if ((configFile = virDomainConfigFile(configDir, name)) == NULL)
17197
        goto error;
17198
    if (!(def = virDomainDefParseFile(configFile, caps, xmlopt,
17199
                                      expectedVirtTypes,
17200
                                      VIR_DOMAIN_XML_INACTIVE)))
17201 17202
        goto error;

17203 17204 17205 17206 17207 17208
    if ((autostartLink = virDomainConfigFile(autostartDir, name)) == NULL)
        goto error;

    if ((autostart = virFileLinkPointsTo(autostartLink, configFile)) < 0)
        goto error;

17209
    if (!(dom = virDomainObjListAddLocked(doms, def, xmlopt, 0, &oldDef)))
17210 17211 17212 17213
        goto error;

    dom->autostart = autostart;

17214
    if (notify)
17215
        (*notify)(dom, oldDef == NULL, opaque);
17216

17217
    virDomainDefFree(oldDef);
17218 17219
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
17220 17221 17222 17223 17224 17225 17226 17227 17228
    return dom;

error:
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
    virDomainDefFree(def);
    return NULL;
}

17229 17230 17231 17232
static virDomainObjPtr
virDomainObjListLoadStatus(virDomainObjListPtr doms,
                           const char *statusDir,
                           const char *name,
17233 17234
                           virCapsPtr caps,
                           virDomainXMLOptionPtr xmlopt,
17235 17236 17237
                           unsigned int expectedVirtTypes,
                           virDomainLoadConfigNotify notify,
                           void *opaque)
17238 17239 17240
{
    char *statusFile = NULL;
    virDomainObjPtr obj = NULL;
17241
    char uuidstr[VIR_UUID_STRING_BUFLEN];
17242

17243
    if ((statusFile = virDomainConfigFile(statusDir, name)) == NULL)
17244 17245
        goto error;

17246
    if (!(obj = virDomainObjParseFile(statusFile, caps, xmlopt, expectedVirtTypes,
17247
                                      VIR_DOMAIN_XML_INTERNAL_STATUS |
17248
                                      VIR_DOMAIN_XML_INTERNAL_ACTUAL_NET |
17249 17250
                                      VIR_DOMAIN_XML_INTERNAL_PCI_ORIG_STATES |
                                      VIR_DOMAIN_XML_INTERNAL_BASEDATE)))
17251 17252
        goto error;

17253 17254 17255
    virUUIDFormat(obj->def->uuid, uuidstr);

    if (virHashLookup(doms->objs, uuidstr) != NULL) {
17256 17257 17258
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected domain %s already exists"),
                       obj->def->name);
17259 17260 17261
        goto error;
    }

17262
    if (virHashAddEntry(doms->objs, uuidstr, obj) < 0)
17263 17264 17265 17266 17267 17268 17269 17270 17271
        goto error;

    if (notify)
        (*notify)(obj, 1, opaque);

    VIR_FREE(statusFile);
    return obj;

error:
17272
    virObjectUnref(obj);
17273 17274 17275 17276
    VIR_FREE(statusFile);
    return NULL;
}

17277 17278 17279 17280 17281
int
virDomainObjListLoadAllConfigs(virDomainObjListPtr doms,
                               const char *configDir,
                               const char *autostartDir,
                               int liveStatus,
17282 17283
                               virCapsPtr caps,
                               virDomainXMLOptionPtr xmlopt,
17284 17285 17286
                               unsigned int expectedVirtTypes,
                               virDomainLoadConfigNotify notify,
                               void *opaque)
17287 17288 17289 17290
{
    DIR *dir;
    struct dirent *entry;

17291 17292
    VIR_INFO("Scanning for configs in %s", configDir);

17293 17294 17295
    if (!(dir = opendir(configDir))) {
        if (errno == ENOENT)
            return 0;
17296
        virReportSystemError(errno,
17297 17298
                             _("Failed to open dir '%s'"),
                             configDir);
17299 17300 17301
        return -1;
    }

17302 17303
    virObjectLock(doms);

17304
    while ((entry = readdir(dir))) {
17305 17306
        virDomainObjPtr dom;

17307 17308 17309
        if (entry->d_name[0] == '.')
            continue;

17310
        if (!virFileStripSuffix(entry->d_name, ".xml"))
17311 17312 17313 17314
            continue;

        /* NB: ignoring errors, so one malformed config doesn't
           kill the whole process */
17315 17316
        VIR_INFO("Loading config file '%s.xml'", entry->d_name);
        if (liveStatus)
17317 17318 17319
            dom = virDomainObjListLoadStatus(doms,
                                             configDir,
                                             entry->d_name,
17320 17321
                                             caps,
                                             xmlopt,
17322 17323 17324
                                             expectedVirtTypes,
                                             notify,
                                             opaque);
17325
        else
17326 17327
            dom = virDomainObjListLoadConfig(doms,
                                             caps,
17328
                                             xmlopt,
17329 17330 17331 17332 17333 17334
                                             configDir,
                                             autostartDir,
                                             entry->d_name,
                                             expectedVirtTypes,
                                             notify,
                                             opaque);
17335
        if (dom) {
17336
            virObjectUnlock(dom);
D
Daniel Veillard 已提交
17337 17338
            if (!liveStatus)
                dom->persistent = 1;
17339
        }
17340 17341 17342
    }

    closedir(dir);
17343
    virObjectUnlock(doms);
17344 17345 17346
    return 0;
}

17347 17348 17349 17350
int
virDomainDeleteConfig(const char *configDir,
                      const char *autostartDir,
                      virDomainObjPtr dom)
17351
{
17352 17353 17354
    char *configFile = NULL, *autostartLink = NULL;
    int ret = -1;

17355
    if ((configFile = virDomainConfigFile(configDir, dom->def->name)) == NULL)
17356
        goto cleanup;
17357 17358
    if ((autostartLink = virDomainConfigFile(autostartDir,
                                             dom->def->name)) == NULL)
17359
        goto cleanup;
17360 17361

    /* Not fatal if this doesn't work */
17362
    unlink(autostartLink);
17363

17364 17365
    if (unlink(configFile) < 0 &&
        errno != ENOENT) {
17366
        virReportSystemError(errno,
17367 17368
                             _("cannot remove config %s"),
                             configFile);
17369
        goto cleanup;
17370 17371
    }

17372 17373 17374 17375 17376 17377
    ret = 0;

cleanup:
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
    return ret;
17378
}
17379

17380 17381 17382
char
*virDomainConfigFile(const char *dir,
                     const char *name)
17383
{
17384
    char *ret;
17385

17386
    ignore_value(virAsprintf(&ret, "%s/%s.xml", dir, name));
17387 17388 17389
    return ret;
}

17390 17391
/* 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 已提交
17392
 *                                               hdd => (1,1), vdaa => (0,26))
17393 17394 17395 17396 17397
 * @param disk The disk device
 * @param busIdx parsed bus number
 * @param devIdx parsed device number
 * @return 0 on success, -1 on failure
 */
17398 17399 17400 17401
int
virDiskNameToBusDeviceIndex(const virDomainDiskDefPtr disk,
                            int *busIdx,
                            int *devIdx) {
17402 17403

    int idx = virDiskNameToIndex(disk->dst);
17404
    if (idx < 0)
17405 17406 17407 17408 17409 17410 17411 17412 17413 17414 17415 17416 17417 17418 17419
        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:
17420
        case VIR_DOMAIN_DISK_BUS_SD:
17421 17422 17423 17424 17425 17426 17427 17428
        default:
            *busIdx = 0;
            *devIdx = idx;
            break;
    }

    return 0;
}
17429

17430 17431
virDomainFSDefPtr
virDomainGetRootFilesystem(virDomainDefPtr def)
17432
{
17433
    size_t i;
17434

17435
    for (i = 0; i < def->nfss; i++) {
17436 17437 17438 17439 17440 17441 17442
        if (STREQ(def->fss[i]->dst, "/"))
            return def->fss[i];
    }

    return NULL;
}

17443

17444 17445 17446 17447 17448 17449
struct virDomainObjListData {
    virDomainObjListFilter filter;
    virConnectPtr conn;
    bool active;
    int count;
};
17450

17451
static void
17452 17453 17454
virDomainObjListCount(void *payload,
                      const void *name ATTRIBUTE_UNUSED,
                      void *opaque)
17455 17456
{
    virDomainObjPtr obj = payload;
17457
    struct virDomainObjListData *data = opaque;
17458
    virObjectLock(obj);
17459 17460 17461 17462 17463 17464 17465 17466 17467 17468 17469
    if (data->filter &&
        !data->filter(data->conn, obj->def))
        goto cleanup;
    if (virDomainObjIsActive(obj)) {
        if (data->active)
            data->count++;
    } else {
        if (!data->active)
            data->count++;
    }
cleanup:
17470
    virObjectUnlock(obj);
17471 17472
}

17473 17474
int
virDomainObjListNumOfDomains(virDomainObjListPtr doms,
17475 17476 17477
                             bool active,
                             virDomainObjListFilter filter,
                             virConnectPtr conn)
17478
{
17479
    struct virDomainObjListData data = { filter, conn, active, 0 };
17480
    virObjectLock(doms);
17481
    virHashForEach(doms->objs, virDomainObjListCount, &data);
17482
    virObjectUnlock(doms);
17483
    return data.count;
17484 17485 17486
}

struct virDomainIDData {
17487 17488
    virDomainObjListFilter filter;
    virConnectPtr conn;
17489 17490 17491 17492 17493
    int numids;
    int maxids;
    int *ids;
};

17494 17495 17496 17497
static void
virDomainObjListCopyActiveIDs(void *payload,
                              const void *name ATTRIBUTE_UNUSED,
                              void *opaque)
17498 17499 17500
{
    virDomainObjPtr obj = payload;
    struct virDomainIDData *data = opaque;
17501
    virObjectLock(obj);
17502 17503 17504
    if (data->filter &&
        !data->filter(data->conn, obj->def))
        goto cleanup;
D
Daniel P. Berrange 已提交
17505
    if (virDomainObjIsActive(obj) && data->numids < data->maxids)
17506
        data->ids[data->numids++] = obj->def->id;
17507
cleanup:
17508
    virObjectUnlock(obj);
17509 17510
}

17511 17512 17513
int
virDomainObjListGetActiveIDs(virDomainObjListPtr doms,
                             int *ids,
17514 17515 17516
                             int maxids,
                             virDomainObjListFilter filter,
                             virConnectPtr conn)
17517
{
17518 17519
    struct virDomainIDData data = { filter, conn,
                                    0, maxids, ids };
17520
    virObjectLock(doms);
17521
    virHashForEach(doms->objs, virDomainObjListCopyActiveIDs, &data);
17522
    virObjectUnlock(doms);
17523 17524 17525 17526
    return data.numids;
}

struct virDomainNameData {
17527 17528
    virDomainObjListFilter filter;
    virConnectPtr conn;
17529 17530 17531 17532 17533 17534
    int oom;
    int numnames;
    int maxnames;
    char **const names;
};

17535 17536 17537 17538
static void
virDomainObjListCopyInactiveNames(void *payload,
                                  const void *name ATTRIBUTE_UNUSED,
                                  void *opaque)
17539 17540 17541 17542 17543 17544 17545
{
    virDomainObjPtr obj = payload;
    struct virDomainNameData *data = opaque;

    if (data->oom)
        return;

17546
    virObjectLock(obj);
17547 17548 17549
    if (data->filter &&
        !data->filter(data->conn, obj->def))
        goto cleanup;
D
Daniel P. Berrange 已提交
17550
    if (!virDomainObjIsActive(obj) && data->numnames < data->maxnames) {
17551
        if (VIR_STRDUP(data->names[data->numnames], obj->def->name) < 0)
17552 17553 17554 17555
            data->oom = 1;
        else
            data->numnames++;
    }
17556
cleanup:
17557
    virObjectUnlock(obj);
17558 17559 17560
}


17561 17562 17563
int
virDomainObjListGetInactiveNames(virDomainObjListPtr doms,
                                 char **const names,
17564 17565 17566
                                 int maxnames,
                                 virDomainObjListFilter filter,
                                 virConnectPtr conn)
17567
{
17568 17569
    struct virDomainNameData data = { filter, conn,
                                      0, 0, maxnames, names };
17570
    size_t i;
17571
    virObjectLock(doms);
17572
    virHashForEach(doms->objs, virDomainObjListCopyInactiveNames, &data);
17573
    virObjectUnlock(doms);
17574
    if (data.oom) {
17575
        for (i = 0; i < data.numnames; i++)
17576 17577
            VIR_FREE(data.names[i]);
        return -1;
17578 17579 17580 17581 17582
    }

    return data.numnames;
}

17583 17584 17585 17586 17587 17588 17589 17590 17591 17592 17593 17594 17595 17596 17597 17598 17599 17600

struct virDomainListIterData {
    virDomainObjListIterator callback;
    void *opaque;
    int ret;
};

static void
virDomainObjListHelper(void *payload,
                       const void *name ATTRIBUTE_UNUSED,
                       void *opaque)
{
    struct virDomainListIterData *data = opaque;

    if (data->callback(payload, data->opaque) < 0)
        data->ret = -1;
}

17601 17602 17603 17604
int
virDomainObjListForEach(virDomainObjListPtr doms,
                        virDomainObjListIterator callback,
                        void *opaque)
17605 17606 17607 17608
{
    struct virDomainListIterData data = {
        callback, opaque, 0,
    };
17609
    virObjectLock(doms);
17610
    virHashForEach(doms->objs, virDomainObjListHelper, &data);
17611
    virObjectUnlock(doms);
17612 17613 17614 17615
    return data.ret;
}


17616 17617 17618 17619 17620
int
virDomainChrDefForeach(virDomainDefPtr def,
                       bool abortOnError,
                       virDomainChrDefIterator iter,
                       void *opaque)
17621
{
17622
    size_t i;
17623 17624
    int rc = 0;

17625
    for (i = 0; i < def->nserials; i++) {
17626 17627 17628 17629 17630 17631 17632 17633 17634
        if ((iter)(def,
                   def->serials[i],
                   opaque) < 0)
            rc = -1;

        if (abortOnError && rc != 0)
            goto done;
    }

17635
    for (i = 0; i < def->nparallels; i++) {
17636 17637 17638 17639 17640 17641 17642 17643 17644
        if ((iter)(def,
                   def->parallels[i],
                   opaque) < 0)
            rc = -1;

        if (abortOnError && rc != 0)
            goto done;
    }

17645
    for (i = 0; i < def->nchannels; i++) {
17646 17647 17648 17649 17650 17651 17652 17653
        if ((iter)(def,
                   def->channels[i],
                   opaque) < 0)
            rc = -1;

        if (abortOnError && rc != 0)
            goto done;
    }
17654
    for (i = 0; i < def->nconsoles; i++) {
17655
        if ((iter)(def,
17656
                   def->consoles[i],
17657 17658 17659 17660 17661 17662 17663 17664 17665 17666 17667 17668
                   opaque) < 0)
            rc = -1;

        if (abortOnError && rc != 0)
            goto done;
    }

done:
    return rc;
}


17669 17670 17671 17672 17673
int
virDomainSmartcardDefForeach(virDomainDefPtr def,
                             bool abortOnError,
                             virDomainSmartcardDefIterator iter,
                             void *opaque)
E
Eric Blake 已提交
17674
{
17675
    size_t i;
E
Eric Blake 已提交
17676 17677
    int rc = 0;

17678
    for (i = 0; i < def->nsmartcards; i++) {
E
Eric Blake 已提交
17679 17680 17681 17682 17683 17684 17685 17686 17687 17688 17689 17690 17691 17692
        if ((iter)(def,
                   def->smartcards[i],
                   opaque) < 0)
            rc = -1;

        if (abortOnError && rc != 0)
            goto done;
    }

done:
    return rc;
}


17693 17694 17695 17696 17697
/* Call iter(disk, name, depth, opaque) for each element of disk and
 * its backing chain in the pre-populated disk->backingChain.
 * ignoreOpenFailure determines whether to warn about a chain that
 * mentions a backing file without also having metadata on that
 * file.  */
17698 17699 17700 17701 17702
int
virDomainDiskDefForeachPath(virDomainDiskDefPtr disk,
                            bool ignoreOpenFailure,
                            virDomainDiskDefPathIterator iter,
                            void *opaque)
17703 17704 17705
{
    int ret = -1;
    size_t depth = 0;
17706
    virStorageFileMetadata *tmp;
17707

17708 17709 17710 17711
    if (!disk->src || disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK ||
        (disk->type == VIR_DOMAIN_DISK_TYPE_VOLUME &&
         disk->srcpool &&
         disk->srcpool->mode == VIR_DOMAIN_DISK_SOURCE_POOL_MODE_DIRECT))
17712 17713
        return 0;

17714 17715
    if (iter(disk, disk->src, 0, opaque) < 0)
        goto cleanup;
17716

17717 17718 17719
    tmp = disk->backingChain;
    while (tmp && tmp->backingStoreIsFile) {
        if (!ignoreOpenFailure && !tmp->backingMeta) {
17720
            virReportError(VIR_ERR_INTERNAL_ERROR,
17721 17722
                           _("unable to visit backing chain file %s"),
                           tmp->backingStore);
17723 17724
            goto cleanup;
        }
17725
        if (iter(disk, tmp->backingStore, ++depth, opaque) < 0)
17726
            goto cleanup;
17727 17728
        tmp = tmp->backingMeta;
    }
17729 17730 17731 17732 17733 17734

    ret = 0;

cleanup:
    return ret;
}
17735 17736


17737 17738 17739 17740
/* 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).  */
17741
virDomainDefPtr
17742 17743
virDomainDefCopy(virDomainDefPtr src,
                 virCapsPtr caps,
17744
                 virDomainXMLOptionPtr xmlopt,
17745
                 bool migratable)
17746 17747
{
    char *xml;
17748 17749 17750
    virDomainDefPtr ret;
    unsigned int write_flags = VIR_DOMAIN_XML_WRITE_FLAGS;
    unsigned int read_flags = VIR_DOMAIN_XML_READ_FLAGS;
17751

17752 17753
    if (migratable)
        write_flags |= VIR_DOMAIN_XML_INACTIVE | VIR_DOMAIN_XML_MIGRATABLE;
17754

17755
    /* Easiest to clone via a round-trip through XML.  */
17756
    if (!(xml = virDomainDefFormat(src, write_flags)))
17757 17758
        return NULL;

17759
    ret = virDomainDefParseString(xml, caps, xmlopt, -1, read_flags);
17760 17761 17762 17763

    VIR_FREE(xml);
    return ret;
}
J
Jiri Denemark 已提交
17764

17765
virDomainDefPtr
17766 17767 17768
virDomainObjCopyPersistentDef(virDomainObjPtr dom,
                              virCapsPtr caps,
                              virDomainXMLOptionPtr xmlopt)
17769 17770 17771
{
    virDomainDefPtr cur;

17772
    cur = virDomainObjGetPersistentDef(caps, xmlopt, dom);
17773
    return virDomainDefCopy(cur, caps, xmlopt, false);
17774 17775
}

J
Jiri Denemark 已提交
17776 17777 17778 17779 17780 17781 17782 17783 17784 17785 17786 17787 17788 17789 17790 17791 17792

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 已提交
17793 17794 17795 17796 17797 17798 17799 17800 17801 17802 17803 17804 17805 17806 17807 17808 17809 17810 17811 17812 17813 17814 17815 17816 17817 17818
    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 已提交
17819 17820 17821 17822 17823 17824 17825 17826 17827 17828 17829 17830 17831 17832 17833 17834 17835 17836 17837 17838 17839 17840 17841 17842 17843 17844 17845 17846 17847 17848 17849 17850 17851
    }

    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);
17852 17853 17854 17855
    case VIR_DOMAIN_PMSUSPENDED:
        return virDomainPMSuspendedReasonTypeToString(reason);
    case VIR_DOMAIN_LAST:
        break;
J
Jiri Denemark 已提交
17856
    }
17857 17858
    VIR_WARN("Unexpected domain state: %d", state);
    return NULL;
J
Jiri Denemark 已提交
17859 17860 17861 17862 17863 17864 17865 17866 17867 17868 17869 17870 17871 17872 17873 17874 17875 17876 17877 17878 17879
}


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);
17880 17881 17882 17883
    case VIR_DOMAIN_PMSUSPENDED:
        return virDomainPMSuspendedReasonTypeFromString(reason);
    case VIR_DOMAIN_LAST:
        break;
J
Jiri Denemark 已提交
17884
    }
17885 17886
    VIR_WARN("Unexpected domain state: %d", state);
    return -1;
J
Jiri Denemark 已提交
17887
}
17888 17889 17890 17891 17892 17893 17894 17895 17896 17897 17898 17899 17900 17901 17902 17903 17904 17905


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

17906
const char *
17907 17908 17909 17910
virDomainNetGetActualBridgeName(virDomainNetDefPtr iface)
{
    if (iface->type == VIR_DOMAIN_NET_TYPE_BRIDGE)
        return iface->data.bridge.brname;
17911 17912 17913 17914 17915 17916
    if (iface->type == VIR_DOMAIN_NET_TYPE_NETWORK &&
        iface->data.network.actual &&
        iface->data.network.actual->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
        return iface->data.network.actual->data.bridge.brname;
    }
    return NULL;
17917 17918
}

17919
const char *
17920 17921 17922 17923
virDomainNetGetActualDirectDev(virDomainNetDefPtr iface)
{
    if (iface->type == VIR_DOMAIN_NET_TYPE_DIRECT)
        return iface->data.direct.linkdev;
17924 17925 17926 17927 17928 17929
    if (iface->type == VIR_DOMAIN_NET_TYPE_NETWORK &&
        iface->data.network.actual &&
        iface->data.network.actual->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
        return iface->data.network.actual->data.direct.linkdev;
    }
    return NULL;
17930 17931 17932 17933 17934 17935 17936
}

int
virDomainNetGetActualDirectMode(virDomainNetDefPtr iface)
{
    if (iface->type == VIR_DOMAIN_NET_TYPE_DIRECT)
        return iface->data.direct.mode;
17937 17938 17939 17940 17941 17942
    if (iface->type == VIR_DOMAIN_NET_TYPE_NETWORK &&
        iface->data.network.actual &&
        iface->data.network.actual->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
        return iface->data.network.actual->data.direct.mode;
    }
    return 0;
17943 17944
}

17945 17946 17947 17948 17949
virDomainHostdevDefPtr
virDomainNetGetActualHostdev(virDomainNetDefPtr iface)
{
    if (iface->type == VIR_DOMAIN_NET_TYPE_HOSTDEV)
        return &iface->data.hostdev.def;
E
Eric Blake 已提交
17950
    if (iface->type == VIR_DOMAIN_NET_TYPE_NETWORK &&
17951
        iface->data.network.actual &&
E
Eric Blake 已提交
17952
        iface->data.network.actual->type == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
17953 17954 17955 17956 17957
        return &iface->data.network.actual->data.hostdev.def;
    }
    return NULL;
}

17958
virNetDevVPortProfilePtr
17959
virDomainNetGetActualVirtPortProfile(virDomainNetDefPtr iface)
17960
{
A
Ansis Atteka 已提交
17961 17962 17963
    switch (iface->type) {
    case VIR_DOMAIN_NET_TYPE_DIRECT:
    case VIR_DOMAIN_NET_TYPE_BRIDGE:
17964
    case VIR_DOMAIN_NET_TYPE_HOSTDEV:
17965
        return iface->virtPortProfile;
A
Ansis Atteka 已提交
17966 17967 17968 17969 17970 17971
    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:
17972
        case VIR_DOMAIN_NET_TYPE_HOSTDEV:
17973
            return iface->data.network.actual->virtPortProfile;
A
Ansis Atteka 已提交
17974 17975 17976 17977
        default:
            return NULL;
        }
    default:
17978
        return NULL;
A
Ansis Atteka 已提交
17979
    }
17980
}
17981

17982
virNetDevBandwidthPtr
17983 17984
virDomainNetGetActualBandwidth(virDomainNetDefPtr iface)
{
E
Eric Blake 已提交
17985
    if (iface->type == VIR_DOMAIN_NET_TYPE_NETWORK &&
17986 17987 17988 17989 17990
        iface->data.network.actual && iface->data.network.actual->bandwidth) {
        return iface->data.network.actual->bandwidth;
    }
    return iface->bandwidth;
}
17991

17992 17993 17994 17995 17996 17997 17998 17999 18000 18001 18002
virNetDevVlanPtr
virDomainNetGetActualVlan(virDomainNetDefPtr iface)
{
    if (iface->type == VIR_DOMAIN_NET_TYPE_NETWORK &&
        iface->data.network.actual &&
        iface->data.network.actual->vlan.nTags > 0)
        return &iface->data.network.actual->vlan;
    if (iface->vlan.nTags > 0)
        return &iface->vlan;
    return 0;
}
18003

18004
/* Return listens[i] from the appropriate union for the graphics
18005
 * type, or NULL if this is an unsuitable type, or the index is out of
18006
 * bounds. If force0 is TRUE, i == 0, and there is no listen array,
18007 18008
 * allocate one with a single item. */
static virDomainGraphicsListenDefPtr
18009
virDomainGraphicsGetListen(virDomainGraphicsDefPtr def, size_t i, bool force0)
18010
{
E
Eric Blake 已提交
18011 18012 18013
    if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC ||
        def->type == VIR_DOMAIN_GRAPHICS_TYPE_RDP ||
        def->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) {
18014

18015
        if (!def->listens && (i == 0) && force0) {
18016
            if (VIR_ALLOC(def->listens) >= 0)
18017 18018 18019
                def->nListens = 1;
        }

18020
        if (!def->listens || (def->nListens <= i))
18021 18022
            return NULL;

18023
        return &def->listens[i];
18024 18025 18026 18027 18028 18029 18030 18031 18032 18033 18034 18035 18036 18037 18038 18039 18040 18041 18042 18043 18044
    }

    /* 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
18045
virDomainGraphicsListenGetType(virDomainGraphicsDefPtr def, size_t i)
18046 18047
{
    virDomainGraphicsListenDefPtr listenInfo
18048
        = virDomainGraphicsGetListen(def, i, false);
18049 18050 18051 18052 18053 18054 18055 18056 18057 18058 18059

    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
18060
virDomainGraphicsListenSetType(virDomainGraphicsDefPtr def, size_t i, int val)
18061 18062
{
    virDomainGraphicsListenDefPtr listenInfo
18063
        = virDomainGraphicsGetListen(def, i, true);
18064 18065 18066 18067 18068 18069 18070 18071 18072

    if (!listenInfo)
        return -1;
    listenInfo->type = val;
    return 0;
}


const char *
18073
virDomainGraphicsListenGetAddress(virDomainGraphicsDefPtr def, size_t i)
18074 18075
{
    virDomainGraphicsListenDefPtr listenInfo
18076
        = virDomainGraphicsGetListen(def, i, false);
18077

18078
    /* even a network can have a listen address */
18079
    if (!listenInfo ||
18080 18081
        !(listenInfo->type == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS ||
          listenInfo->type == VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NETWORK))
18082 18083 18084 18085 18086 18087
        return NULL;
    return listenInfo->address;
}


/* Make a copy of up to len characters of address, and store it in
18088
 * listens[i].address. If setType is true, set the listen's type
18089 18090 18091
 * to 'address', otherwise leave type alone. */
int
virDomainGraphicsListenSetAddress(virDomainGraphicsDefPtr def,
18092
                                  size_t i, const char *address,
18093 18094 18095
                                  int len, bool setType)
{
    virDomainGraphicsListenDefPtr listenInfo
18096
        = virDomainGraphicsGetListen(def, i, true);
18097 18098 18099 18100 18101 18102 18103 18104 18105 18106 18107 18108

    if (!listenInfo)
        return -1;

    if (setType)
        listenInfo->type = VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS;

    if (!address) {
        listenInfo->address = NULL;
        return 0;
    }

18109
    if (VIR_STRNDUP(listenInfo->address, address, len) < 0)
18110 18111 18112 18113 18114 18115
        return -1;
    return 0;
}


const char *
18116
virDomainGraphicsListenGetNetwork(virDomainGraphicsDefPtr def, size_t i)
18117 18118
{
    virDomainGraphicsListenDefPtr listenInfo
18119
        = virDomainGraphicsGetListen(def, i, false);
18120 18121 18122 18123 18124 18125 18126 18127 18128

    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
18129
 * listens[i].network */
18130 18131
int
virDomainGraphicsListenSetNetwork(virDomainGraphicsDefPtr def,
18132
                                  size_t i, const char *network, int len)
18133 18134
{
    virDomainGraphicsListenDefPtr listenInfo
18135
        = virDomainGraphicsGetListen(def, i, true);
18136 18137 18138 18139 18140 18141 18142 18143 18144 18145 18146

    if (!listenInfo)
        return -1;

    listenInfo->type = VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NETWORK;

    if (!network) {
        listenInfo->network = NULL;
        return 0;
    }

18147
    if (VIR_STRNDUP(listenInfo->network, network, len) < 0)
18148 18149 18150
        return -1;
    return 0;
}
18151 18152 18153 18154 18155 18156 18157 18158 18159 18160 18161 18162 18163 18164 18165

/**
 * 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;
18166
    virMacAddr mac;
18167
    size_t i;
18168

18169
    if (virMacAddrParse(device, &mac) == 0)
18170 18171 18172 18173
        isMac = true;

    if (isMac) {
        for (i = 0; i < def->nnets; i++) {
18174
            if (virMacAddrCmp(&mac, &def->nets[i]->mac) == 0) {
18175 18176 18177 18178 18179 18180 18181 18182 18183 18184 18185 18186 18187 18188 18189
                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;
}
18190 18191 18192 18193 18194 18195 18196 18197 18198 18199 18200 18201 18202 18203 18204 18205

/**
 * virDomainDeviceDefCopy:
 * @caps: Capabilities
 * @def: Domain definition to which @src belongs
 * @src: source to be copied
 *
 * virDomainDeviceDefCopy does a deep copy of only the parts of a
 * DeviceDef that are valid when just the flag VIR_DOMAIN_XML_INACTIVE is
 * set. This means that any part of the device xml that is conditionally
 * parsed/formatted based on some other flag being set (or on the INACTIVE
 * flag being reset) *will not* be copied to the destination. Caveat emptor.
 *
 * Returns a pointer to copied @src or NULL in case of error.
 */
virDomainDeviceDefPtr
18206
virDomainDeviceDefCopy(virDomainDeviceDefPtr src,
18207
                       const virDomainDefPtr def,
18208 18209
                       virCapsPtr caps,
                       virDomainXMLOptionPtr xmlopt)
18210 18211 18212 18213 18214 18215 18216
{
    virDomainDeviceDefPtr ret = NULL;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
    int flags = VIR_DOMAIN_XML_INACTIVE;
    char *xmlStr = NULL;
    int rc = -1;

18217
    switch ((virDomainDeviceType) src->type) {
18218 18219 18220 18221 18222 18223 18224 18225 18226 18227 18228 18229 18230 18231 18232 18233 18234 18235 18236 18237 18238 18239 18240 18241 18242 18243 18244 18245 18246 18247 18248 18249 18250 18251 18252 18253 18254 18255 18256
    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;
18257 18258 18259
    case VIR_DOMAIN_DEVICE_RNG:
        rc = virDomainRNGDefFormat(&buf, src->data.rng, flags);
        break;
18260 18261 18262
    case VIR_DOMAIN_DEVICE_CHR:
        rc = virDomainChrDefFormat(&buf, src->data.chr, flags);
        break;
18263 18264 18265
    case VIR_DOMAIN_DEVICE_NONE:
    case VIR_DOMAIN_DEVICE_SMARTCARD:
    case VIR_DOMAIN_DEVICE_MEMBALLOON:
L
Li Zhang 已提交
18266
    case VIR_DOMAIN_DEVICE_NVRAM:
18267
    case VIR_DOMAIN_DEVICE_LAST:
18268 18269 18270 18271
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Copying definition of '%d' type "
                         "is not implemented yet."),
                       src->type);
18272 18273 18274 18275 18276 18277 18278
        goto cleanup;
    }

    if (rc < 0)
        goto cleanup;

    xmlStr = virBufferContentAndReset(&buf);
18279
    ret = virDomainDeviceDefParse(xmlStr, def, caps, xmlopt, flags);
18280 18281 18282 18283 18284

cleanup:
    VIR_FREE(xmlStr);
    return ret;
}
O
Osier Yang 已提交
18285 18286 18287 18288

struct virDomainListData {
    virConnectPtr conn;
    virDomainPtr *domains;
18289
    virDomainObjListFilter filter;
O
Osier Yang 已提交
18290 18291 18292 18293 18294 18295 18296 18297 18298 18299 18300 18301 18302 18303 18304 18305 18306 18307
    unsigned int flags;
    int ndomains;
    bool error;
};

#define MATCH(FLAG) (data->flags & (FLAG))
static void
virDomainListPopulate(void *payload,
                      const void *name ATTRIBUTE_UNUSED,
                      void *opaque)
{
    struct virDomainListData *data = opaque;
    virDomainObjPtr vm = payload;
    virDomainPtr dom;

    if (data->error)
        return;

18308
    virObjectLock(vm);
O
Osier Yang 已提交
18309 18310
    /* check if the domain matches the filter */

18311 18312 18313 18314 18315
    /* filter by the callback function (access control checks) */
    if (data->filter != NULL &&
        !data->filter(data->conn, vm->def))
        goto cleanup;

O
Osier Yang 已提交
18316 18317 18318 18319 18320 18321 18322 18323 18324 18325 18326 18327 18328 18329 18330 18331 18332 18333 18334 18335 18336 18337 18338 18339 18340 18341 18342 18343 18344 18345 18346 18347 18348 18349 18350 18351 18352 18353 18354 18355 18356 18357 18358 18359 18360 18361 18362 18363
    /* filter by active state */
    if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_ACTIVE) &&
        !((MATCH(VIR_CONNECT_LIST_DOMAINS_ACTIVE) &&
           virDomainObjIsActive(vm)) ||
          (MATCH(VIR_CONNECT_LIST_DOMAINS_INACTIVE) &&
           !virDomainObjIsActive(vm))))
        goto cleanup;

    /* filter by persistence */
    if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_PERSISTENT) &&
        !((MATCH(VIR_CONNECT_LIST_DOMAINS_PERSISTENT) &&
           vm->persistent) ||
          (MATCH(VIR_CONNECT_LIST_DOMAINS_TRANSIENT) &&
           !vm->persistent)))
        goto cleanup;

    /* filter by domain state */
    if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_STATE)) {
        int st = virDomainObjGetState(vm, NULL);
        if (!((MATCH(VIR_CONNECT_LIST_DOMAINS_RUNNING) &&
               st == VIR_DOMAIN_RUNNING) ||
              (MATCH(VIR_CONNECT_LIST_DOMAINS_PAUSED) &&
               st == VIR_DOMAIN_PAUSED) ||
              (MATCH(VIR_CONNECT_LIST_DOMAINS_SHUTOFF) &&
               st == VIR_DOMAIN_SHUTOFF) ||
              (MATCH(VIR_CONNECT_LIST_DOMAINS_OTHER) &&
               (st != VIR_DOMAIN_RUNNING &&
                st != VIR_DOMAIN_PAUSED &&
                st != VIR_DOMAIN_SHUTOFF))))
            goto cleanup;
    }

    /* filter by existence of managed save state */
    if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_MANAGEDSAVE) &&
        !((MATCH(VIR_CONNECT_LIST_DOMAINS_MANAGEDSAVE) &&
           vm->hasManagedSave) ||
          (MATCH(VIR_CONNECT_LIST_DOMAINS_NO_MANAGEDSAVE) &&
           !vm->hasManagedSave)))
            goto cleanup;

    /* filter by autostart option */
    if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_AUTOSTART) &&
        !((MATCH(VIR_CONNECT_LIST_DOMAINS_AUTOSTART) && vm->autostart) ||
          (MATCH(VIR_CONNECT_LIST_DOMAINS_NO_AUTOSTART) && !vm->autostart)))
        goto cleanup;

    /* filter by snapshot existence */
    if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_SNAPSHOT)) {
18364
        int nsnap = virDomainSnapshotObjListNum(vm->snapshots, NULL, 0);
O
Osier Yang 已提交
18365 18366 18367 18368 18369 18370 18371 18372 18373 18374 18375 18376 18377 18378 18379 18380 18381 18382 18383 18384 18385
        if (!((MATCH(VIR_CONNECT_LIST_DOMAINS_HAS_SNAPSHOT) && nsnap > 0) ||
              (MATCH(VIR_CONNECT_LIST_DOMAINS_NO_SNAPSHOT) && nsnap <= 0)))
            goto cleanup;
    }

    /* just count the machines */
    if (!data->domains) {
        data->ndomains++;
        return;
    }

    if (!(dom = virGetDomain(data->conn, vm->def->name, vm->def->uuid))) {
        data->error = true;
        goto cleanup;
    }

    dom->id = vm->def->id;

    data->domains[data->ndomains++] = dom;

cleanup:
18386
    virObjectUnlock(vm);
O
Osier Yang 已提交
18387 18388 18389 18390 18391
    return;
}
#undef MATCH

int
18392 18393 18394
virDomainObjListExport(virDomainObjListPtr doms,
                       virConnectPtr conn,
                       virDomainPtr **domains,
18395
                       virDomainObjListFilter filter,
18396
                       unsigned int flags)
O
Osier Yang 已提交
18397 18398
{
    int ret = -1;
18399
    size_t i;
O
Osier Yang 已提交
18400

18401 18402 18403 18404 18405
    struct virDomainListData data = {
        conn, NULL,
        filter,
        flags, 0, false
    };
O
Osier Yang 已提交
18406

18407
    virObjectLock(doms);
18408 18409 18410
    if (domains &&
        VIR_ALLOC_N(data.domains, virHashSize(doms->objs) + 1) < 0)
        goto cleanup;
O
Osier Yang 已提交
18411

18412
    virHashForEach(doms->objs, virDomainListPopulate, &data);
O
Osier Yang 已提交
18413 18414 18415 18416 18417 18418 18419 18420 18421 18422 18423 18424 18425 18426 18427

    if (data.error)
        goto cleanup;

    if (data.domains) {
        /* trim the array to the final size */
        ignore_value(VIR_REALLOC_N(data.domains, data.ndomains + 1));
        *domains = data.domains;
        data.domains = NULL;
    }

    ret = data.ndomains;

cleanup:
    if (data.domains) {
18428
        int count = virHashSize(doms->objs);
O
Osier Yang 已提交
18429 18430 18431 18432 18433
        for (i = 0; i < count; i++)
            virObjectUnref(data.domains[i]);
    }

    VIR_FREE(data.domains);
18434
    virObjectUnlock(doms);
O
Osier Yang 已提交
18435 18436 18437
    return ret;
}

18438 18439 18440
virSecurityLabelDefPtr
virDomainDefGetSecurityLabelDef(virDomainDefPtr def, const char *model)
{
18441
    size_t i;
18442
    virSecurityLabelDefPtr seclabel = NULL;
18443 18444 18445 18446 18447 18448 18449 18450 18451 18452 18453

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

18454
    return seclabel;
18455 18456 18457 18458 18459
}

virSecurityDeviceLabelDefPtr
virDomainDiskDefGetSecurityLabelDef(virDomainDiskDefPtr def, const char *model)
{
18460
    size_t i;
18461 18462 18463 18464 18465

    if (def == NULL)
        return NULL;

    for (i = 0; i < def->nseclabels; i++) {
18466
        if (STREQ_NULLABLE(def->seclabels[i]->model, model))
18467 18468 18469 18470 18471
            return def->seclabels[i];
    }
    return NULL;
}

18472 18473 18474
virSecurityDeviceLabelDefPtr
virDomainChrDefGetSecurityLabelDef(virDomainChrDefPtr def, const char *model)
{
18475
    size_t i;
18476 18477 18478 18479 18480 18481 18482 18483 18484 18485 18486

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

18487
virSecurityLabelDefPtr
18488
virDomainDefGenSecurityLabelDef(const char *model)
18489 18490 18491
{
    virSecurityLabelDefPtr seclabel = NULL;

18492
    if (VIR_ALLOC(seclabel) < 0 ||
18493
        VIR_STRDUP(seclabel->model, model) < 0) {
18494 18495
        virSecurityLabelDefFree(seclabel);
        seclabel = NULL;
18496 18497
    }

18498 18499 18500 18501
    return seclabel;
}

virSecurityDeviceLabelDefPtr
18502
virDomainDiskDefGenSecurityLabelDef(const char *model)
18503 18504 18505
{
    virSecurityDeviceLabelDefPtr seclabel = NULL;

18506
    if (VIR_ALLOC(seclabel) < 0 ||
18507
        VIR_STRDUP(seclabel->model, model) < 0) {
18508 18509
        virSecurityDeviceLabelDefFree(seclabel);
        seclabel = NULL;
18510
    }
18511

18512 18513
    return seclabel;
}
18514 18515 18516 18517 18518 18519 18520 18521 18522 18523 18524 18525 18526 18527 18528 18529 18530 18531 18532 18533 18534 18535 18536 18537 18538


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,
18539 18540
                       virDomainDeviceDefPtr dev,
                       bool reportError)
18541 18542 18543 18544 18545 18546 18547 18548
{
    virDomainDefFindDeviceCallbackData data = { devAlias, dev };

    dev->type = VIR_DOMAIN_DEVICE_NONE;
    virDomainDeviceInfoIterateInternal(def, virDomainDefFindDeviceCallback,
                                       true, &data);

    if (dev->type == VIR_DOMAIN_DEVICE_NONE) {
18549 18550 18551 18552 18553 18554
        if (reportError) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("no device found with alias %s"), devAlias);
        } else {
            VIR_DEBUG("no device found with alias %s", devAlias);
        }
18555 18556 18557 18558 18559
        return -1;
    }

    return 0;
}
18560 18561 18562 18563 18564 18565 18566 18567 18568 18569 18570 18571 18572 18573 18574 18575 18576 18577 18578 18579 18580 18581 18582 18583 18584 18585 18586

/**
 * 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
virDomainDiskSourceIsBlockType(virDomainDiskDefPtr def)
{
    /* No reason to think the disk source is block type if
     * the source is empty
     */
    if (!def->src)
        return false;

    if (def->type == VIR_DOMAIN_DISK_TYPE_BLOCK)
        return true;

    /* For volume types, check the srcpool.
     * If it's a block type source pool, then it's possible
     */
    if (def->type == VIR_DOMAIN_DISK_TYPE_VOLUME && def->srcpool &&
        def->srcpool->voltype == VIR_STORAGE_VOL_BLOCK) {
18587 18588 18589 18590 18591 18592 18593 18594
        /* 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.
         */
         if (def->srcpool->pooltype == VIR_STORAGE_POOL_ISCSI &&
             def->srcpool->mode == VIR_DOMAIN_DISK_SOURCE_POOL_MODE_DIRECT)
             return false;

18595 18596 18597 18598
        return true;
    }
    return false;
}
18599 18600 18601 18602 18603 18604 18605 18606 18607 18608 18609 18610 18611 18612 18613 18614 18615 18616 18617 18618 18619 18620 18621 18622 18623


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

    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:
18624 18625
        if (VIR_STRDUP(ret, def->description) < 0)
            goto cleanup;
18626 18627 18628
        break;

    case VIR_DOMAIN_METADATA_TITLE:
18629 18630
        if (VIR_STRDUP(ret, def->title) < 0)
            goto cleanup;
18631 18632 18633
        break;

    case VIR_DOMAIN_METADATA_ELEMENT:
18634 18635 18636 18637 18638
        if (!def->metadata)
            break;

        if (virXMLExtractNamespaceXML(def->metadata, uri, &ret) < 0)
            goto cleanup;
18639 18640 18641 18642 18643 18644 18645 18646 18647
        break;

    default:
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("unknown metadata type"));
        goto cleanup;
        break;
    }

18648
    if (!ret)
18649 18650 18651 18652 18653 18654
        virReportError(VIR_ERR_NO_DOMAIN_METADATA, "%s",
                       _("Requested metadata element is not present"));

cleanup:
    return ret;
}
18655

18656 18657 18658 18659 18660

static int
virDomainDefSetMetadata(virDomainDefPtr def,
                        int type,
                        const char *metadata,
18661 18662
                        const char *key,
                        const char *uri)
18663
{
18664 18665
    xmlDocPtr doc = NULL;
    xmlNodePtr old;
18666
    xmlNodePtr new = NULL;
18667
    char *tmp;
18668 18669 18670 18671
    int ret = -1;

    switch ((virDomainMetadataType) type) {
    case VIR_DOMAIN_METADATA_DESCRIPTION:
18672
        if (VIR_STRDUP(tmp, metadata) < 0)
18673
            goto cleanup;
18674 18675 18676

        VIR_FREE(def->description);
        def->description = tmp;
18677 18678 18679
        break;

    case VIR_DOMAIN_METADATA_TITLE:
18680
        if (VIR_STRDUP(tmp, metadata) < 0)
18681
            goto cleanup;
18682 18683 18684

        VIR_FREE(def->title);
        def->title = tmp;
18685 18686 18687
        break;

    case VIR_DOMAIN_METADATA_ELEMENT:
18688 18689 18690 18691 18692 18693 18694 18695 18696 18697 18698 18699 18700 18701 18702 18703 18704 18705 18706 18707 18708 18709 18710 18711 18712 18713 18714
        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);
        }

18715 18716
        if (new &&
            !(xmlAddChild(def->metadata, new))) {
18717 18718 18719 18720
            xmlFreeNode(new);
            virReportOOMError();
            goto cleanup;
        }
18721 18722 18723 18724 18725 18726 18727 18728 18729 18730 18731 18732
        break;

    default:
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("unknown metadata type"));
        goto cleanup;
        break;
    }

    ret = 0;

cleanup:
18733
    xmlFreeDoc(doc);
18734 18735 18736 18737
    return ret;
}


18738 18739 18740 18741
int
virDomainObjSetMetadata(virDomainObjPtr vm,
                        int type,
                        const char *metadata,
18742 18743
                        const char *key,
                        const char *uri,
18744 18745 18746 18747 18748 18749 18750 18751 18752 18753 18754 18755
                        virCapsPtr caps,
                        virDomainXMLOptionPtr xmlopt,
                        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)
18756
        return -1;
18757

18758 18759 18760
    if (flags & VIR_DOMAIN_AFFECT_LIVE)
        if (virDomainDefSetMetadata(vm->def, type, metadata, key, uri) < 0)
            return -1;
18761 18762

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
18763 18764
        if (virDomainDefSetMetadata(persistentDef, type, metadata, key, uri) < 0)
            return -1;
18765 18766

        if (virDomainSaveConfig(configDir, persistentDef) < 0)
18767
            return -1;
18768 18769
    }

18770
    return 0;
18771
}