2008-07-11 16:23:36 +00:00
|
|
|
/*
|
|
|
|
* domain_conf.c: domain XML processing
|
|
|
|
*
|
2010-01-20 19:27:43 +01:00
|
|
|
* Copyright (C) 2006-2010 Red Hat, Inc.
|
2008-07-11 16:23:36 +00:00
|
|
|
* Copyright (C) 2006-2008 Daniel P. Berrange
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
*
|
|
|
|
* Author: Daniel P. Berrange <berrange@redhat.com>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
2008-08-12 08:25:48 +00:00
|
|
|
#include <sys/stat.h>
|
2008-07-11 16:23:36 +00:00
|
|
|
#include <unistd.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <dirent.h>
|
2010-04-02 10:41:30 -04:00
|
|
|
#include <sys/time.h>
|
2008-07-11 16:23:36 +00:00
|
|
|
|
2008-11-04 22:30:33 +00:00
|
|
|
#include "virterror_internal.h"
|
2008-11-04 23:22:06 +00:00
|
|
|
#include "datatypes.h"
|
2008-07-11 16:23:36 +00:00
|
|
|
#include "domain_conf.h"
|
|
|
|
#include "memory.h"
|
|
|
|
#include "verify.h"
|
|
|
|
#include "xml.h"
|
|
|
|
#include "uuid.h"
|
|
|
|
#include "util.h"
|
|
|
|
#include "buf.h"
|
|
|
|
#include "c-ctype.h"
|
2009-06-12 11:38:50 +00:00
|
|
|
#include "logging.h"
|
2009-11-05 15:31:03 +01:00
|
|
|
#include "network.h"
|
2010-02-12 18:07:06 +01:00
|
|
|
#include "macvtap.h"
|
2010-03-25 13:46:07 -04:00
|
|
|
#include "nwfilter_conf.h"
|
2010-04-02 10:41:30 -04:00
|
|
|
#include "ignore-value.h"
|
2008-07-11 16:23:36 +00:00
|
|
|
|
2009-01-20 17:13:33 +00:00
|
|
|
#define VIR_FROM_THIS VIR_FROM_DOMAIN
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
VIR_ENUM_IMPL(virDomainVirt, VIR_DOMAIN_VIRT_LAST,
|
|
|
|
"qemu",
|
|
|
|
"kqemu",
|
|
|
|
"kvm",
|
|
|
|
"xen",
|
|
|
|
"lxc",
|
|
|
|
"uml",
|
|
|
|
"openvz",
|
|
|
|
"vserver",
|
|
|
|
"ldom",
|
|
|
|
"test",
|
|
|
|
"vmware",
|
2009-04-17 16:09:07 +00:00
|
|
|
"hyperv",
|
2009-05-25 11:56:00 +00:00
|
|
|
"vbox",
|
2009-07-24 16:17:06 +02:00
|
|
|
"one",
|
|
|
|
"phyp")
|
2008-07-11 16:23:36 +00:00
|
|
|
|
|
|
|
VIR_ENUM_IMPL(virDomainBoot, VIR_DOMAIN_BOOT_LAST,
|
|
|
|
"fd",
|
|
|
|
"cdrom",
|
|
|
|
"hd",
|
|
|
|
"network")
|
|
|
|
|
|
|
|
VIR_ENUM_IMPL(virDomainFeature, VIR_DOMAIN_FEATURE_LAST,
|
|
|
|
"acpi",
|
|
|
|
"apic",
|
|
|
|
"pae")
|
|
|
|
|
|
|
|
VIR_ENUM_IMPL(virDomainLifecycle, VIR_DOMAIN_LIFECYCLE_LAST,
|
|
|
|
"destroy",
|
|
|
|
"restart",
|
|
|
|
"rename-restart",
|
|
|
|
"preserve")
|
|
|
|
|
2009-03-02 17:39:43 +00:00
|
|
|
VIR_ENUM_IMPL(virDomainDevice, VIR_DOMAIN_DEVICE_LAST,
|
|
|
|
"disk",
|
|
|
|
"filesystem",
|
|
|
|
"interface",
|
|
|
|
"input",
|
|
|
|
"sound",
|
2009-07-06 14:54:44 +01:00
|
|
|
"video",
|
2009-10-21 13:26:38 +01:00
|
|
|
"hostdev",
|
2009-12-02 19:15:38 +00:00
|
|
|
"watchdog",
|
2010-03-22 13:22:48 +00:00
|
|
|
"controller",
|
|
|
|
"graphics")
|
2009-03-02 17:39:43 +00:00
|
|
|
|
2009-11-30 18:35:58 +00:00
|
|
|
VIR_ENUM_IMPL(virDomainDeviceAddress, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST,
|
|
|
|
"none",
|
2009-12-01 16:56:24 +00:00
|
|
|
"pci",
|
2010-02-18 17:52:03 +01:00
|
|
|
"drive",
|
|
|
|
"virtio-serial");
|
2009-11-30 18:35:58 +00:00
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
VIR_ENUM_IMPL(virDomainDisk, VIR_DOMAIN_DISK_TYPE_LAST,
|
|
|
|
"block",
|
2009-11-16 18:08:29 +00:00
|
|
|
"file",
|
|
|
|
"dir")
|
2008-07-11 16:23:36 +00:00
|
|
|
|
|
|
|
VIR_ENUM_IMPL(virDomainDiskDevice, VIR_DOMAIN_DISK_DEVICE_LAST,
|
|
|
|
"disk",
|
|
|
|
"cdrom",
|
|
|
|
"floppy")
|
|
|
|
|
|
|
|
VIR_ENUM_IMPL(virDomainDiskBus, VIR_DOMAIN_DISK_BUS_LAST,
|
|
|
|
"ide",
|
|
|
|
"fdc",
|
|
|
|
"scsi",
|
|
|
|
"virtio",
|
2008-08-08 15:03:00 +00:00
|
|
|
"xen",
|
2008-11-19 16:58:23 +00:00
|
|
|
"usb",
|
2009-11-12 15:45:18 +01:00
|
|
|
"uml",
|
|
|
|
"sata")
|
2008-07-11 16:23:36 +00:00
|
|
|
|
2009-01-30 17:15:39 +00:00
|
|
|
VIR_ENUM_IMPL(virDomainDiskCache, VIR_DOMAIN_DISK_CACHE_LAST,
|
|
|
|
"default",
|
|
|
|
"none",
|
|
|
|
"writethrough",
|
2009-01-30 21:52:22 +00:00
|
|
|
"writeback")
|
2009-01-30 17:15:39 +00:00
|
|
|
|
2010-03-24 11:32:10 -04:00
|
|
|
VIR_ENUM_IMPL(virDomainDiskErrorPolicy, VIR_DOMAIN_DISK_ERROR_POLICY_LAST,
|
|
|
|
"default",
|
|
|
|
"stop",
|
2010-04-08 16:05:50 -04:00
|
|
|
"ignore",
|
|
|
|
"enospace")
|
2010-03-24 11:32:10 -04:00
|
|
|
|
2009-12-02 19:15:38 +00:00
|
|
|
VIR_ENUM_IMPL(virDomainController, VIR_DOMAIN_CONTROLLER_TYPE_LAST,
|
|
|
|
"ide",
|
|
|
|
"fdc",
|
|
|
|
"scsi",
|
2010-02-18 17:52:03 +01:00
|
|
|
"sata",
|
|
|
|
"virtio-serial")
|
2009-12-02 19:15:38 +00:00
|
|
|
|
2008-08-01 13:31:37 +00:00
|
|
|
VIR_ENUM_IMPL(virDomainFS, VIR_DOMAIN_FS_TYPE_LAST,
|
|
|
|
"mount",
|
|
|
|
"block",
|
|
|
|
"file",
|
|
|
|
"template")
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
VIR_ENUM_IMPL(virDomainNet, VIR_DOMAIN_NET_TYPE_LAST,
|
|
|
|
"user",
|
|
|
|
"ethernet",
|
|
|
|
"server",
|
|
|
|
"client",
|
|
|
|
"mcast",
|
|
|
|
"network",
|
2009-05-11 09:50:27 +00:00
|
|
|
"bridge",
|
2010-02-12 18:07:06 +01:00
|
|
|
"internal",
|
|
|
|
"direct")
|
2008-07-11 16:23:36 +00:00
|
|
|
|
2009-11-05 14:19:14 +01:00
|
|
|
VIR_ENUM_IMPL(virDomainChrTarget, VIR_DOMAIN_CHR_TARGET_TYPE_LAST,
|
|
|
|
"null",
|
|
|
|
"monitor",
|
|
|
|
"parallel",
|
|
|
|
"serial",
|
2009-11-05 15:31:03 +01:00
|
|
|
"console",
|
2010-02-18 17:52:03 +01:00
|
|
|
"guestfwd",
|
|
|
|
"virtio")
|
2009-11-05 14:19:14 +01:00
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
VIR_ENUM_IMPL(virDomainChr, VIR_DOMAIN_CHR_TYPE_LAST,
|
|
|
|
"null",
|
|
|
|
"vc",
|
|
|
|
"pty",
|
|
|
|
"dev",
|
|
|
|
"file",
|
|
|
|
"pipe",
|
|
|
|
"stdio",
|
|
|
|
"udp",
|
|
|
|
"tcp",
|
|
|
|
"unix")
|
|
|
|
|
|
|
|
VIR_ENUM_IMPL(virDomainSoundModel, VIR_DOMAIN_SOUND_MODEL_LAST,
|
|
|
|
"sb16",
|
|
|
|
"es1370",
|
2009-01-20 22:15:55 +00:00
|
|
|
"pcspk",
|
|
|
|
"ac97")
|
2008-07-11 16:23:36 +00:00
|
|
|
|
2009-10-21 13:26:38 +01:00
|
|
|
VIR_ENUM_IMPL(virDomainWatchdogModel, VIR_DOMAIN_WATCHDOG_MODEL_LAST,
|
|
|
|
"i6300esb",
|
|
|
|
"ib700")
|
|
|
|
|
|
|
|
VIR_ENUM_IMPL(virDomainWatchdogAction, VIR_DOMAIN_WATCHDOG_ACTION_LAST,
|
|
|
|
"reset",
|
|
|
|
"shutdown",
|
|
|
|
"poweroff",
|
|
|
|
"pause",
|
|
|
|
"none")
|
|
|
|
|
2009-07-06 14:54:44 +01:00
|
|
|
VIR_ENUM_IMPL(virDomainVideo, VIR_DOMAIN_VIDEO_TYPE_LAST,
|
|
|
|
"vga",
|
|
|
|
"cirrus",
|
|
|
|
"vmvga",
|
|
|
|
"xen",
|
|
|
|
"vbox")
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
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",
|
2009-05-15 09:43:51 +00:00
|
|
|
"vnc",
|
|
|
|
"rdp",
|
|
|
|
"desktop")
|
2008-07-11 16:23:36 +00:00
|
|
|
|
2008-08-08 14:27:05 +00:00
|
|
|
VIR_ENUM_IMPL(virDomainHostdevMode, VIR_DOMAIN_HOSTDEV_MODE_LAST,
|
|
|
|
"subsystem",
|
|
|
|
"capabilities")
|
|
|
|
|
|
|
|
VIR_ENUM_IMPL(virDomainHostdevSubsys, VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST,
|
|
|
|
"usb",
|
|
|
|
"pci")
|
2008-07-11 16:23:36 +00:00
|
|
|
|
2009-01-19 21:06:26 +00:00
|
|
|
VIR_ENUM_IMPL(virDomainState, VIR_DOMAIN_CRASHED+1,
|
|
|
|
"nostate",
|
|
|
|
"running",
|
|
|
|
"blocked",
|
|
|
|
"paused",
|
|
|
|
"shutdown",
|
|
|
|
"shutoff",
|
|
|
|
"crashed")
|
|
|
|
|
2009-03-03 16:53:13 +00:00
|
|
|
VIR_ENUM_IMPL(virDomainSeclabel, VIR_DOMAIN_SECLABEL_LAST,
|
|
|
|
"dynamic",
|
|
|
|
"static")
|
|
|
|
|
2010-02-12 18:07:06 +01:00
|
|
|
VIR_ENUM_IMPL(virDomainNetdevMacvtap, VIR_DOMAIN_NETDEV_MACVTAP_MODE_LAST,
|
|
|
|
"vepa",
|
|
|
|
"private",
|
|
|
|
"bridge")
|
|
|
|
|
2010-02-02 17:22:03 +00:00
|
|
|
VIR_ENUM_IMPL(virDomainClockOffset, VIR_DOMAIN_CLOCK_OFFSET_LAST,
|
|
|
|
"utc",
|
2010-02-02 17:49:09 +00:00
|
|
|
"localtime",
|
2010-02-02 18:28:44 +00:00
|
|
|
"variable",
|
|
|
|
"timezone");
|
2010-02-02 17:22:03 +00:00
|
|
|
|
2010-03-30 13:44:22 +02:00
|
|
|
VIR_ENUM_IMPL(virDomainTimerName, VIR_DOMAIN_TIMER_NAME_LAST,
|
|
|
|
"platform",
|
|
|
|
"pit",
|
|
|
|
"rtc",
|
|
|
|
"hpet",
|
|
|
|
"tsc");
|
|
|
|
|
2010-03-31 13:03:54 -04:00
|
|
|
VIR_ENUM_IMPL(virDomainTimerTrack, VIR_DOMAIN_TIMER_TRACK_LAST,
|
|
|
|
"boot",
|
|
|
|
"guest",
|
|
|
|
"wall");
|
2010-03-30 13:44:22 +02:00
|
|
|
|
|
|
|
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",
|
2010-03-31 13:03:54 -04:00
|
|
|
"paravirt",
|
|
|
|
"smpsafe");
|
2010-03-30 13:44:22 +02:00
|
|
|
|
2010-03-01 16:38:28 -07:00
|
|
|
#define virDomainReportError(code, ...) \
|
2010-02-09 18:58:01 +00:00
|
|
|
virReportErrorHelper(NULL, VIR_FROM_DOMAIN, code, __FILE__, \
|
2010-03-01 16:38:28 -07:00
|
|
|
__FUNCTION__, __LINE__, __VA_ARGS__)
|
2008-07-11 16:23:36 +00:00
|
|
|
|
2008-12-05 10:10:41 +00:00
|
|
|
#ifndef PROXY
|
|
|
|
|
Convert virDomainObjListPtr to use a hash of domain objects
The current virDomainObjListPtr object stores domain objects in
an array. This means that to find a particular objects requires
O(n) time, and more critically acquiring O(n) mutex locks.
The new impl replaces the array with a virHashTable, keyed off
UUID. Finding a object based on UUID is now O(1) time, and only
requires a single mutex lock. Finding by name/id is unchanged
in complexity.
In changing this, all code which iterates over the array had
to be updated to use a hash table iterator function callback.
Several of the functions which were identically duplicating
across all drivers were pulled into domain_conf.c
* src/conf/domain_conf.h, src/conf/domain_conf.c: Change
virDomainObjListPtr to use virHashTable. Add a initializer
method virDomainObjListInit, and rename virDomainObjListFree
to virDomainObjListDeinit, since its not actually freeing
the container, only its contents. Also add some convenient
methods virDomainObjListGetInactiveNames,
virDomainObjListGetActiveIDs and virDomainObjListNumOfDomains
which can be used to implement the correspondingly named
public API entry points in drivers
* src/libvirt_private.syms: Export new methods from domain_conf.h
* src/lxc/lxc_driver.c, src/opennebula/one_driver.c,
src/openvz/openvz_conf.c, src/openvz/openvz_driver.c,
src/qemu/qemu_driver.c, src/test/test_driver.c,
src/uml/uml_driver.c, src/vbox/vbox_tmpl.c: Update all code
to deal with hash tables instead of arrays for domains
2009-10-09 12:33:51 +01:00
|
|
|
int virDomainObjListInit(virDomainObjListPtr doms)
|
2008-07-11 16:23:36 +00:00
|
|
|
{
|
Convert virDomainObjListPtr to use a hash of domain objects
The current virDomainObjListPtr object stores domain objects in
an array. This means that to find a particular objects requires
O(n) time, and more critically acquiring O(n) mutex locks.
The new impl replaces the array with a virHashTable, keyed off
UUID. Finding a object based on UUID is now O(1) time, and only
requires a single mutex lock. Finding by name/id is unchanged
in complexity.
In changing this, all code which iterates over the array had
to be updated to use a hash table iterator function callback.
Several of the functions which were identically duplicating
across all drivers were pulled into domain_conf.c
* src/conf/domain_conf.h, src/conf/domain_conf.c: Change
virDomainObjListPtr to use virHashTable. Add a initializer
method virDomainObjListInit, and rename virDomainObjListFree
to virDomainObjListDeinit, since its not actually freeing
the container, only its contents. Also add some convenient
methods virDomainObjListGetInactiveNames,
virDomainObjListGetActiveIDs and virDomainObjListNumOfDomains
which can be used to implement the correspondingly named
public API entry points in drivers
* src/libvirt_private.syms: Export new methods from domain_conf.h
* src/lxc/lxc_driver.c, src/opennebula/one_driver.c,
src/openvz/openvz_conf.c, src/openvz/openvz_driver.c,
src/qemu/qemu_driver.c, src/test/test_driver.c,
src/uml/uml_driver.c, src/vbox/vbox_tmpl.c: Update all code
to deal with hash tables instead of arrays for domains
2009-10-09 12:33:51 +01:00
|
|
|
doms->objs = virHashCreate(50);
|
|
|
|
if (!doms->objs) {
|
2010-02-04 19:19:08 +01:00
|
|
|
virReportOOMError();
|
Convert virDomainObjListPtr to use a hash of domain objects
The current virDomainObjListPtr object stores domain objects in
an array. This means that to find a particular objects requires
O(n) time, and more critically acquiring O(n) mutex locks.
The new impl replaces the array with a virHashTable, keyed off
UUID. Finding a object based on UUID is now O(1) time, and only
requires a single mutex lock. Finding by name/id is unchanged
in complexity.
In changing this, all code which iterates over the array had
to be updated to use a hash table iterator function callback.
Several of the functions which were identically duplicating
across all drivers were pulled into domain_conf.c
* src/conf/domain_conf.h, src/conf/domain_conf.c: Change
virDomainObjListPtr to use virHashTable. Add a initializer
method virDomainObjListInit, and rename virDomainObjListFree
to virDomainObjListDeinit, since its not actually freeing
the container, only its contents. Also add some convenient
methods virDomainObjListGetInactiveNames,
virDomainObjListGetActiveIDs and virDomainObjListNumOfDomains
which can be used to implement the correspondingly named
public API entry points in drivers
* src/libvirt_private.syms: Export new methods from domain_conf.h
* src/lxc/lxc_driver.c, src/opennebula/one_driver.c,
src/openvz/openvz_conf.c, src/openvz/openvz_driver.c,
src/qemu/qemu_driver.c, src/test/test_driver.c,
src/uml/uml_driver.c, src/vbox/vbox_tmpl.c: Update all code
to deal with hash tables instead of arrays for domains
2009-10-09 12:33:51 +01:00
|
|
|
return -1;
|
2008-12-04 22:00:14 +00:00
|
|
|
}
|
Convert virDomainObjListPtr to use a hash of domain objects
The current virDomainObjListPtr object stores domain objects in
an array. This means that to find a particular objects requires
O(n) time, and more critically acquiring O(n) mutex locks.
The new impl replaces the array with a virHashTable, keyed off
UUID. Finding a object based on UUID is now O(1) time, and only
requires a single mutex lock. Finding by name/id is unchanged
in complexity.
In changing this, all code which iterates over the array had
to be updated to use a hash table iterator function callback.
Several of the functions which were identically duplicating
across all drivers were pulled into domain_conf.c
* src/conf/domain_conf.h, src/conf/domain_conf.c: Change
virDomainObjListPtr to use virHashTable. Add a initializer
method virDomainObjListInit, and rename virDomainObjListFree
to virDomainObjListDeinit, since its not actually freeing
the container, only its contents. Also add some convenient
methods virDomainObjListGetInactiveNames,
virDomainObjListGetActiveIDs and virDomainObjListNumOfDomains
which can be used to implement the correspondingly named
public API entry points in drivers
* src/libvirt_private.syms: Export new methods from domain_conf.h
* src/lxc/lxc_driver.c, src/opennebula/one_driver.c,
src/openvz/openvz_conf.c, src/openvz/openvz_driver.c,
src/qemu/qemu_driver.c, src/test/test_driver.c,
src/uml/uml_driver.c, src/vbox/vbox_tmpl.c: Update all code
to deal with hash tables instead of arrays for domains
2009-10-09 12:33:51 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2008-07-11 16:23:36 +00:00
|
|
|
|
Convert virDomainObjListPtr to use a hash of domain objects
The current virDomainObjListPtr object stores domain objects in
an array. This means that to find a particular objects requires
O(n) time, and more critically acquiring O(n) mutex locks.
The new impl replaces the array with a virHashTable, keyed off
UUID. Finding a object based on UUID is now O(1) time, and only
requires a single mutex lock. Finding by name/id is unchanged
in complexity.
In changing this, all code which iterates over the array had
to be updated to use a hash table iterator function callback.
Several of the functions which were identically duplicating
across all drivers were pulled into domain_conf.c
* src/conf/domain_conf.h, src/conf/domain_conf.c: Change
virDomainObjListPtr to use virHashTable. Add a initializer
method virDomainObjListInit, and rename virDomainObjListFree
to virDomainObjListDeinit, since its not actually freeing
the container, only its contents. Also add some convenient
methods virDomainObjListGetInactiveNames,
virDomainObjListGetActiveIDs and virDomainObjListNumOfDomains
which can be used to implement the correspondingly named
public API entry points in drivers
* src/libvirt_private.syms: Export new methods from domain_conf.h
* src/lxc/lxc_driver.c, src/opennebula/one_driver.c,
src/openvz/openvz_conf.c, src/openvz/openvz_driver.c,
src/qemu/qemu_driver.c, src/test/test_driver.c,
src/uml/uml_driver.c, src/vbox/vbox_tmpl.c: Update all code
to deal with hash tables instead of arrays for domains
2009-10-09 12:33:51 +01:00
|
|
|
|
|
|
|
static void virDomainObjListDeallocator(void *payload, const char *name ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
virDomainObjPtr obj = payload;
|
2009-10-15 12:30:26 +01:00
|
|
|
virDomainObjLock(obj);
|
2009-12-08 14:42:43 +00:00
|
|
|
if (virDomainObjUnref(obj) > 0)
|
2009-10-15 12:30:26 +01:00
|
|
|
virDomainObjUnlock(obj);
|
Convert virDomainObjListPtr to use a hash of domain objects
The current virDomainObjListPtr object stores domain objects in
an array. This means that to find a particular objects requires
O(n) time, and more critically acquiring O(n) mutex locks.
The new impl replaces the array with a virHashTable, keyed off
UUID. Finding a object based on UUID is now O(1) time, and only
requires a single mutex lock. Finding by name/id is unchanged
in complexity.
In changing this, all code which iterates over the array had
to be updated to use a hash table iterator function callback.
Several of the functions which were identically duplicating
across all drivers were pulled into domain_conf.c
* src/conf/domain_conf.h, src/conf/domain_conf.c: Change
virDomainObjListPtr to use virHashTable. Add a initializer
method virDomainObjListInit, and rename virDomainObjListFree
to virDomainObjListDeinit, since its not actually freeing
the container, only its contents. Also add some convenient
methods virDomainObjListGetInactiveNames,
virDomainObjListGetActiveIDs and virDomainObjListNumOfDomains
which can be used to implement the correspondingly named
public API entry points in drivers
* src/libvirt_private.syms: Export new methods from domain_conf.h
* src/lxc/lxc_driver.c, src/opennebula/one_driver.c,
src/openvz/openvz_conf.c, src/openvz/openvz_driver.c,
src/qemu/qemu_driver.c, src/test/test_driver.c,
src/uml/uml_driver.c, src/vbox/vbox_tmpl.c: Update all code
to deal with hash tables instead of arrays for domains
2009-10-09 12:33:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void virDomainObjListDeinit(virDomainObjListPtr doms)
|
|
|
|
{
|
|
|
|
if (doms->objs)
|
|
|
|
virHashFree(doms->objs, virDomainObjListDeallocator);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int virDomainObjListSearchID(const void *payload,
|
|
|
|
const char *name ATTRIBUTE_UNUSED,
|
|
|
|
const void *data)
|
|
|
|
{
|
|
|
|
virDomainObjPtr obj = (virDomainObjPtr)payload;
|
|
|
|
const int *id = data;
|
|
|
|
int want = 0;
|
|
|
|
|
|
|
|
virDomainObjLock(obj);
|
Rename internal APis
Rename virDomainIsActive to virDomainObjIsActive, and
virInterfaceIsActive to virInterfaceObjIsActive and finally
virNetworkIsActive to virNetworkObjIsActive.
* src/conf/domain_conf.c, src/conf/domain_conf.h,
src/conf/interface_conf.h, src/conf/network_conf.c,
src/conf/network_conf.h, src/lxc/lxc_driver.c,
src/network/bridge_driver.c, src/opennebula/one_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_driver.c,
src/test/test_driver.c, src/uml/uml_driver.c: Update for
renamed APIs.
2009-10-20 15:51:03 +01:00
|
|
|
if (virDomainObjIsActive(obj) &&
|
Convert virDomainObjListPtr to use a hash of domain objects
The current virDomainObjListPtr object stores domain objects in
an array. This means that to find a particular objects requires
O(n) time, and more critically acquiring O(n) mutex locks.
The new impl replaces the array with a virHashTable, keyed off
UUID. Finding a object based on UUID is now O(1) time, and only
requires a single mutex lock. Finding by name/id is unchanged
in complexity.
In changing this, all code which iterates over the array had
to be updated to use a hash table iterator function callback.
Several of the functions which were identically duplicating
across all drivers were pulled into domain_conf.c
* src/conf/domain_conf.h, src/conf/domain_conf.c: Change
virDomainObjListPtr to use virHashTable. Add a initializer
method virDomainObjListInit, and rename virDomainObjListFree
to virDomainObjListDeinit, since its not actually freeing
the container, only its contents. Also add some convenient
methods virDomainObjListGetInactiveNames,
virDomainObjListGetActiveIDs and virDomainObjListNumOfDomains
which can be used to implement the correspondingly named
public API entry points in drivers
* src/libvirt_private.syms: Export new methods from domain_conf.h
* src/lxc/lxc_driver.c, src/opennebula/one_driver.c,
src/openvz/openvz_conf.c, src/openvz/openvz_driver.c,
src/qemu/qemu_driver.c, src/test/test_driver.c,
src/uml/uml_driver.c, src/vbox/vbox_tmpl.c: Update all code
to deal with hash tables instead of arrays for domains
2009-10-09 12:33:51 +01:00
|
|
|
obj->def->id == *id)
|
|
|
|
want = 1;
|
|
|
|
virDomainObjUnlock(obj);
|
|
|
|
return want;
|
|
|
|
}
|
|
|
|
|
|
|
|
virDomainObjPtr virDomainFindByID(const virDomainObjListPtr doms,
|
|
|
|
int id)
|
|
|
|
{
|
|
|
|
virDomainObjPtr obj;
|
|
|
|
obj = virHashSearch(doms->objs, virDomainObjListSearchID, &id);
|
|
|
|
if (obj)
|
|
|
|
virDomainObjLock(obj);
|
|
|
|
return obj;
|
2008-07-11 16:23:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-10-10 14:20:37 +00:00
|
|
|
virDomainObjPtr virDomainFindByUUID(const virDomainObjListPtr doms,
|
2008-07-11 16:23:36 +00:00
|
|
|
const unsigned char *uuid)
|
|
|
|
{
|
Convert virDomainObjListPtr to use a hash of domain objects
The current virDomainObjListPtr object stores domain objects in
an array. This means that to find a particular objects requires
O(n) time, and more critically acquiring O(n) mutex locks.
The new impl replaces the array with a virHashTable, keyed off
UUID. Finding a object based on UUID is now O(1) time, and only
requires a single mutex lock. Finding by name/id is unchanged
in complexity.
In changing this, all code which iterates over the array had
to be updated to use a hash table iterator function callback.
Several of the functions which were identically duplicating
across all drivers were pulled into domain_conf.c
* src/conf/domain_conf.h, src/conf/domain_conf.c: Change
virDomainObjListPtr to use virHashTable. Add a initializer
method virDomainObjListInit, and rename virDomainObjListFree
to virDomainObjListDeinit, since its not actually freeing
the container, only its contents. Also add some convenient
methods virDomainObjListGetInactiveNames,
virDomainObjListGetActiveIDs and virDomainObjListNumOfDomains
which can be used to implement the correspondingly named
public API entry points in drivers
* src/libvirt_private.syms: Export new methods from domain_conf.h
* src/lxc/lxc_driver.c, src/opennebula/one_driver.c,
src/openvz/openvz_conf.c, src/openvz/openvz_driver.c,
src/qemu/qemu_driver.c, src/test/test_driver.c,
src/uml/uml_driver.c, src/vbox/vbox_tmpl.c: Update all code
to deal with hash tables instead of arrays for domains
2009-10-09 12:33:51 +01:00
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
|
|
|
virDomainObjPtr obj;
|
2008-07-11 16:23:36 +00:00
|
|
|
|
Convert virDomainObjListPtr to use a hash of domain objects
The current virDomainObjListPtr object stores domain objects in
an array. This means that to find a particular objects requires
O(n) time, and more critically acquiring O(n) mutex locks.
The new impl replaces the array with a virHashTable, keyed off
UUID. Finding a object based on UUID is now O(1) time, and only
requires a single mutex lock. Finding by name/id is unchanged
in complexity.
In changing this, all code which iterates over the array had
to be updated to use a hash table iterator function callback.
Several of the functions which were identically duplicating
across all drivers were pulled into domain_conf.c
* src/conf/domain_conf.h, src/conf/domain_conf.c: Change
virDomainObjListPtr to use virHashTable. Add a initializer
method virDomainObjListInit, and rename virDomainObjListFree
to virDomainObjListDeinit, since its not actually freeing
the container, only its contents. Also add some convenient
methods virDomainObjListGetInactiveNames,
virDomainObjListGetActiveIDs and virDomainObjListNumOfDomains
which can be used to implement the correspondingly named
public API entry points in drivers
* src/libvirt_private.syms: Export new methods from domain_conf.h
* src/lxc/lxc_driver.c, src/opennebula/one_driver.c,
src/openvz/openvz_conf.c, src/openvz/openvz_driver.c,
src/qemu/qemu_driver.c, src/test/test_driver.c,
src/uml/uml_driver.c, src/vbox/vbox_tmpl.c: Update all code
to deal with hash tables instead of arrays for domains
2009-10-09 12:33:51 +01:00
|
|
|
virUUIDFormat(uuid, uuidstr);
|
2008-07-11 16:23:36 +00:00
|
|
|
|
Convert virDomainObjListPtr to use a hash of domain objects
The current virDomainObjListPtr object stores domain objects in
an array. This means that to find a particular objects requires
O(n) time, and more critically acquiring O(n) mutex locks.
The new impl replaces the array with a virHashTable, keyed off
UUID. Finding a object based on UUID is now O(1) time, and only
requires a single mutex lock. Finding by name/id is unchanged
in complexity.
In changing this, all code which iterates over the array had
to be updated to use a hash table iterator function callback.
Several of the functions which were identically duplicating
across all drivers were pulled into domain_conf.c
* src/conf/domain_conf.h, src/conf/domain_conf.c: Change
virDomainObjListPtr to use virHashTable. Add a initializer
method virDomainObjListInit, and rename virDomainObjListFree
to virDomainObjListDeinit, since its not actually freeing
the container, only its contents. Also add some convenient
methods virDomainObjListGetInactiveNames,
virDomainObjListGetActiveIDs and virDomainObjListNumOfDomains
which can be used to implement the correspondingly named
public API entry points in drivers
* src/libvirt_private.syms: Export new methods from domain_conf.h
* src/lxc/lxc_driver.c, src/opennebula/one_driver.c,
src/openvz/openvz_conf.c, src/openvz/openvz_driver.c,
src/qemu/qemu_driver.c, src/test/test_driver.c,
src/uml/uml_driver.c, src/vbox/vbox_tmpl.c: Update all code
to deal with hash tables instead of arrays for domains
2009-10-09 12:33:51 +01:00
|
|
|
obj = virHashLookup(doms->objs, uuidstr);
|
|
|
|
if (obj)
|
|
|
|
virDomainObjLock(obj);
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int virDomainObjListSearchName(const void *payload,
|
|
|
|
const char *name ATTRIBUTE_UNUSED,
|
|
|
|
const void *data)
|
|
|
|
{
|
|
|
|
virDomainObjPtr obj = (virDomainObjPtr)payload;
|
|
|
|
int want = 0;
|
|
|
|
|
|
|
|
virDomainObjLock(obj);
|
|
|
|
if (STREQ(obj->def->name, (const char *)data))
|
|
|
|
want = 1;
|
|
|
|
virDomainObjUnlock(obj);
|
|
|
|
return want;
|
2008-07-11 16:23:36 +00:00
|
|
|
}
|
|
|
|
|
2008-10-10 14:20:37 +00:00
|
|
|
virDomainObjPtr virDomainFindByName(const virDomainObjListPtr doms,
|
2008-07-11 16:23:36 +00:00
|
|
|
const char *name)
|
|
|
|
{
|
Convert virDomainObjListPtr to use a hash of domain objects
The current virDomainObjListPtr object stores domain objects in
an array. This means that to find a particular objects requires
O(n) time, and more critically acquiring O(n) mutex locks.
The new impl replaces the array with a virHashTable, keyed off
UUID. Finding a object based on UUID is now O(1) time, and only
requires a single mutex lock. Finding by name/id is unchanged
in complexity.
In changing this, all code which iterates over the array had
to be updated to use a hash table iterator function callback.
Several of the functions which were identically duplicating
across all drivers were pulled into domain_conf.c
* src/conf/domain_conf.h, src/conf/domain_conf.c: Change
virDomainObjListPtr to use virHashTable. Add a initializer
method virDomainObjListInit, and rename virDomainObjListFree
to virDomainObjListDeinit, since its not actually freeing
the container, only its contents. Also add some convenient
methods virDomainObjListGetInactiveNames,
virDomainObjListGetActiveIDs and virDomainObjListNumOfDomains
which can be used to implement the correspondingly named
public API entry points in drivers
* src/libvirt_private.syms: Export new methods from domain_conf.h
* src/lxc/lxc_driver.c, src/opennebula/one_driver.c,
src/openvz/openvz_conf.c, src/openvz/openvz_driver.c,
src/qemu/qemu_driver.c, src/test/test_driver.c,
src/uml/uml_driver.c, src/vbox/vbox_tmpl.c: Update all code
to deal with hash tables instead of arrays for domains
2009-10-09 12:33:51 +01:00
|
|
|
virDomainObjPtr obj;
|
|
|
|
obj = virHashSearch(doms->objs, virDomainObjListSearchName, name);
|
|
|
|
if (obj)
|
|
|
|
virDomainObjLock(obj);
|
|
|
|
return obj;
|
2008-07-11 16:23:36 +00:00
|
|
|
}
|
|
|
|
|
2008-12-05 10:10:41 +00:00
|
|
|
#endif /* !PROXY */
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
void virDomainGraphicsDefFree(virDomainGraphicsDefPtr def)
|
|
|
|
{
|
|
|
|
if (!def)
|
|
|
|
return;
|
|
|
|
|
|
|
|
switch (def->type) {
|
|
|
|
case VIR_DOMAIN_GRAPHICS_TYPE_VNC:
|
|
|
|
VIR_FREE(def->data.vnc.listenAddr);
|
|
|
|
VIR_FREE(def->data.vnc.keymap);
|
|
|
|
VIR_FREE(def->data.vnc.passwd);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_GRAPHICS_TYPE_SDL:
|
|
|
|
VIR_FREE(def->data.sdl.display);
|
|
|
|
VIR_FREE(def->data.sdl.xauth);
|
|
|
|
break;
|
2009-05-15 09:43:51 +00:00
|
|
|
|
|
|
|
case VIR_DOMAIN_GRAPHICS_TYPE_RDP:
|
|
|
|
VIR_FREE(def->data.rdp.listenAddr);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP:
|
|
|
|
VIR_FREE(def->data.desktop.display);
|
|
|
|
break;
|
2008-07-11 16:23:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
VIR_FREE(def);
|
|
|
|
}
|
|
|
|
|
|
|
|
void virDomainInputDefFree(virDomainInputDefPtr def)
|
|
|
|
{
|
|
|
|
if (!def)
|
|
|
|
return;
|
|
|
|
|
Add device info to serial, parallel, channel, input & fs devices
Although the serial, parallel, chanel, input & fs devices do
not have PCI address info, they can all have device aliases.
Thus it neccessary to associate the virDomainDeviceInfo data
with them all.
* src/conf/domain_conf.c, src/conf/domain_conf.h: Add hooks for
parsing / formatting device info for serial, parallel, channel
input and fs devices.
* docs/schemas/domain.rng: Associate device info with character
devices, input & fs device
2010-01-06 12:39:53 +00:00
|
|
|
virDomainDeviceInfoClear(&def->info);
|
2008-07-11 16:23:36 +00:00
|
|
|
VIR_FREE(def);
|
|
|
|
}
|
|
|
|
|
|
|
|
void virDomainDiskDefFree(virDomainDiskDefPtr def)
|
|
|
|
{
|
|
|
|
if (!def)
|
|
|
|
return;
|
|
|
|
|
2009-08-14 12:22:01 +01:00
|
|
|
VIR_FREE(def->serial);
|
2008-07-11 16:23:36 +00:00
|
|
|
VIR_FREE(def->src);
|
|
|
|
VIR_FREE(def->dst);
|
|
|
|
VIR_FREE(def->driverName);
|
|
|
|
VIR_FREE(def->driverType);
|
2009-07-21 07:23:03 +02:00
|
|
|
virStorageEncryptionFree(def->encryption);
|
2009-11-30 18:35:58 +00:00
|
|
|
virDomainDeviceInfoClear(&def->info);
|
2008-07-11 16:23:36 +00:00
|
|
|
|
|
|
|
VIR_FREE(def);
|
|
|
|
}
|
|
|
|
|
2009-12-02 19:15:38 +00:00
|
|
|
void virDomainControllerDefFree(virDomainControllerDefPtr def)
|
|
|
|
{
|
|
|
|
if (!def)
|
|
|
|
return;
|
|
|
|
|
|
|
|
virDomainDeviceInfoClear(&def->info);
|
|
|
|
|
|
|
|
VIR_FREE(def);
|
|
|
|
}
|
|
|
|
|
2008-08-01 13:31:37 +00:00
|
|
|
void virDomainFSDefFree(virDomainFSDefPtr def)
|
|
|
|
{
|
|
|
|
if (!def)
|
|
|
|
return;
|
|
|
|
|
|
|
|
VIR_FREE(def->src);
|
|
|
|
VIR_FREE(def->dst);
|
Add device info to serial, parallel, channel, input & fs devices
Although the serial, parallel, chanel, input & fs devices do
not have PCI address info, they can all have device aliases.
Thus it neccessary to associate the virDomainDeviceInfo data
with them all.
* src/conf/domain_conf.c, src/conf/domain_conf.h: Add hooks for
parsing / formatting device info for serial, parallel, channel
input and fs devices.
* docs/schemas/domain.rng: Associate device info with character
devices, input & fs device
2010-01-06 12:39:53 +00:00
|
|
|
virDomainDeviceInfoClear(&def->info);
|
2008-08-01 13:31:37 +00:00
|
|
|
|
|
|
|
VIR_FREE(def);
|
|
|
|
}
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
void virDomainNetDefFree(virDomainNetDefPtr def)
|
|
|
|
{
|
|
|
|
if (!def)
|
|
|
|
return;
|
|
|
|
|
|
|
|
VIR_FREE(def->model);
|
|
|
|
|
|
|
|
switch (def->type) {
|
|
|
|
case VIR_DOMAIN_NET_TYPE_ETHERNET:
|
|
|
|
VIR_FREE(def->data.ethernet.dev);
|
|
|
|
VIR_FREE(def->data.ethernet.script);
|
|
|
|
VIR_FREE(def->data.ethernet.ipaddr);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_NET_TYPE_SERVER:
|
|
|
|
case VIR_DOMAIN_NET_TYPE_CLIENT:
|
|
|
|
case VIR_DOMAIN_NET_TYPE_MCAST:
|
|
|
|
VIR_FREE(def->data.socket.address);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_NET_TYPE_NETWORK:
|
|
|
|
VIR_FREE(def->data.network.name);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_NET_TYPE_BRIDGE:
|
|
|
|
VIR_FREE(def->data.bridge.brname);
|
2009-01-22 18:29:13 +00:00
|
|
|
VIR_FREE(def->data.bridge.script);
|
2009-01-23 01:48:47 +00:00
|
|
|
VIR_FREE(def->data.bridge.ipaddr);
|
2008-07-11 16:23:36 +00:00
|
|
|
break;
|
2009-05-11 09:50:27 +00:00
|
|
|
|
|
|
|
case VIR_DOMAIN_NET_TYPE_INTERNAL:
|
|
|
|
VIR_FREE(def->data.internal.name);
|
|
|
|
break;
|
2010-02-12 18:07:06 +01:00
|
|
|
|
|
|
|
case VIR_DOMAIN_NET_TYPE_DIRECT:
|
|
|
|
VIR_FREE(def->data.direct.linkdev);
|
|
|
|
break;
|
2010-03-26 17:01:35 +01:00
|
|
|
|
|
|
|
case VIR_DOMAIN_NET_TYPE_USER:
|
|
|
|
case VIR_DOMAIN_NET_TYPE_LAST:
|
|
|
|
break;
|
2008-07-11 16:23:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
VIR_FREE(def->ifname);
|
2009-11-30 18:35:58 +00:00
|
|
|
|
|
|
|
virDomainDeviceInfoClear(&def->info);
|
|
|
|
|
2010-03-25 13:46:07 -04:00
|
|
|
VIR_FREE(def->filter);
|
|
|
|
virNWFilterHashTableFree(def->filterparams);
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
VIR_FREE(def);
|
|
|
|
}
|
|
|
|
|
|
|
|
void virDomainChrDefFree(virDomainChrDefPtr def)
|
|
|
|
{
|
|
|
|
if (!def)
|
|
|
|
return;
|
|
|
|
|
2009-11-05 15:31:03 +01:00
|
|
|
switch (def->targetType) {
|
|
|
|
case VIR_DOMAIN_CHR_TARGET_TYPE_GUESTFWD:
|
|
|
|
VIR_FREE(def->target.addr);
|
|
|
|
break;
|
2010-02-18 17:52:03 +01:00
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_TARGET_TYPE_VIRTIO:
|
|
|
|
VIR_FREE(def->target.name);
|
|
|
|
break;
|
2009-11-05 15:31:03 +01:00
|
|
|
}
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
Add device info to serial, parallel, channel, input & fs devices
Although the serial, parallel, chanel, input & fs devices do
not have PCI address info, they can all have device aliases.
Thus it neccessary to associate the virDomainDeviceInfo data
with them all.
* src/conf/domain_conf.c, src/conf/domain_conf.h: Add hooks for
parsing / formatting device info for serial, parallel, channel
input and fs devices.
* docs/schemas/domain.rng: Associate device info with character
devices, input & fs device
2010-01-06 12:39:53 +00:00
|
|
|
virDomainDeviceInfoClear(&def->info);
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
VIR_FREE(def);
|
|
|
|
}
|
|
|
|
|
|
|
|
void virDomainSoundDefFree(virDomainSoundDefPtr def)
|
|
|
|
{
|
|
|
|
if (!def)
|
|
|
|
return;
|
|
|
|
|
2009-12-10 19:19:08 +00:00
|
|
|
virDomainDeviceInfoClear(&def->info);
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
VIR_FREE(def);
|
|
|
|
}
|
|
|
|
|
2009-10-21 13:26:38 +01:00
|
|
|
void virDomainWatchdogDefFree(virDomainWatchdogDefPtr def)
|
|
|
|
{
|
|
|
|
if (!def)
|
|
|
|
return;
|
|
|
|
|
2009-12-10 19:19:08 +00:00
|
|
|
virDomainDeviceInfoClear(&def->info);
|
|
|
|
|
2009-10-21 13:26:38 +01:00
|
|
|
VIR_FREE(def);
|
|
|
|
}
|
|
|
|
|
2009-07-06 14:54:44 +01:00
|
|
|
void virDomainVideoDefFree(virDomainVideoDefPtr def)
|
|
|
|
{
|
|
|
|
if (!def)
|
|
|
|
return;
|
|
|
|
|
2009-12-10 19:19:08 +00:00
|
|
|
virDomainDeviceInfoClear(&def->info);
|
|
|
|
|
2009-09-03 10:26:41 +02:00
|
|
|
VIR_FREE(def->accel);
|
2009-07-06 14:54:44 +01:00
|
|
|
VIR_FREE(def);
|
|
|
|
}
|
|
|
|
|
2008-08-08 14:27:05 +00:00
|
|
|
void virDomainHostdevDefFree(virDomainHostdevDefPtr def)
|
|
|
|
{
|
|
|
|
if (!def)
|
|
|
|
return;
|
|
|
|
|
|
|
|
VIR_FREE(def->target);
|
2009-11-30 18:35:58 +00:00
|
|
|
virDomainDeviceInfoClear(&def->info);
|
2008-08-08 14:27:05 +00:00
|
|
|
VIR_FREE(def);
|
|
|
|
}
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
void virDomainDeviceDefFree(virDomainDeviceDefPtr def)
|
|
|
|
{
|
|
|
|
if (!def)
|
|
|
|
return;
|
|
|
|
|
|
|
|
switch (def->type) {
|
|
|
|
case VIR_DOMAIN_DEVICE_DISK:
|
|
|
|
virDomainDiskDefFree(def->data.disk);
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_DEVICE_NET:
|
|
|
|
virDomainNetDefFree(def->data.net);
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_DEVICE_INPUT:
|
|
|
|
virDomainInputDefFree(def->data.input);
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_DEVICE_SOUND:
|
|
|
|
virDomainSoundDefFree(def->data.sound);
|
|
|
|
break;
|
2009-07-06 14:54:44 +01:00
|
|
|
case VIR_DOMAIN_DEVICE_VIDEO:
|
|
|
|
virDomainVideoDefFree(def->data.video);
|
|
|
|
break;
|
2008-08-08 14:27:05 +00:00
|
|
|
case VIR_DOMAIN_DEVICE_HOSTDEV:
|
|
|
|
virDomainHostdevDefFree(def->data.hostdev);
|
|
|
|
break;
|
2009-10-21 13:26:38 +01:00
|
|
|
case VIR_DOMAIN_DEVICE_WATCHDOG:
|
|
|
|
virDomainWatchdogDefFree(def->data.watchdog);
|
|
|
|
break;
|
2009-12-02 19:15:38 +00:00
|
|
|
case VIR_DOMAIN_DEVICE_CONTROLLER:
|
|
|
|
virDomainControllerDefFree(def->data.controller);
|
|
|
|
break;
|
2010-03-22 13:22:48 +00:00
|
|
|
case VIR_DOMAIN_DEVICE_GRAPHICS:
|
|
|
|
virDomainGraphicsDefFree(def->data.graphics);
|
|
|
|
break;
|
2008-07-11 16:23:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
VIR_FREE(def);
|
|
|
|
}
|
|
|
|
|
2009-03-03 09:44:41 +00:00
|
|
|
void virSecurityLabelDefFree(virDomainDefPtr def);
|
|
|
|
|
|
|
|
void virSecurityLabelDefFree(virDomainDefPtr def)
|
|
|
|
{
|
|
|
|
VIR_FREE(def->seclabel.model);
|
|
|
|
VIR_FREE(def->seclabel.label);
|
|
|
|
VIR_FREE(def->seclabel.imagelabel);
|
|
|
|
}
|
|
|
|
|
2010-03-30 13:44:22 +02:00
|
|
|
static void
|
|
|
|
virDomainClockDefClear(virDomainClockDefPtr def)
|
|
|
|
{
|
|
|
|
if (def->offset == VIR_DOMAIN_CLOCK_OFFSET_TIMEZONE)
|
|
|
|
VIR_FREE(def->data.timezone);
|
|
|
|
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < def->ntimers; i++)
|
|
|
|
VIR_FREE(def->timers[i]);
|
|
|
|
VIR_FREE(def->timers);
|
|
|
|
}
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
void virDomainDefFree(virDomainDefPtr def)
|
|
|
|
{
|
2008-10-10 16:08:01 +00:00
|
|
|
unsigned int i;
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
if (!def)
|
|
|
|
return;
|
|
|
|
|
2009-05-07 07:27:49 +00:00
|
|
|
for (i = 0 ; i < def->ngraphics ; i++)
|
|
|
|
virDomainGraphicsDefFree(def->graphics[i]);
|
|
|
|
VIR_FREE(def->graphics);
|
2008-10-10 16:08:01 +00:00
|
|
|
|
|
|
|
for (i = 0 ; i < def->ninputs ; i++)
|
|
|
|
virDomainInputDefFree(def->inputs[i]);
|
|
|
|
VIR_FREE(def->inputs);
|
|
|
|
|
|
|
|
for (i = 0 ; i < def->ndisks ; i++)
|
|
|
|
virDomainDiskDefFree(def->disks[i]);
|
|
|
|
VIR_FREE(def->disks);
|
|
|
|
|
2009-12-02 19:15:38 +00:00
|
|
|
for (i = 0 ; i < def->ncontrollers ; i++)
|
|
|
|
virDomainControllerDefFree(def->controllers[i]);
|
|
|
|
VIR_FREE(def->controllers);
|
|
|
|
|
2008-10-10 16:08:01 +00:00
|
|
|
for (i = 0 ; i < def->nfss ; i++)
|
|
|
|
virDomainFSDefFree(def->fss[i]);
|
|
|
|
VIR_FREE(def->fss);
|
|
|
|
|
|
|
|
for (i = 0 ; i < def->nnets ; i++)
|
|
|
|
virDomainNetDefFree(def->nets[i]);
|
|
|
|
VIR_FREE(def->nets);
|
2009-11-05 15:31:03 +01:00
|
|
|
|
2008-10-10 16:08:01 +00:00
|
|
|
for (i = 0 ; i < def->nserials ; i++)
|
|
|
|
virDomainChrDefFree(def->serials[i]);
|
|
|
|
VIR_FREE(def->serials);
|
|
|
|
|
|
|
|
for (i = 0 ; i < def->nparallels ; i++)
|
|
|
|
virDomainChrDefFree(def->parallels[i]);
|
|
|
|
VIR_FREE(def->parallels);
|
|
|
|
|
2009-11-05 15:31:03 +01:00
|
|
|
for (i = 0 ; i < def->nchannels ; i++)
|
|
|
|
virDomainChrDefFree(def->channels[i]);
|
|
|
|
VIR_FREE(def->channels);
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
virDomainChrDefFree(def->console);
|
2008-10-10 16:08:01 +00:00
|
|
|
|
|
|
|
for (i = 0 ; i < def->nsounds ; i++)
|
|
|
|
virDomainSoundDefFree(def->sounds[i]);
|
|
|
|
VIR_FREE(def->sounds);
|
|
|
|
|
2009-07-06 14:54:44 +01:00
|
|
|
for (i = 0 ; i < def->nvideos ; i++)
|
|
|
|
virDomainVideoDefFree(def->videos[i]);
|
|
|
|
VIR_FREE(def->videos);
|
|
|
|
|
2008-10-10 16:08:01 +00:00
|
|
|
for (i = 0 ; i < def->nhostdevs ; i++)
|
|
|
|
virDomainHostdevDefFree(def->hostdevs[i]);
|
|
|
|
VIR_FREE(def->hostdevs);
|
2008-07-11 16:23:36 +00:00
|
|
|
|
|
|
|
VIR_FREE(def->os.type);
|
|
|
|
VIR_FREE(def->os.arch);
|
|
|
|
VIR_FREE(def->os.machine);
|
2008-08-01 13:31:37 +00:00
|
|
|
VIR_FREE(def->os.init);
|
2008-07-11 16:23:36 +00:00
|
|
|
VIR_FREE(def->os.kernel);
|
|
|
|
VIR_FREE(def->os.initrd);
|
|
|
|
VIR_FREE(def->os.cmdline);
|
|
|
|
VIR_FREE(def->os.root);
|
|
|
|
VIR_FREE(def->os.loader);
|
|
|
|
VIR_FREE(def->os.bootloader);
|
|
|
|
VIR_FREE(def->os.bootloaderArgs);
|
|
|
|
|
2010-03-30 13:44:22 +02:00
|
|
|
virDomainClockDefClear(&def->clock);
|
2010-02-02 18:28:44 +00:00
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
VIR_FREE(def->name);
|
|
|
|
VIR_FREE(def->cpumask);
|
|
|
|
VIR_FREE(def->emulator);
|
2009-09-30 16:07:24 +02:00
|
|
|
VIR_FREE(def->description);
|
2008-07-11 16:23:36 +00:00
|
|
|
|
2009-10-21 13:26:38 +01:00
|
|
|
virDomainWatchdogDefFree(def->watchdog);
|
|
|
|
|
2009-03-03 09:44:41 +00:00
|
|
|
virSecurityLabelDefFree(def);
|
|
|
|
|
2009-12-18 14:44:55 +01:00
|
|
|
virCPUDefFree(def->cpu);
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
VIR_FREE(def);
|
|
|
|
}
|
|
|
|
|
2008-12-05 10:10:41 +00:00
|
|
|
#ifndef PROXY
|
|
|
|
|
2010-04-23 11:57:50 -04:00
|
|
|
static void virDomainSnapshotObjListDeinit(virDomainSnapshotObjListPtr snapshots);
|
2009-10-15 12:30:26 +01:00
|
|
|
static void virDomainObjFree(virDomainObjPtr dom)
|
2008-07-11 16:23:36 +00:00
|
|
|
{
|
|
|
|
if (!dom)
|
|
|
|
return;
|
|
|
|
|
2009-10-15 12:30:26 +01:00
|
|
|
VIR_DEBUG("obj=%p", dom);
|
2008-07-11 16:23:36 +00:00
|
|
|
virDomainDefFree(dom->def);
|
|
|
|
virDomainDefFree(dom->newDef);
|
|
|
|
|
2009-10-06 12:50:58 +01:00
|
|
|
if (dom->privateDataFreeFunc)
|
|
|
|
(dom->privateDataFreeFunc)(dom->privateData);
|
|
|
|
|
2009-01-15 19:56:05 +00:00
|
|
|
virMutexDestroy(&dom->lock);
|
|
|
|
|
2010-04-02 10:41:30 -04:00
|
|
|
virDomainSnapshotObjListDeinit(&dom->snapshots);
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
VIR_FREE(dom);
|
|
|
|
}
|
|
|
|
|
2009-10-15 12:30:26 +01:00
|
|
|
void virDomainObjRef(virDomainObjPtr dom)
|
|
|
|
{
|
|
|
|
dom->refs++;
|
|
|
|
VIR_DEBUG("obj=%p refs=%d", dom, dom->refs);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int virDomainObjUnref(virDomainObjPtr dom)
|
|
|
|
{
|
|
|
|
dom->refs--;
|
|
|
|
VIR_DEBUG("obj=%p refs=%d", dom, dom->refs);
|
|
|
|
if (dom->refs == 0) {
|
|
|
|
virDomainObjUnlock(dom);
|
|
|
|
virDomainObjFree(dom);
|
2009-12-08 14:42:43 +00:00
|
|
|
return 0;
|
2009-10-15 12:30:26 +01:00
|
|
|
}
|
2009-12-08 14:42:43 +00:00
|
|
|
return dom->refs;
|
2009-10-15 12:30:26 +01:00
|
|
|
}
|
|
|
|
|
2010-02-09 18:58:01 +00:00
|
|
|
static virDomainObjPtr virDomainObjNew(virCapsPtr caps)
|
2009-06-12 11:38:50 +00:00
|
|
|
{
|
|
|
|
virDomainObjPtr domain;
|
|
|
|
|
|
|
|
if (VIR_ALLOC(domain) < 0) {
|
2010-02-04 19:19:08 +01:00
|
|
|
virReportOOMError();
|
2009-06-12 11:38:50 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2009-10-06 12:50:58 +01:00
|
|
|
if (caps->privateDataAllocFunc &&
|
|
|
|
!(domain->privateData = (caps->privateDataAllocFunc)())) {
|
2010-02-04 19:19:08 +01:00
|
|
|
virReportOOMError();
|
2009-10-06 12:50:58 +01:00
|
|
|
VIR_FREE(domain);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
domain->privateDataFreeFunc = caps->privateDataFreeFunc;
|
|
|
|
|
2009-06-12 11:38:50 +00:00
|
|
|
if (virMutexInit(&domain->lock) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-06-12 11:38:50 +00:00
|
|
|
"%s", _("cannot initialize mutex"));
|
2009-10-06 12:50:58 +01:00
|
|
|
if (domain->privateDataFreeFunc)
|
|
|
|
(domain->privateDataFreeFunc)(domain->privateData);
|
2009-06-12 11:38:50 +00:00
|
|
|
VIR_FREE(domain);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
virDomainObjLock(domain);
|
|
|
|
domain->state = VIR_DOMAIN_SHUTOFF;
|
2009-10-15 12:30:26 +01:00
|
|
|
domain->refs = 1;
|
2009-06-12 11:38:50 +00:00
|
|
|
|
2010-04-02 10:41:30 -04:00
|
|
|
virDomainSnapshotObjListInit(&domain->snapshots);
|
|
|
|
|
2009-10-15 12:30:26 +01:00
|
|
|
VIR_DEBUG("obj=%p", domain);
|
2009-06-12 11:38:50 +00:00
|
|
|
return domain;
|
|
|
|
}
|
|
|
|
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainObjPtr virDomainAssignDef(virCapsPtr caps,
|
2008-10-10 14:20:37 +00:00
|
|
|
virDomainObjListPtr doms,
|
2010-03-24 15:31:21 +01:00
|
|
|
const virDomainDefPtr def,
|
|
|
|
bool live)
|
2008-07-11 16:23:36 +00:00
|
|
|
{
|
|
|
|
virDomainObjPtr domain;
|
Convert virDomainObjListPtr to use a hash of domain objects
The current virDomainObjListPtr object stores domain objects in
an array. This means that to find a particular objects requires
O(n) time, and more critically acquiring O(n) mutex locks.
The new impl replaces the array with a virHashTable, keyed off
UUID. Finding a object based on UUID is now O(1) time, and only
requires a single mutex lock. Finding by name/id is unchanged
in complexity.
In changing this, all code which iterates over the array had
to be updated to use a hash table iterator function callback.
Several of the functions which were identically duplicating
across all drivers were pulled into domain_conf.c
* src/conf/domain_conf.h, src/conf/domain_conf.c: Change
virDomainObjListPtr to use virHashTable. Add a initializer
method virDomainObjListInit, and rename virDomainObjListFree
to virDomainObjListDeinit, since its not actually freeing
the container, only its contents. Also add some convenient
methods virDomainObjListGetInactiveNames,
virDomainObjListGetActiveIDs and virDomainObjListNumOfDomains
which can be used to implement the correspondingly named
public API entry points in drivers
* src/libvirt_private.syms: Export new methods from domain_conf.h
* src/lxc/lxc_driver.c, src/opennebula/one_driver.c,
src/openvz/openvz_conf.c, src/openvz/openvz_driver.c,
src/qemu/qemu_driver.c, src/test/test_driver.c,
src/uml/uml_driver.c, src/vbox/vbox_tmpl.c: Update all code
to deal with hash tables instead of arrays for domains
2009-10-09 12:33:51 +01:00
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
2008-07-11 16:23:36 +00:00
|
|
|
|
2009-04-19 15:16:43 +00:00
|
|
|
if ((domain = virDomainFindByUUID(doms, def->uuid))) {
|
Rename internal APis
Rename virDomainIsActive to virDomainObjIsActive, and
virInterfaceIsActive to virInterfaceObjIsActive and finally
virNetworkIsActive to virNetworkObjIsActive.
* src/conf/domain_conf.c, src/conf/domain_conf.h,
src/conf/interface_conf.h, src/conf/network_conf.c,
src/conf/network_conf.h, src/lxc/lxc_driver.c,
src/network/bridge_driver.c, src/opennebula/one_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_driver.c,
src/test/test_driver.c, src/uml/uml_driver.c: Update for
renamed APIs.
2009-10-20 15:51:03 +01:00
|
|
|
if (!virDomainObjIsActive(domain)) {
|
2010-03-24 15:31:21 +01:00
|
|
|
if (live) {
|
|
|
|
/* save current configuration to be restored on domain shutdown */
|
|
|
|
if (!domain->newDef)
|
|
|
|
domain->newDef = domain->def;
|
|
|
|
domain->def = def;
|
|
|
|
} else {
|
|
|
|
virDomainDefFree(domain->def);
|
|
|
|
domain->def = def;
|
|
|
|
}
|
2008-07-11 16:23:36 +00:00
|
|
|
} else {
|
2010-03-25 21:53:29 +01:00
|
|
|
virDomainDefFree(domain->newDef);
|
2008-07-11 16:23:36 +00:00
|
|
|
domain->newDef = def;
|
|
|
|
}
|
|
|
|
|
|
|
|
return domain;
|
|
|
|
}
|
|
|
|
|
2010-02-09 18:58:01 +00:00
|
|
|
if (!(domain = virDomainObjNew(caps)))
|
2009-01-15 19:56:05 +00:00
|
|
|
return NULL;
|
2008-07-11 16:23:36 +00:00
|
|
|
domain->def = def;
|
2008-10-10 14:20:37 +00:00
|
|
|
|
Convert virDomainObjListPtr to use a hash of domain objects
The current virDomainObjListPtr object stores domain objects in
an array. This means that to find a particular objects requires
O(n) time, and more critically acquiring O(n) mutex locks.
The new impl replaces the array with a virHashTable, keyed off
UUID. Finding a object based on UUID is now O(1) time, and only
requires a single mutex lock. Finding by name/id is unchanged
in complexity.
In changing this, all code which iterates over the array had
to be updated to use a hash table iterator function callback.
Several of the functions which were identically duplicating
across all drivers were pulled into domain_conf.c
* src/conf/domain_conf.h, src/conf/domain_conf.c: Change
virDomainObjListPtr to use virHashTable. Add a initializer
method virDomainObjListInit, and rename virDomainObjListFree
to virDomainObjListDeinit, since its not actually freeing
the container, only its contents. Also add some convenient
methods virDomainObjListGetInactiveNames,
virDomainObjListGetActiveIDs and virDomainObjListNumOfDomains
which can be used to implement the correspondingly named
public API entry points in drivers
* src/libvirt_private.syms: Export new methods from domain_conf.h
* src/lxc/lxc_driver.c, src/opennebula/one_driver.c,
src/openvz/openvz_conf.c, src/openvz/openvz_driver.c,
src/qemu/qemu_driver.c, src/test/test_driver.c,
src/uml/uml_driver.c, src/vbox/vbox_tmpl.c: Update all code
to deal with hash tables instead of arrays for domains
2009-10-09 12:33:51 +01:00
|
|
|
virUUIDFormat(def->uuid, uuidstr);
|
|
|
|
if (virHashAddEntry(doms->objs, uuidstr, domain) < 0) {
|
|
|
|
VIR_FREE(domain);
|
2010-02-04 19:19:08 +01:00
|
|
|
virReportOOMError();
|
Convert virDomainObjListPtr to use a hash of domain objects
The current virDomainObjListPtr object stores domain objects in
an array. This means that to find a particular objects requires
O(n) time, and more critically acquiring O(n) mutex locks.
The new impl replaces the array with a virHashTable, keyed off
UUID. Finding a object based on UUID is now O(1) time, and only
requires a single mutex lock. Finding by name/id is unchanged
in complexity.
In changing this, all code which iterates over the array had
to be updated to use a hash table iterator function callback.
Several of the functions which were identically duplicating
across all drivers were pulled into domain_conf.c
* src/conf/domain_conf.h, src/conf/domain_conf.c: Change
virDomainObjListPtr to use virHashTable. Add a initializer
method virDomainObjListInit, and rename virDomainObjListFree
to virDomainObjListDeinit, since its not actually freeing
the container, only its contents. Also add some convenient
methods virDomainObjListGetInactiveNames,
virDomainObjListGetActiveIDs and virDomainObjListNumOfDomains
which can be used to implement the correspondingly named
public API entry points in drivers
* src/libvirt_private.syms: Export new methods from domain_conf.h
* src/lxc/lxc_driver.c, src/opennebula/one_driver.c,
src/openvz/openvz_conf.c, src/openvz/openvz_driver.c,
src/qemu/qemu_driver.c, src/test/test_driver.c,
src/uml/uml_driver.c, src/vbox/vbox_tmpl.c: Update all code
to deal with hash tables instead of arrays for domains
2009-10-09 12:33:51 +01:00
|
|
|
return NULL;
|
|
|
|
}
|
2008-07-11 16:23:36 +00:00
|
|
|
|
|
|
|
return domain;
|
|
|
|
}
|
|
|
|
|
Convert virDomainObjListPtr to use a hash of domain objects
The current virDomainObjListPtr object stores domain objects in
an array. This means that to find a particular objects requires
O(n) time, and more critically acquiring O(n) mutex locks.
The new impl replaces the array with a virHashTable, keyed off
UUID. Finding a object based on UUID is now O(1) time, and only
requires a single mutex lock. Finding by name/id is unchanged
in complexity.
In changing this, all code which iterates over the array had
to be updated to use a hash table iterator function callback.
Several of the functions which were identically duplicating
across all drivers were pulled into domain_conf.c
* src/conf/domain_conf.h, src/conf/domain_conf.c: Change
virDomainObjListPtr to use virHashTable. Add a initializer
method virDomainObjListInit, and rename virDomainObjListFree
to virDomainObjListDeinit, since its not actually freeing
the container, only its contents. Also add some convenient
methods virDomainObjListGetInactiveNames,
virDomainObjListGetActiveIDs and virDomainObjListNumOfDomains
which can be used to implement the correspondingly named
public API entry points in drivers
* src/libvirt_private.syms: Export new methods from domain_conf.h
* src/lxc/lxc_driver.c, src/opennebula/one_driver.c,
src/openvz/openvz_conf.c, src/openvz/openvz_driver.c,
src/qemu/qemu_driver.c, src/test/test_driver.c,
src/uml/uml_driver.c, src/vbox/vbox_tmpl.c: Update all code
to deal with hash tables instead of arrays for domains
2009-10-09 12:33:51 +01:00
|
|
|
/*
|
|
|
|
* The caller must hold a lock on the driver owning 'doms',
|
|
|
|
* and must also have locked 'dom', to ensure no one else
|
|
|
|
* is either waiting for 'dom' or still usingn it
|
|
|
|
*/
|
2008-10-10 14:20:37 +00:00
|
|
|
void virDomainRemoveInactive(virDomainObjListPtr doms,
|
2008-07-11 16:23:36 +00:00
|
|
|
virDomainObjPtr dom)
|
|
|
|
{
|
Convert virDomainObjListPtr to use a hash of domain objects
The current virDomainObjListPtr object stores domain objects in
an array. This means that to find a particular objects requires
O(n) time, and more critically acquiring O(n) mutex locks.
The new impl replaces the array with a virHashTable, keyed off
UUID. Finding a object based on UUID is now O(1) time, and only
requires a single mutex lock. Finding by name/id is unchanged
in complexity.
In changing this, all code which iterates over the array had
to be updated to use a hash table iterator function callback.
Several of the functions which were identically duplicating
across all drivers were pulled into domain_conf.c
* src/conf/domain_conf.h, src/conf/domain_conf.c: Change
virDomainObjListPtr to use virHashTable. Add a initializer
method virDomainObjListInit, and rename virDomainObjListFree
to virDomainObjListDeinit, since its not actually freeing
the container, only its contents. Also add some convenient
methods virDomainObjListGetInactiveNames,
virDomainObjListGetActiveIDs and virDomainObjListNumOfDomains
which can be used to implement the correspondingly named
public API entry points in drivers
* src/libvirt_private.syms: Export new methods from domain_conf.h
* src/lxc/lxc_driver.c, src/opennebula/one_driver.c,
src/openvz/openvz_conf.c, src/openvz/openvz_driver.c,
src/qemu/qemu_driver.c, src/test/test_driver.c,
src/uml/uml_driver.c, src/vbox/vbox_tmpl.c: Update all code
to deal with hash tables instead of arrays for domains
2009-10-09 12:33:51 +01:00
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
|
|
|
virUUIDFormat(dom->def->uuid, uuidstr);
|
2008-07-11 16:23:36 +00:00
|
|
|
|
2008-12-04 22:00:14 +00:00
|
|
|
virDomainObjUnlock(dom);
|
|
|
|
|
Convert virDomainObjListPtr to use a hash of domain objects
The current virDomainObjListPtr object stores domain objects in
an array. This means that to find a particular objects requires
O(n) time, and more critically acquiring O(n) mutex locks.
The new impl replaces the array with a virHashTable, keyed off
UUID. Finding a object based on UUID is now O(1) time, and only
requires a single mutex lock. Finding by name/id is unchanged
in complexity.
In changing this, all code which iterates over the array had
to be updated to use a hash table iterator function callback.
Several of the functions which were identically duplicating
across all drivers were pulled into domain_conf.c
* src/conf/domain_conf.h, src/conf/domain_conf.c: Change
virDomainObjListPtr to use virHashTable. Add a initializer
method virDomainObjListInit, and rename virDomainObjListFree
to virDomainObjListDeinit, since its not actually freeing
the container, only its contents. Also add some convenient
methods virDomainObjListGetInactiveNames,
virDomainObjListGetActiveIDs and virDomainObjListNumOfDomains
which can be used to implement the correspondingly named
public API entry points in drivers
* src/libvirt_private.syms: Export new methods from domain_conf.h
* src/lxc/lxc_driver.c, src/opennebula/one_driver.c,
src/openvz/openvz_conf.c, src/openvz/openvz_driver.c,
src/qemu/qemu_driver.c, src/test/test_driver.c,
src/uml/uml_driver.c, src/vbox/vbox_tmpl.c: Update all code
to deal with hash tables instead of arrays for domains
2009-10-09 12:33:51 +01:00
|
|
|
virHashRemoveEntry(doms->objs, uuidstr, virDomainObjListDeallocator);
|
2008-07-11 16:23:36 +00:00
|
|
|
}
|
2008-12-05 10:10:41 +00:00
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
|
2009-11-30 18:35:58 +00:00
|
|
|
int virDomainDeviceAddressIsValid(virDomainDeviceInfoPtr info,
|
|
|
|
int type)
|
|
|
|
{
|
|
|
|
if (info->type != type)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
switch (info->type) {
|
|
|
|
case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI:
|
|
|
|
return virDomainDevicePCIAddressIsValid(&info->addr.pci);
|
2009-12-01 16:56:24 +00:00
|
|
|
|
|
|
|
case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE:
|
|
|
|
return virDomainDeviceDriveAddressIsValid(&info->addr.drive);
|
2009-11-30 18:35:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int virDomainDevicePCIAddressIsValid(virDomainDevicePCIAddressPtr addr)
|
|
|
|
{
|
|
|
|
return addr->domain || addr->bus || addr->slot;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-12-01 16:56:24 +00:00
|
|
|
int virDomainDeviceDriveAddressIsValid(virDomainDeviceDriveAddressPtr addr ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
/*return addr->controller || addr->bus || addr->unit;*/
|
|
|
|
return 1; /* 0 is valid for all fields, so any successfully parsed addr is valid */
|
|
|
|
}
|
2010-02-18 17:52:03 +01:00
|
|
|
|
|
|
|
|
|
|
|
int virDomainDeviceVirtioSerialAddressIsValid(
|
|
|
|
virDomainDeviceVirtioSerialAddressPtr addr ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
return 1; /* 0 is valid for all fields, so any successfully parsed addr is valid */
|
|
|
|
}
|
2010-01-15 17:55:11 +00:00
|
|
|
#endif /* !PROXY */
|
2009-12-01 16:56:24 +00:00
|
|
|
|
|
|
|
|
2009-11-30 18:35:58 +00:00
|
|
|
int virDomainDeviceInfoIsSet(virDomainDeviceInfoPtr info)
|
|
|
|
{
|
|
|
|
if (info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
|
|
|
|
return 1;
|
2010-01-08 15:53:53 +00:00
|
|
|
if (info->alias)
|
|
|
|
return 1;
|
2009-11-30 18:35:58 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void virDomainDeviceInfoClear(virDomainDeviceInfoPtr info)
|
|
|
|
{
|
2010-01-08 15:53:53 +00:00
|
|
|
VIR_FREE(info->alias);
|
2009-11-30 18:35:58 +00:00
|
|
|
memset(&info->addr, 0, sizeof(info->addr));
|
|
|
|
info->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-01-27 15:10:34 +00:00
|
|
|
static int virDomainDeviceInfoClearAlias(virDomainDefPtr def ATTRIBUTE_UNUSED,
|
|
|
|
virDomainDeviceInfoPtr info,
|
|
|
|
void *opaque ATTRIBUTE_UNUSED)
|
2010-01-06 10:35:30 +00:00
|
|
|
{
|
2010-01-27 15:10:34 +00:00
|
|
|
VIR_FREE(info->alias);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int virDomainDeviceInfoClearPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED,
|
|
|
|
virDomainDeviceInfoPtr info,
|
|
|
|
void *opaque ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
|
2010-01-06 10:35:30 +00:00
|
|
|
memset(&info->addr, 0, sizeof(info->addr));
|
|
|
|
info->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE;
|
|
|
|
}
|
2010-01-27 15:10:34 +00:00
|
|
|
return 0;
|
2010-01-06 10:35:30 +00:00
|
|
|
}
|
|
|
|
|
2010-01-27 15:10:34 +00:00
|
|
|
int virDomainDeviceInfoIterate(virDomainDefPtr def,
|
|
|
|
virDomainDeviceInfoCallback cb,
|
|
|
|
void *opaque)
|
2010-01-06 10:35:30 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < def->ndisks ; i++)
|
2010-01-27 15:10:34 +00:00
|
|
|
if (cb(def, &def->disks[i]->info, opaque) < 0)
|
|
|
|
return -1;
|
2010-01-06 10:35:30 +00:00
|
|
|
for (i = 0; i < def->nnets ; i++)
|
2010-01-27 15:10:34 +00:00
|
|
|
if (cb(def, &def->nets[i]->info, opaque) < 0)
|
|
|
|
return -1;
|
2010-01-06 10:35:30 +00:00
|
|
|
for (i = 0; i < def->nsounds ; i++)
|
2010-01-27 15:10:34 +00:00
|
|
|
if (cb(def, &def->sounds[i]->info, opaque) < 0)
|
|
|
|
return -1;
|
2010-01-06 10:35:30 +00:00
|
|
|
for (i = 0; i < def->nhostdevs ; i++)
|
2010-01-27 15:10:34 +00:00
|
|
|
if (cb(def, &def->hostdevs[i]->info, opaque) < 0)
|
|
|
|
return -1;
|
2010-01-06 10:35:30 +00:00
|
|
|
for (i = 0; i < def->nvideos ; i++)
|
2010-01-27 15:10:34 +00:00
|
|
|
if (cb(def, &def->videos[i]->info, opaque) < 0)
|
|
|
|
return -1;
|
2010-01-06 10:35:30 +00:00
|
|
|
for (i = 0; i < def->ncontrollers ; i++)
|
2010-01-27 15:10:34 +00:00
|
|
|
if (cb(def, &def->controllers[i]->info, opaque) < 0)
|
|
|
|
return -1;
|
Add device info to serial, parallel, channel, input & fs devices
Although the serial, parallel, chanel, input & fs devices do
not have PCI address info, they can all have device aliases.
Thus it neccessary to associate the virDomainDeviceInfo data
with them all.
* src/conf/domain_conf.c, src/conf/domain_conf.h: Add hooks for
parsing / formatting device info for serial, parallel, channel
input and fs devices.
* docs/schemas/domain.rng: Associate device info with character
devices, input & fs device
2010-01-06 12:39:53 +00:00
|
|
|
for (i = 0; i < def->nserials ; i++)
|
2010-01-27 15:10:34 +00:00
|
|
|
if (cb(def, &def->serials[i]->info, opaque) < 0)
|
|
|
|
return -1;
|
Add device info to serial, parallel, channel, input & fs devices
Although the serial, parallel, chanel, input & fs devices do
not have PCI address info, they can all have device aliases.
Thus it neccessary to associate the virDomainDeviceInfo data
with them all.
* src/conf/domain_conf.c, src/conf/domain_conf.h: Add hooks for
parsing / formatting device info for serial, parallel, channel
input and fs devices.
* docs/schemas/domain.rng: Associate device info with character
devices, input & fs device
2010-01-06 12:39:53 +00:00
|
|
|
for (i = 0; i < def->nparallels ; i++)
|
2010-01-27 15:10:34 +00:00
|
|
|
if (cb(def, &def->parallels[i]->info, opaque) < 0)
|
|
|
|
return -1;
|
Add device info to serial, parallel, channel, input & fs devices
Although the serial, parallel, chanel, input & fs devices do
not have PCI address info, they can all have device aliases.
Thus it neccessary to associate the virDomainDeviceInfo data
with them all.
* src/conf/domain_conf.c, src/conf/domain_conf.h: Add hooks for
parsing / formatting device info for serial, parallel, channel
input and fs devices.
* docs/schemas/domain.rng: Associate device info with character
devices, input & fs device
2010-01-06 12:39:53 +00:00
|
|
|
for (i = 0; i < def->nchannels ; i++)
|
2010-01-27 15:10:34 +00:00
|
|
|
if (cb(def, &def->channels[i]->info, opaque) < 0)
|
|
|
|
return -1;
|
Add device info to serial, parallel, channel, input & fs devices
Although the serial, parallel, chanel, input & fs devices do
not have PCI address info, they can all have device aliases.
Thus it neccessary to associate the virDomainDeviceInfo data
with them all.
* src/conf/domain_conf.c, src/conf/domain_conf.h: Add hooks for
parsing / formatting device info for serial, parallel, channel
input and fs devices.
* docs/schemas/domain.rng: Associate device info with character
devices, input & fs device
2010-01-06 12:39:53 +00:00
|
|
|
for (i = 0; i < def->ninputs ; i++)
|
2010-01-27 15:10:34 +00:00
|
|
|
if (cb(def, &def->inputs[i]->info, opaque) < 0)
|
|
|
|
return -1;
|
Add device info to serial, parallel, channel, input & fs devices
Although the serial, parallel, chanel, input & fs devices do
not have PCI address info, they can all have device aliases.
Thus it neccessary to associate the virDomainDeviceInfo data
with them all.
* src/conf/domain_conf.c, src/conf/domain_conf.h: Add hooks for
parsing / formatting device info for serial, parallel, channel
input and fs devices.
* docs/schemas/domain.rng: Associate device info with character
devices, input & fs device
2010-01-06 12:39:53 +00:00
|
|
|
for (i = 0; i < def->nfss ; i++)
|
2010-01-27 15:10:34 +00:00
|
|
|
if (cb(def, &def->fss[i]->info, opaque) < 0)
|
|
|
|
return -1;
|
2010-01-06 10:35:30 +00:00
|
|
|
if (def->watchdog)
|
2010-01-27 15:10:34 +00:00
|
|
|
if (cb(def, &def->watchdog->info, opaque) < 0)
|
|
|
|
return -1;
|
Add device info to serial, parallel, channel, input & fs devices
Although the serial, parallel, chanel, input & fs devices do
not have PCI address info, they can all have device aliases.
Thus it neccessary to associate the virDomainDeviceInfo data
with them all.
* src/conf/domain_conf.c, src/conf/domain_conf.h: Add hooks for
parsing / formatting device info for serial, parallel, channel
input and fs devices.
* docs/schemas/domain.rng: Associate device info with character
devices, input & fs device
2010-01-06 12:39:53 +00:00
|
|
|
if (def->console)
|
2010-01-27 15:10:34 +00:00
|
|
|
if (cb(def, &def->console->info, opaque) < 0)
|
|
|
|
return -1;
|
|
|
|
return 0;
|
2010-01-06 10:35:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void virDomainDefClearPCIAddresses(virDomainDefPtr def)
|
|
|
|
{
|
2010-01-27 15:10:34 +00:00
|
|
|
virDomainDeviceInfoIterate(def, virDomainDeviceInfoClearPCIAddress, NULL);
|
2010-01-08 15:53:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void virDomainDefClearDeviceAliases(virDomainDefPtr def)
|
|
|
|
{
|
2010-01-27 15:10:34 +00:00
|
|
|
virDomainDeviceInfoIterate(def, virDomainDeviceInfoClearAlias, NULL);
|
2010-01-06 10:35:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-11-30 18:35:58 +00:00
|
|
|
/* Generate a string representation of a device address
|
|
|
|
* @param address Device address to stringify
|
|
|
|
*/
|
|
|
|
static int virDomainDeviceInfoFormat(virBufferPtr buf,
|
2010-01-08 15:53:53 +00:00
|
|
|
virDomainDeviceInfoPtr info,
|
|
|
|
int flags)
|
2009-11-30 18:35:58 +00:00
|
|
|
{
|
|
|
|
if (!info) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
2009-11-30 18:35:58 +00:00
|
|
|
_("missing device information"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2010-01-08 15:53:53 +00:00
|
|
|
if (info->alias &&
|
|
|
|
!(flags & VIR_DOMAIN_XML_INACTIVE)) {
|
|
|
|
virBufferVSprintf(buf, " <alias name='%s'/>\n", info->alias);
|
|
|
|
}
|
|
|
|
|
2009-11-30 18:35:58 +00:00
|
|
|
if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* We'll be in domain/devices/[device type]/ so 3 level indent */
|
|
|
|
virBufferVSprintf(buf, " <address type='%s'",
|
|
|
|
virDomainDeviceAddressTypeToString(info->type));
|
|
|
|
|
|
|
|
switch (info->type) {
|
|
|
|
case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI:
|
|
|
|
virBufferVSprintf(buf, " domain='0x%.4x' bus='0x%.2x' slot='0x%.2x' function='0x%.1x'",
|
|
|
|
info->addr.pci.domain,
|
|
|
|
info->addr.pci.bus,
|
|
|
|
info->addr.pci.slot,
|
|
|
|
info->addr.pci.function);
|
|
|
|
break;
|
|
|
|
|
2009-12-01 16:56:24 +00:00
|
|
|
case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE:
|
|
|
|
virBufferVSprintf(buf, " controller='%d' bus='%d' unit='%d'",
|
|
|
|
info->addr.drive.controller,
|
|
|
|
info->addr.drive.bus,
|
|
|
|
info->addr.drive.unit);
|
|
|
|
break;
|
|
|
|
|
2010-02-18 17:52:03 +01:00
|
|
|
case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL:
|
|
|
|
virBufferVSprintf(buf, " controller='%d' bus='%d'",
|
|
|
|
info->addr.vioserial.controller,
|
|
|
|
info->addr.vioserial.bus);
|
|
|
|
break;
|
|
|
|
|
2009-11-30 18:35:58 +00:00
|
|
|
default:
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-11-30 18:35:58 +00:00
|
|
|
_("unknown address type '%d'"), info->type);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferAddLit(buf, "/>\n");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-01-15 17:55:11 +00:00
|
|
|
#ifndef PROXY
|
|
|
|
|
2009-12-01 16:56:24 +00:00
|
|
|
|
2009-11-30 18:35:58 +00:00
|
|
|
static int
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainDevicePCIAddressParseXML(xmlNodePtr node,
|
2009-11-30 18:35:58 +00:00
|
|
|
virDomainDevicePCIAddressPtr addr)
|
|
|
|
{
|
|
|
|
char *domain, *slot, *bus, *function;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
memset(addr, 0, sizeof(*addr));
|
|
|
|
|
|
|
|
domain = virXMLPropString(node, "domain");
|
|
|
|
bus = virXMLPropString(node, "bus");
|
|
|
|
slot = virXMLPropString(node, "slot");
|
|
|
|
function = virXMLPropString(node, "function");
|
|
|
|
|
|
|
|
if (domain &&
|
|
|
|
virStrToLong_ui(domain, NULL, 16, &addr->domain) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
2009-11-30 18:35:58 +00:00
|
|
|
_("Cannot parse <address> 'domain' attribute"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bus &&
|
|
|
|
virStrToLong_ui(bus, NULL, 16, &addr->bus) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
2009-11-30 18:35:58 +00:00
|
|
|
_("Cannot parse <address> 'bus' attribute"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (slot &&
|
|
|
|
virStrToLong_ui(slot, NULL, 16, &addr->slot) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
2009-11-30 18:35:58 +00:00
|
|
|
_("Cannot parse <address> 'slot' attribute"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (function &&
|
|
|
|
virStrToLong_ui(function, NULL, 16, &addr->function) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
2009-11-30 18:35:58 +00:00
|
|
|
_("Cannot parse <address> 'function' attribute"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!virDomainDevicePCIAddressIsValid(addr)) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
2009-11-30 18:35:58 +00:00
|
|
|
_("Insufficient specification for PCI address"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(domain);
|
|
|
|
VIR_FREE(bus);
|
|
|
|
VIR_FREE(slot);
|
|
|
|
VIR_FREE(function);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-12-01 16:56:24 +00:00
|
|
|
static int
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainDeviceDriveAddressParseXML(xmlNodePtr node,
|
2009-12-01 16:56:24 +00:00
|
|
|
virDomainDeviceDriveAddressPtr addr)
|
|
|
|
{
|
|
|
|
char *bus, *unit, *controller;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
memset(addr, 0, sizeof(*addr));
|
|
|
|
|
|
|
|
controller = virXMLPropString(node, "controller");
|
|
|
|
bus = virXMLPropString(node, "bus");
|
|
|
|
unit = virXMLPropString(node, "unit");
|
|
|
|
|
|
|
|
if (controller &&
|
|
|
|
virStrToLong_ui(controller, NULL, 10, &addr->controller) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
2009-12-01 16:56:24 +00:00
|
|
|
_("Cannot parse <address> 'controller' attribute"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bus &&
|
|
|
|
virStrToLong_ui(bus, NULL, 10, &addr->bus) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
2009-12-01 16:56:24 +00:00
|
|
|
_("Cannot parse <address> 'bus' attribute"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (unit &&
|
|
|
|
virStrToLong_ui(unit, NULL, 10, &addr->unit) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
2009-12-01 16:56:24 +00:00
|
|
|
_("Cannot parse <address> 'unit' attribute"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!virDomainDeviceDriveAddressIsValid(addr)) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
2009-12-01 16:56:24 +00:00
|
|
|
_("Insufficient specification for drive address"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(controller);
|
|
|
|
VIR_FREE(bus);
|
|
|
|
VIR_FREE(unit);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2010-02-18 17:52:03 +01:00
|
|
|
|
|
|
|
static int
|
|
|
|
virDomainDeviceVirtioSerialAddressParseXML(
|
|
|
|
xmlNodePtr node,
|
|
|
|
virDomainDeviceVirtioSerialAddressPtr addr
|
|
|
|
)
|
|
|
|
{
|
|
|
|
char *controller, *bus;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
memset(addr, 0, sizeof(*addr));
|
|
|
|
|
|
|
|
controller = virXMLPropString(node, "controller");
|
|
|
|
bus = virXMLPropString(node, "bus");
|
|
|
|
|
|
|
|
if (controller &&
|
|
|
|
virStrToLong_ui(controller, NULL, 10, &addr->controller) < 0) {
|
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Cannot parse <address> 'controller' attribute"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bus &&
|
|
|
|
virStrToLong_ui(bus, NULL, 10, &addr->bus) < 0) {
|
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Cannot parse <address> 'bus' attribute"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!virDomainDeviceVirtioSerialAddressIsValid(addr)) {
|
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Insufficient specification for "
|
|
|
|
"virtio serial address"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(controller);
|
|
|
|
VIR_FREE(bus);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2009-11-30 18:35:58 +00:00
|
|
|
/* Parse the XML definition for a device address
|
|
|
|
* @param node XML nodeset to parse for device address definition
|
|
|
|
*/
|
|
|
|
static int
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainDeviceInfoParseXML(xmlNodePtr node,
|
2009-11-30 18:35:58 +00:00
|
|
|
virDomainDeviceInfoPtr info,
|
2010-01-08 15:53:53 +00:00
|
|
|
int flags)
|
2009-11-30 18:35:58 +00:00
|
|
|
{
|
|
|
|
xmlNodePtr cur;
|
|
|
|
xmlNodePtr address = NULL;
|
2010-01-08 15:53:53 +00:00
|
|
|
xmlNodePtr alias = NULL;
|
2009-11-30 18:35:58 +00:00
|
|
|
char *type = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
virDomainDeviceInfoClear(info);
|
|
|
|
|
|
|
|
cur = node->children;
|
|
|
|
while (cur != NULL) {
|
|
|
|
if (cur->type == XML_ELEMENT_NODE) {
|
2010-01-08 15:53:53 +00:00
|
|
|
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")) {
|
2009-11-30 18:35:58 +00:00
|
|
|
address = cur;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
cur = cur->next;
|
|
|
|
}
|
|
|
|
|
2010-01-08 15:53:53 +00:00
|
|
|
if (alias)
|
|
|
|
info->alias = virXMLPropString(alias, "name");
|
|
|
|
|
2009-11-30 18:35:58 +00:00
|
|
|
if (!address)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
type = virXMLPropString(address, "type");
|
|
|
|
|
|
|
|
if (type) {
|
|
|
|
if ((info->type = virDomainDeviceAddressTypeFromString(type)) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-11-30 18:35:58 +00:00
|
|
|
_("unknown address type '%s'"), type);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
} else {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2010-01-21 14:39:42 +01:00
|
|
|
"%s", _("No type specified for device address"));
|
2009-11-30 18:35:58 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (info->type) {
|
|
|
|
case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI:
|
2010-02-09 18:58:01 +00:00
|
|
|
if (virDomainDevicePCIAddressParseXML(address, &info->addr.pci) < 0)
|
2009-11-30 18:35:58 +00:00
|
|
|
goto cleanup;
|
|
|
|
break;
|
|
|
|
|
2009-12-01 16:56:24 +00:00
|
|
|
case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE:
|
2010-02-09 18:58:01 +00:00
|
|
|
if (virDomainDeviceDriveAddressParseXML(address, &info->addr.drive) < 0)
|
2009-12-01 16:56:24 +00:00
|
|
|
goto cleanup;
|
|
|
|
break;
|
|
|
|
|
2010-02-18 17:52:03 +01:00
|
|
|
case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL:
|
|
|
|
if (virDomainDeviceVirtioSerialAddressParseXML
|
|
|
|
(address, &info->addr.vioserial) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
break;
|
|
|
|
|
2009-11-30 18:35:58 +00:00
|
|
|
default:
|
|
|
|
/* Should not happen */
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2010-01-21 14:39:42 +01:00
|
|
|
"%s", _("Unknown device address type"));
|
2009-11-30 18:35:58 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
2010-01-08 15:53:53 +00:00
|
|
|
if (ret == -1)
|
|
|
|
VIR_FREE(info->alias);
|
2009-11-30 18:35:58 +00:00
|
|
|
VIR_FREE(type);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2010-03-30 15:45:53 +02:00
|
|
|
static int
|
|
|
|
virDomainParseLegacyDeviceAddress(char *devaddr,
|
|
|
|
virDomainDevicePCIAddressPtr pci)
|
|
|
|
{
|
|
|
|
char *tmp;
|
|
|
|
|
|
|
|
/* expected format: <domain>:<bus>:<slot> */
|
|
|
|
if (/* domain */
|
|
|
|
virStrToLong_ui(devaddr, &tmp, 16, &pci->domain) < 0 || *tmp != ':' ||
|
|
|
|
/* bus */
|
|
|
|
virStrToLong_ui(tmp + 1, &tmp, 16, &pci->bus) < 0 || *tmp != ':' ||
|
|
|
|
/* slot */
|
|
|
|
virStrToLong_ui(tmp + 1, NULL, 16, &pci->slot) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2009-11-30 18:35:58 +00:00
|
|
|
|
2010-03-15 21:42:01 +01:00
|
|
|
int
|
2009-12-22 16:53:20 +00:00
|
|
|
virDomainDiskDefAssignAddress(virDomainDiskDefPtr def)
|
|
|
|
{
|
|
|
|
int idx = virDiskNameToIndex(def->dst);
|
2010-03-15 21:42:01 +01:00
|
|
|
if (idx < 0)
|
|
|
|
return -1;
|
2009-12-22 16:53:20 +00:00
|
|
|
|
|
|
|
switch (def->bus) {
|
|
|
|
case VIR_DOMAIN_DISK_BUS_SCSI:
|
|
|
|
/* For SCSI we define the default mapping to be 7 units
|
|
|
|
* per bus, 1 bus per controller, many controllers */
|
|
|
|
def->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE;
|
|
|
|
def->info.addr.drive.controller = idx / 7;
|
|
|
|
def->info.addr.drive.bus = 0;
|
|
|
|
def->info.addr.drive.unit = idx % 7;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_DISK_BUS_IDE:
|
|
|
|
/* For IDE we define the default mapping to be 2 units
|
|
|
|
* per bus, 2 bus per controller, many controllers */
|
|
|
|
def->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE;
|
|
|
|
def->info.addr.drive.controller = idx / 4;
|
|
|
|
def->info.addr.drive.bus = (idx % 4) / 2;
|
|
|
|
def->info.addr.drive.unit = (idx % 2);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_DISK_BUS_FDC:
|
|
|
|
/* For FDC we define the default mapping to be 2 units
|
|
|
|
* per bus, 1 bus per controller, many controllers */
|
|
|
|
def->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE;
|
|
|
|
def->info.addr.drive.controller = idx / 2;
|
|
|
|
def->info.addr.drive.bus = 0;
|
|
|
|
def->info.addr.drive.unit = idx % 2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
/* Other disk bus's aren't controller based */
|
|
|
|
break;
|
|
|
|
}
|
2010-03-15 21:42:01 +01:00
|
|
|
|
|
|
|
return 0;
|
2009-12-22 16:53:20 +00:00
|
|
|
}
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
/* Parse the XML definition for a disk
|
|
|
|
* @param node XML nodeset to parse for disk definition
|
|
|
|
*/
|
|
|
|
static virDomainDiskDefPtr
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainDiskDefParseXML(xmlNodePtr node,
|
2009-07-17 22:08:33 +01:00
|
|
|
int flags) {
|
2008-07-11 16:23:36 +00:00
|
|
|
virDomainDiskDefPtr def;
|
|
|
|
xmlNodePtr cur;
|
|
|
|
char *type = NULL;
|
|
|
|
char *device = NULL;
|
|
|
|
char *driverName = NULL;
|
|
|
|
char *driverType = NULL;
|
|
|
|
char *source = NULL;
|
|
|
|
char *target = NULL;
|
|
|
|
char *bus = NULL;
|
2009-01-30 17:15:39 +00:00
|
|
|
char *cachetag = NULL;
|
2010-03-24 11:32:10 -04:00
|
|
|
char *error_policy = NULL;
|
2009-07-17 22:08:33 +01:00
|
|
|
char *devaddr = NULL;
|
2009-07-21 07:23:03 +02:00
|
|
|
virStorageEncryptionPtr encryption = NULL;
|
2009-08-14 12:22:01 +01:00
|
|
|
char *serial = NULL;
|
2008-07-11 16:23:36 +00:00
|
|
|
|
|
|
|
if (VIR_ALLOC(def) < 0) {
|
2010-02-04 19:19:08 +01:00
|
|
|
virReportOOMError();
|
2008-07-11 16:23:36 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
type = virXMLPropString(node, "type");
|
|
|
|
if (type) {
|
|
|
|
if ((def->type = virDomainDiskTypeFromString(type)) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
_("unknown disk type '%s'"), type);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
def->type = VIR_DOMAIN_DISK_TYPE_FILE;
|
|
|
|
}
|
|
|
|
|
|
|
|
cur = node->children;
|
|
|
|
while (cur != NULL) {
|
|
|
|
if (cur->type == XML_ELEMENT_NODE) {
|
|
|
|
if ((source == NULL) &&
|
|
|
|
(xmlStrEqual(cur->name, BAD_CAST "source"))) {
|
|
|
|
|
2009-11-16 18:08:29 +00:00
|
|
|
switch (def->type) {
|
|
|
|
case VIR_DOMAIN_DISK_TYPE_FILE:
|
2008-07-11 16:23:36 +00:00
|
|
|
source = virXMLPropString(cur, "file");
|
2009-11-16 18:08:29 +00:00
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_DISK_TYPE_BLOCK:
|
2008-07-11 16:23:36 +00:00
|
|
|
source = virXMLPropString(cur, "dev");
|
2009-11-16 18:08:29 +00:00
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_DISK_TYPE_DIR:
|
|
|
|
source = virXMLPropString(cur, "dir");
|
|
|
|
break;
|
|
|
|
default:
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-11-16 18:08:29 +00:00
|
|
|
_("unexpected disk type %s"),
|
|
|
|
virDomainDiskTypeToString(def->type));
|
|
|
|
goto error;
|
|
|
|
}
|
2008-11-28 11:23:34 +00:00
|
|
|
|
|
|
|
/* People sometimes pass a bogus '' source path
|
|
|
|
when they mean to omit the source element
|
|
|
|
completely. eg CDROM without media. This is
|
|
|
|
just a little compatability check to help
|
|
|
|
those broken apps */
|
|
|
|
if (source && STREQ(source, ""))
|
|
|
|
VIR_FREE(source);
|
2008-07-11 16:23:36 +00:00
|
|
|
} else if ((target == NULL) &&
|
|
|
|
(xmlStrEqual(cur->name, BAD_CAST "target"))) {
|
|
|
|
target = virXMLPropString(cur, "dev");
|
|
|
|
bus = virXMLPropString(cur, "bus");
|
2008-07-25 13:17:27 +00:00
|
|
|
|
|
|
|
/* HACK: Work around for compat with Xen
|
|
|
|
* driver in previous libvirt releases */
|
|
|
|
if (target &&
|
|
|
|
STRPREFIX(target, "ioemu:"))
|
|
|
|
memmove(target, target+6, strlen(target)-5);
|
2008-07-11 16:23:36 +00:00
|
|
|
} else if ((driverName == NULL) &&
|
|
|
|
(xmlStrEqual(cur->name, BAD_CAST "driver"))) {
|
|
|
|
driverName = virXMLPropString(cur, "name");
|
|
|
|
driverType = virXMLPropString(cur, "type");
|
2009-01-30 17:15:39 +00:00
|
|
|
cachetag = virXMLPropString(cur, "cache");
|
2010-03-24 11:32:10 -04:00
|
|
|
error_policy = virXMLPropString(cur, "error_policy");
|
2008-07-11 16:23:36 +00:00
|
|
|
} else if (xmlStrEqual(cur->name, BAD_CAST "readonly")) {
|
|
|
|
def->readonly = 1;
|
|
|
|
} else if (xmlStrEqual(cur->name, BAD_CAST "shareable")) {
|
|
|
|
def->shared = 1;
|
2009-07-17 22:08:33 +01:00
|
|
|
} else if ((flags & VIR_DOMAIN_XML_INTERNAL_STATUS) &&
|
|
|
|
xmlStrEqual(cur->name, BAD_CAST "state")) {
|
2009-11-30 18:35:58 +00:00
|
|
|
/* Legacy back-compat. Don't add any more attributes here */
|
2009-07-17 22:08:33 +01:00
|
|
|
devaddr = virXMLPropString(cur, "devaddr");
|
2009-07-21 07:23:03 +02:00
|
|
|
} else if (encryption == NULL &&
|
|
|
|
xmlStrEqual(cur->name, BAD_CAST "encryption")) {
|
2010-02-10 11:42:56 +00:00
|
|
|
encryption = virStorageEncryptionParseNode(node->doc,
|
2009-07-21 07:23:03 +02:00
|
|
|
cur);
|
|
|
|
if (encryption == NULL)
|
|
|
|
goto error;
|
2009-08-14 12:22:01 +01:00
|
|
|
} else if ((serial == NULL) &&
|
|
|
|
(xmlStrEqual(cur->name, BAD_CAST "serial"))) {
|
|
|
|
serial = (char *)xmlNodeGetContent(cur);
|
2008-07-11 16:23:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
cur = cur->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
device = virXMLPropString(node, "device");
|
|
|
|
if (device) {
|
|
|
|
if ((def->device = virDomainDiskDeviceTypeFromString(device)) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
_("unknown disk device '%s'"), device);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
def->device = VIR_DOMAIN_DISK_DEVICE_DISK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Only CDROM and Floppy devices are allowed missing source path
|
|
|
|
* to indicate no media present */
|
|
|
|
if (source == NULL &&
|
|
|
|
def->device != VIR_DOMAIN_DISK_DEVICE_CDROM &&
|
|
|
|
def->device != VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_NO_SOURCE,
|
2008-07-11 16:23:36 +00:00
|
|
|
target ? "%s" : NULL, target);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (target == NULL) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_NO_TARGET,
|
2008-07-11 16:23:36 +00:00
|
|
|
source ? "%s" : NULL, source);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (def->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY &&
|
|
|
|
!STRPREFIX(target, "fd")) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
_("Invalid floppy device name: %s"), target);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Force CDROM to be listed as read only */
|
|
|
|
if (def->device == VIR_DOMAIN_DISK_DEVICE_CDROM)
|
|
|
|
def->readonly = 1;
|
|
|
|
|
|
|
|
if (def->device == VIR_DOMAIN_DISK_DEVICE_DISK &&
|
|
|
|
!STRPREFIX((const char *)target, "hd") &&
|
|
|
|
!STRPREFIX((const char *)target, "sd") &&
|
|
|
|
!STRPREFIX((const char *)target, "vd") &&
|
2008-11-19 16:58:23 +00:00
|
|
|
!STRPREFIX((const char *)target, "xvd") &&
|
|
|
|
!STRPREFIX((const char *)target, "ubd")) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
_("Invalid harddisk device name: %s"), target);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bus) {
|
|
|
|
if ((def->bus = virDomainDiskBusTypeFromString(bus)) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
_("unknown disk bus type '%s'"), bus);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (def->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
|
|
|
|
def->bus = VIR_DOMAIN_DISK_BUS_FDC;
|
|
|
|
} else {
|
|
|
|
if (STRPREFIX(target, "hd"))
|
|
|
|
def->bus = VIR_DOMAIN_DISK_BUS_IDE;
|
|
|
|
else if (STRPREFIX(target, "sd"))
|
|
|
|
def->bus = VIR_DOMAIN_DISK_BUS_SCSI;
|
|
|
|
else if (STRPREFIX(target, "vd"))
|
|
|
|
def->bus = VIR_DOMAIN_DISK_BUS_VIRTIO;
|
|
|
|
else if (STRPREFIX(target, "xvd"))
|
|
|
|
def->bus = VIR_DOMAIN_DISK_BUS_XEN;
|
2008-11-19 16:58:23 +00:00
|
|
|
else if (STRPREFIX(target, "ubd"))
|
|
|
|
def->bus = VIR_DOMAIN_DISK_BUS_UML;
|
2008-07-11 16:23:36 +00:00
|
|
|
else
|
|
|
|
def->bus = VIR_DOMAIN_DISK_BUS_IDE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (def->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY &&
|
|
|
|
def->bus != VIR_DOMAIN_DISK_BUS_FDC) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
_("Invalid bus type '%s' for floppy disk"), bus);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (def->device != VIR_DOMAIN_DISK_DEVICE_FLOPPY &&
|
|
|
|
def->bus == VIR_DOMAIN_DISK_BUS_FDC) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
_("Invalid bus type '%s' for disk"), bus);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2009-01-30 17:15:39 +00:00
|
|
|
if (cachetag &&
|
|
|
|
(def->cachemode = virDomainDiskCacheTypeFromString(cachetag)) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-01-30 17:15:39 +00:00
|
|
|
_("unknown disk cache mode '%s'"), cachetag);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2010-03-24 11:32:10 -04:00
|
|
|
if (error_policy &&
|
|
|
|
(def->error_policy = virDomainDiskErrorPolicyTypeFromString(error_policy)) < 0) {
|
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unknown disk error policy '%s'"), error_policy);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2009-11-30 18:35:58 +00:00
|
|
|
if (devaddr) {
|
2010-03-30 15:45:53 +02:00
|
|
|
if (virDomainParseLegacyDeviceAddress(devaddr,
|
|
|
|
&def->info.addr.pci) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-11-30 18:35:58 +00:00
|
|
|
_("Unable to parse devaddr parameter '%s'"),
|
|
|
|
devaddr);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
def->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
|
|
|
|
} else {
|
2010-02-09 18:58:01 +00:00
|
|
|
if (virDomainDeviceInfoParseXML(node, &def->info, flags) < 0)
|
2009-11-30 18:35:58 +00:00
|
|
|
goto error;
|
2009-07-17 22:08:33 +01:00
|
|
|
}
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
def->src = source;
|
|
|
|
source = NULL;
|
|
|
|
def->dst = target;
|
|
|
|
target = NULL;
|
|
|
|
def->driverName = driverName;
|
|
|
|
driverName = NULL;
|
|
|
|
def->driverType = driverType;
|
|
|
|
driverType = NULL;
|
2009-07-21 07:23:03 +02:00
|
|
|
def->encryption = encryption;
|
|
|
|
encryption = NULL;
|
2009-08-14 12:22:01 +01:00
|
|
|
def->serial = serial;
|
|
|
|
serial = NULL;
|
2008-07-11 16:23:36 +00:00
|
|
|
|
2010-03-15 21:42:01 +01:00
|
|
|
if (def->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE
|
|
|
|
&& virDomainDiskDefAssignAddress(def) < 0)
|
|
|
|
goto error;
|
2009-12-22 16:53:20 +00:00
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
cleanup:
|
|
|
|
VIR_FREE(bus);
|
|
|
|
VIR_FREE(type);
|
|
|
|
VIR_FREE(target);
|
|
|
|
VIR_FREE(source);
|
|
|
|
VIR_FREE(device);
|
|
|
|
VIR_FREE(driverType);
|
|
|
|
VIR_FREE(driverName);
|
2009-01-30 17:15:39 +00:00
|
|
|
VIR_FREE(cachetag);
|
2010-03-24 11:32:10 -04:00
|
|
|
VIR_FREE(error_policy);
|
2009-07-17 22:08:33 +01:00
|
|
|
VIR_FREE(devaddr);
|
2009-08-14 12:22:01 +01:00
|
|
|
VIR_FREE(serial);
|
2009-07-21 07:23:03 +02:00
|
|
|
virStorageEncryptionFree(encryption);
|
2008-07-11 16:23:36 +00:00
|
|
|
|
|
|
|
return def;
|
|
|
|
|
|
|
|
error:
|
|
|
|
virDomainDiskDefFree(def);
|
|
|
|
def = NULL;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-12-02 19:15:38 +00:00
|
|
|
/* Parse the XML definition for a controller
|
|
|
|
* @param node XML nodeset to parse for controller definition
|
|
|
|
*/
|
|
|
|
static virDomainControllerDefPtr
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainControllerDefParseXML(xmlNodePtr node,
|
2009-12-02 19:15:38 +00:00
|
|
|
int flags)
|
|
|
|
{
|
|
|
|
virDomainControllerDefPtr def;
|
|
|
|
char *type = NULL;
|
|
|
|
char *idx = NULL;
|
|
|
|
|
|
|
|
if (VIR_ALLOC(def) < 0) {
|
2010-02-04 19:19:08 +01:00
|
|
|
virReportOOMError();
|
2009-12-02 19:15:38 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
type = virXMLPropString(node, "type");
|
|
|
|
if (type) {
|
2010-02-18 17:52:03 +01:00
|
|
|
if ((def->type = virDomainControllerTypeFromString(type)) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2010-02-18 17:52:03 +01:00
|
|
|
_("Unknown controller type '%s'"), type);
|
2009-12-02 19:15:38 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
idx = virXMLPropString(node, "index");
|
|
|
|
if (idx) {
|
|
|
|
if (virStrToLong_i(idx, NULL, 10, &def->idx) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2010-02-18 17:52:03 +01:00
|
|
|
_("Cannot parse controller index %s"), idx);
|
2009-12-02 19:15:38 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-02-09 18:58:01 +00:00
|
|
|
if (virDomainDeviceInfoParseXML(node, &def->info, flags) < 0)
|
2009-12-02 19:15:38 +00:00
|
|
|
goto error;
|
|
|
|
|
2010-02-18 17:52:03 +01:00
|
|
|
switch (def->type) {
|
|
|
|
case VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL: {
|
|
|
|
char *ports = virXMLPropString(node, "ports");
|
|
|
|
if (ports) {
|
|
|
|
int r = virStrToLong_i(ports, NULL, 10,
|
|
|
|
&def->opts.vioserial.ports);
|
|
|
|
if (r != 0 || def->opts.vioserial.ports < 0) {
|
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Invalid ports: %s"), ports);
|
|
|
|
VIR_FREE(ports);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
def->opts.vioserial.ports = -1;
|
|
|
|
}
|
|
|
|
VIR_FREE(ports);
|
|
|
|
|
|
|
|
char *vectors = virXMLPropString(node, "vectors");
|
|
|
|
if (vectors) {
|
|
|
|
int r = virStrToLong_i(vectors, NULL, 10,
|
|
|
|
&def->opts.vioserial.vectors);
|
|
|
|
if (r != 0 || def->opts.vioserial.vectors < 0) {
|
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Invalid vectors: %s"), vectors);
|
|
|
|
VIR_FREE(vectors);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
def->opts.vioserial.vectors = -1;
|
|
|
|
}
|
|
|
|
VIR_FREE(vectors);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2009-12-02 19:15:38 +00:00
|
|
|
if (def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
|
|
|
|
def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
2010-02-18 17:52:03 +01:00
|
|
|
_("Controllers must use the 'pci' address type"));
|
2009-12-02 19:15:38 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(type);
|
|
|
|
VIR_FREE(idx);
|
|
|
|
|
|
|
|
return def;
|
|
|
|
|
|
|
|
error:
|
|
|
|
virDomainControllerDefFree(def);
|
|
|
|
def = NULL;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2008-08-01 13:31:37 +00:00
|
|
|
/* Parse the XML definition for a disk
|
|
|
|
* @param node XML nodeset to parse for disk definition
|
|
|
|
*/
|
|
|
|
static virDomainFSDefPtr
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainFSDefParseXML(xmlNodePtr node,
|
Add device info to serial, parallel, channel, input & fs devices
Although the serial, parallel, chanel, input & fs devices do
not have PCI address info, they can all have device aliases.
Thus it neccessary to associate the virDomainDeviceInfo data
with them all.
* src/conf/domain_conf.c, src/conf/domain_conf.h: Add hooks for
parsing / formatting device info for serial, parallel, channel
input and fs devices.
* docs/schemas/domain.rng: Associate device info with character
devices, input & fs device
2010-01-06 12:39:53 +00:00
|
|
|
int flags) {
|
2008-08-01 13:31:37 +00:00
|
|
|
virDomainFSDefPtr def;
|
|
|
|
xmlNodePtr cur;
|
|
|
|
char *type = NULL;
|
|
|
|
char *source = NULL;
|
|
|
|
char *target = NULL;
|
|
|
|
|
|
|
|
if (VIR_ALLOC(def) < 0) {
|
2010-02-04 19:19:08 +01:00
|
|
|
virReportOOMError();
|
2008-08-01 13:31:37 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
type = virXMLPropString(node, "type");
|
|
|
|
if (type) {
|
|
|
|
if ((def->type = virDomainFSTypeFromString(type)) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-08-01 13:31:37 +00:00
|
|
|
_("unknown filesystem type '%s'"), type);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
def->type = VIR_DOMAIN_FS_TYPE_MOUNT;
|
|
|
|
}
|
|
|
|
|
|
|
|
cur = node->children;
|
|
|
|
while (cur != NULL) {
|
|
|
|
if (cur->type == XML_ELEMENT_NODE) {
|
|
|
|
if ((source == NULL) &&
|
|
|
|
(xmlStrEqual(cur->name, BAD_CAST "source"))) {
|
|
|
|
|
|
|
|
if (def->type == VIR_DOMAIN_FS_TYPE_MOUNT)
|
|
|
|
source = virXMLPropString(cur, "dir");
|
|
|
|
else if (def->type == VIR_DOMAIN_FS_TYPE_FILE)
|
|
|
|
source = virXMLPropString(cur, "file");
|
|
|
|
else if (def->type == VIR_DOMAIN_FS_TYPE_BLOCK)
|
|
|
|
source = virXMLPropString(cur, "dev");
|
|
|
|
else if (def->type == VIR_DOMAIN_FS_TYPE_TEMPLATE)
|
|
|
|
source = virXMLPropString(cur, "name");
|
|
|
|
} else if ((target == NULL) &&
|
|
|
|
(xmlStrEqual(cur->name, BAD_CAST "target"))) {
|
|
|
|
target = virXMLPropString(cur, "dir");
|
|
|
|
} else if (xmlStrEqual(cur->name, BAD_CAST "readonly")) {
|
|
|
|
def->readonly = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
cur = cur->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (source == NULL) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_NO_SOURCE,
|
2008-08-01 13:31:37 +00:00
|
|
|
target ? "%s" : NULL, target);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (target == NULL) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_NO_TARGET,
|
2008-08-01 13:31:37 +00:00
|
|
|
source ? "%s" : NULL, source);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
def->src = source;
|
|
|
|
source = NULL;
|
|
|
|
def->dst = target;
|
|
|
|
target = NULL;
|
|
|
|
|
2010-02-09 18:58:01 +00:00
|
|
|
if (virDomainDeviceInfoParseXML(node, &def->info, flags) < 0)
|
Add device info to serial, parallel, channel, input & fs devices
Although the serial, parallel, chanel, input & fs devices do
not have PCI address info, they can all have device aliases.
Thus it neccessary to associate the virDomainDeviceInfo data
with them all.
* src/conf/domain_conf.c, src/conf/domain_conf.h: Add hooks for
parsing / formatting device info for serial, parallel, channel
input and fs devices.
* docs/schemas/domain.rng: Associate device info with character
devices, input & fs device
2010-01-06 12:39:53 +00:00
|
|
|
goto error;
|
|
|
|
|
2008-08-01 13:31:37 +00:00
|
|
|
cleanup:
|
|
|
|
VIR_FREE(type);
|
|
|
|
VIR_FREE(target);
|
|
|
|
VIR_FREE(source);
|
|
|
|
|
|
|
|
return def;
|
|
|
|
|
|
|
|
error:
|
|
|
|
virDomainFSDefFree(def);
|
|
|
|
def = NULL;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-03-31 10:22:10 -04:00
|
|
|
static bool
|
|
|
|
isValidIfname(const char *ifname) {
|
2010-04-02 14:57:01 -04:00
|
|
|
return ifname[strspn(ifname, VALID_IFNAME_CHARS)] == 0;
|
2010-03-31 10:22:10 -04:00
|
|
|
}
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
|
|
|
|
/* Parse the XML definition for a network interface
|
|
|
|
* @param node XML nodeset to parse for net definition
|
|
|
|
* @return 0 on success, -1 on failure
|
|
|
|
*/
|
2008-10-24 11:20:08 +00:00
|
|
|
static virDomainNetDefPtr
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainNetDefParseXML(virCapsPtr caps,
|
2009-01-08 13:54:20 +00:00
|
|
|
xmlNodePtr node,
|
|
|
|
int flags ATTRIBUTE_UNUSED) {
|
2008-07-11 16:23:36 +00:00
|
|
|
virDomainNetDefPtr def;
|
|
|
|
xmlNodePtr cur;
|
|
|
|
char *macaddr = NULL;
|
|
|
|
char *type = NULL;
|
|
|
|
char *network = NULL;
|
|
|
|
char *bridge = NULL;
|
|
|
|
char *dev = NULL;
|
|
|
|
char *ifname = NULL;
|
|
|
|
char *script = NULL;
|
|
|
|
char *address = NULL;
|
|
|
|
char *port = NULL;
|
|
|
|
char *model = NULL;
|
2010-03-25 13:46:07 -04:00
|
|
|
char *filter = NULL;
|
2009-05-11 09:50:27 +00:00
|
|
|
char *internal = NULL;
|
2009-07-17 22:08:34 +01:00
|
|
|
char *devaddr = NULL;
|
2010-02-12 18:07:06 +01:00
|
|
|
char *mode = NULL;
|
2010-03-25 13:46:07 -04:00
|
|
|
virNWFilterHashTablePtr filterparams = NULL;
|
2008-07-11 16:23:36 +00:00
|
|
|
|
|
|
|
if (VIR_ALLOC(def) < 0) {
|
2010-02-04 19:19:08 +01:00
|
|
|
virReportOOMError();
|
2008-07-11 16:23:36 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
type = virXMLPropString(node, "type");
|
|
|
|
if (type != NULL) {
|
2010-03-26 17:01:35 +01:00
|
|
|
if ((int)(def->type = virDomainNetTypeFromString(type)) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
_("unknown interface type '%s'"), type);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
def->type = VIR_DOMAIN_NET_TYPE_USER;
|
|
|
|
}
|
|
|
|
|
|
|
|
cur = node->children;
|
|
|
|
while (cur != NULL) {
|
|
|
|
if (cur->type == XML_ELEMENT_NODE) {
|
|
|
|
if ((macaddr == NULL) &&
|
|
|
|
(xmlStrEqual(cur->name, BAD_CAST "mac"))) {
|
|
|
|
macaddr = virXMLPropString(cur, "address");
|
|
|
|
} else if ((network == NULL) &&
|
|
|
|
(def->type == VIR_DOMAIN_NET_TYPE_NETWORK) &&
|
|
|
|
(xmlStrEqual(cur->name, BAD_CAST "source"))) {
|
|
|
|
network = virXMLPropString(cur, "network");
|
2009-05-11 09:50:27 +00:00
|
|
|
} else if ((internal == NULL) &&
|
|
|
|
(def->type == VIR_DOMAIN_NET_TYPE_INTERNAL) &&
|
|
|
|
(xmlStrEqual(cur->name, BAD_CAST "source"))) {
|
|
|
|
internal = virXMLPropString(cur, "name");
|
2008-07-11 16:23:36 +00:00
|
|
|
} else if ((network == NULL) &&
|
|
|
|
(def->type == VIR_DOMAIN_NET_TYPE_BRIDGE) &&
|
|
|
|
(xmlStrEqual(cur->name, BAD_CAST "source"))) {
|
|
|
|
bridge = virXMLPropString(cur, "bridge");
|
|
|
|
} else if ((dev == NULL) &&
|
2010-02-12 18:07:06 +01:00
|
|
|
(def->type == VIR_DOMAIN_NET_TYPE_ETHERNET ||
|
|
|
|
def->type == VIR_DOMAIN_NET_TYPE_DIRECT) &&
|
2008-07-11 16:23:36 +00:00
|
|
|
xmlStrEqual(cur->name, BAD_CAST "source")) {
|
2010-02-12 18:07:06 +01:00
|
|
|
dev = virXMLPropString(cur, "dev");
|
|
|
|
mode = virXMLPropString(cur, "mode");
|
2008-07-11 16:23:36 +00:00
|
|
|
} else if ((network == NULL) &&
|
|
|
|
((def->type == VIR_DOMAIN_NET_TYPE_SERVER) ||
|
|
|
|
(def->type == VIR_DOMAIN_NET_TYPE_CLIENT) ||
|
|
|
|
(def->type == VIR_DOMAIN_NET_TYPE_MCAST)) &&
|
|
|
|
(xmlStrEqual(cur->name, BAD_CAST "source"))) {
|
|
|
|
address = virXMLPropString(cur, "address");
|
|
|
|
port = virXMLPropString(cur, "port");
|
|
|
|
} else if ((address == NULL) &&
|
2009-01-23 01:48:47 +00:00
|
|
|
(def->type == VIR_DOMAIN_NET_TYPE_ETHERNET ||
|
|
|
|
def->type == VIR_DOMAIN_NET_TYPE_BRIDGE) &&
|
2008-07-11 16:23:36 +00:00
|
|
|
(xmlStrEqual(cur->name, BAD_CAST "ip"))) {
|
|
|
|
address = virXMLPropString(cur, "address");
|
|
|
|
} else if ((ifname == NULL) &&
|
|
|
|
xmlStrEqual(cur->name, BAD_CAST "target")) {
|
|
|
|
ifname = virXMLPropString(cur, "dev");
|
2009-10-01 11:54:38 +02:00
|
|
|
if ((ifname != NULL) &&
|
2010-03-31 10:22:10 -04:00
|
|
|
((STRPREFIX((const char*)ifname, "vnet")) ||
|
|
|
|
(!isValidIfname(ifname)))) {
|
2008-07-11 16:23:36 +00:00
|
|
|
/* An auto-generated target name, blank it out */
|
2010-03-31 10:22:10 -04:00
|
|
|
/* blank out invalid interface names */
|
2008-07-11 16:23:36 +00:00
|
|
|
VIR_FREE(ifname);
|
|
|
|
}
|
|
|
|
} else if ((script == NULL) &&
|
2009-01-22 18:29:13 +00:00
|
|
|
(def->type == VIR_DOMAIN_NET_TYPE_ETHERNET ||
|
|
|
|
def->type == VIR_DOMAIN_NET_TYPE_BRIDGE) &&
|
2008-07-11 16:23:36 +00:00
|
|
|
xmlStrEqual(cur->name, BAD_CAST "script")) {
|
|
|
|
script = virXMLPropString(cur, "path");
|
|
|
|
} else if (xmlStrEqual (cur->name, BAD_CAST "model")) {
|
|
|
|
model = virXMLPropString(cur, "type");
|
2010-03-25 13:46:07 -04:00
|
|
|
} else if (xmlStrEqual (cur->name, BAD_CAST "filterref")) {
|
|
|
|
filter = virXMLPropString(cur, "filter");
|
|
|
|
filterparams = virNWFilterParseParamAttributes(cur);
|
2009-07-17 22:08:34 +01:00
|
|
|
} else if ((flags & VIR_DOMAIN_XML_INTERNAL_STATUS) &&
|
|
|
|
xmlStrEqual(cur->name, BAD_CAST "state")) {
|
2009-11-30 18:35:58 +00:00
|
|
|
/* Legacy back-compat. Don't add any more attributes here */
|
2009-07-17 22:08:34 +01:00
|
|
|
devaddr = virXMLPropString(cur, "devaddr");
|
2008-07-11 16:23:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
cur = cur->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (macaddr) {
|
2009-10-16 11:09:13 +01:00
|
|
|
if (virParseMacAddr((const char *)macaddr, def->mac) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-10-16 11:09:13 +01:00
|
|
|
_("unable to parse mac address '%s'"),
|
|
|
|
(const char *)macaddr);
|
|
|
|
goto error;
|
|
|
|
}
|
2008-07-11 16:23:36 +00:00
|
|
|
} else {
|
2008-10-24 11:20:08 +00:00
|
|
|
virCapabilitiesGenerateMac(caps, def->mac);
|
2008-07-11 16:23:36 +00:00
|
|
|
}
|
|
|
|
|
2009-11-30 18:35:58 +00:00
|
|
|
if (devaddr) {
|
2010-03-30 15:45:53 +02:00
|
|
|
if (virDomainParseLegacyDeviceAddress(devaddr,
|
|
|
|
&def->info.addr.pci) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-11-30 18:35:58 +00:00
|
|
|
_("Unable to parse devaddr parameter '%s'"),
|
|
|
|
devaddr);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
def->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
|
|
|
|
} else {
|
2010-02-09 18:58:01 +00:00
|
|
|
if (virDomainDeviceInfoParseXML(node, &def->info, flags) < 0)
|
2009-11-30 18:35:58 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX what about ISA/USB based NIC models - once we support
|
|
|
|
* them we should make sure address type is correct */
|
|
|
|
if (def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
|
|
|
|
def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
2009-11-30 18:35:58 +00:00
|
|
|
_("Network interfaces must use 'pci' address type"));
|
2009-07-17 22:08:34 +01:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
switch (def->type) {
|
|
|
|
case VIR_DOMAIN_NET_TYPE_NETWORK:
|
|
|
|
if (network == NULL) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
2009-01-07 12:56:13 +00:00
|
|
|
_("No <source> 'network' attribute specified with <interface type='network'/>"));
|
2008-07-11 16:23:36 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
def->data.network.name = network;
|
|
|
|
network = NULL;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_NET_TYPE_ETHERNET:
|
|
|
|
|
|
|
|
if (script != NULL) {
|
|
|
|
def->data.ethernet.script = script;
|
|
|
|
script = NULL;
|
|
|
|
}
|
|
|
|
if (dev != NULL) {
|
|
|
|
def->data.ethernet.dev = dev;
|
|
|
|
dev = NULL;
|
|
|
|
}
|
|
|
|
if (address != NULL) {
|
|
|
|
def->data.ethernet.ipaddr = address;
|
|
|
|
address = NULL;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_NET_TYPE_BRIDGE:
|
|
|
|
if (bridge == NULL) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
2009-09-30 18:51:30 +02:00
|
|
|
_("No <source> 'bridge' attribute specified with <interface type='bridge'/>"));
|
2008-07-11 16:23:36 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
def->data.bridge.brname = bridge;
|
|
|
|
bridge = NULL;
|
2009-01-22 18:29:13 +00:00
|
|
|
if (script != NULL) {
|
|
|
|
def->data.bridge.script = script;
|
|
|
|
script = NULL;
|
|
|
|
}
|
2009-01-23 01:48:47 +00:00
|
|
|
if (address != NULL) {
|
|
|
|
def->data.bridge.ipaddr = address;
|
|
|
|
address = NULL;
|
|
|
|
}
|
2008-07-11 16:23:36 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_NET_TYPE_CLIENT:
|
|
|
|
case VIR_DOMAIN_NET_TYPE_SERVER:
|
|
|
|
case VIR_DOMAIN_NET_TYPE_MCAST:
|
|
|
|
if (port == NULL) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
2009-01-07 12:56:13 +00:00
|
|
|
_("No <source> 'port' attribute specified with socket interface"));
|
2008-07-11 16:23:36 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (virStrToLong_i(port, NULL, 10, &def->data.socket.port) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
2009-01-07 12:56:13 +00:00
|
|
|
_("Cannot parse <source> 'port' attribute with socket interface"));
|
2008-07-11 16:23:36 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (address == NULL) {
|
|
|
|
if (def->type == VIR_DOMAIN_NET_TYPE_CLIENT ||
|
|
|
|
def->type == VIR_DOMAIN_NET_TYPE_MCAST) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
2009-01-07 12:56:13 +00:00
|
|
|
_("No <source> 'address' attribute specified with socket interface"));
|
2008-07-11 16:23:36 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
def->data.socket.address = address;
|
|
|
|
address = NULL;
|
|
|
|
}
|
2009-05-29 13:26:45 +00:00
|
|
|
break;
|
|
|
|
|
2009-05-11 09:50:27 +00:00
|
|
|
case VIR_DOMAIN_NET_TYPE_INTERNAL:
|
|
|
|
if (internal == NULL) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
2009-05-11 09:50:27 +00:00
|
|
|
_("No <source> 'name' attribute specified with <interface type='internal'/>"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
def->data.internal.name = internal;
|
|
|
|
internal = NULL;
|
|
|
|
break;
|
2010-02-12 18:07:06 +01:00
|
|
|
|
|
|
|
case VIR_DOMAIN_NET_TYPE_DIRECT:
|
|
|
|
if (dev == NULL) {
|
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("No <source> 'dev' attribute specified with <interface type='direct'/>"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mode != NULL) {
|
|
|
|
int m;
|
|
|
|
if ((m = virDomainNetdevMacvtapTypeFromString(mode)) < 0) {
|
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Unkown mode has been specified"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
def->data.direct.mode = m;
|
|
|
|
} else
|
|
|
|
def->data.direct.mode = VIR_DOMAIN_NETDEV_MACVTAP_MODE_VEPA;
|
|
|
|
|
|
|
|
def->data.direct.linkdev = dev;
|
|
|
|
dev = NULL;
|
|
|
|
|
|
|
|
break;
|
2010-03-26 17:01:35 +01:00
|
|
|
|
|
|
|
case VIR_DOMAIN_NET_TYPE_USER:
|
|
|
|
case VIR_DOMAIN_NET_TYPE_LAST:
|
|
|
|
break;
|
2008-07-11 16:23:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ifname != NULL) {
|
|
|
|
def->ifname = ifname;
|
|
|
|
ifname = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* NIC model (see -net nic,model=?). We only check that it looks
|
|
|
|
* reasonable, not that it is a supported NIC type. FWIW kvm
|
|
|
|
* supports these types as of April 2008:
|
|
|
|
* i82551 i82557b i82559er ne2k_pci pcnet rtl8139 e1000 virtio
|
|
|
|
*/
|
|
|
|
if (model != NULL) {
|
|
|
|
int i;
|
|
|
|
for (i = 0 ; i < strlen(model) ; i++) {
|
|
|
|
int char_ok = c_isalnum(model[i]) || model[i] == '_';
|
|
|
|
if (!char_ok) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INVALID_ARG, "%s",
|
|
|
|
_("Model name contains invalid characters"));
|
2008-07-11 16:23:36 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
def->model = model;
|
|
|
|
model = NULL;
|
|
|
|
}
|
|
|
|
|
2010-03-25 13:46:07 -04:00
|
|
|
if (filter != NULL) {
|
|
|
|
switch (def->type) {
|
|
|
|
case VIR_DOMAIN_NET_TYPE_ETHERNET:
|
|
|
|
case VIR_DOMAIN_NET_TYPE_NETWORK:
|
|
|
|
case VIR_DOMAIN_NET_TYPE_BRIDGE:
|
|
|
|
case VIR_DOMAIN_NET_TYPE_DIRECT:
|
|
|
|
def->filter = filter;
|
|
|
|
filter = NULL;
|
|
|
|
def->filterparams = filterparams;
|
|
|
|
filterparams = NULL;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
cleanup:
|
|
|
|
VIR_FREE(macaddr);
|
|
|
|
VIR_FREE(network);
|
|
|
|
VIR_FREE(address);
|
|
|
|
VIR_FREE(port);
|
|
|
|
VIR_FREE(ifname);
|
|
|
|
VIR_FREE(dev);
|
|
|
|
VIR_FREE(script);
|
|
|
|
VIR_FREE(bridge);
|
|
|
|
VIR_FREE(model);
|
2010-03-25 13:46:07 -04:00
|
|
|
VIR_FREE(filter);
|
2008-07-11 16:23:36 +00:00
|
|
|
VIR_FREE(type);
|
2009-05-11 09:50:27 +00:00
|
|
|
VIR_FREE(internal);
|
2009-07-17 22:08:34 +01:00
|
|
|
VIR_FREE(devaddr);
|
2010-03-01 13:09:42 +01:00
|
|
|
VIR_FREE(mode);
|
2010-03-25 13:46:07 -04:00
|
|
|
virNWFilterHashTableFree(filterparams);
|
2008-07-11 16:23:36 +00:00
|
|
|
|
|
|
|
return def;
|
|
|
|
|
|
|
|
error:
|
|
|
|
virDomainNetDefFree(def);
|
|
|
|
def = NULL;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 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"/>
|
2009-07-08 17:59:23 -04:00
|
|
|
* <protocol type='raw'/>
|
2008-07-11 16:23:36 +00:00
|
|
|
* </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
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainChrDefParseXML(xmlNodePtr node,
|
Add device info to serial, parallel, channel, input & fs devices
Although the serial, parallel, chanel, input & fs devices do
not have PCI address info, they can all have device aliases.
Thus it neccessary to associate the virDomainDeviceInfo data
with them all.
* src/conf/domain_conf.c, src/conf/domain_conf.h: Add hooks for
parsing / formatting device info for serial, parallel, channel
input and fs devices.
* docs/schemas/domain.rng: Associate device info with character
devices, input & fs device
2010-01-06 12:39:53 +00:00
|
|
|
int flags) {
|
2008-07-11 16:23:36 +00:00
|
|
|
xmlNodePtr cur;
|
|
|
|
char *type = NULL;
|
|
|
|
char *bindHost = NULL;
|
|
|
|
char *bindService = NULL;
|
|
|
|
char *connectHost = NULL;
|
|
|
|
char *connectService = NULL;
|
|
|
|
char *path = NULL;
|
|
|
|
char *mode = NULL;
|
|
|
|
char *protocol = NULL;
|
2009-11-05 15:31:03 +01:00
|
|
|
const char *nodeName;
|
2009-11-05 14:19:14 +01:00
|
|
|
const char *targetType = NULL;
|
2009-11-05 15:31:03 +01:00
|
|
|
const char *addrStr = NULL;
|
|
|
|
const char *portStr = NULL;
|
2008-07-11 16:23:36 +00:00
|
|
|
virDomainChrDefPtr def;
|
|
|
|
|
|
|
|
if (VIR_ALLOC(def) < 0) {
|
2010-02-04 19:19:08 +01:00
|
|
|
virReportOOMError();
|
2008-07-11 16:23:36 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
type = virXMLPropString(node, "type");
|
2009-07-10 09:33:34 +01:00
|
|
|
if (type == NULL)
|
|
|
|
def->type = VIR_DOMAIN_CHR_TYPE_PTY;
|
|
|
|
else if ((def->type = virDomainChrTypeFromString(type)) < 0)
|
|
|
|
def->type = VIR_DOMAIN_CHR_TYPE_NULL;
|
2008-07-11 16:23:36 +00:00
|
|
|
|
2009-11-05 15:31:03 +01:00
|
|
|
nodeName = (const char *) node->name;
|
|
|
|
if ((def->targetType = virDomainChrTargetTypeFromString(nodeName)) < 0) {
|
|
|
|
/* channel is handled below */
|
2009-11-05 16:04:34 +01:00
|
|
|
if (STRNEQ(nodeName, "channel")) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_XML_ERROR,
|
2009-11-05 15:31:03 +01:00
|
|
|
_("unknown target type for character device: %s"),
|
|
|
|
nodeName);
|
2010-02-04 12:49:53 +01:00
|
|
|
VIR_FREE(def);
|
2009-11-05 15:31:03 +01:00
|
|
|
return NULL;
|
|
|
|
}
|
2009-11-05 14:19:14 +01:00
|
|
|
def->targetType = VIR_DOMAIN_CHR_TARGET_TYPE_NULL;
|
|
|
|
}
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
cur = node->children;
|
|
|
|
while (cur != NULL) {
|
|
|
|
if (cur->type == XML_ELEMENT_NODE) {
|
|
|
|
if (xmlStrEqual(cur->name, BAD_CAST "source")) {
|
|
|
|
if (mode == NULL)
|
|
|
|
mode = virXMLPropString(cur, "mode");
|
|
|
|
|
|
|
|
switch (def->type) {
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_PTY:
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_DEV:
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_FILE:
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_PIPE:
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_UNIX:
|
|
|
|
if (path == NULL)
|
|
|
|
path = virXMLPropString(cur, "path");
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_UDP:
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_TCP:
|
|
|
|
if (mode == NULL ||
|
|
|
|
STREQ((const char *)mode, "connect")) {
|
|
|
|
|
|
|
|
if (connectHost == NULL)
|
|
|
|
connectHost = virXMLPropString(cur, "host");
|
|
|
|
if (connectService == NULL)
|
|
|
|
connectService = virXMLPropString(cur, "service");
|
2009-07-08 17:59:23 -04:00
|
|
|
} else if (STREQ((const char *)mode, "bind")) {
|
2008-07-11 16:23:36 +00:00
|
|
|
if (bindHost == NULL)
|
|
|
|
bindHost = virXMLPropString(cur, "host");
|
|
|
|
if (bindService == NULL)
|
|
|
|
bindService = virXMLPropString(cur, "service");
|
2009-07-08 17:59:23 -04:00
|
|
|
} else {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-07-08 17:59:23 -04:00
|
|
|
_("Unknown source mode '%s'"),
|
|
|
|
mode);
|
|
|
|
goto error;
|
2008-07-11 16:23:36 +00:00
|
|
|
}
|
|
|
|
|
2008-07-19 07:42:34 +00:00
|
|
|
if (def->type == VIR_DOMAIN_CHR_TYPE_UDP)
|
2008-07-11 16:23:36 +00:00
|
|
|
VIR_FREE(mode);
|
|
|
|
}
|
|
|
|
} else if (xmlStrEqual(cur->name, BAD_CAST "protocol")) {
|
|
|
|
if (protocol == NULL)
|
|
|
|
protocol = virXMLPropString(cur, "type");
|
2009-11-05 15:31:03 +01:00
|
|
|
} else if (xmlStrEqual(cur->name, BAD_CAST "target")) {
|
|
|
|
/* If target type isn't set yet, expect it to be set here */
|
2009-11-05 16:04:34 +01:00
|
|
|
if (def->targetType == VIR_DOMAIN_CHR_TARGET_TYPE_NULL) {
|
2009-11-05 15:31:03 +01:00
|
|
|
targetType = virXMLPropString(cur, "type");
|
2009-11-05 16:04:34 +01:00
|
|
|
if (targetType == NULL) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_XML_ERROR, "%s",
|
2009-11-05 15:31:03 +01:00
|
|
|
_("character device target does "
|
|
|
|
"not define a type"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if ((def->targetType =
|
|
|
|
virDomainChrTargetTypeFromString(targetType)) < 0)
|
|
|
|
{
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_XML_ERROR,
|
2009-11-05 15:31:03 +01:00
|
|
|
_("unknown target type for "
|
|
|
|
"character device: %s"),
|
|
|
|
targetType);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int port;
|
|
|
|
switch (def->targetType) {
|
|
|
|
case VIR_DOMAIN_CHR_TARGET_TYPE_PARALLEL:
|
|
|
|
case VIR_DOMAIN_CHR_TARGET_TYPE_SERIAL:
|
|
|
|
case VIR_DOMAIN_CHR_TARGET_TYPE_CONSOLE:
|
|
|
|
portStr = virXMLPropString(cur, "port");
|
2009-11-05 16:04:34 +01:00
|
|
|
if (portStr == NULL) {
|
2009-11-05 15:31:03 +01:00
|
|
|
/* Not required. It will be assigned automatically
|
|
|
|
* later */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2009-11-05 16:04:34 +01:00
|
|
|
if (virStrToLong_ui(portStr, NULL, 10, &port) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_XML_ERROR,
|
2009-11-05 15:31:03 +01:00
|
|
|
_("Invalid port number: %s"),
|
|
|
|
portStr);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_TARGET_TYPE_GUESTFWD:
|
|
|
|
addrStr = virXMLPropString(cur, "address");
|
|
|
|
portStr = virXMLPropString(cur, "port");
|
|
|
|
|
2009-11-05 16:04:34 +01:00
|
|
|
if (addrStr == NULL) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_XML_ERROR, "%s",
|
2009-11-05 15:31:03 +01:00
|
|
|
_("guestfwd channel does not "
|
|
|
|
"define a target address"));
|
|
|
|
goto error;
|
|
|
|
}
|
2009-11-05 16:04:34 +01:00
|
|
|
if (VIR_ALLOC(def->target.addr) < 0) {
|
2010-02-04 19:19:08 +01:00
|
|
|
virReportOOMError();
|
2009-11-05 15:31:03 +01:00
|
|
|
goto error;
|
|
|
|
}
|
2009-11-05 16:04:34 +01:00
|
|
|
if (virSocketParseAddr(addrStr, def->target.addr, 0) < 0)
|
2009-11-05 15:31:03 +01:00
|
|
|
{
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_XML_ERROR,
|
2009-11-05 15:31:03 +01:00
|
|
|
_("%s is not a valid address"),
|
|
|
|
addrStr);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2009-11-05 16:04:34 +01:00
|
|
|
if (def->target.addr->stor.ss_family != AF_INET) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
2009-11-05 16:04:34 +01:00
|
|
|
"%s", _("guestfwd channel only supports "
|
|
|
|
"IPv4 addresses"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (portStr == NULL) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_XML_ERROR, "%s",
|
2009-11-05 15:31:03 +01:00
|
|
|
_("guestfwd channel does "
|
|
|
|
"not define a target port"));
|
|
|
|
goto error;
|
|
|
|
}
|
2009-11-05 16:04:34 +01:00
|
|
|
if (virStrToLong_ui(portStr, NULL, 10, &port) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_XML_ERROR,
|
2009-11-05 15:31:03 +01:00
|
|
|
_("Invalid port number: %s"),
|
|
|
|
portStr);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
virSocketSetPort(def->target.addr, port);
|
|
|
|
break;
|
|
|
|
|
2010-02-18 17:52:03 +01:00
|
|
|
case VIR_DOMAIN_CHR_TARGET_TYPE_VIRTIO:
|
|
|
|
def->target.name = virXMLPropString(cur, "name");
|
|
|
|
break;
|
|
|
|
|
2009-11-05 15:31:03 +01:00
|
|
|
default:
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_XML_ERROR,
|
2009-11-05 15:31:03 +01:00
|
|
|
_("unexpected target type type %u"),
|
|
|
|
def->targetType);
|
|
|
|
}
|
2008-07-11 16:23:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
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:
|
2008-08-20 20:55:32 +00:00
|
|
|
if (path == NULL &&
|
|
|
|
def->type != VIR_DOMAIN_CHR_TYPE_PTY) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
2009-01-07 12:56:13 +00:00
|
|
|
_("Missing source path attribute for char device"));
|
2008-07-11 16:23:36 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
def->data.file.path = path;
|
|
|
|
path = NULL;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_STDIO:
|
|
|
|
/* Nada */
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_TCP:
|
|
|
|
if (mode == NULL ||
|
|
|
|
STREQ(mode, "connect")) {
|
|
|
|
if (connectHost == NULL) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
2009-01-07 12:56:13 +00:00
|
|
|
_("Missing source host attribute for char device"));
|
2008-07-11 16:23:36 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (connectService == NULL) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
2009-01-07 12:56:13 +00:00
|
|
|
_("Missing source service attribute for char device"));
|
2008-07-11 16:23:36 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
def->data.tcp.host = connectHost;
|
|
|
|
connectHost = NULL;
|
|
|
|
def->data.tcp.service = connectService;
|
|
|
|
connectService = NULL;
|
|
|
|
def->data.tcp.listen = 0;
|
|
|
|
} else {
|
|
|
|
if (bindHost == NULL) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
2009-01-07 12:56:13 +00:00
|
|
|
_("Missing source host attribute for char device"));
|
2008-07-11 16:23:36 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (bindService == NULL) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
2009-01-07 12:56:13 +00:00
|
|
|
_("Missing source service attribute for char device"));
|
2008-07-11 16:23:36 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
def->data.tcp.host = bindHost;
|
|
|
|
bindHost = NULL;
|
|
|
|
def->data.tcp.service = bindService;
|
|
|
|
bindService = NULL;
|
|
|
|
def->data.tcp.listen = 1;
|
|
|
|
}
|
2009-07-08 17:59:23 -04:00
|
|
|
|
|
|
|
if (protocol == NULL ||
|
|
|
|
STREQ(protocol, "raw"))
|
2008-07-11 16:23:36 +00:00
|
|
|
def->data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_RAW;
|
2009-07-08 17:59:23 -04:00
|
|
|
else if (STREQ(protocol, "telnet"))
|
|
|
|
def->data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET;
|
|
|
|
else {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-07-08 17:59:23 -04:00
|
|
|
_("Unknown protocol '%s'"), protocol);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_UDP:
|
|
|
|
if (connectService == NULL) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
2009-01-07 12:56:13 +00:00
|
|
|
_("Missing source service attribute for char device"));
|
2008-07-11 16:23:36 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
def->data.udp.connectHost = connectHost;
|
|
|
|
connectHost = NULL;
|
|
|
|
def->data.udp.connectService = connectService;
|
|
|
|
connectService = NULL;
|
|
|
|
|
|
|
|
def->data.udp.bindHost = bindHost;
|
|
|
|
bindHost = NULL;
|
|
|
|
def->data.udp.bindService = bindService;
|
|
|
|
bindService = NULL;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_UNIX:
|
|
|
|
if (path == NULL) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
2009-01-07 12:56:13 +00:00
|
|
|
_("Missing source path attribute for char device"));
|
2008-07-11 16:23:36 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mode != NULL &&
|
|
|
|
STRNEQ(mode, "connect"))
|
|
|
|
def->data.nix.listen = 1;
|
|
|
|
else
|
|
|
|
def->data.nix.listen = 0;
|
|
|
|
|
|
|
|
def->data.nix.path = path;
|
|
|
|
path = NULL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-02-09 18:58:01 +00:00
|
|
|
if (virDomainDeviceInfoParseXML(node, &def->info, flags) < 0)
|
Add device info to serial, parallel, channel, input & fs devices
Although the serial, parallel, chanel, input & fs devices do
not have PCI address info, they can all have device aliases.
Thus it neccessary to associate the virDomainDeviceInfo data
with them all.
* src/conf/domain_conf.c, src/conf/domain_conf.h: Add hooks for
parsing / formatting device info for serial, parallel, channel
input and fs devices.
* docs/schemas/domain.rng: Associate device info with character
devices, input & fs device
2010-01-06 12:39:53 +00:00
|
|
|
goto error;
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
cleanup:
|
|
|
|
VIR_FREE(mode);
|
|
|
|
VIR_FREE(protocol);
|
|
|
|
VIR_FREE(type);
|
|
|
|
VIR_FREE(bindHost);
|
|
|
|
VIR_FREE(bindService);
|
|
|
|
VIR_FREE(connectHost);
|
|
|
|
VIR_FREE(connectService);
|
|
|
|
VIR_FREE(path);
|
2009-11-05 15:31:03 +01:00
|
|
|
VIR_FREE(targetType);
|
|
|
|
VIR_FREE(addrStr);
|
|
|
|
VIR_FREE(portStr);
|
2008-07-11 16:23:36 +00:00
|
|
|
|
|
|
|
return def;
|
|
|
|
|
|
|
|
error:
|
|
|
|
virDomainChrDefFree(def);
|
|
|
|
def = NULL;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Parse the XML definition for a network interface */
|
|
|
|
static virDomainInputDefPtr
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainInputDefParseXML(const char *ostype,
|
2009-01-08 13:54:20 +00:00
|
|
|
xmlNodePtr node,
|
Add device info to serial, parallel, channel, input & fs devices
Although the serial, parallel, chanel, input & fs devices do
not have PCI address info, they can all have device aliases.
Thus it neccessary to associate the virDomainDeviceInfo data
with them all.
* src/conf/domain_conf.c, src/conf/domain_conf.h: Add hooks for
parsing / formatting device info for serial, parallel, channel
input and fs devices.
* docs/schemas/domain.rng: Associate device info with character
devices, input & fs device
2010-01-06 12:39:53 +00:00
|
|
|
int flags) {
|
2008-07-11 16:23:36 +00:00
|
|
|
virDomainInputDefPtr def;
|
|
|
|
char *type = NULL;
|
|
|
|
char *bus = NULL;
|
|
|
|
|
|
|
|
if (VIR_ALLOC(def) < 0) {
|
2010-02-04 19:19:08 +01:00
|
|
|
virReportOOMError();
|
2008-07-11 16:23:36 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
type = virXMLPropString(node, "type");
|
|
|
|
bus = virXMLPropString(node, "bus");
|
|
|
|
|
|
|
|
if (!type) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
"%s", _("missing input device type"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((def->type = virDomainInputTypeFromString(type)) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
_("unknown input device type '%s'"), type);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bus) {
|
|
|
|
if ((def->bus = virDomainInputBusTypeFromString(bus)) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
_("unknown input bus type '%s'"), bus);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (STREQ(ostype, "hvm")) {
|
|
|
|
if (def->bus == VIR_DOMAIN_INPUT_BUS_PS2 && /* Only allow mouse for ps2 */
|
|
|
|
def->type != VIR_DOMAIN_INPUT_TYPE_MOUSE) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-01-07 12:56:13 +00:00
|
|
|
_("ps2 bus does not support %s input device"),
|
2008-07-11 16:23:36 +00:00
|
|
|
type);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (def->bus == VIR_DOMAIN_INPUT_BUS_XEN) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
_("unsupported input bus %s"),
|
|
|
|
bus);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (def->bus != VIR_DOMAIN_INPUT_BUS_XEN) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
_("unsupported input bus %s"),
|
|
|
|
bus);
|
|
|
|
}
|
|
|
|
if (def->type != VIR_DOMAIN_INPUT_TYPE_MOUSE) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-01-07 12:56:13 +00:00
|
|
|
_("xen bus does not support %s input device"),
|
2008-07-11 16:23:36 +00:00
|
|
|
type);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (STREQ(ostype, "hvm")) {
|
|
|
|
if (def->type == VIR_DOMAIN_INPUT_TYPE_MOUSE)
|
|
|
|
def->bus = VIR_DOMAIN_INPUT_BUS_PS2;
|
|
|
|
else
|
|
|
|
def->bus = VIR_DOMAIN_INPUT_BUS_USB;
|
|
|
|
} else {
|
|
|
|
def->bus = VIR_DOMAIN_INPUT_BUS_XEN;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-02-09 18:58:01 +00:00
|
|
|
if (virDomainDeviceInfoParseXML(node, &def->info, flags) < 0)
|
Add device info to serial, parallel, channel, input & fs devices
Although the serial, parallel, chanel, input & fs devices do
not have PCI address info, they can all have device aliases.
Thus it neccessary to associate the virDomainDeviceInfo data
with them all.
* src/conf/domain_conf.c, src/conf/domain_conf.h: Add hooks for
parsing / formatting device info for serial, parallel, channel
input and fs devices.
* docs/schemas/domain.rng: Associate device info with character
devices, input & fs device
2010-01-06 12:39:53 +00:00
|
|
|
goto error;
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
cleanup:
|
|
|
|
VIR_FREE(type);
|
|
|
|
VIR_FREE(bus);
|
|
|
|
|
|
|
|
return def;
|
|
|
|
|
|
|
|
error:
|
|
|
|
virDomainInputDefFree(def);
|
|
|
|
def = NULL;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-03-30 13:44:22 +02:00
|
|
|
/* Parse the XML definition for a clock timer */
|
|
|
|
static virDomainTimerDefPtr
|
|
|
|
virDomainTimerDefParseXML(const xmlNodePtr node,
|
|
|
|
xmlXPathContextPtr ctxt,
|
|
|
|
int flags ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
char *name = NULL;
|
|
|
|
char *present = NULL;
|
|
|
|
char *tickpolicy = NULL;
|
2010-03-31 13:03:54 -04:00
|
|
|
char *track = NULL;
|
2010-03-30 13:44:22 +02:00
|
|
|
char *mode = NULL;
|
|
|
|
|
|
|
|
virDomainTimerDefPtr def;
|
|
|
|
xmlNodePtr oldnode = ctxt->node;
|
|
|
|
|
|
|
|
if (VIR_ALLOC(def) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctxt->node = node;
|
|
|
|
|
|
|
|
name = virXMLPropString(node, "name");
|
|
|
|
if (name == NULL) {
|
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("missing timer name"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if ((def->name = virDomainTimerNameTypeFromString(name)) < 0) {
|
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unknown timer name '%s'"), name);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
def->present = -1; /* unspecified */
|
|
|
|
if ((present = virXMLPropString(node, "present")) != NULL) {
|
|
|
|
if (STREQ(present, "yes")) {
|
|
|
|
def->present = 1;
|
|
|
|
} else if (STREQ(present, "no")) {
|
|
|
|
def->present = 0;
|
|
|
|
} else {
|
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unknown timer present value '%s'"), present);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
def->tickpolicy = -1;
|
|
|
|
tickpolicy = virXMLPropString(node, "tickpolicy");
|
|
|
|
if (tickpolicy != NULL) {
|
|
|
|
if ((def->tickpolicy = virDomainTimerTickpolicyTypeFromString(tickpolicy)) < 0) {
|
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unknown timer tickpolicy '%s'"), tickpolicy);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-03-31 13:03:54 -04:00
|
|
|
def->track = -1;
|
|
|
|
track = virXMLPropString(node, "track");
|
|
|
|
if (track != NULL) {
|
|
|
|
if ((def->track = virDomainTimerTrackTypeFromString(track)) < 0) {
|
2010-03-30 13:44:22 +02:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2010-03-31 13:03:54 -04:00
|
|
|
_("unknown timer track '%s'"), track);
|
2010-03-30 13:44:22 +02:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int ret = virXPathULong("string(./frequency)", ctxt, &def->frequency);
|
|
|
|
if (ret == -1) {
|
|
|
|
def->frequency = 0;
|
2010-03-31 13:03:54 -04:00
|
|
|
} else if (ret < 0) {
|
2010-03-30 13:44:22 +02:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("invalid timer frequency"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
def->mode = -1;
|
|
|
|
mode = virXMLPropString(node, "mode");
|
|
|
|
if (mode != NULL) {
|
|
|
|
if ((def->mode = virDomainTimerModeTypeFromString(mode)) < 0) {
|
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unknown timer mode '%s'"), mode);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-03-31 13:03:54 -04:00
|
|
|
xmlNodePtr catchup = virXPathNode("./catchup", ctxt);
|
|
|
|
if (catchup != NULL) {
|
|
|
|
ret = virXPathULong("string(./catchup/@threshold)", ctxt,
|
|
|
|
&def->catchup.threshold);
|
|
|
|
if (ret == -1) {
|
|
|
|
def->catchup.threshold = 0;
|
|
|
|
} else if (ret < 0) {
|
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("invalid catchup threshold"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = virXPathULong("string(./catchup/@slew)", ctxt, &def->catchup.slew);
|
|
|
|
if (ret == -1) {
|
|
|
|
def->catchup.slew = 0;
|
|
|
|
} else if (ret < 0) {
|
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("invalid catchup slew"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = virXPathULong("string(./catchup/@limit)", ctxt, &def->catchup.limit);
|
|
|
|
if (ret == -1) {
|
|
|
|
def->catchup.limit = 0;
|
|
|
|
} else if (ret < 0) {
|
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("invalid catchup limit"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-03-30 13:44:22 +02:00
|
|
|
cleanup:
|
|
|
|
VIR_FREE(name);
|
|
|
|
VIR_FREE(present);
|
|
|
|
VIR_FREE(tickpolicy);
|
2010-03-31 13:03:54 -04:00
|
|
|
VIR_FREE(track);
|
2010-03-30 13:44:22 +02:00
|
|
|
VIR_FREE(mode);
|
|
|
|
ctxt->node = oldnode;
|
|
|
|
|
|
|
|
return def;
|
|
|
|
|
|
|
|
error:
|
|
|
|
VIR_FREE(def);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
/* Parse the XML definition for a graphics device */
|
|
|
|
static virDomainGraphicsDefPtr
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainGraphicsDefParseXML(xmlNodePtr node, int flags) {
|
2008-07-11 16:23:36 +00:00
|
|
|
virDomainGraphicsDefPtr def;
|
|
|
|
char *type = NULL;
|
|
|
|
|
|
|
|
if (VIR_ALLOC(def) < 0) {
|
2010-02-04 19:19:08 +01:00
|
|
|
virReportOOMError();
|
2008-07-11 16:23:36 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
type = virXMLPropString(node, "type");
|
|
|
|
|
|
|
|
if (!type) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
"%s", _("missing graphics device type"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((def->type = virDomainGraphicsTypeFromString(type)) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
_("unknown graphics device type '%s'"), type);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
|
|
|
|
char *port = virXMLPropString(node, "port");
|
|
|
|
char *autoport;
|
|
|
|
|
|
|
|
if (port) {
|
|
|
|
if (virStrToLong_i(port, NULL, 10, &def->data.vnc.port) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
_("cannot parse vnc port %s"), port);
|
|
|
|
VIR_FREE(port);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
VIR_FREE(port);
|
|
|
|
/* Legacy compat syntax, used -1 for auto-port */
|
|
|
|
if (def->data.vnc.port == -1) {
|
2008-12-04 12:02:59 +00:00
|
|
|
if (flags & VIR_DOMAIN_XML_INACTIVE)
|
|
|
|
def->data.vnc.port = 0;
|
2008-07-11 16:23:36 +00:00
|
|
|
def->data.vnc.autoport = 1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
def->data.vnc.port = 0;
|
|
|
|
def->data.vnc.autoport = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((autoport = virXMLPropString(node, "autoport")) != NULL) {
|
|
|
|
if (STREQ(autoport, "yes")) {
|
2008-12-04 12:02:59 +00:00
|
|
|
if (flags & VIR_DOMAIN_XML_INACTIVE)
|
|
|
|
def->data.vnc.port = 0;
|
2008-07-11 16:23:36 +00:00
|
|
|
def->data.vnc.autoport = 1;
|
|
|
|
}
|
|
|
|
VIR_FREE(autoport);
|
|
|
|
}
|
|
|
|
|
|
|
|
def->data.vnc.listenAddr = virXMLPropString(node, "listen");
|
|
|
|
def->data.vnc.passwd = virXMLPropString(node, "passwd");
|
|
|
|
def->data.vnc.keymap = virXMLPropString(node, "keymap");
|
|
|
|
} else if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) {
|
2008-12-11 11:44:30 +00:00
|
|
|
char *fullscreen = virXMLPropString(node, "fullscreen");
|
|
|
|
|
|
|
|
if (fullscreen != NULL) {
|
|
|
|
if (STREQ(fullscreen, "yes")) {
|
|
|
|
def->data.sdl.fullscreen = 1;
|
|
|
|
} else if (STREQ(fullscreen, "no")) {
|
|
|
|
def->data.sdl.fullscreen = 0;
|
|
|
|
} else {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-12-11 11:44:30 +00:00
|
|
|
_("unknown fullscreen value '%s'"), fullscreen);
|
|
|
|
VIR_FREE(fullscreen);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
VIR_FREE(fullscreen);
|
|
|
|
} else
|
|
|
|
def->data.sdl.fullscreen = 0;
|
2008-07-11 16:23:36 +00:00
|
|
|
def->data.sdl.xauth = virXMLPropString(node, "xauth");
|
|
|
|
def->data.sdl.display = virXMLPropString(node, "display");
|
2009-05-15 09:43:51 +00:00
|
|
|
} 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) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-05-15 09:43:51 +00:00
|
|
|
_("cannot parse rdp port %s"), port);
|
|
|
|
VIR_FREE(port);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
VIR_FREE(port);
|
|
|
|
} else {
|
|
|
|
def->data.rdp.port = 0;
|
|
|
|
def->data.rdp.autoport = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((autoport = virXMLPropString(node, "autoport")) != NULL) {
|
|
|
|
if (STREQ(autoport, "yes")) {
|
|
|
|
if (flags & VIR_DOMAIN_XML_INACTIVE)
|
|
|
|
def->data.rdp.port = 0;
|
|
|
|
def->data.rdp.autoport = 1;
|
|
|
|
}
|
|
|
|
VIR_FREE(autoport);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((replaceUser = virXMLPropString(node, "replaceUser")) != NULL) {
|
|
|
|
if (STREQ(replaceUser, "yes")) {
|
|
|
|
def->data.rdp.replaceUser = 1;
|
|
|
|
}
|
|
|
|
VIR_FREE(replaceUser);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((multiUser = virXMLPropString(node, "multiUser")) != NULL) {
|
|
|
|
if (STREQ(multiUser, "yes")) {
|
|
|
|
def->data.rdp.multiUser = 1;
|
|
|
|
}
|
|
|
|
VIR_FREE(multiUser);
|
|
|
|
}
|
|
|
|
|
|
|
|
def->data.rdp.listenAddr = virXMLPropString(node, "listen");
|
|
|
|
} else if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP) {
|
|
|
|
char *fullscreen = virXMLPropString(node, "fullscreen");
|
|
|
|
|
|
|
|
if (fullscreen != NULL) {
|
|
|
|
if (STREQ(fullscreen, "yes")) {
|
|
|
|
def->data.desktop.fullscreen = 1;
|
|
|
|
} else if (STREQ(fullscreen, "no")) {
|
|
|
|
def->data.desktop.fullscreen = 0;
|
|
|
|
} else {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-05-15 09:43:51 +00:00
|
|
|
_("unknown fullscreen value '%s'"), fullscreen);
|
|
|
|
VIR_FREE(fullscreen);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
VIR_FREE(fullscreen);
|
|
|
|
} else
|
|
|
|
def->data.desktop.fullscreen = 0;
|
|
|
|
|
|
|
|
def->data.desktop.display = virXMLPropString(node, "display");
|
2008-07-11 16:23:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(type);
|
|
|
|
|
|
|
|
return def;
|
|
|
|
|
|
|
|
error:
|
|
|
|
virDomainGraphicsDefFree(def);
|
|
|
|
def = NULL;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static virDomainSoundDefPtr
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainSoundDefParseXML(const xmlNodePtr node,
|
2009-12-10 19:19:08 +00:00
|
|
|
int flags)
|
|
|
|
{
|
2008-07-11 16:23:36 +00:00
|
|
|
char *model;
|
|
|
|
virDomainSoundDefPtr def;
|
|
|
|
|
|
|
|
if (VIR_ALLOC(def) < 0) {
|
2010-02-04 19:19:08 +01:00
|
|
|
virReportOOMError();
|
2008-07-11 16:23:36 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
model = virXMLPropString(node, "model");
|
|
|
|
if ((def->model = virDomainSoundModelTypeFromString(model)) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
_("unknown sound model '%s'"), model);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2010-02-09 18:58:01 +00:00
|
|
|
if (virDomainDeviceInfoParseXML(node, &def->info, flags) < 0)
|
2009-12-10 19:19:08 +00:00
|
|
|
goto error;
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
cleanup:
|
|
|
|
VIR_FREE(model);
|
|
|
|
|
|
|
|
return def;
|
|
|
|
|
|
|
|
error:
|
|
|
|
virDomainSoundDefFree(def);
|
|
|
|
def = NULL;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2009-07-06 14:54:44 +01:00
|
|
|
|
2009-10-21 13:26:38 +01:00
|
|
|
static virDomainWatchdogDefPtr
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainWatchdogDefParseXML(const xmlNodePtr node,
|
2009-12-10 19:19:08 +00:00
|
|
|
int flags)
|
|
|
|
{
|
2009-10-21 13:26:38 +01:00
|
|
|
|
|
|
|
char *model = NULL;
|
|
|
|
char *action = NULL;
|
|
|
|
virDomainWatchdogDefPtr def;
|
|
|
|
|
|
|
|
if (VIR_ALLOC (def) < 0) {
|
2010-02-04 19:19:08 +01:00
|
|
|
virReportOOMError();
|
2009-10-21 13:26:38 +01:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
model = virXMLPropString (node, "model");
|
|
|
|
if (model == NULL) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("watchdog must contain model name"));
|
2009-10-21 13:26:38 +01:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
def->model = virDomainWatchdogModelTypeFromString (model);
|
|
|
|
if (def->model < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unknown watchdog model '%s'"), model);
|
2009-10-21 13:26:38 +01:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
action = virXMLPropString (node, "action");
|
|
|
|
if (action == NULL)
|
|
|
|
def->action = VIR_DOMAIN_WATCHDOG_ACTION_RESET;
|
|
|
|
else {
|
|
|
|
def->action = virDomainWatchdogActionTypeFromString (action);
|
|
|
|
if (def->action < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unknown watchdog action '%s'"), action);
|
2009-10-21 13:26:38 +01:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-02-09 18:58:01 +00:00
|
|
|
if (virDomainDeviceInfoParseXML(node, &def->info, flags) < 0)
|
2009-12-10 19:19:08 +00:00
|
|
|
goto error;
|
|
|
|
|
2009-10-21 13:26:38 +01:00
|
|
|
cleanup:
|
|
|
|
VIR_FREE (action);
|
|
|
|
VIR_FREE (model);
|
|
|
|
|
|
|
|
return def;
|
|
|
|
|
|
|
|
error:
|
|
|
|
virDomainWatchdogDefFree (def);
|
|
|
|
def = NULL;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-07-06 14:54:44 +01:00
|
|
|
int
|
|
|
|
virDomainVideoDefaultRAM(virDomainDefPtr def,
|
|
|
|
int type)
|
|
|
|
{
|
|
|
|
switch (type) {
|
|
|
|
/* Wierd, QEMU defaults to 9 MB ??! */
|
|
|
|
case VIR_DOMAIN_VIDEO_TYPE_VGA:
|
|
|
|
case VIR_DOMAIN_VIDEO_TYPE_CIRRUS:
|
|
|
|
case VIR_DOMAIN_VIDEO_TYPE_VMVGA:
|
|
|
|
if (def->virtType == VIR_DOMAIN_VIRT_VBOX)
|
|
|
|
return 8 * 1024;
|
2010-01-16 13:52:34 +01:00
|
|
|
else if (def->virtType == VIR_DOMAIN_VIRT_VMWARE)
|
|
|
|
return 4 * 1024;
|
2009-07-06 14:54:44 +01:00
|
|
|
else
|
|
|
|
return 9 * 1024;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_VIDEO_TYPE_XEN:
|
|
|
|
/* Original Xen PVFB hardcoded to 4 MB */
|
|
|
|
return 4 * 1024;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
virDomainVideoDefaultType(virDomainDefPtr def)
|
|
|
|
{
|
|
|
|
switch (def->virtType) {
|
|
|
|
case VIR_DOMAIN_VIRT_TEST:
|
|
|
|
case VIR_DOMAIN_VIRT_QEMU:
|
|
|
|
case VIR_DOMAIN_VIRT_KQEMU:
|
|
|
|
case VIR_DOMAIN_VIRT_KVM:
|
|
|
|
case VIR_DOMAIN_VIRT_XEN:
|
|
|
|
if (def->os.type &&
|
|
|
|
(STREQ(def->os.type, "xen") ||
|
|
|
|
STREQ(def->os.type, "linux")))
|
|
|
|
return VIR_DOMAIN_VIDEO_TYPE_XEN;
|
|
|
|
else
|
|
|
|
return VIR_DOMAIN_VIDEO_TYPE_CIRRUS;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_VIRT_VBOX:
|
|
|
|
return VIR_DOMAIN_VIDEO_TYPE_VBOX;
|
|
|
|
|
2010-01-16 13:52:34 +01:00
|
|
|
case VIR_DOMAIN_VIRT_VMWARE:
|
|
|
|
return VIR_DOMAIN_VIDEO_TYPE_VMVGA;
|
|
|
|
|
2009-07-06 14:54:44 +01:00
|
|
|
default:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-09-03 10:26:41 +02:00
|
|
|
static virDomainVideoAccelDefPtr
|
2010-02-04 19:19:08 +01:00
|
|
|
virDomainVideoAccelDefParseXML(const xmlNodePtr node) {
|
2009-09-03 10:26:41 +02:00
|
|
|
xmlNodePtr cur;
|
|
|
|
virDomainVideoAccelDefPtr def;
|
|
|
|
char *support3d = NULL;
|
|
|
|
char *support2d = NULL;
|
|
|
|
|
|
|
|
cur = node->children;
|
|
|
|
while (cur != NULL) {
|
|
|
|
if (cur->type == XML_ELEMENT_NODE) {
|
|
|
|
if ((support3d == NULL) && (support2d == NULL) &&
|
|
|
|
xmlStrEqual(cur->name, BAD_CAST "acceleration")) {
|
|
|
|
support3d = virXMLPropString(cur, "accel3d");
|
|
|
|
support2d = virXMLPropString(cur, "accel2d");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
cur = cur->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((support3d == NULL) && (support2d == NULL))
|
|
|
|
return(NULL);
|
|
|
|
|
|
|
|
if (VIR_ALLOC(def) < 0) {
|
2010-02-04 19:19:08 +01:00
|
|
|
virReportOOMError();
|
2009-09-03 10:26:41 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (support3d) {
|
|
|
|
if (STREQ(support3d, "yes"))
|
|
|
|
def->support3d = 1;
|
|
|
|
else
|
|
|
|
def->support3d = 0;
|
|
|
|
VIR_FREE(support3d);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (support2d) {
|
|
|
|
if (STREQ(support2d, "yes"))
|
|
|
|
def->support2d = 1;
|
|
|
|
else
|
|
|
|
def->support2d = 0;
|
|
|
|
VIR_FREE(support2d);
|
|
|
|
}
|
|
|
|
|
|
|
|
return def;
|
|
|
|
}
|
|
|
|
|
2009-07-06 14:54:44 +01:00
|
|
|
static virDomainVideoDefPtr
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainVideoDefParseXML(const xmlNodePtr node,
|
2009-07-06 14:54:44 +01:00
|
|
|
virDomainDefPtr dom,
|
2009-12-10 19:19:08 +00:00
|
|
|
int flags) {
|
2009-07-06 14:54:44 +01:00
|
|
|
virDomainVideoDefPtr def;
|
|
|
|
xmlNodePtr cur;
|
|
|
|
char *type = NULL;
|
|
|
|
char *heads = NULL;
|
|
|
|
char *vram = NULL;
|
|
|
|
|
|
|
|
if (VIR_ALLOC(def) < 0) {
|
2010-02-04 19:19:08 +01:00
|
|
|
virReportOOMError();
|
2009-07-06 14:54:44 +01:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
cur = node->children;
|
|
|
|
while (cur != NULL) {
|
|
|
|
if (cur->type == XML_ELEMENT_NODE) {
|
|
|
|
if ((type == NULL) && (vram == NULL) && (heads == NULL) &&
|
|
|
|
xmlStrEqual(cur->name, BAD_CAST "model")) {
|
|
|
|
type = virXMLPropString(cur, "type");
|
|
|
|
vram = virXMLPropString(cur, "vram");
|
|
|
|
heads = virXMLPropString(cur, "heads");
|
2010-02-04 19:19:08 +01:00
|
|
|
def->accel = virDomainVideoAccelDefParseXML(cur);
|
2009-07-06 14:54:44 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
cur = cur->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (type) {
|
|
|
|
if ((def->type = virDomainVideoTypeFromString(type)) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-07-06 14:54:44 +01:00
|
|
|
_("unknown video model '%s'"), type);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if ((def->type = virDomainVideoDefaultType(dom)) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
2009-07-06 14:54:44 +01:00
|
|
|
_("missing video model and cannot determine default"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (vram) {
|
|
|
|
if (virStrToLong_ui(vram, NULL, 10, &def->vram) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-07-06 14:54:44 +01:00
|
|
|
_("cannot parse video ram '%s'"), vram);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
def->vram = virDomainVideoDefaultRAM(dom, def->type);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (heads) {
|
|
|
|
if (virStrToLong_ui(heads, NULL, 10, &def->heads) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-07-06 14:54:44 +01:00
|
|
|
_("cannot parse video heads '%s'"), heads);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
def->heads = 1;
|
|
|
|
}
|
|
|
|
|
2010-02-09 18:58:01 +00:00
|
|
|
if (virDomainDeviceInfoParseXML(node, &def->info, flags) < 0)
|
2009-12-10 19:19:08 +00:00
|
|
|
goto error;
|
|
|
|
|
2009-07-06 14:54:44 +01:00
|
|
|
VIR_FREE(type);
|
|
|
|
VIR_FREE(vram);
|
|
|
|
VIR_FREE(heads);
|
|
|
|
|
|
|
|
return def;
|
|
|
|
|
|
|
|
error:
|
|
|
|
virDomainVideoDefFree(def);
|
|
|
|
VIR_FREE(type);
|
|
|
|
VIR_FREE(vram);
|
|
|
|
VIR_FREE(heads);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2008-08-08 14:27:05 +00:00
|
|
|
static int
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainHostdevSubsysUsbDefParseXML(const xmlNodePtr node,
|
2009-01-08 13:54:20 +00:00
|
|
|
virDomainHostdevDefPtr def,
|
|
|
|
int flags ATTRIBUTE_UNUSED) {
|
2008-08-08 14:27:05 +00:00
|
|
|
|
|
|
|
int ret = -1;
|
2009-06-16 18:46:06 +00:00
|
|
|
int got_product, got_vendor;
|
2008-08-08 14:27:05 +00:00
|
|
|
xmlNodePtr cur;
|
|
|
|
|
2009-06-16 18:46:06 +00:00
|
|
|
/* Product can validly be 0, so we need some extra help to determine
|
|
|
|
* if it is uninitialized*/
|
|
|
|
got_product = 0;
|
|
|
|
got_vendor = 0;
|
|
|
|
|
2008-08-08 14:27:05 +00:00
|
|
|
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) {
|
2009-06-16 18:46:06 +00:00
|
|
|
got_vendor = 1;
|
2008-08-08 14:27:05 +00:00
|
|
|
if (virStrToLong_ui(vendor, NULL, 0,
|
2009-01-07 12:56:13 +00:00
|
|
|
&def->source.subsys.u.usb.vendor) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-08-08 14:27:05 +00:00
|
|
|
_("cannot parse vendor id %s"), vendor);
|
|
|
|
VIR_FREE(vendor);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
VIR_FREE(vendor);
|
|
|
|
} else {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-08-08 14:27:05 +00:00
|
|
|
"%s", _("usb vendor needs id"));
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
} else if (xmlStrEqual(cur->name, BAD_CAST "product")) {
|
|
|
|
char* product = virXMLPropString(cur, "id");
|
|
|
|
|
|
|
|
if (product) {
|
2009-06-16 18:46:06 +00:00
|
|
|
got_product = 1;
|
2008-08-08 14:27:05 +00:00
|
|
|
if (virStrToLong_ui(product, NULL, 0,
|
2008-12-17 18:12:07 +00:00
|
|
|
&def->source.subsys.u.usb.product) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-01-07 12:56:13 +00:00
|
|
|
_("cannot parse product %s"),
|
|
|
|
product);
|
2008-08-08 14:27:05 +00:00
|
|
|
VIR_FREE(product);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
VIR_FREE(product);
|
|
|
|
} else {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-08-08 14:27:05 +00:00
|
|
|
"%s", _("usb product needs id"));
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
} else if (xmlStrEqual(cur->name, BAD_CAST "address")) {
|
|
|
|
char *bus, *device;
|
|
|
|
|
|
|
|
bus = virXMLPropString(cur, "bus");
|
|
|
|
if (bus) {
|
|
|
|
if (virStrToLong_ui(bus, NULL, 0,
|
2008-12-17 18:12:07 +00:00
|
|
|
&def->source.subsys.u.usb.bus) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-08-08 14:27:05 +00:00
|
|
|
_("cannot parse bus %s"), bus);
|
|
|
|
VIR_FREE(bus);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
VIR_FREE(bus);
|
|
|
|
} else {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-08-08 14:27:05 +00:00
|
|
|
"%s", _("usb address needs bus id"));
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
device = virXMLPropString(cur, "device");
|
|
|
|
if (device) {
|
|
|
|
if (virStrToLong_ui(device, NULL, 0,
|
2008-12-17 18:12:07 +00:00
|
|
|
&def->source.subsys.u.usb.device) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-08-08 14:27:05 +00:00
|
|
|
_("cannot parse device %s"),
|
|
|
|
device);
|
|
|
|
VIR_FREE(device);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
VIR_FREE(device);
|
|
|
|
} else {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
2009-01-07 12:56:13 +00:00
|
|
|
_("usb address needs device id"));
|
2008-08-08 14:27:05 +00:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
} else {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-01-07 12:56:13 +00:00
|
|
|
_("unknown usb source type '%s'"),
|
|
|
|
cur->name);
|
2008-08-08 14:27:05 +00:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
cur = cur->next;
|
|
|
|
}
|
|
|
|
|
2009-06-16 18:46:06 +00:00
|
|
|
if (got_vendor && def->source.subsys.u.usb.vendor == 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-06-16 18:46:06 +00:00
|
|
|
"%s", _("vendor cannot be 0."));
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!got_vendor && got_product) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
avoid many format string warnings
Building with --disable-nls exposed many new warnings like these:
virsh.c:4952: warning: format not a string literal and no format ...
util.c:163: warning: format not a string literal and no format arguments
All but one of the following changes add a "%s" argument before
the offending _(...) argument.
This was the only manual change:
* src/lxc_driver.c (lxcVersion): Use %s and strerror(errno)
rather than %m, to avoid a warning from gcc -Wformat-security.
Add "%s" before each warned about format-string-with-no-%-directive:
* src/domain_conf.c (virDomainHostdevSubsysUsbDefParseXML)
(virDomainDefParseString, virDomainDefParseFile):
* src/hash.c (virGetConnect, __virGetDomain, virReleaseDomain)
(__virGetNetwork, virReleaseNetwork, __virGetStoragePool)
(virReleaseStoragePool, __virGetStorageVol, virReleaseStorageVol):
* src/lxc_container.c (lxcContainerChild):
* src/lxc_driver.c (lxcDomainDefine, lxcDomainUndefine)
(lxcDomainGetInfo, lxcGetOSType, lxcDomainDumpXML)
(lxcSetupInterfaces, lxcDomainStart, lxcDomainCreateAndStart)
(lxcVersion, lxcGetSchedulerParameters):
* src/network_conf.c (virNetworkDefParseString)
(virNetworkDefParseFile):
* src/openvz_conf.c (openvzReadNetworkConf, openvzLoadDomains):
* src/openvz_driver.c (openvzDomainDefineCmd)
(openvzDomainGetInfo, openvzDomainDumpXML, openvzDomainShutdown)
(openvzDomainReboot, ADD_ARG_LIT, openvzDomainDefineXML)
(openvzDomainCreateXML, openvzDomainCreate, openvzDomainUndefine)
(openvzDomainSetAutostart, openvzDomainGetAutostart)
(openvzDomainSetVcpus):
* src/qemu_driver.c (qemudDomainBlockPeek, qemudDomainMemoryPeek):
* src/remote_internal.c (remoteDomainBlockPeek)
(remoteDomainMemoryPeek, remoteAuthPolkit):
* src/sexpr.c (sexpr_new, _string2sexpr):
* src/storage_backend_disk.c (virStorageBackendDiskMakeDataVol)
(virStorageBackendDiskCreateVol):
* src/storage_backend_fs.c
(virStorageBackendFileSystemNetFindPoolSources):
* src/storage_backend_logical.c (virStorageBackendLogicalFindLVs)
(virStorageBackendLogicalFindPoolSources):
* src/test.c (testOpenDefault, testOpenFromFile, testOpen)
(testGetDomainInfo, testDomainRestore)
(testNodeGetCellsFreeMemory):
* src/util.c (virExec):
* src/virsh.c (cmdAttachDevice, cmdDetachDevice)
(cmdAttachInterface, cmdDetachInterface, cmdAttachDisk)
(cmdDetachDisk, cmdEdit):
* src/xend_internal.c (do_connect, wr_sync, xend_op_ext)
(urlencode, xenDaemonDomainCreateXML)
(xenDaemonDomainLookupByName_ids, xenDaemonDomainLookupByID)
(xenDaemonParseSxprOS, xend_parse_sexp_desc_char)
(xenDaemonParseSxprChar, xenDaemonParseSxprDisks)
(xenDaemonParseSxpr, sexpr_to_xend_topology, sexpr_to_domain)
(xenDaemonDomainFetch, xenDaemonDomainGetAutostart)
(xenDaemonDomainSetAutostart, xenDaemonDomainMigratePerform)
(xenDaemonDomainDefineXML, xenDaemonGetSchedulerType)
(xenDaemonGetSchedulerParameters)
(xenDaemonSetSchedulerParameters, xenDaemonDomainBlockPeek)
(xenDaemonFormatSxprChr, virDomainXMLDevID):
* src/xm_internal.c (xenXMConfigCacheRefresh, xenXMDomainPinVcpu)
(xenXMDomainCreate, xenXMDomainDefineXML)
(xenXMDomainAttachDevice, xenXMDomainDetachDevice):
* src/xml.c (virXPathString, virXPathNumber, virXPathLong)
(virXPathULong, virXPathBoolean, virXPathNode, virXPathNodeSet):
* src/xs_internal.c (xenStoreOpen):
2008-10-13 16:46:28 +00:00
|
|
|
"%s", _("missing vendor"));
|
2008-08-08 14:27:05 +00:00
|
|
|
goto out;
|
|
|
|
}
|
2009-06-16 18:46:06 +00:00
|
|
|
if (got_vendor && !got_product) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
avoid many format string warnings
Building with --disable-nls exposed many new warnings like these:
virsh.c:4952: warning: format not a string literal and no format ...
util.c:163: warning: format not a string literal and no format arguments
All but one of the following changes add a "%s" argument before
the offending _(...) argument.
This was the only manual change:
* src/lxc_driver.c (lxcVersion): Use %s and strerror(errno)
rather than %m, to avoid a warning from gcc -Wformat-security.
Add "%s" before each warned about format-string-with-no-%-directive:
* src/domain_conf.c (virDomainHostdevSubsysUsbDefParseXML)
(virDomainDefParseString, virDomainDefParseFile):
* src/hash.c (virGetConnect, __virGetDomain, virReleaseDomain)
(__virGetNetwork, virReleaseNetwork, __virGetStoragePool)
(virReleaseStoragePool, __virGetStorageVol, virReleaseStorageVol):
* src/lxc_container.c (lxcContainerChild):
* src/lxc_driver.c (lxcDomainDefine, lxcDomainUndefine)
(lxcDomainGetInfo, lxcGetOSType, lxcDomainDumpXML)
(lxcSetupInterfaces, lxcDomainStart, lxcDomainCreateAndStart)
(lxcVersion, lxcGetSchedulerParameters):
* src/network_conf.c (virNetworkDefParseString)
(virNetworkDefParseFile):
* src/openvz_conf.c (openvzReadNetworkConf, openvzLoadDomains):
* src/openvz_driver.c (openvzDomainDefineCmd)
(openvzDomainGetInfo, openvzDomainDumpXML, openvzDomainShutdown)
(openvzDomainReboot, ADD_ARG_LIT, openvzDomainDefineXML)
(openvzDomainCreateXML, openvzDomainCreate, openvzDomainUndefine)
(openvzDomainSetAutostart, openvzDomainGetAutostart)
(openvzDomainSetVcpus):
* src/qemu_driver.c (qemudDomainBlockPeek, qemudDomainMemoryPeek):
* src/remote_internal.c (remoteDomainBlockPeek)
(remoteDomainMemoryPeek, remoteAuthPolkit):
* src/sexpr.c (sexpr_new, _string2sexpr):
* src/storage_backend_disk.c (virStorageBackendDiskMakeDataVol)
(virStorageBackendDiskCreateVol):
* src/storage_backend_fs.c
(virStorageBackendFileSystemNetFindPoolSources):
* src/storage_backend_logical.c (virStorageBackendLogicalFindLVs)
(virStorageBackendLogicalFindPoolSources):
* src/test.c (testOpenDefault, testOpenFromFile, testOpen)
(testGetDomainInfo, testDomainRestore)
(testNodeGetCellsFreeMemory):
* src/util.c (virExec):
* src/virsh.c (cmdAttachDevice, cmdDetachDevice)
(cmdAttachInterface, cmdDetachInterface, cmdAttachDisk)
(cmdDetachDisk, cmdEdit):
* src/xend_internal.c (do_connect, wr_sync, xend_op_ext)
(urlencode, xenDaemonDomainCreateXML)
(xenDaemonDomainLookupByName_ids, xenDaemonDomainLookupByID)
(xenDaemonParseSxprOS, xend_parse_sexp_desc_char)
(xenDaemonParseSxprChar, xenDaemonParseSxprDisks)
(xenDaemonParseSxpr, sexpr_to_xend_topology, sexpr_to_domain)
(xenDaemonDomainFetch, xenDaemonDomainGetAutostart)
(xenDaemonDomainSetAutostart, xenDaemonDomainMigratePerform)
(xenDaemonDomainDefineXML, xenDaemonGetSchedulerType)
(xenDaemonGetSchedulerParameters)
(xenDaemonSetSchedulerParameters, xenDaemonDomainBlockPeek)
(xenDaemonFormatSxprChr, virDomainXMLDevID):
* src/xm_internal.c (xenXMConfigCacheRefresh, xenXMDomainPinVcpu)
(xenXMDomainCreate, xenXMDomainDefineXML)
(xenXMDomainAttachDevice, xenXMDomainDetachDevice):
* src/xml.c (virXPathString, virXPathNumber, virXPathLong)
(virXPathULong, virXPathBoolean, virXPathNode, virXPathNodeSet):
* src/xs_internal.c (xenStoreOpen):
2008-10-13 16:46:28 +00:00
|
|
|
"%s", _("missing product"));
|
2008-08-08 14:27:05 +00:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
out:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-01-07 12:56:13 +00:00
|
|
|
static int
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainHostdevSubsysPciDefParseXML(const xmlNodePtr node,
|
2009-08-14 08:31:10 +01:00
|
|
|
virDomainHostdevDefPtr def,
|
2010-01-25 13:35:05 -05:00
|
|
|
int flags) {
|
2009-01-07 12:56:13 +00:00
|
|
|
|
|
|
|
int ret = -1;
|
|
|
|
xmlNodePtr cur;
|
|
|
|
|
|
|
|
cur = node->children;
|
|
|
|
while (cur != NULL) {
|
|
|
|
if (cur->type == XML_ELEMENT_NODE) {
|
|
|
|
if (xmlStrEqual(cur->name, BAD_CAST "address")) {
|
2009-11-30 18:35:58 +00:00
|
|
|
virDomainDevicePCIAddressPtr addr =
|
|
|
|
&def->source.subsys.u.pci;
|
2009-01-07 12:56:13 +00:00
|
|
|
|
2010-02-09 18:58:01 +00:00
|
|
|
if (virDomainDevicePCIAddressParseXML(cur, addr) < 0)
|
2009-01-07 12:56:13 +00:00
|
|
|
goto out;
|
2010-01-25 13:35:05 -05:00
|
|
|
} else if ((flags & VIR_DOMAIN_XML_INTERNAL_STATUS) &&
|
|
|
|
xmlStrEqual(cur->name, BAD_CAST "state")) {
|
2009-11-30 18:35:58 +00:00
|
|
|
/* Legacy back-compat. Don't add any more attributes here */
|
2009-08-14 08:31:10 +01:00
|
|
|
char *devaddr = virXMLPropString(cur, "devaddr");
|
|
|
|
if (devaddr &&
|
2010-03-30 15:45:53 +02:00
|
|
|
virDomainParseLegacyDeviceAddress(devaddr,
|
|
|
|
&def->info.addr.pci) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-08-14 08:31:10 +01:00
|
|
|
_("Unable to parse devaddr parameter '%s'"),
|
|
|
|
devaddr);
|
|
|
|
VIR_FREE(devaddr);
|
|
|
|
goto out;
|
|
|
|
}
|
2009-11-30 18:35:58 +00:00
|
|
|
def->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
|
2009-01-07 12:56:13 +00:00
|
|
|
} else {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-01-07 12:56:13 +00:00
|
|
|
_("unknown pci source type '%s'"),
|
|
|
|
cur->name);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
cur = cur->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
out:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-08-08 14:27:05 +00:00
|
|
|
static virDomainHostdevDefPtr
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainHostdevDefParseXML(const xmlNodePtr node,
|
2009-01-08 13:54:20 +00:00
|
|
|
int flags) {
|
2008-08-08 14:27:05 +00:00
|
|
|
|
|
|
|
xmlNodePtr cur;
|
|
|
|
virDomainHostdevDefPtr def;
|
2009-03-02 16:40:30 +00:00
|
|
|
char *mode, *type = NULL, *managed = NULL;
|
2008-08-08 14:27:05 +00:00
|
|
|
|
|
|
|
if (VIR_ALLOC(def) < 0) {
|
2010-02-04 19:19:08 +01:00
|
|
|
virReportOOMError();
|
2008-08-08 14:27:05 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
def->target = NULL;
|
|
|
|
|
|
|
|
mode = virXMLPropString(node, "mode");
|
|
|
|
if (mode) {
|
|
|
|
if ((def->mode=virDomainHostdevModeTypeFromString(mode)) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-08-08 14:27:05 +00:00
|
|
|
_("unknown hostdev mode '%s'"), mode);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
def->mode = VIR_DOMAIN_HOSTDEV_MODE_SUBSYS;
|
|
|
|
}
|
|
|
|
|
|
|
|
type = virXMLPropString(node, "type");
|
|
|
|
if (type) {
|
|
|
|
if ((def->source.subsys.type = virDomainHostdevSubsysTypeFromString(type)) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-08-08 14:27:05 +00:00
|
|
|
_("unknown host device type '%s'"), type);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
} else {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-08-08 14:27:05 +00:00
|
|
|
"%s", _("missing type in hostdev"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2009-03-02 16:40:30 +00:00
|
|
|
managed = virXMLPropString(node, "managed");
|
|
|
|
if (managed != NULL) {
|
|
|
|
if (STREQ(managed, "yes"))
|
|
|
|
def->managed = 1;
|
|
|
|
VIR_FREE(managed);
|
|
|
|
}
|
|
|
|
|
2008-08-08 14:27:05 +00:00
|
|
|
cur = node->children;
|
|
|
|
while (cur != NULL) {
|
|
|
|
if (cur->type == XML_ELEMENT_NODE) {
|
|
|
|
if (xmlStrEqual(cur->name, BAD_CAST "source")) {
|
|
|
|
if (def->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
|
|
|
|
def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {
|
2010-02-09 18:58:01 +00:00
|
|
|
if (virDomainHostdevSubsysUsbDefParseXML(cur, def, flags) < 0)
|
2008-08-08 14:27:05 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2009-01-07 12:56:13 +00:00
|
|
|
if (def->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
|
|
|
|
def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) {
|
2010-02-09 18:58:01 +00:00
|
|
|
if (virDomainHostdevSubsysPciDefParseXML(cur, def, flags) < 0)
|
2009-01-07 12:56:13 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2010-01-08 15:53:53 +00:00
|
|
|
} else if (xmlStrEqual(cur->name, BAD_CAST "address")) {
|
|
|
|
} else {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2010-01-08 15:53:53 +00:00
|
|
|
_("unknown node %s"), cur->name);
|
2008-08-08 14:27:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
cur = cur->next;
|
|
|
|
}
|
|
|
|
|
2009-11-30 18:35:58 +00:00
|
|
|
if (def->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
|
2010-02-09 18:58:01 +00:00
|
|
|
if (virDomainDeviceInfoParseXML(node, &def->info, flags) < 0)
|
2009-11-30 18:35:58 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (def->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
|
|
|
|
switch (def->source.subsys.type) {
|
|
|
|
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
|
|
|
|
if (def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
|
|
|
|
def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
2009-11-30 18:35:58 +00:00
|
|
|
_("PCI host devices must use 'pci' address type"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-08-08 14:27:05 +00:00
|
|
|
cleanup:
|
|
|
|
VIR_FREE(type);
|
|
|
|
VIR_FREE(mode);
|
|
|
|
return def;
|
|
|
|
|
|
|
|
error:
|
|
|
|
virDomainHostdevDefFree(def);
|
|
|
|
def = NULL;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
|
2010-02-09 18:58:01 +00:00
|
|
|
static int virDomainLifecycleParseXML(xmlXPathContextPtr ctxt,
|
2008-07-11 16:23:36 +00:00
|
|
|
const char *xpath,
|
|
|
|
int *val,
|
|
|
|
int defaultVal)
|
|
|
|
{
|
2010-02-04 22:52:34 +01:00
|
|
|
char *tmp = virXPathString(xpath, ctxt);
|
2008-07-11 16:23:36 +00:00
|
|
|
if (tmp == NULL) {
|
|
|
|
*val = defaultVal;
|
|
|
|
} else {
|
|
|
|
*val = virDomainLifecycleTypeFromString(tmp);
|
|
|
|
if (*val < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
_("unknown lifecycle action %s"), tmp);
|
|
|
|
VIR_FREE(tmp);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
VIR_FREE(tmp);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-03-03 09:44:41 +00:00
|
|
|
static int
|
2010-02-09 18:58:01 +00:00
|
|
|
virSecurityLabelDefParseXML(const virDomainDefPtr def,
|
2009-03-03 16:53:13 +00:00
|
|
|
xmlXPathContextPtr ctxt,
|
|
|
|
int flags)
|
2009-03-03 09:44:41 +00:00
|
|
|
{
|
|
|
|
char *p;
|
|
|
|
|
2010-02-04 22:52:34 +01:00
|
|
|
if (virXPathNode("./seclabel", ctxt) == NULL)
|
2009-03-03 09:44:41 +00:00
|
|
|
return 0;
|
|
|
|
|
2010-02-04 22:52:34 +01:00
|
|
|
p = virXPathStringLimit("string(./seclabel/@type)",
|
2009-03-03 09:44:41 +00:00
|
|
|
VIR_SECURITY_LABEL_BUFLEN-1, ctxt);
|
2009-04-03 10:55:51 +00:00
|
|
|
if (p == NULL) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_XML_ERROR,
|
2009-04-03 10:55:51 +00:00
|
|
|
"%s", _("missing security type"));
|
2009-03-03 09:44:41 +00:00
|
|
|
goto error;
|
2009-04-03 10:55:51 +00:00
|
|
|
}
|
|
|
|
def->seclabel.type = virDomainSeclabelTypeFromString(p);
|
2009-03-03 16:53:13 +00:00
|
|
|
VIR_FREE(p);
|
2009-04-03 10:55:51 +00:00
|
|
|
if (def->seclabel.type < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_XML_ERROR,
|
2009-07-23 18:27:47 +02:00
|
|
|
"%s", _("invalid security type"));
|
2009-04-03 10:55:51 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2009-03-03 16:53:13 +00:00
|
|
|
|
|
|
|
/* Only parse details, if using static labels, or
|
|
|
|
* if the 'live' VM XML is requested
|
|
|
|
*/
|
|
|
|
if (def->seclabel.type == VIR_DOMAIN_SECLABEL_STATIC ||
|
|
|
|
!(flags & VIR_DOMAIN_XML_INACTIVE)) {
|
2010-02-04 22:52:34 +01:00
|
|
|
p = virXPathStringLimit("string(./seclabel/@model)",
|
2009-04-03 14:10:17 +00:00
|
|
|
VIR_SECURITY_MODEL_BUFLEN-1, ctxt);
|
|
|
|
if (p == NULL) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_XML_ERROR,
|
2009-04-03 14:10:17 +00:00
|
|
|
"%s", _("missing security model"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
def->seclabel.model = p;
|
2009-03-03 16:53:13 +00:00
|
|
|
|
2010-02-04 22:52:34 +01:00
|
|
|
p = virXPathStringLimit("string(./seclabel/label[1])",
|
2009-03-03 16:53:13 +00:00
|
|
|
VIR_SECURITY_LABEL_BUFLEN-1, ctxt);
|
2009-04-03 10:55:51 +00:00
|
|
|
if (p == NULL) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_XML_ERROR,
|
2009-07-23 18:27:47 +02:00
|
|
|
"%s", _("security label is missing"));
|
2009-03-03 16:53:13 +00:00
|
|
|
goto error;
|
2009-04-03 10:55:51 +00:00
|
|
|
}
|
|
|
|
|
2009-03-03 16:53:13 +00:00
|
|
|
def->seclabel.label = p;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Only parse imagelabel, if requested live XML for dynamic label */
|
|
|
|
if (def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC &&
|
|
|
|
!(flags & VIR_DOMAIN_XML_INACTIVE)) {
|
2010-02-04 22:52:34 +01:00
|
|
|
p = virXPathStringLimit("string(./seclabel/imagelabel[1])",
|
2009-03-03 16:53:13 +00:00
|
|
|
VIR_SECURITY_LABEL_BUFLEN-1, ctxt);
|
2009-04-03 14:10:17 +00:00
|
|
|
if (p == NULL) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_XML_ERROR,
|
2009-07-23 18:27:47 +02:00
|
|
|
"%s", _("security imagelabel is missing"));
|
2009-03-03 16:53:13 +00:00
|
|
|
goto error;
|
2009-04-03 14:10:17 +00:00
|
|
|
}
|
2009-03-03 16:53:13 +00:00
|
|
|
def->seclabel.imagelabel = p;
|
|
|
|
}
|
2009-03-03 09:44:41 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
|
|
|
virSecurityLabelDefFree(def);
|
|
|
|
return -1;
|
|
|
|
}
|
2008-07-11 16:23:36 +00:00
|
|
|
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainDeviceDefPtr virDomainDeviceDefParse(virCapsPtr caps,
|
2008-07-11 16:23:36 +00:00
|
|
|
const virDomainDefPtr def,
|
2009-01-08 13:54:20 +00:00
|
|
|
const char *xmlStr,
|
|
|
|
int flags)
|
2008-07-11 16:23:36 +00:00
|
|
|
{
|
|
|
|
xmlDocPtr xml;
|
|
|
|
xmlNodePtr node;
|
|
|
|
virDomainDeviceDefPtr dev = NULL;
|
|
|
|
|
|
|
|
if (!(xml = xmlReadDoc(BAD_CAST xmlStr, "device.xml", NULL,
|
|
|
|
XML_PARSE_NOENT | XML_PARSE_NONET |
|
|
|
|
XML_PARSE_NOERROR | XML_PARSE_NOWARNING))) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_XML_ERROR, NULL);
|
2008-07-11 16:23:36 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
node = xmlDocGetRootElement(xml);
|
|
|
|
if (node == NULL) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_XML_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
"%s", _("missing root element"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VIR_ALLOC(dev) < 0) {
|
2010-02-04 19:19:08 +01:00
|
|
|
virReportOOMError();
|
2008-07-11 16:23:36 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (xmlStrEqual(node->name, BAD_CAST "disk")) {
|
|
|
|
dev->type = VIR_DOMAIN_DEVICE_DISK;
|
2010-02-09 18:58:01 +00:00
|
|
|
if (!(dev->data.disk = virDomainDiskDefParseXML(node, flags)))
|
2008-07-11 16:23:36 +00:00
|
|
|
goto error;
|
2008-08-01 13:31:37 +00:00
|
|
|
} else if (xmlStrEqual(node->name, BAD_CAST "filesystem")) {
|
|
|
|
dev->type = VIR_DOMAIN_DEVICE_FS;
|
2010-02-09 18:58:01 +00:00
|
|
|
if (!(dev->data.fs = virDomainFSDefParseXML(node, flags)))
|
2008-08-01 13:31:37 +00:00
|
|
|
goto error;
|
2008-07-11 16:23:36 +00:00
|
|
|
} else if (xmlStrEqual(node->name, BAD_CAST "interface")) {
|
|
|
|
dev->type = VIR_DOMAIN_DEVICE_NET;
|
2010-02-09 18:58:01 +00:00
|
|
|
if (!(dev->data.net = virDomainNetDefParseXML(caps, node, flags)))
|
2008-07-11 16:23:36 +00:00
|
|
|
goto error;
|
|
|
|
} else if (xmlStrEqual(node->name, BAD_CAST "input")) {
|
2008-09-02 15:33:39 +00:00
|
|
|
dev->type = VIR_DOMAIN_DEVICE_INPUT;
|
2010-02-09 18:58:01 +00:00
|
|
|
if (!(dev->data.input = virDomainInputDefParseXML(def->os.type,
|
2009-01-08 13:54:20 +00:00
|
|
|
node, flags)))
|
2008-07-11 16:23:36 +00:00
|
|
|
goto error;
|
|
|
|
} else if (xmlStrEqual(node->name, BAD_CAST "sound")) {
|
|
|
|
dev->type = VIR_DOMAIN_DEVICE_SOUND;
|
2010-02-09 18:58:01 +00:00
|
|
|
if (!(dev->data.sound = virDomainSoundDefParseXML(node, flags)))
|
2008-07-11 16:23:36 +00:00
|
|
|
goto error;
|
2009-10-21 13:26:38 +01:00
|
|
|
} else if (xmlStrEqual(node->name, BAD_CAST "watchdog")) {
|
|
|
|
dev->type = VIR_DOMAIN_DEVICE_WATCHDOG;
|
2010-02-09 18:58:01 +00:00
|
|
|
if (!(dev->data.watchdog = virDomainWatchdogDefParseXML(node, flags)))
|
2009-10-21 13:26:38 +01:00
|
|
|
goto error;
|
2009-07-06 14:54:44 +01:00
|
|
|
} else if (xmlStrEqual(node->name, BAD_CAST "video")) {
|
|
|
|
dev->type = VIR_DOMAIN_DEVICE_VIDEO;
|
2010-02-09 18:58:01 +00:00
|
|
|
if (!(dev->data.video = virDomainVideoDefParseXML(node, def, flags)))
|
2009-07-06 14:54:44 +01:00
|
|
|
goto error;
|
2008-08-08 14:27:05 +00:00
|
|
|
} else if (xmlStrEqual(node->name, BAD_CAST "hostdev")) {
|
|
|
|
dev->type = VIR_DOMAIN_DEVICE_HOSTDEV;
|
2010-02-09 18:58:01 +00:00
|
|
|
if (!(dev->data.hostdev = virDomainHostdevDefParseXML(node, flags)))
|
2008-08-08 14:27:05 +00:00
|
|
|
goto error;
|
2009-12-02 19:15:38 +00:00
|
|
|
} else if (xmlStrEqual(node->name, BAD_CAST "controller")) {
|
|
|
|
dev->type = VIR_DOMAIN_DEVICE_CONTROLLER;
|
2010-02-09 18:58:01 +00:00
|
|
|
if (!(dev->data.controller = virDomainControllerDefParseXML(node, flags)))
|
2009-12-02 19:15:38 +00:00
|
|
|
goto error;
|
2010-03-22 13:22:48 +00:00
|
|
|
} else if (xmlStrEqual(node->name, BAD_CAST "graphics")) {
|
|
|
|
dev->type = VIR_DOMAIN_DEVICE_GRAPHICS;
|
|
|
|
if (!(dev->data.graphics = virDomainGraphicsDefParseXML(node, flags)))
|
|
|
|
goto error;
|
2008-07-11 16:23:36 +00:00
|
|
|
} else {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_XML_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
"%s", _("unknown device type"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
xmlFreeDoc(xml);
|
|
|
|
|
|
|
|
return dev;
|
|
|
|
|
|
|
|
error:
|
|
|
|
xmlFreeDoc(xml);
|
|
|
|
VIR_FREE(dev);
|
|
|
|
return NULL;
|
|
|
|
}
|
2008-10-13 15:24:34 +00:00
|
|
|
#endif
|
2008-07-11 16:23:36 +00:00
|
|
|
|
2009-08-14 10:31:36 +01:00
|
|
|
|
|
|
|
int virDomainDiskInsert(virDomainDefPtr def,
|
|
|
|
virDomainDiskDefPtr disk)
|
2008-10-10 16:08:01 +00:00
|
|
|
{
|
|
|
|
|
2009-08-14 10:31:36 +01:00
|
|
|
if (VIR_REALLOC_N(def->disks, def->ndisks+1) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
virDomainDiskInsertPreAlloced(def, disk);
|
|
|
|
|
|
|
|
return 0;
|
2008-10-10 16:08:01 +00:00
|
|
|
}
|
|
|
|
|
2009-08-14 10:31:36 +01:00
|
|
|
void virDomainDiskInsertPreAlloced(virDomainDefPtr def,
|
|
|
|
virDomainDiskDefPtr disk)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
/* Tenatively plan to insert disk at the end. */
|
|
|
|
int insertAt = -1;
|
|
|
|
|
|
|
|
/* Then work backwards looking for disks on
|
|
|
|
* the same bus. If we find a disk with a drive
|
|
|
|
* index greater than the new one, insert at
|
|
|
|
* that position
|
|
|
|
*/
|
|
|
|
for (i = (def->ndisks - 1) ; i >= 0 ; i--) {
|
|
|
|
/* If bus matches and current disk is after
|
|
|
|
* new disk, then new disk should go here */
|
|
|
|
if (def->disks[i]->bus == disk->bus &&
|
|
|
|
(virDiskNameToIndex(def->disks[i]->dst) >
|
|
|
|
virDiskNameToIndex(disk->dst))) {
|
|
|
|
insertAt = i;
|
|
|
|
} else if (def->disks[i]->bus == disk->bus &&
|
|
|
|
insertAt == -1) {
|
|
|
|
/* Last disk with match bus is before the
|
|
|
|
* new disk, then put new disk just after
|
|
|
|
*/
|
|
|
|
insertAt = i + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* No disks with this bus yet, so put at end of list */
|
|
|
|
if (insertAt == -1)
|
|
|
|
insertAt = def->ndisks;
|
|
|
|
|
|
|
|
if (insertAt < def->ndisks)
|
|
|
|
memmove(def->disks + insertAt + 1,
|
|
|
|
def->disks + insertAt,
|
|
|
|
(sizeof(def->disks[0]) * (def->ndisks-insertAt)));
|
|
|
|
|
|
|
|
def->disks[insertAt] = disk;
|
|
|
|
def->ndisks++;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-12-02 19:15:38 +00:00
|
|
|
int virDomainControllerInsert(virDomainDefPtr def,
|
|
|
|
virDomainControllerDefPtr controller)
|
|
|
|
{
|
|
|
|
|
|
|
|
if (VIR_REALLOC_N(def->controllers, def->ncontrollers+1) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
virDomainControllerInsertPreAlloced(def, controller);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void virDomainControllerInsertPreAlloced(virDomainDefPtr def,
|
|
|
|
virDomainControllerDefPtr controller)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
/* Tenatively plan to insert controller at the end. */
|
|
|
|
int insertAt = -1;
|
|
|
|
|
|
|
|
/* Then work backwards looking for controllers of
|
|
|
|
* the same type. If we find a controller with a
|
|
|
|
* index greater than the new one, insert at
|
|
|
|
* that position
|
|
|
|
*/
|
|
|
|
for (i = (def->ncontrollers - 1) ; i >= 0 ; i--) {
|
|
|
|
/* If bus matches and current controller is after
|
|
|
|
* new controller, then new controller should go here */
|
|
|
|
if ((def->controllers[i]->type == controller->type) &&
|
|
|
|
(def->controllers[i]->idx > controller->idx)) {
|
|
|
|
insertAt = i;
|
|
|
|
} else if (def->controllers[i]->type == controller->type &&
|
|
|
|
insertAt == -1) {
|
|
|
|
/* Last controller with match bus is before the
|
|
|
|
* new controller, then put new controller just after
|
|
|
|
*/
|
|
|
|
insertAt = i + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* No controllers with this bus yet, so put at end of list */
|
|
|
|
if (insertAt == -1)
|
|
|
|
insertAt = def->ncontrollers;
|
|
|
|
|
|
|
|
if (insertAt < def->ncontrollers)
|
|
|
|
memmove(def->controllers + insertAt + 1,
|
|
|
|
def->controllers + insertAt,
|
|
|
|
(sizeof(def->controllers[0]) * (def->ncontrollers-insertAt)));
|
|
|
|
|
|
|
|
def->controllers[insertAt] = controller;
|
|
|
|
def->ncontrollers++;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-10-13 15:24:34 +00:00
|
|
|
#ifndef PROXY
|
2010-02-09 18:58:01 +00:00
|
|
|
static char *virDomainDefDefaultEmulator(virDomainDefPtr def,
|
2009-06-16 15:42:46 +00:00
|
|
|
virCapsPtr caps) {
|
|
|
|
const char *type;
|
|
|
|
const char *emulator;
|
|
|
|
char *retemu;
|
|
|
|
|
|
|
|
type = virDomainVirtTypeToString(def->virtType);
|
|
|
|
if (!type) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-06-16 15:42:46 +00:00
|
|
|
"%s", _("unknown virt type"));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
emulator = virCapabilitiesDefaultGuestEmulator(caps,
|
|
|
|
def->os.type,
|
|
|
|
def->os.arch,
|
|
|
|
type);
|
|
|
|
|
|
|
|
if (!emulator) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-06-16 15:42:46 +00:00
|
|
|
_("no emulator for domain %s os type %s on architecture %s"),
|
|
|
|
type, def->os.type, def->os.arch);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
retemu = strdup(emulator);
|
|
|
|
if (!retemu)
|
2010-02-04 19:19:08 +01:00
|
|
|
virReportOOMError();
|
2009-06-16 15:42:46 +00:00
|
|
|
|
|
|
|
return retemu;
|
|
|
|
}
|
|
|
|
|
2010-02-09 18:58:01 +00:00
|
|
|
static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
|
2008-12-04 12:02:59 +00:00
|
|
|
xmlXPathContextPtr ctxt, int flags)
|
2008-07-11 16:23:36 +00:00
|
|
|
{
|
|
|
|
xmlNodePtr *nodes = NULL, node = NULL;
|
|
|
|
char *tmp = NULL;
|
|
|
|
int i, n;
|
2008-12-04 12:02:59 +00:00
|
|
|
long id = -1;
|
2008-07-11 16:23:36 +00:00
|
|
|
virDomainDefPtr def;
|
|
|
|
|
|
|
|
if (VIR_ALLOC(def) < 0) {
|
2010-02-04 19:19:08 +01:00
|
|
|
virReportOOMError();
|
2008-07-11 16:23:36 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2008-12-04 12:02:59 +00:00
|
|
|
|
|
|
|
if (!(flags & VIR_DOMAIN_XML_INACTIVE))
|
2010-02-04 22:52:34 +01:00
|
|
|
if ((virXPathLong("string(./@id)", ctxt, &id)) < 0)
|
2008-12-04 12:02:59 +00:00
|
|
|
id = -1;
|
|
|
|
def->id = (int)id;
|
2008-07-11 16:23:36 +00:00
|
|
|
|
2008-07-25 16:25:11 +00:00
|
|
|
/* Find out what type of virtualization to use */
|
2010-02-04 22:52:34 +01:00
|
|
|
if (!(tmp = virXPathString("string(./@type)", ctxt))) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
"%s", _("missing domain type attribute"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((def->virtType = virDomainVirtTypeFromString(tmp)) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
_("invalid domain type %s"), tmp);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
VIR_FREE(tmp);
|
|
|
|
|
|
|
|
/* Extract domain name */
|
2010-02-04 22:52:34 +01:00
|
|
|
if (!(def->name = virXPathString("string(./name[1])", ctxt))) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_NO_NAME, NULL);
|
2008-07-11 16:23:36 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Extract domain uuid */
|
2010-02-04 22:52:34 +01:00
|
|
|
tmp = virXPathString("string(./uuid[1])", ctxt);
|
2008-07-11 16:23:36 +00:00
|
|
|
if (!tmp) {
|
2009-09-04 17:27:34 +02:00
|
|
|
if (virUUIDGenerate(def->uuid)) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-01-20 17:13:33 +00:00
|
|
|
"%s", _("Failed to generate UUID"));
|
2008-07-11 16:23:36 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (virUUIDParse(tmp, def->uuid) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
"%s", _("malformed uuid element"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
VIR_FREE(tmp);
|
|
|
|
}
|
|
|
|
|
2009-09-30 16:07:24 +02:00
|
|
|
/* Extract documentation if present */
|
2010-02-04 22:52:34 +01:00
|
|
|
def->description = virXPathString("string(./description[1])", ctxt);
|
2009-09-30 16:07:24 +02:00
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
/* Extract domain memory */
|
2010-02-04 22:52:34 +01:00
|
|
|
if (virXPathULong("string(./memory[1])", ctxt, &def->maxmem) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
"%s", _("missing memory element"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2010-02-04 22:52:34 +01:00
|
|
|
if (virXPathULong("string(./currentMemory[1])", ctxt, &def->memory) < 0)
|
2008-07-11 16:23:36 +00:00
|
|
|
def->memory = def->maxmem;
|
|
|
|
|
2010-02-04 22:52:34 +01:00
|
|
|
node = virXPathNode("./memoryBacking/hugepages", ctxt);
|
Support configuration of huge pages in guests
Add option to domain XML for
<memoryBacking>
<hugepages/>
</memoryBacking>
* configure.in: Add check for mntent.h
* qemud/libvirtd_qemu.aug, qemud/test_libvirtd_qemu.aug, src/qemu.conf
Add 'hugetlbfs_mount' config parameter
* src/qemu_conf.c, src/qemu_conf.h: Check for -mem-path flag in QEMU,
and pass it when hugepages are requested.
Load hugetlbfs_mount config parameter, search for mount if not given.
* src/qemu_driver.c: Free hugetlbfs_mount/path parameter in driver shutdown.
Create directory for QEMU hugepage usage, chowning if required.
* docs/formatdomain.html.in: Document memoryBacking/hugepages elements
* docs/schemas/domain.rng: Add memoryBacking/hugepages elements to schema
* src/util.c, src/util.h, src/libvirt_private.syms: Add virFileFindMountPoint
helper API
* tests/qemuhelptest.c: Add -mem-path constants
* tests/qemuxml2argvtest.c, tests/qemuxml2xmltest.c: Add tests for hugepage
handling
* tests/qemuxml2argvdata/qemuxml2argv-hugepages.xml,
tests/qemuxml2argvdata/qemuxml2argv-hugepages.args: Data files for
hugepage tests
2009-08-25 15:05:18 +01:00
|
|
|
if (node)
|
|
|
|
def->hugepage_backed = 1;
|
|
|
|
|
2010-02-04 22:52:34 +01:00
|
|
|
if (virXPathULong("string(./vcpu[1])", ctxt, &def->vcpus) < 0)
|
2008-07-11 16:23:36 +00:00
|
|
|
def->vcpus = 1;
|
|
|
|
|
2010-02-04 22:52:34 +01:00
|
|
|
tmp = virXPathString("string(./vcpu[1]/@cpuset)", ctxt);
|
2008-07-11 16:23:36 +00:00
|
|
|
if (tmp) {
|
|
|
|
char *set = tmp;
|
|
|
|
def->cpumasklen = VIR_DOMAIN_CPUMASK_LEN;
|
|
|
|
if (VIR_ALLOC_N(def->cpumask, def->cpumasklen) < 0) {
|
2010-02-04 19:19:08 +01:00
|
|
|
virReportOOMError();
|
2008-07-11 16:23:36 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2010-02-09 18:58:01 +00:00
|
|
|
if (virDomainCpuSetParse((const char **)&set,
|
2008-07-11 16:23:36 +00:00
|
|
|
0, def->cpumask,
|
|
|
|
def->cpumasklen) < 0)
|
|
|
|
goto error;
|
|
|
|
VIR_FREE(tmp);
|
|
|
|
}
|
|
|
|
|
2010-02-04 22:52:34 +01:00
|
|
|
n = virXPathNodeSet("./features/*", ctxt, &nodes);
|
2009-04-01 10:31:01 +00:00
|
|
|
if (n < 0)
|
|
|
|
goto error;
|
|
|
|
if (n) {
|
2008-07-11 16:23:36 +00:00
|
|
|
for (i = 0 ; i < n ; i++) {
|
|
|
|
int val = virDomainFeatureTypeFromString((const char *)nodes[i]->name);
|
|
|
|
if (val < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
_("unexpected feature %s"),
|
|
|
|
nodes[i]->name);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
def->features |= (1 << val);
|
|
|
|
}
|
2009-04-01 10:31:01 +00:00
|
|
|
VIR_FREE(nodes);
|
2008-07-11 16:23:36 +00:00
|
|
|
}
|
|
|
|
|
2010-02-09 18:58:01 +00:00
|
|
|
if (virDomainLifecycleParseXML(ctxt, "string(./on_reboot[1])",
|
2008-07-11 16:23:36 +00:00
|
|
|
&def->onReboot, VIR_DOMAIN_LIFECYCLE_RESTART) < 0)
|
|
|
|
goto error;
|
|
|
|
|
2010-02-09 18:58:01 +00:00
|
|
|
if (virDomainLifecycleParseXML(ctxt, "string(./on_poweroff[1])",
|
2008-07-11 16:23:36 +00:00
|
|
|
&def->onPoweroff, VIR_DOMAIN_LIFECYCLE_DESTROY) < 0)
|
|
|
|
goto error;
|
|
|
|
|
2010-02-09 18:58:01 +00:00
|
|
|
if (virDomainLifecycleParseXML(ctxt, "string(./on_crash[1])",
|
2008-07-11 16:23:36 +00:00
|
|
|
&def->onCrash, VIR_DOMAIN_LIFECYCLE_DESTROY) < 0)
|
|
|
|
goto error;
|
|
|
|
|
2010-02-04 22:52:34 +01:00
|
|
|
tmp = virXPathString("string(./clock/@offset)", ctxt);
|
2010-02-02 17:22:03 +00:00
|
|
|
if (tmp) {
|
|
|
|
if ((def->clock.offset = virDomainClockOffsetTypeFromString(tmp)) < 0) {
|
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unknown clock offset '%s'"), tmp);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
VIR_FREE(tmp);
|
|
|
|
} else {
|
|
|
|
def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_UTC;
|
|
|
|
}
|
2010-02-02 17:49:09 +00:00
|
|
|
switch (def->clock.offset) {
|
|
|
|
case VIR_DOMAIN_CLOCK_OFFSET_VARIABLE:
|
|
|
|
if (virXPathLongLong("number(./clock/@adjustment)", ctxt,
|
2010-02-02 18:28:44 +00:00
|
|
|
&def->clock.data.adjustment) < 0)
|
|
|
|
def->clock.data.adjustment = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CLOCK_OFFSET_TIMEZONE:
|
|
|
|
def->clock.data.timezone = virXPathString("string(./clock/@timezone)", ctxt);
|
|
|
|
if (!def->clock.data.timezone) {
|
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("missing 'timezone' attribute for clock with offset='timezone'"));
|
|
|
|
goto error;
|
|
|
|
}
|
2010-02-02 17:49:09 +00:00
|
|
|
break;
|
|
|
|
}
|
2008-07-11 16:23:36 +00:00
|
|
|
|
2010-03-30 13:44:22 +02:00
|
|
|
if ((n = virXPathNodeSet("./clock/timer", ctxt, &nodes)) < 0) {
|
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("failed to parse timers"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (n && VIR_ALLOC_N(def->clock.timers, n) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
for (i = 0 ; i < n ; i++) {
|
|
|
|
virDomainTimerDefPtr timer = virDomainTimerDefParseXML(nodes[i],
|
|
|
|
ctxt,
|
|
|
|
flags);
|
|
|
|
if (!timer)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
def->clock.timers[def->clock.ntimers++] = timer;
|
|
|
|
}
|
|
|
|
VIR_FREE(nodes);
|
|
|
|
|
2010-02-04 22:52:34 +01:00
|
|
|
def->os.bootloader = virXPathString("string(./bootloader)", ctxt);
|
|
|
|
def->os.bootloaderArgs = virXPathString("string(./bootloader_args)", ctxt);
|
2008-07-11 16:23:36 +00:00
|
|
|
|
2010-02-04 22:52:34 +01:00
|
|
|
def->os.type = virXPathString("string(./os/type[1])", ctxt);
|
2008-07-11 16:23:36 +00:00
|
|
|
if (!def->os.type) {
|
|
|
|
if (def->os.bootloader) {
|
|
|
|
def->os.type = strdup("xen");
|
|
|
|
if (!def->os.type) {
|
2010-02-04 19:19:08 +01:00
|
|
|
virReportOOMError();
|
2008-07-11 16:23:36 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
} else {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_OS_TYPE,
|
2008-07-11 16:23:36 +00:00
|
|
|
"%s", _("no OS type"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* HACK: For xen driver we previously used bogus 'linux' as the
|
|
|
|
* os type for paravirt, whereas capabilities declare it to
|
|
|
|
* be 'xen'. So we accept the former and convert
|
|
|
|
*/
|
|
|
|
if (STREQ(def->os.type, "linux") &&
|
|
|
|
def->virtType == VIR_DOMAIN_VIRT_XEN) {
|
|
|
|
VIR_FREE(def->os.type);
|
|
|
|
if (!(def->os.type = strdup("xen"))) {
|
2010-02-04 19:19:08 +01:00
|
|
|
virReportOOMError();
|
2008-07-11 16:23:36 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!virCapabilitiesSupportsGuestOSType(caps, def->os.type)) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_OS_TYPE,
|
2008-07-11 16:23:36 +00:00
|
|
|
"%s", def->os.type);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2010-02-04 22:52:34 +01:00
|
|
|
def->os.arch = virXPathString("string(./os/type[1]/@arch)", ctxt);
|
2009-01-30 17:12:28 +00:00
|
|
|
if (def->os.arch) {
|
|
|
|
if (!virCapabilitiesSupportsGuestArch(caps, def->os.type, def->os.arch)) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-01-30 17:12:28 +00:00
|
|
|
_("os type '%s' & arch '%s' combination is not supported"),
|
|
|
|
def->os.type, def->os.arch);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
} else {
|
2009-03-24 11:16:29 +00:00
|
|
|
const char *defaultArch = virCapabilitiesDefaultGuestArch(caps, def->os.type, virDomainVirtTypeToString(def->virtType));
|
2008-07-11 16:23:36 +00:00
|
|
|
if (defaultArch == NULL) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
_("no supported architecture for os type '%s'"),
|
|
|
|
def->os.type);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (!(def->os.arch = strdup(defaultArch))) {
|
2010-02-04 19:19:08 +01:00
|
|
|
virReportOOMError();
|
2008-07-11 16:23:36 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-02-04 22:52:34 +01:00
|
|
|
def->os.machine = virXPathString("string(./os/type[1]/@machine)", ctxt);
|
2008-07-11 16:23:36 +00:00
|
|
|
if (!def->os.machine) {
|
|
|
|
const char *defaultMachine = virCapabilitiesDefaultGuestMachine(caps,
|
|
|
|
def->os.type,
|
2009-10-12 10:52:13 +01:00
|
|
|
def->os.arch,
|
|
|
|
virDomainVirtTypeToString(def->virtType));
|
2008-07-11 16:23:36 +00:00
|
|
|
if (defaultMachine != NULL) {
|
|
|
|
if (!(def->os.machine = strdup(defaultMachine))) {
|
2010-02-04 19:19:08 +01:00
|
|
|
virReportOOMError();
|
2008-07-11 16:23:36 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-08-01 13:31:37 +00:00
|
|
|
/*
|
|
|
|
* 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")) {
|
2010-02-04 22:52:34 +01:00
|
|
|
def->os.init = virXPathString("string(./os/init[1])", ctxt);
|
2008-08-01 13:31:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (STREQ(def->os.type, "xen") ||
|
2008-11-19 16:58:23 +00:00
|
|
|
STREQ(def->os.type, "hvm") ||
|
|
|
|
STREQ(def->os.type, "uml")) {
|
2010-02-04 22:52:34 +01:00
|
|
|
def->os.kernel = virXPathString("string(./os/kernel[1])", ctxt);
|
|
|
|
def->os.initrd = virXPathString("string(./os/initrd[1])", ctxt);
|
|
|
|
def->os.cmdline = virXPathString("string(./os/cmdline[1])", ctxt);
|
|
|
|
def->os.root = virXPathString("string(./os/root[1])", ctxt);
|
|
|
|
def->os.loader = virXPathString("string(./os/loader[1])", ctxt);
|
2008-11-19 16:58:23 +00:00
|
|
|
}
|
2008-07-11 16:23:36 +00:00
|
|
|
|
2008-11-19 16:58:23 +00:00
|
|
|
if (STREQ(def->os.type, "hvm")) {
|
2008-07-11 16:23:36 +00:00
|
|
|
/* analysis of the boot devices */
|
2010-02-04 22:52:34 +01:00
|
|
|
if ((n = virXPathNodeSet("./os/boot", ctxt, &nodes)) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
"%s", _("cannot extract boot device"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
for (i = 0 ; i < n && i < VIR_DOMAIN_BOOT_LAST ; i++) {
|
|
|
|
int val;
|
|
|
|
char *dev = virXMLPropString(nodes[i], "dev");
|
|
|
|
if (!dev) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
"%s", _("missing boot device"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if ((val = virDomainBootTypeFromString(dev)) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
_("unknown boot device '%s'"),
|
|
|
|
dev);
|
|
|
|
VIR_FREE(dev);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
VIR_FREE(dev);
|
|
|
|
def->os.bootDevs[def->os.nBootDevs++] = val;
|
|
|
|
}
|
|
|
|
if (def->os.nBootDevs == 0) {
|
|
|
|
def->os.nBootDevs = 1;
|
|
|
|
def->os.bootDevs[0] = VIR_DOMAIN_BOOT_DISK;
|
|
|
|
}
|
|
|
|
VIR_FREE(nodes);
|
|
|
|
}
|
|
|
|
|
2010-02-04 22:52:34 +01:00
|
|
|
def->emulator = virXPathString("string(./devices/emulator[1])", ctxt);
|
2009-06-16 15:42:46 +00:00
|
|
|
if (!def->emulator && virCapabilitiesIsEmulatorRequired(caps)) {
|
2010-02-09 18:58:01 +00:00
|
|
|
def->emulator = virDomainDefDefaultEmulator(def, caps);
|
2009-06-16 15:42:46 +00:00
|
|
|
if (!def->emulator)
|
|
|
|
goto error;
|
|
|
|
}
|
2008-07-11 16:23:36 +00:00
|
|
|
|
|
|
|
/* analysis of the disk devices */
|
2010-02-04 22:52:34 +01:00
|
|
|
if ((n = virXPathNodeSet("./devices/disk", ctxt, &nodes)) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
"%s", _("cannot extract disk devices"));
|
|
|
|
goto error;
|
|
|
|
}
|
2008-10-10 16:08:01 +00:00
|
|
|
if (n && VIR_ALLOC_N(def->disks, n) < 0)
|
|
|
|
goto no_memory;
|
2008-07-11 16:23:36 +00:00
|
|
|
for (i = 0 ; i < n ; i++) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainDiskDefPtr disk = virDomainDiskDefParseXML(nodes[i],
|
2009-01-08 13:54:20 +00:00
|
|
|
flags);
|
2008-07-11 16:23:36 +00:00
|
|
|
if (!disk)
|
|
|
|
goto error;
|
|
|
|
|
2008-10-10 16:08:01 +00:00
|
|
|
def->disks[def->ndisks++] = disk;
|
2008-07-11 16:23:36 +00:00
|
|
|
}
|
|
|
|
VIR_FREE(nodes);
|
|
|
|
|
2009-12-02 19:15:38 +00:00
|
|
|
/* analysis of the controller devices */
|
2010-02-04 22:52:34 +01:00
|
|
|
if ((n = virXPathNodeSet("./devices/controller", ctxt, &nodes)) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-12-02 19:15:38 +00:00
|
|
|
"%s", _("cannot extract controller devices"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (n && VIR_ALLOC_N(def->controllers, n) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
for (i = 0 ; i < n ; i++) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainControllerDefPtr controller = virDomainControllerDefParseXML(nodes[i],
|
2009-12-02 19:15:38 +00:00
|
|
|
flags);
|
|
|
|
if (!controller)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
def->controllers[def->ncontrollers++] = controller;
|
|
|
|
}
|
|
|
|
VIR_FREE(nodes);
|
|
|
|
|
2008-08-01 13:31:37 +00:00
|
|
|
/* analysis of the filesystems */
|
2010-02-04 22:52:34 +01:00
|
|
|
if ((n = virXPathNodeSet("./devices/filesystem", ctxt, &nodes)) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-08-01 13:31:37 +00:00
|
|
|
"%s", _("cannot extract filesystem devices"));
|
|
|
|
goto error;
|
|
|
|
}
|
2008-10-10 16:08:01 +00:00
|
|
|
if (n && VIR_ALLOC_N(def->fss, n) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
for (i = 0 ; i < n ; i++) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainFSDefPtr fs = virDomainFSDefParseXML(nodes[i],
|
2009-01-08 13:54:20 +00:00
|
|
|
flags);
|
2008-08-01 13:31:37 +00:00
|
|
|
if (!fs)
|
|
|
|
goto error;
|
|
|
|
|
2008-10-10 16:08:01 +00:00
|
|
|
def->fss[def->nfss++] = fs;
|
2008-08-01 13:31:37 +00:00
|
|
|
}
|
|
|
|
VIR_FREE(nodes);
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
/* analysis of the network devices */
|
2010-02-04 22:52:34 +01:00
|
|
|
if ((n = virXPathNodeSet("./devices/interface", ctxt, &nodes)) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
"%s", _("cannot extract network devices"));
|
|
|
|
goto error;
|
|
|
|
}
|
2008-10-10 16:08:01 +00:00
|
|
|
if (n && VIR_ALLOC_N(def->nets, n) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
for (i = 0 ; i < n ; i++) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainNetDefPtr net = virDomainNetDefParseXML(caps,
|
2009-01-08 13:54:20 +00:00
|
|
|
nodes[i],
|
|
|
|
flags);
|
2008-07-11 16:23:36 +00:00
|
|
|
if (!net)
|
|
|
|
goto error;
|
|
|
|
|
2008-10-10 16:08:01 +00:00
|
|
|
def->nets[def->nnets++] = net;
|
2008-07-11 16:23:36 +00:00
|
|
|
}
|
|
|
|
VIR_FREE(nodes);
|
|
|
|
|
|
|
|
|
|
|
|
/* analysis of the character devices */
|
2010-02-04 22:52:34 +01:00
|
|
|
if ((n = virXPathNodeSet("./devices/parallel", ctxt, &nodes)) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
"%s", _("cannot extract parallel devices"));
|
|
|
|
goto error;
|
|
|
|
}
|
2008-10-10 16:08:01 +00:00
|
|
|
if (n && VIR_ALLOC_N(def->parallels, n) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
for (i = 0 ; i < n ; i++) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainChrDefPtr chr = virDomainChrDefParseXML(nodes[i],
|
2009-01-08 13:54:20 +00:00
|
|
|
flags);
|
2008-07-11 16:23:36 +00:00
|
|
|
if (!chr)
|
|
|
|
goto error;
|
|
|
|
|
2009-11-05 14:19:14 +01:00
|
|
|
chr->target.port = i;
|
2008-10-10 16:08:01 +00:00
|
|
|
def->parallels[def->nparallels++] = chr;
|
2008-07-11 16:23:36 +00:00
|
|
|
}
|
|
|
|
VIR_FREE(nodes);
|
|
|
|
|
2010-02-04 22:52:34 +01:00
|
|
|
if ((n = virXPathNodeSet("./devices/serial", ctxt, &nodes)) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
"%s", _("cannot extract serial devices"));
|
|
|
|
goto error;
|
|
|
|
}
|
2008-10-10 16:08:01 +00:00
|
|
|
if (n && VIR_ALLOC_N(def->serials, n) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
for (i = 0 ; i < n ; i++) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainChrDefPtr chr = virDomainChrDefParseXML(nodes[i],
|
2009-01-08 13:54:20 +00:00
|
|
|
flags);
|
2008-07-11 16:23:36 +00:00
|
|
|
if (!chr)
|
|
|
|
goto error;
|
|
|
|
|
2009-11-05 14:19:14 +01:00
|
|
|
chr->target.port = i;
|
2008-10-10 16:08:01 +00:00
|
|
|
def->serials[def->nserials++] = chr;
|
2008-07-11 16:23:36 +00:00
|
|
|
}
|
|
|
|
VIR_FREE(nodes);
|
|
|
|
|
2010-02-04 22:52:34 +01:00
|
|
|
if ((node = virXPathNode("./devices/console[1]", ctxt)) != NULL) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainChrDefPtr chr = virDomainChrDefParseXML(node,
|
2009-01-08 13:54:20 +00:00
|
|
|
flags);
|
2008-11-19 16:58:23 +00:00
|
|
|
if (!chr)
|
|
|
|
goto error;
|
2008-07-11 16:23:36 +00:00
|
|
|
|
2009-11-05 14:19:14 +01:00
|
|
|
chr->target.port = 0;
|
2008-11-19 16:58:23 +00:00
|
|
|
/*
|
|
|
|
* For HVM console actually created a serial device
|
|
|
|
* while for non-HVM it was a parvirt console
|
|
|
|
*/
|
|
|
|
if (STREQ(def->os.type, "hvm")) {
|
|
|
|
if (def->nserials != 0) {
|
|
|
|
virDomainChrDefFree(chr);
|
|
|
|
} else {
|
2008-10-10 16:08:01 +00:00
|
|
|
if (VIR_ALLOC_N(def->serials, 1) < 0) {
|
|
|
|
virDomainChrDefFree(chr);
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
def->nserials = 1;
|
|
|
|
def->serials[0] = chr;
|
2010-01-22 13:19:24 +00:00
|
|
|
chr->targetType = VIR_DOMAIN_CHR_TARGET_TYPE_SERIAL;
|
2008-07-11 16:23:36 +00:00
|
|
|
}
|
2008-11-19 16:58:23 +00:00
|
|
|
} else {
|
|
|
|
def->console = chr;
|
2008-07-11 16:23:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-02-04 22:52:34 +01:00
|
|
|
if ((n = virXPathNodeSet("./devices/channel", ctxt, &nodes)) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-11-05 15:31:03 +01:00
|
|
|
"%s", _("cannot extract channel devices"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (n && VIR_ALLOC_N(def->channels, n) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
for (i = 0 ; i < n ; i++) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainChrDefPtr chr = virDomainChrDefParseXML(nodes[i],
|
2009-11-05 15:31:03 +01:00
|
|
|
flags);
|
|
|
|
if (!chr)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
def->channels[def->nchannels++] = chr;
|
|
|
|
}
|
|
|
|
VIR_FREE(nodes);
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
|
|
|
|
/* analysis of the input devices */
|
2010-02-04 22:52:34 +01:00
|
|
|
if ((n = virXPathNodeSet("./devices/input", ctxt, &nodes)) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
"%s", _("cannot extract input devices"));
|
|
|
|
goto error;
|
|
|
|
}
|
2008-10-10 16:08:01 +00:00
|
|
|
if (n && VIR_ALLOC_N(def->inputs, n) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
for (i = 0 ; i < n ; i++) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainInputDefPtr input = virDomainInputDefParseXML(def->os.type,
|
2009-01-08 13:54:20 +00:00
|
|
|
nodes[i],
|
|
|
|
flags);
|
2008-07-11 16:23:36 +00:00
|
|
|
if (!input)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
|
|
|
|
/* With QEMU / KVM / Xen graphics, mouse + PS/2 is implicit
|
|
|
|
* with graphics, so don't store it.
|
|
|
|
* XXX will this be true for other virt types ? */
|
|
|
|
if ((STREQ(def->os.type, "hvm") &&
|
|
|
|
input->bus == VIR_DOMAIN_INPUT_BUS_PS2 &&
|
|
|
|
input->type == VIR_DOMAIN_INPUT_TYPE_MOUSE) ||
|
|
|
|
(STRNEQ(def->os.type, "hvm") &&
|
|
|
|
input->bus == VIR_DOMAIN_INPUT_BUS_XEN &&
|
|
|
|
input->type == VIR_DOMAIN_INPUT_TYPE_MOUSE)) {
|
|
|
|
virDomainInputDefFree(input);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2008-10-10 16:08:01 +00:00
|
|
|
def->inputs[def->ninputs++] = input;
|
2008-07-11 16:23:36 +00:00
|
|
|
}
|
|
|
|
VIR_FREE(nodes);
|
|
|
|
|
2008-07-25 16:25:11 +00:00
|
|
|
/* analysis of the graphics devices */
|
2010-02-04 22:52:34 +01:00
|
|
|
if ((n = virXPathNodeSet("./devices/graphics", ctxt, &nodes)) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
"%s", _("cannot extract graphics devices"));
|
|
|
|
goto error;
|
|
|
|
}
|
2009-05-07 07:27:49 +00:00
|
|
|
if (n && VIR_ALLOC_N(def->graphics, n) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
for (i = 0 ; i < n ; i++) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainGraphicsDefPtr graphics = virDomainGraphicsDefParseXML(nodes[i],
|
2008-12-04 12:02:59 +00:00
|
|
|
flags);
|
2008-07-11 16:23:36 +00:00
|
|
|
if (!graphics)
|
|
|
|
goto error;
|
|
|
|
|
2009-05-07 07:27:49 +00:00
|
|
|
def->graphics[def->ngraphics++] = graphics;
|
2008-07-11 16:23:36 +00:00
|
|
|
}
|
|
|
|
VIR_FREE(nodes);
|
|
|
|
|
|
|
|
/* If graphics are enabled, there's an implicit PS2 mouse */
|
2009-05-07 07:27:49 +00:00
|
|
|
if (def->ngraphics > 0) {
|
2008-07-11 16:23:36 +00:00
|
|
|
virDomainInputDefPtr input;
|
|
|
|
|
|
|
|
if (VIR_ALLOC(input) < 0) {
|
2010-02-04 19:19:08 +01:00
|
|
|
virReportOOMError();
|
2008-07-11 16:23:36 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (STREQ(def->os.type, "hvm")) {
|
|
|
|
input->type = VIR_DOMAIN_INPUT_TYPE_MOUSE;
|
|
|
|
input->bus = VIR_DOMAIN_INPUT_BUS_PS2;
|
|
|
|
} else {
|
|
|
|
input->type = VIR_DOMAIN_INPUT_TYPE_MOUSE;
|
|
|
|
input->bus = VIR_DOMAIN_INPUT_BUS_XEN;
|
|
|
|
}
|
2008-10-10 16:08:01 +00:00
|
|
|
|
|
|
|
if (VIR_REALLOC_N(def->inputs, def->ninputs + 1) < 0) {
|
|
|
|
virDomainInputDefFree(input);
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
def->inputs[def->ninputs] = input;
|
|
|
|
def->ninputs++;
|
2008-07-11 16:23:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* analysis of the sound devices */
|
2010-02-04 22:52:34 +01:00
|
|
|
if ((n = virXPathNodeSet("./devices/sound", ctxt, &nodes)) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
"%s", _("cannot extract sound devices"));
|
|
|
|
goto error;
|
|
|
|
}
|
2008-10-10 16:08:01 +00:00
|
|
|
if (n && VIR_ALLOC_N(def->sounds, n) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
for (i = 0 ; i < n ; i++) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainSoundDefPtr sound = virDomainSoundDefParseXML(nodes[i],
|
2009-01-08 13:54:20 +00:00
|
|
|
flags);
|
2008-07-11 16:23:36 +00:00
|
|
|
if (!sound)
|
|
|
|
goto error;
|
|
|
|
|
2008-10-10 16:08:01 +00:00
|
|
|
def->sounds[def->nsounds++] = sound;
|
2008-07-11 16:23:36 +00:00
|
|
|
}
|
|
|
|
VIR_FREE(nodes);
|
|
|
|
|
2009-07-06 14:54:44 +01:00
|
|
|
/* analysis of the video devices */
|
2010-02-04 22:52:34 +01:00
|
|
|
if ((n = virXPathNodeSet("./devices/video", ctxt, &nodes)) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-07-06 14:54:44 +01:00
|
|
|
"%s", _("cannot extract video devices"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (n && VIR_ALLOC_N(def->videos, n) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
for (i = 0 ; i < n ; i++) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainVideoDefPtr video = virDomainVideoDefParseXML(nodes[i],
|
2009-07-06 14:54:44 +01:00
|
|
|
def,
|
|
|
|
flags);
|
|
|
|
if (!video)
|
|
|
|
goto error;
|
|
|
|
def->videos[def->nvideos++] = video;
|
|
|
|
}
|
|
|
|
VIR_FREE(nodes);
|
|
|
|
|
|
|
|
/* For backwards compatability, if no <video> tag is set but there
|
|
|
|
* is a <graphics> tag, then we add a single video tag */
|
|
|
|
if (def->ngraphics && !def->nvideos) {
|
|
|
|
virDomainVideoDefPtr video;
|
|
|
|
if (VIR_ALLOC(video) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
video->type = virDomainVideoDefaultType(def);
|
|
|
|
if (video->type < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
2009-07-06 14:54:44 +01:00
|
|
|
_("cannot determine default video type"));
|
|
|
|
VIR_FREE(video);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
video->vram = virDomainVideoDefaultRAM(def, video->type);
|
|
|
|
video->heads = 1;
|
|
|
|
if (VIR_ALLOC_N(def->videos, 1) < 0) {
|
|
|
|
virDomainVideoDefFree(video);
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
def->videos[def->nvideos++] = video;
|
|
|
|
}
|
|
|
|
|
2008-08-08 14:27:05 +00:00
|
|
|
/* analysis of the host devices */
|
2010-02-04 22:52:34 +01:00
|
|
|
if ((n = virXPathNodeSet("./devices/hostdev", ctxt, &nodes)) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-08-08 14:27:05 +00:00
|
|
|
"%s", _("cannot extract host devices"));
|
|
|
|
goto error;
|
|
|
|
}
|
2008-10-10 16:08:01 +00:00
|
|
|
if (n && VIR_ALLOC_N(def->hostdevs, n) < 0)
|
|
|
|
goto no_memory;
|
2008-08-08 14:27:05 +00:00
|
|
|
for (i = 0 ; i < n ; i++) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainHostdevDefPtr hostdev = virDomainHostdevDefParseXML(nodes[i],
|
2009-01-08 13:54:20 +00:00
|
|
|
flags);
|
2008-08-08 14:27:05 +00:00
|
|
|
if (!hostdev)
|
|
|
|
goto error;
|
|
|
|
|
2008-10-10 16:08:01 +00:00
|
|
|
def->hostdevs[def->nhostdevs++] = hostdev;
|
2008-08-08 14:27:05 +00:00
|
|
|
}
|
|
|
|
VIR_FREE(nodes);
|
|
|
|
|
2009-10-21 13:26:38 +01:00
|
|
|
/* analysis of the watchdog devices */
|
|
|
|
def->watchdog = NULL;
|
2010-02-04 22:52:34 +01:00
|
|
|
if ((n = virXPathNodeSet("./devices/watchdog", ctxt, &nodes)) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-10-21 13:26:38 +01:00
|
|
|
"%s", _("cannot extract watchdog devices"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (n > 1) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError (VIR_ERR_INTERNAL_ERROR,
|
2009-10-21 13:26:38 +01:00
|
|
|
"%s", _("only a single watchdog device is supported"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (n > 0) {
|
|
|
|
virDomainWatchdogDefPtr watchdog =
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainWatchdogDefParseXML(nodes[0], flags);
|
2009-10-21 13:26:38 +01:00
|
|
|
if (!watchdog)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
def->watchdog = watchdog;
|
|
|
|
VIR_FREE(nodes);
|
|
|
|
}
|
|
|
|
|
2009-03-03 09:44:41 +00:00
|
|
|
/* analysis of security label */
|
2010-02-09 18:58:01 +00:00
|
|
|
if (virSecurityLabelDefParseXML(def, ctxt, flags) == -1)
|
2009-03-03 09:44:41 +00:00
|
|
|
goto error;
|
|
|
|
|
2010-02-04 22:52:34 +01:00
|
|
|
if ((node = virXPathNode("./cpu[1]", ctxt)) != NULL) {
|
2009-12-18 14:44:55 +01:00
|
|
|
xmlNodePtr oldnode = ctxt->node;
|
|
|
|
ctxt->node = node;
|
2010-02-10 12:22:36 +00:00
|
|
|
def->cpu = virCPUDefParseXML(node, ctxt, VIR_CPU_TYPE_GUEST);
|
2009-12-18 14:44:55 +01:00
|
|
|
ctxt->node = oldnode;
|
|
|
|
|
|
|
|
if (def->cpu == NULL)
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2010-02-18 17:52:03 +01:00
|
|
|
/* Auto-add any implied controllers which aren't present
|
|
|
|
*/
|
|
|
|
if (virDomainDefAddImplicitControllers(def) < 0)
|
|
|
|
goto error;
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
return def;
|
|
|
|
|
2008-10-10 16:08:01 +00:00
|
|
|
no_memory:
|
2010-02-04 19:19:08 +01:00
|
|
|
virReportOOMError();
|
2008-10-10 16:08:01 +00:00
|
|
|
/* fallthrough */
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
error:
|
|
|
|
VIR_FREE(tmp);
|
|
|
|
VIR_FREE(nodes);
|
|
|
|
virDomainDefFree(def);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2009-06-12 11:38:50 +00:00
|
|
|
|
2010-02-09 18:58:01 +00:00
|
|
|
static virDomainObjPtr virDomainObjParseXML(virCapsPtr caps,
|
2009-06-12 11:38:50 +00:00
|
|
|
xmlXPathContextPtr ctxt)
|
|
|
|
{
|
|
|
|
char *tmp = NULL;
|
|
|
|
long val;
|
|
|
|
xmlNodePtr config;
|
|
|
|
xmlNodePtr oldnode;
|
|
|
|
virDomainObjPtr obj;
|
|
|
|
|
2010-02-09 18:58:01 +00:00
|
|
|
if (!(obj = virDomainObjNew(caps)))
|
2009-06-12 11:38:50 +00:00
|
|
|
return NULL;
|
|
|
|
|
2010-02-04 22:52:34 +01:00
|
|
|
if (!(config = virXPathNode("./domain", ctxt))) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-06-12 11:38:50 +00:00
|
|
|
"%s", _("no domain config"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
oldnode = ctxt->node;
|
|
|
|
ctxt->node = config;
|
2010-02-09 18:58:01 +00:00
|
|
|
obj->def = virDomainDefParseXML(caps, ctxt,
|
2009-07-17 22:08:33 +01:00
|
|
|
VIR_DOMAIN_XML_INTERNAL_STATUS);
|
2009-06-12 11:38:50 +00:00
|
|
|
ctxt->node = oldnode;
|
|
|
|
if (!obj->def)
|
|
|
|
goto error;
|
|
|
|
|
2010-02-04 22:52:34 +01:00
|
|
|
if (!(tmp = virXPathString("string(./@state)", ctxt))) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-06-12 11:38:50 +00:00
|
|
|
"%s", _("missing domain state"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if ((obj->state = virDomainStateTypeFromString(tmp)) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-06-12 11:38:50 +00:00
|
|
|
_("invalid domain state '%s'"), tmp);
|
|
|
|
VIR_FREE(tmp);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
VIR_FREE(tmp);
|
|
|
|
|
2010-02-04 22:52:34 +01:00
|
|
|
if ((virXPathLong("string(./@pid)", ctxt, &val)) < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-06-12 11:38:50 +00:00
|
|
|
"%s", _("invalid pid"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
obj->pid = (pid_t)val;
|
|
|
|
|
2009-11-26 17:57:00 +00:00
|
|
|
if (caps->privateDataXMLParse &&
|
|
|
|
((caps->privateDataXMLParse)(ctxt, obj->privateData)) < 0)
|
2009-06-12 11:38:50 +00:00
|
|
|
goto error;
|
2009-09-11 16:26:40 +01:00
|
|
|
|
2009-06-12 11:38:50 +00:00
|
|
|
return obj;
|
|
|
|
|
|
|
|
error:
|
2009-10-15 12:30:26 +01:00
|
|
|
virDomainObjUnref(obj);
|
2009-06-12 11:38:50 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-02-24 21:53:16 +01:00
|
|
|
static virDomainDefPtr
|
|
|
|
virDomainDefParse(const char *xmlStr,
|
|
|
|
const char *filename,
|
|
|
|
virCapsPtr caps,
|
|
|
|
int flags)
|
2008-08-01 09:39:44 +00:00
|
|
|
{
|
2010-02-24 21:53:16 +01:00
|
|
|
xmlDocPtr xml;
|
|
|
|
virDomainDefPtr def = NULL;
|
|
|
|
|
|
|
|
if ((xml = virXMLParse(filename, xmlStr, "domain.xml"))) {
|
|
|
|
def = virDomainDefParseNode(caps, xml, xmlDocGetRootElement(xml), flags);
|
|
|
|
xmlFreeDoc(xml);
|
2008-08-01 09:39:44 +00:00
|
|
|
}
|
2010-02-24 21:53:16 +01:00
|
|
|
|
|
|
|
return def;
|
2008-08-01 09:39:44 +00:00
|
|
|
}
|
2008-07-11 16:23:36 +00:00
|
|
|
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainDefPtr virDomainDefParseString(virCapsPtr caps,
|
2009-01-08 13:54:20 +00:00
|
|
|
const char *xmlStr,
|
|
|
|
int flags)
|
2008-07-11 16:23:36 +00:00
|
|
|
{
|
2010-02-24 21:53:16 +01:00
|
|
|
return virDomainDefParse(xmlStr, NULL, caps, flags);
|
2008-07-11 16:23:36 +00:00
|
|
|
}
|
|
|
|
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainDefPtr virDomainDefParseFile(virCapsPtr caps,
|
2010-02-24 21:53:16 +01:00
|
|
|
const char *filename,
|
|
|
|
int flags)
|
2008-07-11 16:23:36 +00:00
|
|
|
{
|
2010-02-24 21:53:16 +01:00
|
|
|
return virDomainDefParse(NULL, filename, caps, flags);
|
2008-07-11 16:23:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainDefPtr virDomainDefParseNode(virCapsPtr caps,
|
2008-07-11 16:23:36 +00:00
|
|
|
xmlDocPtr xml,
|
2008-12-04 12:02:59 +00:00
|
|
|
xmlNodePtr root,
|
|
|
|
int flags)
|
2008-07-11 16:23:36 +00:00
|
|
|
{
|
|
|
|
xmlXPathContextPtr ctxt = NULL;
|
|
|
|
virDomainDefPtr def = NULL;
|
|
|
|
|
|
|
|
if (!xmlStrEqual(root->name, BAD_CAST "domain")) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
"%s", _("incorrect root element"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctxt = xmlXPathNewContext(xml);
|
|
|
|
if (ctxt == NULL) {
|
2010-02-04 19:19:08 +01:00
|
|
|
virReportOOMError();
|
2008-07-11 16:23:36 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctxt->node = root;
|
2010-02-09 18:58:01 +00:00
|
|
|
def = virDomainDefParseXML(caps, ctxt, flags);
|
2008-07-11 16:23:36 +00:00
|
|
|
|
|
|
|
cleanup:
|
|
|
|
xmlXPathFreeContext(ctxt);
|
|
|
|
return def;
|
|
|
|
}
|
2009-06-12 11:38:50 +00:00
|
|
|
|
|
|
|
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainObjPtr virDomainObjParseFile(virCapsPtr caps,
|
2009-06-12 11:38:50 +00:00
|
|
|
const char *filename)
|
|
|
|
{
|
2010-02-24 21:53:16 +01:00
|
|
|
xmlDocPtr xml;
|
2009-06-12 11:38:50 +00:00
|
|
|
virDomainObjPtr obj = NULL;
|
|
|
|
|
2010-02-24 21:53:16 +01:00
|
|
|
if ((xml = virXMLParseFile(filename))) {
|
|
|
|
obj = virDomainObjParseNode(caps, xml, xmlDocGetRootElement(xml));
|
|
|
|
xmlFreeDoc(xml);
|
2009-06-12 11:38:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainObjPtr virDomainObjParseNode(virCapsPtr caps,
|
2009-06-12 11:38:50 +00:00
|
|
|
xmlDocPtr xml,
|
|
|
|
xmlNodePtr root)
|
|
|
|
{
|
|
|
|
xmlXPathContextPtr ctxt = NULL;
|
|
|
|
virDomainObjPtr obj = NULL;
|
|
|
|
|
|
|
|
if (!xmlStrEqual(root->name, BAD_CAST "domstatus")) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-06-12 11:38:50 +00:00
|
|
|
"%s", _("incorrect root element"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctxt = xmlXPathNewContext(xml);
|
|
|
|
if (ctxt == NULL) {
|
2010-02-04 19:19:08 +01:00
|
|
|
virReportOOMError();
|
2009-06-12 11:38:50 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctxt->node = root;
|
2010-02-09 18:58:01 +00:00
|
|
|
obj = virDomainObjParseXML(caps, ctxt);
|
2009-06-12 11:38:50 +00:00
|
|
|
|
|
|
|
cleanup:
|
|
|
|
xmlXPathFreeContext(ctxt);
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
2010-02-18 17:52:03 +01:00
|
|
|
static int virDomainDefMaybeAddController(virDomainDefPtr def,
|
|
|
|
int type,
|
|
|
|
int idx)
|
2010-01-05 13:31:20 +00:00
|
|
|
{
|
|
|
|
int found = 0;
|
|
|
|
int i;
|
|
|
|
virDomainControllerDefPtr cont;
|
|
|
|
|
|
|
|
for (i = 0 ; (i < def->ncontrollers) && !found; i++) {
|
|
|
|
if (def->controllers[i]->type == type &&
|
|
|
|
def->controllers[i]->idx == idx)
|
|
|
|
found = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (found)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (VIR_ALLOC(cont) < 0) {
|
2010-02-04 19:19:08 +01:00
|
|
|
virReportOOMError();
|
2010-01-05 13:31:20 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
cont->type = type;
|
|
|
|
cont->idx = idx;
|
|
|
|
|
|
|
|
if (VIR_REALLOC_N(def->controllers, def->ncontrollers+1) < 0) {
|
|
|
|
VIR_FREE(cont);
|
2010-02-04 19:19:08 +01:00
|
|
|
virReportOOMError();
|
2010-01-05 13:31:20 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
def->controllers[def->ncontrollers] = cont;
|
|
|
|
def->ncontrollers++;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int virDomainDefAddDiskControllersForType(virDomainDefPtr def,
|
|
|
|
int controllerType,
|
|
|
|
int diskBus)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int maxController = -1;
|
|
|
|
|
|
|
|
for (i = 0 ; i < def->ndisks ; i++) {
|
|
|
|
if (def->disks[i]->bus != diskBus)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (def->disks[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if ((int)def->disks[i]->info.addr.drive.controller > maxController)
|
|
|
|
maxController = def->disks[i]->info.addr.drive.controller;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0 ; i <= maxController ; i++) {
|
2010-02-18 17:52:03 +01:00
|
|
|
if (virDomainDefMaybeAddController(def, controllerType, i) < 0)
|
2010-01-05 13:31:20 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-02-18 17:52:03 +01:00
|
|
|
static int virDomainDefMaybeAddVirtioSerialController(virDomainDefPtr def)
|
|
|
|
{
|
|
|
|
/* Look for any virtio serial device */
|
|
|
|
int i;
|
|
|
|
for (i = 0 ; i < def->nchannels ; i++) {
|
|
|
|
virDomainChrDefPtr channel = def->channels[i];
|
|
|
|
|
|
|
|
if (channel->targetType == VIR_DOMAIN_CHR_TARGET_TYPE_VIRTIO) {
|
|
|
|
/* Try to add a virtio serial controller with index 0 */
|
|
|
|
if (virDomainDefMaybeAddController(def,
|
|
|
|
VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL, 0) < 0)
|
|
|
|
return -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-01-05 13:31:20 +00:00
|
|
|
/*
|
2010-02-18 17:52:03 +01:00
|
|
|
* Based on the declared <address/> info for any devices,
|
2010-01-05 13:31:20 +00:00
|
|
|
* add neccessary drive controllers which are not already present
|
|
|
|
* in the XML. This is for compat with existing apps which will
|
|
|
|
* not know/care about <controller> info in the XML
|
|
|
|
*/
|
2010-02-18 17:52:03 +01:00
|
|
|
int virDomainDefAddImplicitControllers(virDomainDefPtr def)
|
2010-01-05 13:31:20 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
2010-02-18 17:52:03 +01:00
|
|
|
if (virDomainDefMaybeAddVirtioSerialController(def) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2010-01-05 13:31:20 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-07-25 10:49:33 +00:00
|
|
|
#endif /* ! PROXY */
|
2008-07-11 16:23:36 +00:00
|
|
|
|
|
|
|
/************************************************************************
|
2009-01-07 12:56:13 +00:00
|
|
|
* *
|
|
|
|
* Parser and converter for the CPUset strings used in libvirt *
|
|
|
|
* *
|
2008-07-11 16:23:36 +00:00
|
|
|
************************************************************************/
|
|
|
|
/**
|
|
|
|
* virDomainCpuNumberParse
|
|
|
|
* @str: pointer to the char pointer used
|
|
|
|
* @maxcpu: maximum CPU number allowed
|
|
|
|
*
|
|
|
|
* Parse a CPU number
|
|
|
|
*
|
|
|
|
* Returns the CPU number or -1 in case of error. @str will be
|
|
|
|
* updated to skip the number.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
virDomainCpuNumberParse(const char **str, int maxcpu)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
const char *cur = *str;
|
|
|
|
|
|
|
|
if (!c_isdigit(*cur))
|
|
|
|
return (-1);
|
|
|
|
|
|
|
|
while (c_isdigit(*cur)) {
|
|
|
|
ret = ret * 10 + (*cur - '0');
|
|
|
|
if (ret >= maxcpu)
|
|
|
|
return (-1);
|
|
|
|
cur++;
|
|
|
|
}
|
|
|
|
*str = cur;
|
|
|
|
return (ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virDomainCpuSetFormat:
|
|
|
|
* @conn: connection
|
|
|
|
* @cpuset: pointer to a char array for the CPU set
|
|
|
|
* @maxcpu: number of elements available in @cpuset
|
|
|
|
*
|
|
|
|
* Serialize the cpuset to a string
|
|
|
|
*
|
|
|
|
* Returns the new string NULL in case of error. The string need to be
|
|
|
|
* freed by the caller.
|
|
|
|
*/
|
|
|
|
char *
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainCpuSetFormat(char *cpuset, int maxcpu)
|
2008-07-11 16:23:36 +00:00
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
int start, cur;
|
|
|
|
int first = 1;
|
|
|
|
|
|
|
|
if ((cpuset == NULL) || (maxcpu <= 0) || (maxcpu > 100000))
|
|
|
|
return (NULL);
|
|
|
|
|
|
|
|
cur = 0;
|
|
|
|
start = -1;
|
|
|
|
while (cur < maxcpu) {
|
|
|
|
if (cpuset[cur]) {
|
|
|
|
if (start == -1)
|
|
|
|
start = cur;
|
|
|
|
} else if (start != -1) {
|
|
|
|
if (!first)
|
|
|
|
virBufferAddLit(&buf, ",");
|
|
|
|
else
|
|
|
|
first = 0;
|
|
|
|
if (cur == start + 1)
|
|
|
|
virBufferVSprintf(&buf, "%d", start);
|
|
|
|
else
|
|
|
|
virBufferVSprintf(&buf, "%d-%d", start, cur - 1);
|
|
|
|
start = -1;
|
|
|
|
}
|
|
|
|
cur++;
|
|
|
|
}
|
|
|
|
if (start != -1) {
|
|
|
|
if (!first)
|
|
|
|
virBufferAddLit(&buf, ",");
|
|
|
|
if (maxcpu == start + 1)
|
|
|
|
virBufferVSprintf(&buf, "%d", start);
|
|
|
|
else
|
|
|
|
virBufferVSprintf(&buf, "%d-%d", start, maxcpu - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virBufferError(&buf)) {
|
2009-12-10 00:00:50 +01:00
|
|
|
virBufferFreeAndReset(&buf);
|
2010-02-04 19:19:08 +01:00
|
|
|
virReportOOMError();
|
2008-07-11 16:23:36 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virDomainCpuSetParse:
|
|
|
|
* @conn: connection
|
|
|
|
* @str: pointer to a CPU set string pointer
|
|
|
|
* @sep: potential character used to mark the end of string if not 0
|
|
|
|
* @cpuset: pointer to a char array for the CPU set
|
|
|
|
* @maxcpu: number of elements available in @cpuset
|
|
|
|
*
|
|
|
|
* Parse the cpu set, it will set the value for enabled CPUs in the @cpuset
|
|
|
|
* to 1, and 0 otherwise. The syntax allows coma separated entries each
|
|
|
|
* can be either a CPU number, ^N to unset that CPU or N-M for ranges.
|
|
|
|
*
|
|
|
|
* Returns the number of CPU found in that set, or -1 in case of error.
|
|
|
|
* @cpuset is modified accordingly to the value parsed.
|
|
|
|
* @str is updated to the end of the part parsed
|
|
|
|
*/
|
|
|
|
int
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainCpuSetParse(const char **str, char sep,
|
2008-07-11 16:23:36 +00:00
|
|
|
char *cpuset, int maxcpu)
|
|
|
|
{
|
|
|
|
const char *cur;
|
|
|
|
int ret = 0;
|
|
|
|
int i, start, last;
|
|
|
|
int neg = 0;
|
|
|
|
|
|
|
|
if ((str == NULL) || (cpuset == NULL) || (maxcpu <= 0) ||
|
|
|
|
(maxcpu > 100000))
|
|
|
|
return (-1);
|
|
|
|
|
|
|
|
cur = *str;
|
|
|
|
virSkipSpaces(&cur);
|
|
|
|
if (*cur == 0)
|
|
|
|
goto parse_error;
|
|
|
|
|
|
|
|
/* initialize cpumap to all 0s */
|
|
|
|
for (i = 0; i < maxcpu; i++)
|
|
|
|
cpuset[i] = 0;
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
while ((*cur != 0) && (*cur != sep)) {
|
|
|
|
/*
|
|
|
|
* 3 constructs are allowed:
|
|
|
|
* - N : a single CPU number
|
|
|
|
* - N-M : a range of CPU numbers with N < M
|
|
|
|
* - ^N : remove a single CPU number from the current set
|
|
|
|
*/
|
|
|
|
if (*cur == '^') {
|
|
|
|
cur++;
|
|
|
|
neg = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!c_isdigit(*cur))
|
|
|
|
goto parse_error;
|
|
|
|
start = virDomainCpuNumberParse(&cur, maxcpu);
|
|
|
|
if (start < 0)
|
|
|
|
goto parse_error;
|
|
|
|
virSkipSpaces(&cur);
|
|
|
|
if ((*cur == ',') || (*cur == 0) || (*cur == sep)) {
|
|
|
|
if (neg) {
|
|
|
|
if (cpuset[start] == 1) {
|
|
|
|
cpuset[start] = 0;
|
|
|
|
ret--;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (cpuset[start] == 0) {
|
|
|
|
cpuset[start] = 1;
|
|
|
|
ret++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (*cur == '-') {
|
|
|
|
if (neg)
|
|
|
|
goto parse_error;
|
|
|
|
cur++;
|
|
|
|
virSkipSpaces(&cur);
|
|
|
|
last = virDomainCpuNumberParse(&cur, maxcpu);
|
|
|
|
if (last < start)
|
|
|
|
goto parse_error;
|
|
|
|
for (i = start; i <= last; i++) {
|
|
|
|
if (cpuset[i] == 0) {
|
|
|
|
cpuset[i] = 1;
|
|
|
|
ret++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
virSkipSpaces(&cur);
|
|
|
|
}
|
|
|
|
if (*cur == ',') {
|
|
|
|
cur++;
|
|
|
|
virSkipSpaces(&cur);
|
|
|
|
neg = 0;
|
|
|
|
} else if ((*cur == 0) || (*cur == sep)) {
|
|
|
|
break;
|
|
|
|
} else
|
|
|
|
goto parse_error;
|
|
|
|
}
|
|
|
|
*str = cur;
|
|
|
|
return (ret);
|
|
|
|
|
|
|
|
parse_error:
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
"%s", _("topology cpuset syntax error"));
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainLifecycleDefFormat(virBufferPtr buf,
|
2008-07-11 16:23:36 +00:00
|
|
|
int type,
|
|
|
|
const char *name)
|
|
|
|
{
|
|
|
|
const char *typeStr = virDomainLifecycleTypeToString(type);
|
|
|
|
if (!typeStr) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
_("unexpected lifecycle type %d"), type);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferVSprintf(buf, " <%s>%s</%s>\n", name, typeStr, name);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainDiskDefFormat(virBufferPtr buf,
|
2010-01-08 15:53:53 +00:00
|
|
|
virDomainDiskDefPtr def,
|
|
|
|
int flags)
|
2008-07-11 16:23:36 +00:00
|
|
|
{
|
|
|
|
const char *type = virDomainDiskTypeToString(def->type);
|
|
|
|
const char *device = virDomainDiskDeviceTypeToString(def->device);
|
|
|
|
const char *bus = virDomainDiskBusTypeToString(def->bus);
|
2009-01-30 17:15:39 +00:00
|
|
|
const char *cachemode = virDomainDiskCacheTypeToString(def->cachemode);
|
2010-03-24 11:32:10 -04:00
|
|
|
const char *error_policy = virDomainDiskErrorPolicyTypeToString(def->error_policy);
|
2008-07-11 16:23:36 +00:00
|
|
|
|
|
|
|
if (!type) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
_("unexpected disk type %d"), def->type);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (!device) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
_("unexpected disk device %d"), def->device);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (!bus) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
_("unexpected disk bus %d"), def->bus);
|
|
|
|
return -1;
|
|
|
|
}
|
2009-01-30 17:15:39 +00:00
|
|
|
if (!cachemode) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-01-30 17:15:39 +00:00
|
|
|
_("unexpected disk cache mode %d"), def->cachemode);
|
|
|
|
return -1;
|
|
|
|
}
|
2008-07-11 16:23:36 +00:00
|
|
|
|
|
|
|
virBufferVSprintf(buf,
|
|
|
|
" <disk type='%s' device='%s'>\n",
|
|
|
|
type, device);
|
|
|
|
|
2010-03-09 13:59:51 +01:00
|
|
|
if (def->driverName || def->driverType || def->cachemode) {
|
|
|
|
virBufferVSprintf(buf, " <driver");
|
|
|
|
if (def->driverName)
|
|
|
|
virBufferVSprintf(buf, " name='%s'", def->driverName);
|
2008-07-11 16:23:36 +00:00
|
|
|
if (def->driverType)
|
2009-01-30 17:15:39 +00:00
|
|
|
virBufferVSprintf(buf, " type='%s'", def->driverType);
|
|
|
|
if (def->cachemode)
|
|
|
|
virBufferVSprintf(buf, " cache='%s'", cachemode);
|
2010-03-24 11:32:10 -04:00
|
|
|
if (def->error_policy)
|
|
|
|
virBufferVSprintf(buf, " error_policy='%s'", error_policy);
|
2009-01-30 17:15:39 +00:00
|
|
|
virBufferVSprintf(buf, "/>\n");
|
2008-07-11 16:23:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (def->src) {
|
2009-11-16 18:08:29 +00:00
|
|
|
switch (def->type) {
|
|
|
|
case VIR_DOMAIN_DISK_TYPE_FILE:
|
2008-07-11 16:23:36 +00:00
|
|
|
virBufferEscapeString(buf, " <source file='%s'/>\n",
|
|
|
|
def->src);
|
2009-11-16 18:08:29 +00:00
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_DISK_TYPE_BLOCK:
|
2008-07-11 16:23:36 +00:00
|
|
|
virBufferEscapeString(buf, " <source dev='%s'/>\n",
|
|
|
|
def->src);
|
2009-11-16 18:08:29 +00:00
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_DISK_TYPE_DIR:
|
|
|
|
virBufferEscapeString(buf, " <source dir='%s'/>\n",
|
|
|
|
def->src);
|
|
|
|
break;
|
|
|
|
default:
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-11-16 18:08:29 +00:00
|
|
|
_("unexpected disk type %s"),
|
|
|
|
virDomainDiskTypeToString(def->type));
|
|
|
|
return -1;
|
|
|
|
}
|
2008-07-11 16:23:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virBufferVSprintf(buf, " <target dev='%s' bus='%s'/>\n",
|
|
|
|
def->dst, bus);
|
|
|
|
|
|
|
|
if (def->readonly)
|
|
|
|
virBufferAddLit(buf, " <readonly/>\n");
|
|
|
|
if (def->shared)
|
|
|
|
virBufferAddLit(buf, " <shareable/>\n");
|
2009-08-14 12:22:01 +01:00
|
|
|
if (def->serial)
|
|
|
|
virBufferEscapeString(buf, " <serial>%s</serial>\n",
|
|
|
|
def->serial);
|
2009-07-21 07:23:03 +02:00
|
|
|
if (def->encryption != NULL &&
|
2010-04-27 12:01:32 +02:00
|
|
|
virStorageEncryptionFormat(buf, def->encryption, 6) < 0)
|
2009-07-21 07:23:03 +02:00
|
|
|
return -1;
|
2008-07-11 16:23:36 +00:00
|
|
|
|
2010-01-08 15:53:53 +00:00
|
|
|
if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
|
2009-11-30 18:35:58 +00:00
|
|
|
return -1;
|
2009-07-17 22:08:33 +01:00
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
virBufferAddLit(buf, " </disk>\n");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-12-02 19:15:38 +00:00
|
|
|
static int
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainControllerDefFormat(virBufferPtr buf,
|
2010-01-08 15:53:53 +00:00
|
|
|
virDomainControllerDefPtr def,
|
|
|
|
int flags)
|
2009-12-02 19:15:38 +00:00
|
|
|
{
|
|
|
|
const char *type = virDomainControllerTypeToString(def->type);
|
|
|
|
|
|
|
|
if (!type) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-12-02 19:15:38 +00:00
|
|
|
_("unexpected controller type %d"), def->type);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferVSprintf(buf,
|
|
|
|
" <controller type='%s' index='%d'",
|
|
|
|
type, def->idx);
|
|
|
|
|
2010-02-18 17:52:03 +01:00
|
|
|
switch (def->type) {
|
|
|
|
case VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL:
|
|
|
|
if (def->opts.vioserial.ports != -1) {
|
|
|
|
virBufferVSprintf(buf, " ports='%d'",
|
|
|
|
def->opts.vioserial.ports);
|
|
|
|
}
|
|
|
|
if (def->opts.vioserial.vectors != -1) {
|
|
|
|
virBufferVSprintf(buf, " vectors='%d'",
|
|
|
|
def->opts.vioserial.vectors);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2009-12-02 19:15:38 +00:00
|
|
|
if (virDomainDeviceInfoIsSet(&def->info)) {
|
|
|
|
virBufferAddLit(buf, ">\n");
|
2010-01-08 15:53:53 +00:00
|
|
|
if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
|
2009-12-02 19:15:38 +00:00
|
|
|
return -1;
|
|
|
|
virBufferAddLit(buf, " </controller>\n");
|
|
|
|
} else {
|
|
|
|
virBufferAddLit(buf, "/>\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-08-01 13:31:37 +00:00
|
|
|
static int
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainFSDefFormat(virBufferPtr buf,
|
Add device info to serial, parallel, channel, input & fs devices
Although the serial, parallel, chanel, input & fs devices do
not have PCI address info, they can all have device aliases.
Thus it neccessary to associate the virDomainDeviceInfo data
with them all.
* src/conf/domain_conf.c, src/conf/domain_conf.h: Add hooks for
parsing / formatting device info for serial, parallel, channel
input and fs devices.
* docs/schemas/domain.rng: Associate device info with character
devices, input & fs device
2010-01-06 12:39:53 +00:00
|
|
|
virDomainFSDefPtr def,
|
|
|
|
int flags)
|
2008-08-01 13:31:37 +00:00
|
|
|
{
|
|
|
|
const char *type = virDomainFSTypeToString(def->type);
|
|
|
|
|
|
|
|
if (!type) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-08-01 13:31:37 +00:00
|
|
|
_("unexpected filesystem type %d"), def->type);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferVSprintf(buf,
|
|
|
|
" <filesystem type='%s'>\n",
|
|
|
|
type);
|
|
|
|
|
|
|
|
if (def->src) {
|
|
|
|
switch (def->type) {
|
|
|
|
case VIR_DOMAIN_FS_TYPE_MOUNT:
|
|
|
|
virBufferEscapeString(buf, " <source dir='%s'/>\n",
|
|
|
|
def->src);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_FS_TYPE_BLOCK:
|
|
|
|
virBufferEscapeString(buf, " <source dev='%s'/>\n",
|
|
|
|
def->src);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_FS_TYPE_FILE:
|
|
|
|
virBufferEscapeString(buf, " <source file='%s'/>\n",
|
|
|
|
def->src);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_FS_TYPE_TEMPLATE:
|
|
|
|
virBufferEscapeString(buf, " <source name='%s'/>\n",
|
|
|
|
def->src);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferVSprintf(buf, " <target dir='%s'/>\n",
|
|
|
|
def->dst);
|
|
|
|
|
|
|
|
if (def->readonly)
|
|
|
|
virBufferAddLit(buf, " <readonly/>\n");
|
|
|
|
|
Add device info to serial, parallel, channel, input & fs devices
Although the serial, parallel, chanel, input & fs devices do
not have PCI address info, they can all have device aliases.
Thus it neccessary to associate the virDomainDeviceInfo data
with them all.
* src/conf/domain_conf.c, src/conf/domain_conf.h: Add hooks for
parsing / formatting device info for serial, parallel, channel
input and fs devices.
* docs/schemas/domain.rng: Associate device info with character
devices, input & fs device
2010-01-06 12:39:53 +00:00
|
|
|
if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2008-08-01 13:31:37 +00:00
|
|
|
virBufferAddLit(buf, " </filesystem>\n");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
static int
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainNetDefFormat(virBufferPtr buf,
|
2009-07-17 22:08:34 +01:00
|
|
|
virDomainNetDefPtr def,
|
|
|
|
int flags)
|
2008-07-11 16:23:36 +00:00
|
|
|
{
|
|
|
|
const char *type = virDomainNetTypeToString(def->type);
|
2010-03-25 13:46:07 -04:00
|
|
|
char *attrs;
|
2008-07-11 16:23:36 +00:00
|
|
|
|
|
|
|
if (!type) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
_("unexpected net type %d"), def->type);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferVSprintf(buf, " <interface type='%s'>\n", type);
|
|
|
|
|
|
|
|
virBufferVSprintf(buf,
|
|
|
|
" <mac address='%02x:%02x:%02x:%02x:%02x:%02x'/>\n",
|
|
|
|
def->mac[0], def->mac[1], def->mac[2],
|
|
|
|
def->mac[3], def->mac[4], def->mac[5]);
|
|
|
|
|
|
|
|
switch (def->type) {
|
|
|
|
case VIR_DOMAIN_NET_TYPE_NETWORK:
|
|
|
|
virBufferEscapeString(buf, " <source network='%s'/>\n",
|
|
|
|
def->data.network.name);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_NET_TYPE_ETHERNET:
|
|
|
|
if (def->data.ethernet.dev)
|
|
|
|
virBufferEscapeString(buf, " <source dev='%s'/>\n",
|
|
|
|
def->data.ethernet.dev);
|
|
|
|
if (def->data.ethernet.ipaddr)
|
|
|
|
virBufferVSprintf(buf, " <ip address='%s'/>\n",
|
|
|
|
def->data.ethernet.ipaddr);
|
|
|
|
if (def->data.ethernet.script)
|
|
|
|
virBufferEscapeString(buf, " <script path='%s'/>\n",
|
|
|
|
def->data.ethernet.script);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_NET_TYPE_BRIDGE:
|
|
|
|
virBufferEscapeString(buf, " <source bridge='%s'/>\n",
|
|
|
|
def->data.bridge.brname);
|
2009-01-23 01:48:47 +00:00
|
|
|
if (def->data.bridge.ipaddr)
|
|
|
|
virBufferVSprintf(buf, " <ip address='%s'/>\n",
|
|
|
|
def->data.bridge.ipaddr);
|
2009-01-22 18:29:13 +00:00
|
|
|
if (def->data.bridge.script)
|
|
|
|
virBufferEscapeString(buf, " <script path='%s'/>\n",
|
|
|
|
def->data.bridge.script);
|
2008-07-11 16:23:36 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_NET_TYPE_SERVER:
|
|
|
|
case VIR_DOMAIN_NET_TYPE_CLIENT:
|
|
|
|
case VIR_DOMAIN_NET_TYPE_MCAST:
|
|
|
|
if (def->data.socket.address)
|
|
|
|
virBufferVSprintf(buf, " <source address='%s' port='%d'/>\n",
|
|
|
|
def->data.socket.address, def->data.socket.port);
|
|
|
|
else
|
|
|
|
virBufferVSprintf(buf, " <source port='%d'/>\n",
|
|
|
|
def->data.socket.port);
|
2009-06-03 11:13:33 +00:00
|
|
|
break;
|
2009-05-11 09:50:27 +00:00
|
|
|
|
|
|
|
case VIR_DOMAIN_NET_TYPE_INTERNAL:
|
|
|
|
virBufferEscapeString(buf, " <source name='%s'/>\n",
|
|
|
|
def->data.internal.name);
|
|
|
|
break;
|
|
|
|
|
2010-02-12 18:07:06 +01:00
|
|
|
case VIR_DOMAIN_NET_TYPE_DIRECT:
|
|
|
|
virBufferEscapeString(buf, " <source dev='%s'",
|
|
|
|
def->data.direct.linkdev);
|
|
|
|
virBufferVSprintf(buf, " mode='%s'",
|
|
|
|
virDomainNetdevMacvtapTypeToString(def->data.direct.mode));
|
|
|
|
virBufferAddLit(buf, "/>\n");
|
|
|
|
break;
|
2010-03-26 17:01:35 +01:00
|
|
|
|
|
|
|
case VIR_DOMAIN_NET_TYPE_USER:
|
|
|
|
case VIR_DOMAIN_NET_TYPE_LAST:
|
|
|
|
break;
|
2008-07-11 16:23:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (def->ifname)
|
|
|
|
virBufferEscapeString(buf, " <target dev='%s'/>\n",
|
|
|
|
def->ifname);
|
|
|
|
if (def->model)
|
|
|
|
virBufferEscapeString(buf, " <model type='%s'/>\n",
|
|
|
|
def->model);
|
2010-03-25 13:46:07 -04:00
|
|
|
if (def->filter) {
|
|
|
|
virBufferEscapeString(buf, " <filterref filter='%s'",
|
|
|
|
def->filter);
|
|
|
|
attrs = virNWFilterFormatParamAttributes(def->filterparams,
|
|
|
|
" ");
|
|
|
|
if (!attrs || strlen(attrs) <= 1)
|
|
|
|
virBufferAddLit(buf, "/>\n");
|
|
|
|
else
|
|
|
|
virBufferVSprintf(buf, ">\n%s </filterref>\n", attrs);
|
|
|
|
VIR_FREE(attrs);
|
|
|
|
}
|
2008-07-11 16:23:36 +00:00
|
|
|
|
2010-01-08 15:53:53 +00:00
|
|
|
if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
|
2009-11-30 18:35:58 +00:00
|
|
|
return -1;
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
virBufferAddLit(buf, " </interface>\n");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainChrDefFormat(virBufferPtr buf,
|
2008-07-11 16:23:36 +00:00
|
|
|
virDomainChrDefPtr def,
|
2009-04-22 14:26:50 +00:00
|
|
|
int flags)
|
2008-07-11 16:23:36 +00:00
|
|
|
{
|
|
|
|
const char *type = virDomainChrTypeToString(def->type);
|
2009-11-05 14:19:14 +01:00
|
|
|
const char *targetName = virDomainChrTargetTypeToString(def->targetType);
|
2009-11-05 15:31:03 +01:00
|
|
|
const char *elementName;
|
|
|
|
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
switch (def->targetType) {
|
|
|
|
/* channel types are in a common channel element */
|
|
|
|
case VIR_DOMAIN_CHR_TARGET_TYPE_GUESTFWD:
|
2010-02-18 17:52:03 +01:00
|
|
|
case VIR_DOMAIN_CHR_TARGET_TYPE_VIRTIO:
|
2009-11-05 15:31:03 +01:00
|
|
|
elementName = "channel";
|
|
|
|
break;
|
2009-11-05 14:19:14 +01:00
|
|
|
|
2009-11-05 15:31:03 +01:00
|
|
|
default:
|
|
|
|
elementName = targetName;
|
|
|
|
}
|
2008-07-11 16:23:36 +00:00
|
|
|
|
|
|
|
if (!type) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
_("unexpected char type %d"), def->type);
|
2010-01-20 19:27:43 +01:00
|
|
|
return -1;
|
2008-07-11 16:23:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Compat with legacy <console tty='/dev/pts/5'/> syntax */
|
|
|
|
virBufferVSprintf(buf, " <%s type='%s'",
|
2009-11-05 14:19:14 +01:00
|
|
|
elementName, type);
|
|
|
|
if (def->targetType == VIR_DOMAIN_CHR_TARGET_TYPE_CONSOLE &&
|
2008-07-11 16:23:36 +00:00
|
|
|
def->type == VIR_DOMAIN_CHR_TYPE_PTY &&
|
2009-04-22 14:26:50 +00:00
|
|
|
!(flags & VIR_DOMAIN_XML_INACTIVE) &&
|
2008-07-11 16:23:36 +00:00
|
|
|
def->data.file.path) {
|
|
|
|
virBufferEscapeString(buf, " tty='%s'>\n",
|
|
|
|
def->data.file.path);
|
|
|
|
} else {
|
|
|
|
virBufferAddLit(buf, ">\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (def->type) {
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_NULL:
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_VC:
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_STDIO:
|
|
|
|
/* 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 ||
|
2009-04-22 14:26:50 +00:00
|
|
|
(def->data.file.path && !(flags & VIR_DOMAIN_XML_INACTIVE))) {
|
2008-07-11 16:23:36 +00:00
|
|
|
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) {
|
|
|
|
virBufferVSprintf(buf, " <source mode='bind' host='%s' service='%s'/>\n",
|
|
|
|
def->data.udp.bindHost,
|
|
|
|
def->data.udp.bindService);
|
|
|
|
} else if (def->data.udp.bindHost) {
|
|
|
|
virBufferVSprintf(buf, " <source mode='bind' host='%s'/>\n",
|
|
|
|
def->data.udp.bindHost);
|
|
|
|
} else if (def->data.udp.bindService) {
|
|
|
|
virBufferVSprintf(buf, " <source mode='bind' service='%s'/>\n",
|
|
|
|
def->data.udp.bindService);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (def->data.udp.connectService &&
|
|
|
|
def->data.udp.connectHost) {
|
|
|
|
virBufferVSprintf(buf, " <source mode='connect' host='%s' service='%s'/>\n",
|
|
|
|
def->data.udp.connectHost,
|
|
|
|
def->data.udp.connectService);
|
|
|
|
} else if (def->data.udp.connectHost) {
|
|
|
|
virBufferVSprintf(buf, " <source mode='connect' host='%s'/>\n",
|
|
|
|
def->data.udp.connectHost);
|
|
|
|
} else if (def->data.udp.connectService) {
|
|
|
|
virBufferVSprintf(buf, " <source mode='connect' service='%s'/>\n",
|
|
|
|
def->data.udp.connectService);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_TCP:
|
|
|
|
virBufferVSprintf(buf, " <source mode='%s' host='%s' service='%s'/>\n",
|
|
|
|
def->data.tcp.listen ? "bind" : "connect",
|
|
|
|
def->data.tcp.host,
|
|
|
|
def->data.tcp.service);
|
|
|
|
virBufferVSprintf(buf, " <protocol type='%s'/>\n",
|
|
|
|
def->data.tcp.protocol ==
|
|
|
|
VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET
|
|
|
|
? "telnet" : "raw");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_UNIX:
|
|
|
|
virBufferVSprintf(buf, " <source mode='%s'",
|
|
|
|
def->data.nix.listen ? "bind" : "connect");
|
|
|
|
virBufferEscapeString(buf, " path='%s'/>\n",
|
|
|
|
def->data.nix.path);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2009-11-05 14:19:14 +01:00
|
|
|
switch (def->targetType) {
|
2009-11-05 15:31:03 +01:00
|
|
|
case VIR_DOMAIN_CHR_TARGET_TYPE_GUESTFWD:
|
2010-01-20 19:27:43 +01:00
|
|
|
{
|
|
|
|
int port = virSocketGetPort(def->target.addr);
|
|
|
|
if (port < 0) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
2010-01-20 19:27:43 +01:00
|
|
|
_("Unable to format guestfwd port"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
const char *addr = virSocketFormatAddr(def->target.addr);
|
|
|
|
if (addr == NULL) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
2010-01-20 19:27:43 +01:00
|
|
|
_("Unable to format guestfwd address"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
virBufferVSprintf(buf,
|
|
|
|
" <target type='guestfwd' address='%s' port='%d'/>\n",
|
|
|
|
addr, port);
|
|
|
|
VIR_FREE(addr);
|
|
|
|
break;
|
2009-11-05 15:31:03 +01:00
|
|
|
}
|
|
|
|
|
2010-02-18 17:52:03 +01:00
|
|
|
case VIR_DOMAIN_CHR_TARGET_TYPE_VIRTIO:
|
|
|
|
virBufferAddLit(buf, " <target type='virtio'");
|
|
|
|
if (def->target.name) {
|
|
|
|
virBufferEscapeString(buf, " name='%s'", def->target.name);
|
|
|
|
}
|
|
|
|
virBufferAddLit(buf, "/>\n");
|
|
|
|
break;
|
|
|
|
|
2009-11-05 14:19:14 +01:00
|
|
|
case VIR_DOMAIN_CHR_TARGET_TYPE_PARALLEL:
|
|
|
|
case VIR_DOMAIN_CHR_TARGET_TYPE_SERIAL:
|
|
|
|
case VIR_DOMAIN_CHR_TARGET_TYPE_CONSOLE:
|
2010-02-18 17:52:03 +01:00
|
|
|
virBufferVSprintf(buf, " <target port='%d'/>\n", def->target.port);
|
2009-11-05 14:19:14 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-11-05 14:19:14 +01:00
|
|
|
_("unexpected character destination type %d"),
|
|
|
|
def->targetType);
|
|
|
|
return -1;
|
|
|
|
}
|
2008-07-11 16:23:36 +00:00
|
|
|
|
2010-02-18 17:52:03 +01:00
|
|
|
if (virDomainDeviceInfoIsSet(&def->info)) {
|
|
|
|
if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
Add device info to serial, parallel, channel, input & fs devices
Although the serial, parallel, chanel, input & fs devices do
not have PCI address info, they can all have device aliases.
Thus it neccessary to associate the virDomainDeviceInfo data
with them all.
* src/conf/domain_conf.c, src/conf/domain_conf.h: Add hooks for
parsing / formatting device info for serial, parallel, channel
input and fs devices.
* docs/schemas/domain.rng: Associate device info with character
devices, input & fs device
2010-01-06 12:39:53 +00:00
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
virBufferVSprintf(buf, " </%s>\n",
|
2009-11-05 14:19:14 +01:00
|
|
|
elementName);
|
2008-07-11 16:23:36 +00:00
|
|
|
|
2009-11-05 15:31:03 +01:00
|
|
|
return ret;
|
2008-07-11 16:23:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainSoundDefFormat(virBufferPtr buf,
|
2010-01-08 15:53:53 +00:00
|
|
|
virDomainSoundDefPtr def,
|
|
|
|
int flags)
|
2008-07-11 16:23:36 +00:00
|
|
|
{
|
|
|
|
const char *model = virDomainSoundModelTypeToString(def->model);
|
|
|
|
|
|
|
|
if (!model) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
_("unexpected sound model %d"), def->model);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2009-12-10 19:19:08 +00:00
|
|
|
virBufferVSprintf(buf, " <sound model='%s'",
|
2008-07-11 16:23:36 +00:00
|
|
|
model);
|
|
|
|
|
2009-12-10 19:19:08 +00:00
|
|
|
if (virDomainDeviceInfoIsSet(&def->info)) {
|
|
|
|
virBufferAddLit(buf, ">\n");
|
2010-01-08 15:53:53 +00:00
|
|
|
if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
|
2009-12-10 19:19:08 +00:00
|
|
|
return -1;
|
|
|
|
virBufferAddLit(buf, " </sound>\n");
|
|
|
|
} else {
|
|
|
|
virBufferAddLit(buf, "/>\n");
|
|
|
|
}
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-09-03 10:26:41 +02:00
|
|
|
|
2009-10-21 13:26:38 +01:00
|
|
|
static int
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainWatchdogDefFormat(virBufferPtr buf,
|
2010-01-08 15:53:53 +00:00
|
|
|
virDomainWatchdogDefPtr def,
|
|
|
|
int flags)
|
2009-10-21 13:26:38 +01:00
|
|
|
{
|
|
|
|
const char *model = virDomainWatchdogModelTypeToString (def->model);
|
|
|
|
const char *action = virDomainWatchdogActionTypeToString (def->action);
|
|
|
|
|
|
|
|
if (!model) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-10-21 13:26:38 +01:00
|
|
|
_("unexpected watchdog model %d"), def->model);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!action) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-10-21 13:26:38 +01:00
|
|
|
_("unexpected watchdog action %d"), def->action);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2009-12-10 19:19:08 +00:00
|
|
|
virBufferVSprintf(buf, " <watchdog model='%s' action='%s'",
|
2009-10-21 13:26:38 +01:00
|
|
|
model, action);
|
|
|
|
|
2009-12-10 19:19:08 +00:00
|
|
|
if (virDomainDeviceInfoIsSet(&def->info)) {
|
|
|
|
virBufferAddLit(buf, ">\n");
|
2010-01-08 15:53:53 +00:00
|
|
|
if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
|
2009-12-10 19:19:08 +00:00
|
|
|
return -1;
|
|
|
|
virBufferAddLit(buf, " </watchdog>\n");
|
|
|
|
} else {
|
|
|
|
virBufferAddLit(buf, "/>\n");
|
|
|
|
}
|
|
|
|
|
2009-10-21 13:26:38 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-09-03 10:26:41 +02:00
|
|
|
static void
|
|
|
|
virDomainVideoAccelDefFormat(virBufferPtr buf,
|
|
|
|
virDomainVideoAccelDefPtr def)
|
|
|
|
{
|
|
|
|
virBufferVSprintf(buf, " <acceleration accel3d='%s'",
|
|
|
|
def->support3d ? "yes" : "no");
|
|
|
|
virBufferVSprintf(buf, " accel2d='%s'",
|
|
|
|
def->support2d ? "yes" : "no");
|
|
|
|
virBufferAddLit(buf, "/>\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-07-06 14:54:44 +01:00
|
|
|
static int
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainVideoDefFormat(virBufferPtr buf,
|
2010-01-08 15:53:53 +00:00
|
|
|
virDomainVideoDefPtr def,
|
|
|
|
int flags)
|
2009-07-06 14:54:44 +01:00
|
|
|
{
|
|
|
|
const char *model = virDomainVideoTypeToString(def->type);
|
|
|
|
|
|
|
|
if (!model) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-07-06 14:54:44 +01:00
|
|
|
_("unexpected video model %d"), def->type);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferAddLit(buf, " <video>\n");
|
|
|
|
virBufferVSprintf(buf, " <model type='%s'",
|
|
|
|
model);
|
|
|
|
if (def->vram)
|
|
|
|
virBufferVSprintf(buf, " vram='%u'", def->vram);
|
|
|
|
if (def->heads)
|
|
|
|
virBufferVSprintf(buf, " heads='%u'", def->heads);
|
2009-09-03 10:26:41 +02:00
|
|
|
if (def->accel) {
|
|
|
|
virBufferAddLit(buf, ">\n");
|
|
|
|
virDomainVideoAccelDefFormat(buf, def->accel);
|
|
|
|
virBufferAddLit(buf, " </model>\n");
|
|
|
|
} else {
|
|
|
|
virBufferAddLit(buf, "/>\n");
|
|
|
|
}
|
|
|
|
|
2010-01-08 15:53:53 +00:00
|
|
|
if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
|
2009-12-10 19:19:08 +00:00
|
|
|
return -1;
|
|
|
|
|
2009-07-06 14:54:44 +01:00
|
|
|
virBufferAddLit(buf, " </video>\n");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
static int
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainInputDefFormat(virBufferPtr buf,
|
Add device info to serial, parallel, channel, input & fs devices
Although the serial, parallel, chanel, input & fs devices do
not have PCI address info, they can all have device aliases.
Thus it neccessary to associate the virDomainDeviceInfo data
with them all.
* src/conf/domain_conf.c, src/conf/domain_conf.h: Add hooks for
parsing / formatting device info for serial, parallel, channel
input and fs devices.
* docs/schemas/domain.rng: Associate device info with character
devices, input & fs device
2010-01-06 12:39:53 +00:00
|
|
|
virDomainInputDefPtr def,
|
|
|
|
int flags)
|
2008-07-11 16:23:36 +00:00
|
|
|
{
|
|
|
|
const char *type = virDomainInputTypeToString(def->type);
|
|
|
|
const char *bus = virDomainInputBusTypeToString(def->bus);
|
|
|
|
|
|
|
|
if (!type) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
_("unexpected input type %d"), def->type);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (!bus) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
_("unexpected input bus type %d"), def->bus);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
Add device info to serial, parallel, channel, input & fs devices
Although the serial, parallel, chanel, input & fs devices do
not have PCI address info, they can all have device aliases.
Thus it neccessary to associate the virDomainDeviceInfo data
with them all.
* src/conf/domain_conf.c, src/conf/domain_conf.h: Add hooks for
parsing / formatting device info for serial, parallel, channel
input and fs devices.
* docs/schemas/domain.rng: Associate device info with character
devices, input & fs device
2010-01-06 12:39:53 +00:00
|
|
|
virBufferVSprintf(buf, " <input type='%s' bus='%s'",
|
2008-07-11 16:23:36 +00:00
|
|
|
type, bus);
|
|
|
|
|
Add device info to serial, parallel, channel, input & fs devices
Although the serial, parallel, chanel, input & fs devices do
not have PCI address info, they can all have device aliases.
Thus it neccessary to associate the virDomainDeviceInfo data
with them all.
* src/conf/domain_conf.c, src/conf/domain_conf.h: Add hooks for
parsing / formatting device info for serial, parallel, channel
input and fs devices.
* docs/schemas/domain.rng: Associate device info with character
devices, input & fs device
2010-01-06 12:39:53 +00:00
|
|
|
if (virDomainDeviceInfoIsSet(&def->info)) {
|
|
|
|
virBufferAddLit(buf, ">\n");
|
|
|
|
if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
|
|
|
|
return -1;
|
|
|
|
virBufferAddLit(buf, " </input>\n");
|
|
|
|
} else {
|
|
|
|
virBufferAddLit(buf, "/>\n");
|
|
|
|
}
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-03-30 13:44:22 +02:00
|
|
|
static int
|
|
|
|
virDomainTimerDefFormat(virBufferPtr buf,
|
|
|
|
virDomainTimerDefPtr def)
|
|
|
|
{
|
|
|
|
const char *name = virDomainTimerNameTypeToString(def->name);
|
|
|
|
|
|
|
|
if (!name) {
|
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unexpected timer name %d"), def->name);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
virBufferVSprintf(buf, " <timer name='%s'", name);
|
|
|
|
|
|
|
|
if (def->present == 0) {
|
|
|
|
virBufferAddLit(buf, " present='no'");
|
|
|
|
} else if (def->present == 1) {
|
|
|
|
virBufferAddLit(buf, " present='yes'");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (def->tickpolicy != -1) {
|
|
|
|
const char *tickpolicy
|
|
|
|
= virDomainTimerTickpolicyTypeToString(def->tickpolicy);
|
|
|
|
if (!tickpolicy) {
|
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unexpected timer tickpolicy %d"),
|
|
|
|
def->tickpolicy);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
virBufferVSprintf(buf, " tickpolicy='%s'", tickpolicy);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((def->name == VIR_DOMAIN_TIMER_NAME_PLATFORM)
|
|
|
|
|| (def->name == VIR_DOMAIN_TIMER_NAME_RTC)) {
|
2010-03-31 13:03:54 -04:00
|
|
|
if (def->track != -1) {
|
|
|
|
const char *track
|
|
|
|
= virDomainTimerTrackTypeToString(def->track);
|
|
|
|
if (!track) {
|
2010-03-30 13:44:22 +02:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2010-03-31 13:03:54 -04:00
|
|
|
_("unexpected timer track %d"),
|
|
|
|
def->track);
|
2010-03-30 13:44:22 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2010-03-31 13:03:54 -04:00
|
|
|
virBufferVSprintf(buf, " track='%s'", track);
|
2010-03-30 13:44:22 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (def->name == VIR_DOMAIN_TIMER_NAME_TSC) {
|
|
|
|
if (def->frequency > 0) {
|
|
|
|
virBufferVSprintf(buf, " frequency='%lu'", def->frequency);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (def->mode != -1) {
|
|
|
|
const char *mode
|
|
|
|
= virDomainTimerModeTypeToString(def->mode);
|
|
|
|
if (!mode) {
|
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unexpected timer mode %d"),
|
|
|
|
def->mode);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
virBufferVSprintf(buf, " mode='%s'", mode);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-03-31 13:03:54 -04:00
|
|
|
if ((def->catchup.threshold == 0)
|
|
|
|
&& (def->catchup.slew == 0)
|
|
|
|
&& (def->catchup.limit == 0)) {
|
|
|
|
virBufferAddLit(buf, "/>\n");
|
|
|
|
} else {
|
|
|
|
virBufferAddLit(buf, ">\n <catchup ");
|
|
|
|
if (def->catchup.threshold > 0) {
|
|
|
|
virBufferVSprintf(buf, " threshold='%lu'", def->catchup.threshold);
|
|
|
|
}
|
|
|
|
if (def->catchup.slew > 0) {
|
|
|
|
virBufferVSprintf(buf, " slew='%lu'", def->catchup.slew);
|
|
|
|
}
|
|
|
|
if (def->catchup.limit > 0) {
|
|
|
|
virBufferVSprintf(buf, " limit='%lu'", def->catchup.limit);
|
|
|
|
}
|
|
|
|
virBufferAddLit(buf, "/>\n </timer>\n");
|
|
|
|
}
|
2010-03-30 13:44:22 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
static int
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainGraphicsDefFormat(virBufferPtr buf,
|
2008-07-11 16:23:36 +00:00
|
|
|
virDomainGraphicsDefPtr def,
|
|
|
|
int flags)
|
|
|
|
{
|
|
|
|
const char *type = virDomainGraphicsTypeToString(def->type);
|
|
|
|
|
|
|
|
if (!type) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
_("unexpected net type %d"), def->type);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferVSprintf(buf, " <graphics type='%s'", type);
|
|
|
|
|
|
|
|
switch (def->type) {
|
|
|
|
case VIR_DOMAIN_GRAPHICS_TYPE_VNC:
|
2008-07-31 14:39:30 +00:00
|
|
|
if (def->data.vnc.port &&
|
2009-11-12 14:08:43 +00:00
|
|
|
(!def->data.vnc.autoport || !(flags & VIR_DOMAIN_XML_INACTIVE)))
|
2008-07-11 16:23:36 +00:00
|
|
|
virBufferVSprintf(buf, " port='%d'",
|
|
|
|
def->data.vnc.port);
|
2008-07-31 12:30:34 +00:00
|
|
|
else if (def->data.vnc.autoport)
|
|
|
|
virBufferAddLit(buf, " port='-1'");
|
2008-07-11 16:23:36 +00:00
|
|
|
|
|
|
|
virBufferVSprintf(buf, " autoport='%s'",
|
|
|
|
def->data.vnc.autoport ? "yes" : "no");
|
|
|
|
|
|
|
|
if (def->data.vnc.listenAddr)
|
|
|
|
virBufferVSprintf(buf, " listen='%s'",
|
|
|
|
def->data.vnc.listenAddr);
|
|
|
|
|
|
|
|
if (def->data.vnc.keymap)
|
|
|
|
virBufferEscapeString(buf, " keymap='%s'",
|
|
|
|
def->data.vnc.keymap);
|
|
|
|
|
|
|
|
if (def->data.vnc.passwd &&
|
|
|
|
(flags & VIR_DOMAIN_XML_SECURE))
|
|
|
|
virBufferEscapeString(buf, " passwd='%s'",
|
|
|
|
def->data.vnc.passwd);
|
|
|
|
|
|
|
|
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);
|
2008-12-11 11:44:30 +00:00
|
|
|
if (def->data.sdl.fullscreen)
|
|
|
|
virBufferAddLit(buf, " fullscreen='yes'");
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
break;
|
2009-05-15 09:43:51 +00:00
|
|
|
|
|
|
|
case VIR_DOMAIN_GRAPHICS_TYPE_RDP:
|
|
|
|
if (def->data.rdp.port)
|
|
|
|
virBufferVSprintf(buf, " port='%d'",
|
|
|
|
def->data.rdp.port);
|
|
|
|
else if (def->data.rdp.autoport)
|
|
|
|
virBufferAddLit(buf, " port='0'");
|
|
|
|
|
|
|
|
if (def->data.rdp.autoport)
|
|
|
|
virBufferVSprintf(buf, " autoport='yes'");
|
|
|
|
|
|
|
|
if (def->data.rdp.replaceUser)
|
|
|
|
virBufferVSprintf(buf, " replaceUser='yes'");
|
|
|
|
|
|
|
|
if (def->data.rdp.multiUser)
|
|
|
|
virBufferVSprintf(buf, " multiUser='yes'");
|
|
|
|
|
|
|
|
if (def->data.rdp.listenAddr)
|
|
|
|
virBufferVSprintf(buf, " listen='%s'", def->data.rdp.listenAddr);
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virBufferAddLit(buf, "/>\n");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-08-08 14:27:05 +00:00
|
|
|
|
|
|
|
static int
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainHostdevDefFormat(virBufferPtr buf,
|
2010-01-08 15:53:53 +00:00
|
|
|
virDomainHostdevDefPtr def,
|
|
|
|
int flags)
|
2008-08-08 14:27:05 +00:00
|
|
|
{
|
|
|
|
const char *mode = virDomainHostdevModeTypeToString(def->mode);
|
|
|
|
const char *type;
|
|
|
|
|
|
|
|
if (!mode || def->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-08-08 14:27:05 +00:00
|
|
|
_("unexpected hostdev mode %d"), def->mode);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
type = virDomainHostdevSubsysTypeToString(def->source.subsys.type);
|
2009-01-07 12:56:13 +00:00
|
|
|
if (!type || (def->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB && def->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) ) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-08-08 14:27:05 +00:00
|
|
|
_("unexpected hostdev type %d"),
|
|
|
|
def->source.subsys.type);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2009-03-02 16:40:30 +00:00
|
|
|
virBufferVSprintf(buf, " <hostdev mode='%s' type='%s' managed='%s'>\n",
|
|
|
|
mode, type, def->managed ? "yes" : "no");
|
2008-08-08 14:27:05 +00:00
|
|
|
virBufferAddLit(buf, " <source>\n");
|
|
|
|
|
2009-01-07 12:56:13 +00:00
|
|
|
if (def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {
|
|
|
|
if (def->source.subsys.u.usb.vendor) {
|
|
|
|
virBufferVSprintf(buf, " <vendor id='0x%.4x'/>\n",
|
|
|
|
def->source.subsys.u.usb.vendor);
|
|
|
|
virBufferVSprintf(buf, " <product id='0x%.4x'/>\n",
|
|
|
|
def->source.subsys.u.usb.product);
|
2010-02-01 17:21:05 +00:00
|
|
|
}
|
|
|
|
if (def->source.subsys.u.usb.bus ||
|
|
|
|
def->source.subsys.u.usb.device)
|
2009-01-07 12:56:13 +00:00
|
|
|
virBufferVSprintf(buf, " <address bus='%d' device='%d'/>\n",
|
|
|
|
def->source.subsys.u.usb.bus,
|
|
|
|
def->source.subsys.u.usb.device);
|
2009-11-30 18:35:58 +00:00
|
|
|
} else if (def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) {
|
2009-01-07 12:56:13 +00:00
|
|
|
virBufferVSprintf(buf, " <address domain='0x%.4x' bus='0x%.2x' slot='0x%.2x' function='0x%.1x'/>\n",
|
|
|
|
def->source.subsys.u.pci.domain,
|
|
|
|
def->source.subsys.u.pci.bus,
|
|
|
|
def->source.subsys.u.pci.slot,
|
|
|
|
def->source.subsys.u.pci.function);
|
2008-08-08 14:27:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virBufferAddLit(buf, " </source>\n");
|
2009-11-30 18:35:58 +00:00
|
|
|
|
2010-01-08 15:53:53 +00:00
|
|
|
if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
|
2009-11-30 18:35:58 +00:00
|
|
|
return -1;
|
|
|
|
|
2008-08-08 14:27:05 +00:00
|
|
|
virBufferAddLit(buf, " </hostdev>\n");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-02-09 18:58:01 +00:00
|
|
|
char *virDomainDefFormat(virDomainDefPtr def,
|
2008-07-11 16:23:36 +00:00
|
|
|
int flags)
|
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
unsigned char *uuid;
|
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
2009-12-10 00:00:50 +01:00
|
|
|
const char *type = NULL;
|
2008-07-11 16:23:36 +00:00
|
|
|
int n, allones = 1;
|
|
|
|
|
|
|
|
if (!(type = virDomainVirtTypeToString(def->virtType))) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
_("unexpected domain type %d"), def->virtType);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2009-11-12 14:08:43 +00:00
|
|
|
if (def->id == -1)
|
|
|
|
flags |= VIR_DOMAIN_XML_INACTIVE;
|
|
|
|
|
|
|
|
if (!(flags & VIR_DOMAIN_XML_INACTIVE))
|
2008-07-11 16:23:36 +00:00
|
|
|
virBufferVSprintf(&buf, "<domain type='%s' id='%d'>\n", type, def->id);
|
|
|
|
else
|
|
|
|
virBufferVSprintf(&buf, "<domain type='%s'>\n", type);
|
|
|
|
|
|
|
|
virBufferEscapeString(&buf, " <name>%s</name>\n", def->name);
|
|
|
|
|
|
|
|
uuid = def->uuid;
|
|
|
|
virUUIDFormat(uuid, uuidstr);
|
|
|
|
virBufferVSprintf(&buf, " <uuid>%s</uuid>\n", uuidstr);
|
|
|
|
|
2009-09-30 16:07:24 +02:00
|
|
|
if (def->description)
|
|
|
|
virBufferEscapeString(&buf, " <description>%s</description>\n",
|
|
|
|
def->description);
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
virBufferVSprintf(&buf, " <memory>%lu</memory>\n", def->maxmem);
|
|
|
|
virBufferVSprintf(&buf, " <currentMemory>%lu</currentMemory>\n",
|
|
|
|
def->memory);
|
Support configuration of huge pages in guests
Add option to domain XML for
<memoryBacking>
<hugepages/>
</memoryBacking>
* configure.in: Add check for mntent.h
* qemud/libvirtd_qemu.aug, qemud/test_libvirtd_qemu.aug, src/qemu.conf
Add 'hugetlbfs_mount' config parameter
* src/qemu_conf.c, src/qemu_conf.h: Check for -mem-path flag in QEMU,
and pass it when hugepages are requested.
Load hugetlbfs_mount config parameter, search for mount if not given.
* src/qemu_driver.c: Free hugetlbfs_mount/path parameter in driver shutdown.
Create directory for QEMU hugepage usage, chowning if required.
* docs/formatdomain.html.in: Document memoryBacking/hugepages elements
* docs/schemas/domain.rng: Add memoryBacking/hugepages elements to schema
* src/util.c, src/util.h, src/libvirt_private.syms: Add virFileFindMountPoint
helper API
* tests/qemuhelptest.c: Add -mem-path constants
* tests/qemuxml2argvtest.c, tests/qemuxml2xmltest.c: Add tests for hugepage
handling
* tests/qemuxml2argvdata/qemuxml2argv-hugepages.xml,
tests/qemuxml2argvdata/qemuxml2argv-hugepages.args: Data files for
hugepage tests
2009-08-25 15:05:18 +01:00
|
|
|
if (def->hugepage_backed) {
|
|
|
|
virBufferAddLit(&buf, " <memoryBacking>\n");
|
|
|
|
virBufferAddLit(&buf, " <hugepages/>\n");
|
|
|
|
virBufferAddLit(&buf, " </memoryBacking>\n");
|
|
|
|
}
|
2008-07-11 16:23:36 +00:00
|
|
|
for (n = 0 ; n < def->cpumasklen ; n++)
|
|
|
|
if (def->cpumask[n] != 1)
|
|
|
|
allones = 0;
|
|
|
|
|
|
|
|
if (allones) {
|
|
|
|
virBufferVSprintf(&buf, " <vcpu>%lu</vcpu>\n", def->vcpus);
|
|
|
|
} else {
|
|
|
|
char *cpumask = NULL;
|
|
|
|
if ((cpumask =
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainCpuSetFormat(def->cpumask, def->cpumasklen)) == NULL)
|
2008-07-11 16:23:36 +00:00
|
|
|
goto cleanup;
|
|
|
|
virBufferVSprintf(&buf, " <vcpu cpuset='%s'>%lu</vcpu>\n",
|
|
|
|
cpumask, def->vcpus);
|
|
|
|
VIR_FREE(cpumask);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (def->os.bootloader) {
|
|
|
|
virBufferEscapeString(&buf, " <bootloader>%s</bootloader>\n",
|
|
|
|
def->os.bootloader);
|
|
|
|
if (def->os.bootloaderArgs)
|
|
|
|
virBufferEscapeString(&buf, " <bootloader_args>%s</bootloader_args>\n",
|
|
|
|
def->os.bootloaderArgs);
|
|
|
|
}
|
|
|
|
virBufferAddLit(&buf, " <os>\n");
|
|
|
|
|
|
|
|
virBufferAddLit(&buf, " <type");
|
|
|
|
if (def->os.arch)
|
|
|
|
virBufferVSprintf(&buf, " arch='%s'", def->os.arch);
|
|
|
|
if (def->os.machine)
|
|
|
|
virBufferVSprintf(&buf, " machine='%s'", def->os.machine);
|
|
|
|
/*
|
|
|
|
* 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"))
|
|
|
|
virBufferVSprintf(&buf, ">%s</type>\n", "linux");
|
|
|
|
else
|
|
|
|
virBufferVSprintf(&buf, ">%s</type>\n", def->os.type);
|
|
|
|
|
2008-08-01 13:31:37 +00:00
|
|
|
if (def->os.init)
|
|
|
|
virBufferEscapeString(&buf, " <init>%s</init>\n",
|
|
|
|
def->os.init);
|
2008-07-11 16:23:36 +00:00
|
|
|
if (def->os.loader)
|
|
|
|
virBufferEscapeString(&buf, " <loader>%s</loader>\n",
|
|
|
|
def->os.loader);
|
|
|
|
if (def->os.kernel)
|
|
|
|
virBufferEscapeString(&buf, " <kernel>%s</kernel>\n",
|
|
|
|
def->os.kernel);
|
|
|
|
if (def->os.initrd)
|
|
|
|
virBufferEscapeString(&buf, " <initrd>%s</initrd>\n",
|
|
|
|
def->os.initrd);
|
|
|
|
if (def->os.cmdline)
|
|
|
|
virBufferEscapeString(&buf, " <cmdline>%s</cmdline>\n",
|
|
|
|
def->os.cmdline);
|
|
|
|
if (def->os.root)
|
|
|
|
virBufferEscapeString(&buf, " <root>%s</root>\n",
|
|
|
|
def->os.root);
|
|
|
|
|
|
|
|
if (!def->os.bootloader) {
|
|
|
|
for (n = 0 ; n < def->os.nBootDevs ; n++) {
|
|
|
|
const char *boottype =
|
|
|
|
virDomainBootTypeToString(def->os.bootDevs[n]);
|
|
|
|
if (!boottype) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
_("unexpected boot device type %d"),
|
|
|
|
def->os.bootDevs[n]);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
virBufferVSprintf(&buf, " <boot dev='%s'/>\n", boottype);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferAddLit(&buf, " </os>\n");
|
|
|
|
|
|
|
|
if (def->features) {
|
|
|
|
int i;
|
|
|
|
virBufferAddLit(&buf, " <features>\n");
|
|
|
|
for (i = 0 ; i < VIR_DOMAIN_FEATURE_LAST ; i++) {
|
|
|
|
if (def->features & (1 << i)) {
|
|
|
|
const char *name = virDomainFeatureTypeToString(i);
|
|
|
|
if (!name) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
_("unexpected feature %d"), i);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
virBufferVSprintf(&buf, " <%s/>\n", name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
virBufferAddLit(&buf, " </features>\n");
|
|
|
|
}
|
|
|
|
|
2010-02-10 12:22:36 +00:00
|
|
|
if (virCPUDefFormatBuf(&buf, def->cpu, " ", 0) < 0)
|
2009-12-18 14:44:55 +01:00
|
|
|
goto cleanup;
|
|
|
|
|
2010-02-02 17:49:09 +00:00
|
|
|
virBufferVSprintf(&buf, " <clock offset='%s'",
|
2010-02-02 17:22:03 +00:00
|
|
|
virDomainClockOffsetTypeToString(def->clock.offset));
|
2010-02-02 17:49:09 +00:00
|
|
|
switch (def->clock.offset) {
|
|
|
|
case VIR_DOMAIN_CLOCK_OFFSET_VARIABLE:
|
2010-02-02 18:28:44 +00:00
|
|
|
virBufferVSprintf(&buf, " adjustment='%lld'", def->clock.data.adjustment);
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_CLOCK_OFFSET_TIMEZONE:
|
|
|
|
virBufferEscapeString(&buf, " timezone='%s'", def->clock.data.timezone);
|
2010-02-02 17:49:09 +00:00
|
|
|
break;
|
|
|
|
}
|
2010-03-30 13:44:22 +02:00
|
|
|
if (def->clock.ntimers == 0) {
|
|
|
|
virBufferAddLit(&buf, "/>\n");
|
|
|
|
} else {
|
|
|
|
virBufferAddLit(&buf, ">\n");
|
|
|
|
for (n = 0; n < def->clock.ntimers; n++) {
|
|
|
|
if (virDomainTimerDefFormat(&buf, def->clock.timers[n]) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
virBufferAddLit(&buf, " </clock>\n");
|
|
|
|
}
|
2008-07-11 16:23:36 +00:00
|
|
|
|
2010-02-09 18:58:01 +00:00
|
|
|
if (virDomainLifecycleDefFormat(&buf, def->onPoweroff,
|
2008-07-11 16:23:36 +00:00
|
|
|
"on_poweroff") < 0)
|
|
|
|
goto cleanup;
|
2010-02-09 18:58:01 +00:00
|
|
|
if (virDomainLifecycleDefFormat(&buf, def->onReboot,
|
2008-07-11 16:23:36 +00:00
|
|
|
"on_reboot") < 0)
|
|
|
|
goto cleanup;
|
2010-02-09 18:58:01 +00:00
|
|
|
if (virDomainLifecycleDefFormat(&buf, def->onCrash,
|
2008-07-11 16:23:36 +00:00
|
|
|
"on_crash") < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
virBufferAddLit(&buf, " <devices>\n");
|
|
|
|
|
|
|
|
if (def->emulator)
|
|
|
|
virBufferEscapeString(&buf, " <emulator>%s</emulator>\n",
|
|
|
|
def->emulator);
|
|
|
|
|
2008-10-10 16:08:01 +00:00
|
|
|
for (n = 0 ; n < def->ndisks ; n++)
|
2010-02-09 18:58:01 +00:00
|
|
|
if (virDomainDiskDefFormat(&buf, def->disks[n], flags) < 0)
|
2008-07-11 16:23:36 +00:00
|
|
|
goto cleanup;
|
2008-08-01 13:31:37 +00:00
|
|
|
|
2009-12-02 19:15:38 +00:00
|
|
|
for (n = 0 ; n < def->ncontrollers ; n++)
|
2010-02-09 18:58:01 +00:00
|
|
|
if (virDomainControllerDefFormat(&buf, def->controllers[n], flags) < 0)
|
2009-12-02 19:15:38 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2008-10-10 16:08:01 +00:00
|
|
|
for (n = 0 ; n < def->nfss ; n++)
|
2010-02-09 18:58:01 +00:00
|
|
|
if (virDomainFSDefFormat(&buf, def->fss[n], flags) < 0)
|
2008-08-01 13:31:37 +00:00
|
|
|
goto cleanup;
|
2008-07-11 16:23:36 +00:00
|
|
|
|
|
|
|
|
2008-10-10 16:08:01 +00:00
|
|
|
for (n = 0 ; n < def->nnets ; n++)
|
2010-02-09 18:58:01 +00:00
|
|
|
if (virDomainNetDefFormat(&buf, def->nets[n], flags) < 0)
|
2008-10-10 16:08:01 +00:00
|
|
|
goto cleanup;
|
2008-07-11 16:23:36 +00:00
|
|
|
|
2008-10-10 16:08:01 +00:00
|
|
|
for (n = 0 ; n < def->nserials ; n++)
|
2010-02-09 18:58:01 +00:00
|
|
|
if (virDomainChrDefFormat(&buf, def->serials[n], flags) < 0)
|
2008-07-11 16:23:36 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2008-10-10 16:08:01 +00:00
|
|
|
for (n = 0 ; n < def->nparallels ; n++)
|
2010-02-09 18:58:01 +00:00
|
|
|
if (virDomainChrDefFormat(&buf, def->parallels[n], flags) < 0)
|
2008-07-11 16:23:36 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
/* If there's a PV console that's preferred.. */
|
|
|
|
if (def->console) {
|
2010-02-09 18:58:01 +00:00
|
|
|
if (virDomainChrDefFormat(&buf, def->console, flags) < 0)
|
2008-07-11 16:23:36 +00:00
|
|
|
goto cleanup;
|
2008-10-10 16:08:01 +00:00
|
|
|
} else if (def->nserials != 0) {
|
2009-01-16 16:50:11 +00:00
|
|
|
/* ..else for legacy compat duplicate the first serial device as a
|
|
|
|
* console */
|
2009-11-05 14:19:14 +01:00
|
|
|
virDomainChrDef console;
|
|
|
|
memcpy(&console, def->serials[0], sizeof(console));
|
|
|
|
console.targetType = VIR_DOMAIN_CHR_TARGET_TYPE_CONSOLE;
|
2010-02-09 18:58:01 +00:00
|
|
|
if (virDomainChrDefFormat(&buf, &console, flags) < 0)
|
2008-07-11 16:23:36 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2009-11-05 15:31:03 +01:00
|
|
|
for (n = 0 ; n < def->nchannels ; n++)
|
2010-02-09 18:58:01 +00:00
|
|
|
if (virDomainChrDefFormat(&buf, def->channels[n], flags) < 0)
|
2009-11-05 15:31:03 +01:00
|
|
|
goto cleanup;
|
|
|
|
|
2008-10-10 16:08:01 +00:00
|
|
|
for (n = 0 ; n < def->ninputs ; n++)
|
|
|
|
if (def->inputs[n]->bus == VIR_DOMAIN_INPUT_BUS_USB &&
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainInputDefFormat(&buf, def->inputs[n], flags) < 0)
|
2008-07-11 16:23:36 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2009-05-07 07:27:49 +00:00
|
|
|
if (def->ngraphics > 0) {
|
2008-07-11 16:23:36 +00:00
|
|
|
/* If graphics is enabled, add the implicit mouse */
|
|
|
|
virDomainInputDef autoInput = {
|
|
|
|
VIR_DOMAIN_INPUT_TYPE_MOUSE,
|
|
|
|
STREQ(def->os.type, "hvm") ?
|
Add device info to serial, parallel, channel, input & fs devices
Although the serial, parallel, chanel, input & fs devices do
not have PCI address info, they can all have device aliases.
Thus it neccessary to associate the virDomainDeviceInfo data
with them all.
* src/conf/domain_conf.c, src/conf/domain_conf.h: Add hooks for
parsing / formatting device info for serial, parallel, channel
input and fs devices.
* docs/schemas/domain.rng: Associate device info with character
devices, input & fs device
2010-01-06 12:39:53 +00:00
|
|
|
VIR_DOMAIN_INPUT_BUS_PS2 : VIR_DOMAIN_INPUT_BUS_XEN,
|
|
|
|
{ .alias = NULL },
|
2008-10-10 16:08:01 +00:00
|
|
|
};
|
2008-07-11 16:23:36 +00:00
|
|
|
|
2010-02-09 18:58:01 +00:00
|
|
|
if (virDomainInputDefFormat(&buf, &autoInput, flags) < 0)
|
2008-07-11 16:23:36 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2009-05-07 07:27:49 +00:00
|
|
|
for (n = 0 ; n < def->ngraphics ; n++)
|
2010-02-09 18:58:01 +00:00
|
|
|
if (virDomainGraphicsDefFormat(&buf, def->graphics[n], flags) < 0)
|
2009-05-07 07:27:49 +00:00
|
|
|
goto cleanup;
|
2008-07-11 16:23:36 +00:00
|
|
|
}
|
|
|
|
|
2008-10-10 16:08:01 +00:00
|
|
|
for (n = 0 ; n < def->nsounds ; n++)
|
2010-02-09 18:58:01 +00:00
|
|
|
if (virDomainSoundDefFormat(&buf, def->sounds[n], flags) < 0)
|
2008-07-11 16:23:36 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2009-07-06 14:54:44 +01:00
|
|
|
for (n = 0 ; n < def->nvideos ; n++)
|
2010-02-09 18:58:01 +00:00
|
|
|
if (virDomainVideoDefFormat(&buf, def->videos[n], flags) < 0)
|
2009-07-06 14:54:44 +01:00
|
|
|
goto cleanup;
|
|
|
|
|
2008-10-10 16:08:01 +00:00
|
|
|
for (n = 0 ; n < def->nhostdevs ; n++)
|
2010-02-09 18:58:01 +00:00
|
|
|
if (virDomainHostdevDefFormat(&buf, def->hostdevs[n], flags) < 0)
|
2008-08-08 14:27:05 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2009-10-21 13:26:38 +01:00
|
|
|
if (def->watchdog)
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainWatchdogDefFormat (&buf, def->watchdog, flags);
|
2009-10-21 13:26:38 +01:00
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
virBufferAddLit(&buf, " </devices>\n");
|
2009-03-03 09:44:41 +00:00
|
|
|
|
|
|
|
if (def->seclabel.model) {
|
2009-03-03 16:53:13 +00:00
|
|
|
const char *sectype = virDomainSeclabelTypeToString(def->seclabel.type);
|
|
|
|
if (!sectype)
|
|
|
|
goto cleanup;
|
|
|
|
if (!def->seclabel.label ||
|
|
|
|
(def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC &&
|
|
|
|
(flags & VIR_DOMAIN_XML_INACTIVE))) {
|
|
|
|
virBufferVSprintf(&buf, " <seclabel type='%s' model='%s'/>\n",
|
|
|
|
sectype, def->seclabel.model);
|
|
|
|
} else {
|
|
|
|
virBufferVSprintf(&buf, " <seclabel type='%s' model='%s'>\n",
|
|
|
|
sectype, def->seclabel.model);
|
|
|
|
virBufferEscapeString(&buf, " <label>%s</label>\n",
|
|
|
|
def->seclabel.label);
|
|
|
|
if (def->seclabel.imagelabel &&
|
|
|
|
def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC)
|
|
|
|
virBufferEscapeString(&buf, " <imagelabel>%s</imagelabel>\n",
|
|
|
|
def->seclabel.imagelabel);
|
|
|
|
virBufferAddLit(&buf, " </seclabel>\n");
|
|
|
|
}
|
2009-03-03 09:44:41 +00:00
|
|
|
}
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
virBufferAddLit(&buf, "</domain>\n");
|
|
|
|
|
|
|
|
if (virBufferError(&buf))
|
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
|
|
|
no_memory:
|
2010-02-04 19:19:08 +01:00
|
|
|
virReportOOMError();
|
2008-07-11 16:23:36 +00:00
|
|
|
cleanup:
|
2009-12-10 00:00:50 +01:00
|
|
|
virBufferFreeAndReset(&buf);
|
2008-07-11 16:23:36 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-02-24 15:45:16 -05:00
|
|
|
#ifndef PROXY
|
|
|
|
|
2010-02-19 16:06:08 +01:00
|
|
|
static char *virDomainObjFormat(virCapsPtr caps,
|
|
|
|
virDomainObjPtr obj,
|
|
|
|
int flags)
|
2009-06-12 11:38:50 +00:00
|
|
|
{
|
2009-12-10 00:00:50 +01:00
|
|
|
char *config_xml = NULL;
|
2009-06-12 11:38:50 +00:00
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
|
|
|
|
virBufferVSprintf(&buf, "<domstatus state='%s' pid='%d'>\n",
|
|
|
|
virDomainStateTypeToString(obj->state),
|
|
|
|
obj->pid);
|
2009-07-09 18:06:38 +01:00
|
|
|
|
2009-11-26 17:57:00 +00:00
|
|
|
if (caps->privateDataXMLFormat &&
|
|
|
|
((caps->privateDataXMLFormat)(&buf, obj->privateData)) < 0)
|
|
|
|
goto error;
|
2009-09-11 16:26:40 +01:00
|
|
|
|
2010-02-09 18:58:01 +00:00
|
|
|
if (!(config_xml = virDomainDefFormat(obj->def,
|
2009-06-12 11:38:50 +00:00
|
|
|
flags)))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
virBufferAdd(&buf, config_xml, strlen(config_xml));
|
|
|
|
VIR_FREE(config_xml);
|
|
|
|
virBufferAddLit(&buf, "</domstatus>\n");
|
|
|
|
|
|
|
|
if (virBufferError(&buf))
|
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
|
|
|
no_memory:
|
2010-02-04 19:19:08 +01:00
|
|
|
virReportOOMError();
|
2009-06-12 11:38:50 +00:00
|
|
|
error:
|
2009-12-10 00:00:50 +01:00
|
|
|
virBufferFreeAndReset(&buf);
|
2009-06-12 11:38:50 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-02-09 18:58:01 +00:00
|
|
|
int virDomainSaveXML(const char *configDir,
|
2008-12-20 13:09:45 +00:00
|
|
|
virDomainDefPtr def,
|
|
|
|
const char *xml)
|
2008-07-11 16:23:36 +00:00
|
|
|
{
|
2008-08-20 19:42:36 +00:00
|
|
|
char *configFile = NULL;
|
2008-07-11 16:23:36 +00:00
|
|
|
int fd = -1, ret = -1;
|
|
|
|
size_t towrite;
|
|
|
|
|
2010-02-09 18:58:01 +00:00
|
|
|
if ((configFile = virDomainConfigFile(configDir, def->name)) == NULL)
|
2008-07-11 16:23:36 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2009-09-04 17:27:34 +02:00
|
|
|
if (virFileMakePath(configDir)) {
|
2010-02-04 21:02:58 +01:00
|
|
|
virReportSystemError(errno,
|
2009-01-20 17:13:33 +00:00
|
|
|
_("cannot create config directory '%s'"),
|
|
|
|
configDir);
|
2008-07-11 16:23:36 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2008-08-20 19:42:36 +00:00
|
|
|
if ((fd = open(configFile,
|
2008-07-11 16:23:36 +00:00
|
|
|
O_WRONLY | O_CREAT | O_TRUNC,
|
|
|
|
S_IRUSR | S_IWUSR )) < 0) {
|
2010-02-04 21:02:58 +01:00
|
|
|
virReportSystemError(errno,
|
2009-01-20 17:13:33 +00:00
|
|
|
_("cannot create config file '%s'"),
|
|
|
|
configFile);
|
2008-07-11 16:23:36 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
towrite = strlen(xml);
|
|
|
|
if (safewrite(fd, xml, towrite) < 0) {
|
2010-02-04 21:02:58 +01:00
|
|
|
virReportSystemError(errno,
|
2009-01-20 17:13:33 +00:00
|
|
|
_("cannot write config file '%s'"),
|
|
|
|
configFile);
|
2008-07-11 16:23:36 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (close(fd) < 0) {
|
2010-02-04 21:02:58 +01:00
|
|
|
virReportSystemError(errno,
|
2009-01-20 17:13:33 +00:00
|
|
|
_("cannot save config file '%s'"),
|
|
|
|
configFile);
|
2008-07-11 16:23:36 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
|
|
if (fd != -1)
|
|
|
|
close(fd);
|
2009-09-04 15:56:32 +02:00
|
|
|
VIR_FREE(configFile);
|
2008-12-20 13:09:45 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2010-02-09 18:58:01 +00:00
|
|
|
int virDomainSaveConfig(const char *configDir,
|
2008-12-20 13:09:45 +00:00
|
|
|
virDomainDefPtr def)
|
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
char *xml;
|
2008-07-11 16:23:36 +00:00
|
|
|
|
2010-02-09 18:58:01 +00:00
|
|
|
if (!(xml = virDomainDefFormat(def,
|
2008-12-20 13:09:45 +00:00
|
|
|
VIR_DOMAIN_XML_SECURE)))
|
|
|
|
goto cleanup;
|
|
|
|
|
2010-02-09 18:58:01 +00:00
|
|
|
if (virDomainSaveXML(configDir, def, xml))
|
2008-12-20 13:09:45 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(xml);
|
2008-07-11 16:23:36 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2010-02-09 18:58:01 +00:00
|
|
|
int virDomainSaveStatus(virCapsPtr caps,
|
2009-06-12 11:38:50 +00:00
|
|
|
const char *statusDir,
|
|
|
|
virDomainObjPtr obj)
|
|
|
|
{
|
2009-07-17 22:08:33 +01:00
|
|
|
int flags = VIR_DOMAIN_XML_SECURE|VIR_DOMAIN_XML_INTERNAL_STATUS;
|
2009-06-12 11:38:50 +00:00
|
|
|
int ret = -1;
|
|
|
|
char *xml;
|
|
|
|
|
2010-02-09 18:58:01 +00:00
|
|
|
if (!(xml = virDomainObjFormat(caps, obj, flags)))
|
2009-06-12 11:38:50 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2010-02-09 18:58:01 +00:00
|
|
|
if (virDomainSaveXML(statusDir, obj->def, xml))
|
2009-06-12 11:38:50 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(xml);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2008-07-25 10:49:33 +00:00
|
|
|
|
2010-03-31 16:25:41 -04:00
|
|
|
static virDomainObjPtr virDomainLoadConfig(virCapsPtr caps,
|
|
|
|
virDomainObjListPtr doms,
|
|
|
|
const char *configDir,
|
|
|
|
const char *autostartDir,
|
|
|
|
const char *name,
|
|
|
|
virDomainLoadConfigNotify notify,
|
|
|
|
void *opaque)
|
2008-07-11 16:23:36 +00:00
|
|
|
{
|
|
|
|
char *configFile = NULL, *autostartLink = NULL;
|
|
|
|
virDomainDefPtr def = NULL;
|
|
|
|
virDomainObjPtr dom;
|
|
|
|
int autostart;
|
2008-11-17 16:52:32 +00:00
|
|
|
int newVM = 1;
|
2008-07-11 16:23:36 +00:00
|
|
|
|
2010-02-09 18:58:01 +00:00
|
|
|
if ((configFile = virDomainConfigFile(configDir, name)) == NULL)
|
2008-07-11 16:23:36 +00:00
|
|
|
goto error;
|
2010-02-09 18:58:01 +00:00
|
|
|
if (!(def = virDomainDefParseFile(caps, configFile,
|
2008-12-04 12:02:59 +00:00
|
|
|
VIR_DOMAIN_XML_INACTIVE)))
|
2008-07-11 16:23:36 +00:00
|
|
|
goto error;
|
|
|
|
|
2010-04-02 10:41:47 -04:00
|
|
|
/* if the domain is already in our hashtable, we don't need to do
|
|
|
|
* anything further
|
|
|
|
*/
|
|
|
|
if ((dom = virDomainFindByUUID(doms, def->uuid))) {
|
|
|
|
VIR_FREE(configFile);
|
|
|
|
virDomainDefFree(def);
|
|
|
|
return dom;
|
2008-12-15 11:00:11 +00:00
|
|
|
}
|
2008-11-17 16:52:32 +00:00
|
|
|
|
2010-04-02 10:41:47 -04:00
|
|
|
if ((autostartLink = virDomainConfigFile(autostartDir, name)) == NULL)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if ((autostart = virFileLinkPointsTo(autostartLink, configFile)) < 0)
|
|
|
|
goto error;
|
|
|
|
|
2010-03-24 15:31:21 +01:00
|
|
|
if (!(dom = virDomainAssignDef(caps, doms, def, false)))
|
2008-07-11 16:23:36 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
dom->autostart = autostart;
|
|
|
|
|
2008-11-17 16:52:32 +00:00
|
|
|
if (notify)
|
|
|
|
(*notify)(dom, newVM, opaque);
|
|
|
|
|
2008-11-21 11:42:51 +00:00
|
|
|
VIR_FREE(configFile);
|
|
|
|
VIR_FREE(autostartLink);
|
2008-07-11 16:23:36 +00:00
|
|
|
return dom;
|
|
|
|
|
|
|
|
error:
|
|
|
|
VIR_FREE(configFile);
|
|
|
|
VIR_FREE(autostartLink);
|
|
|
|
virDomainDefFree(def);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-02-09 18:58:01 +00:00
|
|
|
static virDomainObjPtr virDomainLoadStatus(virCapsPtr caps,
|
2009-06-12 11:38:50 +00:00
|
|
|
virDomainObjListPtr doms,
|
|
|
|
const char *statusDir,
|
|
|
|
const char *name,
|
|
|
|
virDomainLoadConfigNotify notify,
|
|
|
|
void *opaque)
|
|
|
|
{
|
|
|
|
char *statusFile = NULL;
|
|
|
|
virDomainObjPtr obj = NULL;
|
Convert virDomainObjListPtr to use a hash of domain objects
The current virDomainObjListPtr object stores domain objects in
an array. This means that to find a particular objects requires
O(n) time, and more critically acquiring O(n) mutex locks.
The new impl replaces the array with a virHashTable, keyed off
UUID. Finding a object based on UUID is now O(1) time, and only
requires a single mutex lock. Finding by name/id is unchanged
in complexity.
In changing this, all code which iterates over the array had
to be updated to use a hash table iterator function callback.
Several of the functions which were identically duplicating
across all drivers were pulled into domain_conf.c
* src/conf/domain_conf.h, src/conf/domain_conf.c: Change
virDomainObjListPtr to use virHashTable. Add a initializer
method virDomainObjListInit, and rename virDomainObjListFree
to virDomainObjListDeinit, since its not actually freeing
the container, only its contents. Also add some convenient
methods virDomainObjListGetInactiveNames,
virDomainObjListGetActiveIDs and virDomainObjListNumOfDomains
which can be used to implement the correspondingly named
public API entry points in drivers
* src/libvirt_private.syms: Export new methods from domain_conf.h
* src/lxc/lxc_driver.c, src/opennebula/one_driver.c,
src/openvz/openvz_conf.c, src/openvz/openvz_driver.c,
src/qemu/qemu_driver.c, src/test/test_driver.c,
src/uml/uml_driver.c, src/vbox/vbox_tmpl.c: Update all code
to deal with hash tables instead of arrays for domains
2009-10-09 12:33:51 +01:00
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
2009-06-12 11:38:50 +00:00
|
|
|
|
2010-02-09 18:58:01 +00:00
|
|
|
if ((statusFile = virDomainConfigFile(statusDir, name)) == NULL)
|
2009-06-12 11:38:50 +00:00
|
|
|
goto error;
|
|
|
|
|
2010-02-09 18:58:01 +00:00
|
|
|
if (!(obj = virDomainObjParseFile(caps, statusFile)))
|
2009-06-12 11:38:50 +00:00
|
|
|
goto error;
|
|
|
|
|
Convert virDomainObjListPtr to use a hash of domain objects
The current virDomainObjListPtr object stores domain objects in
an array. This means that to find a particular objects requires
O(n) time, and more critically acquiring O(n) mutex locks.
The new impl replaces the array with a virHashTable, keyed off
UUID. Finding a object based on UUID is now O(1) time, and only
requires a single mutex lock. Finding by name/id is unchanged
in complexity.
In changing this, all code which iterates over the array had
to be updated to use a hash table iterator function callback.
Several of the functions which were identically duplicating
across all drivers were pulled into domain_conf.c
* src/conf/domain_conf.h, src/conf/domain_conf.c: Change
virDomainObjListPtr to use virHashTable. Add a initializer
method virDomainObjListInit, and rename virDomainObjListFree
to virDomainObjListDeinit, since its not actually freeing
the container, only its contents. Also add some convenient
methods virDomainObjListGetInactiveNames,
virDomainObjListGetActiveIDs and virDomainObjListNumOfDomains
which can be used to implement the correspondingly named
public API entry points in drivers
* src/libvirt_private.syms: Export new methods from domain_conf.h
* src/lxc/lxc_driver.c, src/opennebula/one_driver.c,
src/openvz/openvz_conf.c, src/openvz/openvz_driver.c,
src/qemu/qemu_driver.c, src/test/test_driver.c,
src/uml/uml_driver.c, src/vbox/vbox_tmpl.c: Update all code
to deal with hash tables instead of arrays for domains
2009-10-09 12:33:51 +01:00
|
|
|
virUUIDFormat(obj->def->uuid, uuidstr);
|
|
|
|
|
|
|
|
if (virHashLookup(doms->objs, uuidstr) != NULL) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-06-12 11:38:50 +00:00
|
|
|
_("unexpected domain %s already exists"),
|
|
|
|
obj->def->name);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
Convert virDomainObjListPtr to use a hash of domain objects
The current virDomainObjListPtr object stores domain objects in
an array. This means that to find a particular objects requires
O(n) time, and more critically acquiring O(n) mutex locks.
The new impl replaces the array with a virHashTable, keyed off
UUID. Finding a object based on UUID is now O(1) time, and only
requires a single mutex lock. Finding by name/id is unchanged
in complexity.
In changing this, all code which iterates over the array had
to be updated to use a hash table iterator function callback.
Several of the functions which were identically duplicating
across all drivers were pulled into domain_conf.c
* src/conf/domain_conf.h, src/conf/domain_conf.c: Change
virDomainObjListPtr to use virHashTable. Add a initializer
method virDomainObjListInit, and rename virDomainObjListFree
to virDomainObjListDeinit, since its not actually freeing
the container, only its contents. Also add some convenient
methods virDomainObjListGetInactiveNames,
virDomainObjListGetActiveIDs and virDomainObjListNumOfDomains
which can be used to implement the correspondingly named
public API entry points in drivers
* src/libvirt_private.syms: Export new methods from domain_conf.h
* src/lxc/lxc_driver.c, src/opennebula/one_driver.c,
src/openvz/openvz_conf.c, src/openvz/openvz_driver.c,
src/qemu/qemu_driver.c, src/test/test_driver.c,
src/uml/uml_driver.c, src/vbox/vbox_tmpl.c: Update all code
to deal with hash tables instead of arrays for domains
2009-10-09 12:33:51 +01:00
|
|
|
if (virHashAddEntry(doms->objs, uuidstr, obj) < 0) {
|
2010-02-04 19:19:08 +01:00
|
|
|
virReportOOMError();
|
2009-06-12 11:38:50 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (notify)
|
|
|
|
(*notify)(obj, 1, opaque);
|
|
|
|
|
|
|
|
VIR_FREE(statusFile);
|
|
|
|
return obj;
|
|
|
|
|
|
|
|
error:
|
Fully asynchronous monitor I/O processing
Change the QEMU monitor file handle watch to poll for both
read & write events, as well as EOF. All I/O to/from the
QEMU monitor FD is now done in the event callback thread.
When the QEMU driver needs to send a command, it puts the
data to be sent into a qemuMonitorMessagePtr object instance,
queues it for dispatch, and then goes to sleep on a condition
variable. The event thread sends all the data, and then waits
for the reply to arrive, putting the response / error data
back into the qemuMonitorMessagePtr and notifying the condition
variable.
There is a temporary hack in the disk passphrase callback to
avoid acquiring the domain lock. This avoids a deadlock in
the command processing, since the domain lock is still held
when running monitor commands. The next commit will remove
the locking when running commands & thus allow re-introduction
of locking the disk passphrase callback
* src/qemu/qemu_driver.c: Temporarily don't acquire lock in
disk passphrase callback. To be reverted in next commit
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Remove
raw I/O functions, and a generic qemuMonitorSend() for
invoking a command
* src/qemu/qemu_monitor_text.c, src/qemu/qemu_monitor_text.h:
Remove all low level I/O, and use the new qemuMonitorSend()
API. Provide a qemuMonitorTextIOProcess() method for detecting
command/reply/prompt boundaries in the monitor data stream
2009-10-14 18:40:51 +01:00
|
|
|
if (obj)
|
|
|
|
virDomainObjUnref(obj);
|
2009-06-12 11:38:50 +00:00
|
|
|
VIR_FREE(statusFile);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-02-09 18:58:01 +00:00
|
|
|
int virDomainLoadAllConfigs(virCapsPtr caps,
|
2008-10-10 14:20:37 +00:00
|
|
|
virDomainObjListPtr doms,
|
2008-07-11 16:23:36 +00:00
|
|
|
const char *configDir,
|
2008-11-17 16:52:32 +00:00
|
|
|
const char *autostartDir,
|
2009-06-12 11:38:50 +00:00
|
|
|
int liveStatus,
|
2008-11-17 16:52:32 +00:00
|
|
|
virDomainLoadConfigNotify notify,
|
|
|
|
void *opaque)
|
2008-07-11 16:23:36 +00:00
|
|
|
{
|
|
|
|
DIR *dir;
|
|
|
|
struct dirent *entry;
|
|
|
|
|
2009-06-12 11:38:50 +00:00
|
|
|
VIR_INFO("Scanning for configs in %s", configDir);
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
if (!(dir = opendir(configDir))) {
|
|
|
|
if (errno == ENOENT)
|
|
|
|
return 0;
|
2010-02-04 21:02:58 +01:00
|
|
|
virReportSystemError(errno,
|
2009-01-20 17:13:33 +00:00
|
|
|
_("Failed to open dir '%s'"),
|
|
|
|
configDir);
|
2008-07-11 16:23:36 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
while ((entry = readdir(dir))) {
|
2008-08-20 19:42:36 +00:00
|
|
|
virDomainObjPtr dom;
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
if (entry->d_name[0] == '.')
|
|
|
|
continue;
|
|
|
|
|
2008-08-20 19:42:36 +00:00
|
|
|
if (!virFileStripSuffix(entry->d_name, ".xml"))
|
2008-07-11 16:23:36 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
/* NB: ignoring errors, so one malformed config doesn't
|
|
|
|
kill the whole process */
|
2009-06-12 11:38:50 +00:00
|
|
|
VIR_INFO("Loading config file '%s.xml'", entry->d_name);
|
|
|
|
if (liveStatus)
|
2010-02-09 18:58:01 +00:00
|
|
|
dom = virDomainLoadStatus(caps,
|
2009-06-12 11:38:50 +00:00
|
|
|
doms,
|
|
|
|
configDir,
|
|
|
|
entry->d_name,
|
|
|
|
notify,
|
|
|
|
opaque);
|
|
|
|
else
|
2010-02-09 18:58:01 +00:00
|
|
|
dom = virDomainLoadConfig(caps,
|
2009-06-12 11:38:50 +00:00
|
|
|
doms,
|
|
|
|
configDir,
|
|
|
|
autostartDir,
|
|
|
|
entry->d_name,
|
|
|
|
notify,
|
|
|
|
opaque);
|
2008-12-04 22:00:14 +00:00
|
|
|
if (dom) {
|
|
|
|
virDomainObjUnlock(dom);
|
2009-06-25 13:55:58 +00:00
|
|
|
if (!liveStatus)
|
|
|
|
dom->persistent = 1;
|
2008-12-04 22:00:14 +00:00
|
|
|
}
|
2008-07-11 16:23:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
closedir(dir);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-02-09 18:58:01 +00:00
|
|
|
int virDomainDeleteConfig(const char *configDir,
|
2008-08-20 19:42:36 +00:00
|
|
|
const char *autostartDir,
|
|
|
|
virDomainObjPtr dom)
|
2008-07-11 16:23:36 +00:00
|
|
|
{
|
2008-08-20 19:42:36 +00:00
|
|
|
char *configFile = NULL, *autostartLink = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
|
2010-02-09 18:58:01 +00:00
|
|
|
if ((configFile = virDomainConfigFile(configDir, dom->def->name)) == NULL)
|
2008-08-20 19:42:36 +00:00
|
|
|
goto cleanup;
|
2010-02-09 18:58:01 +00:00
|
|
|
if ((autostartLink = virDomainConfigFile(autostartDir, dom->def->name)) == NULL)
|
2008-08-20 19:42:36 +00:00
|
|
|
goto cleanup;
|
2008-07-11 16:23:36 +00:00
|
|
|
|
|
|
|
/* Not fatal if this doesn't work */
|
2008-08-20 19:42:36 +00:00
|
|
|
unlink(autostartLink);
|
2008-07-11 16:23:36 +00:00
|
|
|
|
2008-08-20 19:42:36 +00:00
|
|
|
if (unlink(configFile) < 0 &&
|
|
|
|
errno != ENOENT) {
|
2010-02-04 21:02:58 +01:00
|
|
|
virReportSystemError(errno,
|
2009-01-20 17:13:33 +00:00
|
|
|
_("cannot remove config %s"),
|
|
|
|
configFile);
|
2008-08-20 19:42:36 +00:00
|
|
|
goto cleanup;
|
2008-07-11 16:23:36 +00:00
|
|
|
}
|
|
|
|
|
2008-08-20 19:42:36 +00:00
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(configFile);
|
|
|
|
VIR_FREE(autostartLink);
|
|
|
|
return ret;
|
2008-07-11 16:23:36 +00:00
|
|
|
}
|
2008-07-25 10:49:33 +00:00
|
|
|
|
2010-02-09 18:58:01 +00:00
|
|
|
char *virDomainConfigFile(const char *dir,
|
2008-08-20 19:42:36 +00:00
|
|
|
const char *name)
|
|
|
|
{
|
|
|
|
char *ret = NULL;
|
|
|
|
|
2008-12-23 13:03:29 +00:00
|
|
|
if (virAsprintf(&ret, "%s/%s.xml", dir, name) < 0) {
|
2010-02-04 19:19:08 +01:00
|
|
|
virReportOOMError();
|
2008-08-20 19:42:36 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2008-09-03 16:05:25 +00:00
|
|
|
/* 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),
|
2008-10-10 08:37:35 +00:00
|
|
|
* hdd => (1,1), vdaa => (0,26))
|
2008-09-03 16:05:25 +00:00
|
|
|
* @param disk The disk device
|
|
|
|
* @param busIdx parsed bus number
|
|
|
|
* @param devIdx parsed device number
|
|
|
|
* @return 0 on success, -1 on failure
|
|
|
|
*/
|
2008-10-17 09:18:21 +00:00
|
|
|
int virDiskNameToBusDeviceIndex(const virDomainDiskDefPtr disk,
|
2008-09-03 16:05:25 +00:00
|
|
|
int *busIdx,
|
|
|
|
int *devIdx) {
|
|
|
|
|
|
|
|
int idx = virDiskNameToIndex(disk->dst);
|
2008-10-17 09:18:21 +00:00
|
|
|
if (idx < 0)
|
2008-09-03 16:05:25 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
switch (disk->bus) {
|
|
|
|
case VIR_DOMAIN_DISK_BUS_IDE:
|
|
|
|
*busIdx = idx / 2;
|
|
|
|
*devIdx = idx % 2;
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_DISK_BUS_SCSI:
|
|
|
|
*busIdx = idx / 7;
|
|
|
|
*devIdx = idx % 7;
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_DISK_BUS_FDC:
|
|
|
|
case VIR_DOMAIN_DISK_BUS_USB:
|
|
|
|
case VIR_DOMAIN_DISK_BUS_VIRTIO:
|
|
|
|
case VIR_DOMAIN_DISK_BUS_XEN:
|
|
|
|
default:
|
|
|
|
*busIdx = 0;
|
|
|
|
*devIdx = idx;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2008-08-20 19:42:36 +00:00
|
|
|
|
2009-04-22 14:26:50 +00:00
|
|
|
virDomainFSDefPtr virDomainGetRootFilesystem(virDomainDefPtr def)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0 ; i < def->nfss ; i++) {
|
|
|
|
if (def->fss[i]->type != VIR_DOMAIN_FS_TYPE_MOUNT)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (STREQ(def->fss[i]->dst, "/"))
|
|
|
|
return def->fss[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2009-11-02 13:37:38 -05:00
|
|
|
/*
|
|
|
|
* virDomainObjIsDuplicate:
|
|
|
|
* @doms : virDomainObjListPtr to search
|
|
|
|
* @def : virDomainDefPtr definition of domain to lookup
|
|
|
|
* @check_active: If true, ensure that domain is not active
|
|
|
|
*
|
|
|
|
* Returns: -1 on error
|
|
|
|
* 0 if domain is new
|
|
|
|
* 1 if domain is a duplicate
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virDomainObjIsDuplicate(virDomainObjListPtr doms,
|
|
|
|
virDomainDefPtr def,
|
|
|
|
unsigned int check_active)
|
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
int dupVM = 0;
|
|
|
|
virDomainObjPtr vm = NULL;
|
|
|
|
|
|
|
|
/* See if a VM with matching UUID already exists */
|
|
|
|
vm = virDomainFindByUUID(doms, def->uuid);
|
|
|
|
if (vm) {
|
|
|
|
/* UUID matches, but if names don't match, refuse it */
|
|
|
|
if (STRNEQ(vm->def->name, def->name)) {
|
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
|
|
|
virUUIDFormat(vm->def->uuid, uuidstr);
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("domain '%s' is already defined with uuid %s"),
|
|
|
|
vm->def->name, uuidstr);
|
2009-11-02 13:37:38 -05:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (check_active) {
|
|
|
|
/* UUID & name match, but if VM is already active, refuse it */
|
|
|
|
if (virDomainObjIsActive(vm)) {
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_OPERATION_INVALID,
|
2009-11-02 13:37:38 -05:00
|
|
|
_("domain is already active as '%s'"),
|
|
|
|
vm->def->name);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
dupVM = 1;
|
|
|
|
} else {
|
|
|
|
/* UUID does not match, but if a name matches, refuse it */
|
|
|
|
vm = virDomainFindByName(doms, def->name);
|
|
|
|
if (vm) {
|
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
|
|
|
virUUIDFormat(vm->def->uuid, uuidstr);
|
2010-02-09 18:58:01 +00:00
|
|
|
virDomainReportError(VIR_ERR_OPERATION_FAILED,
|
2009-11-02 13:37:38 -05:00
|
|
|
_("domain '%s' already exists with uuid %s"),
|
|
|
|
def->name, uuidstr);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = dupVM;
|
|
|
|
cleanup:
|
|
|
|
if (vm)
|
|
|
|
virDomainObjUnlock(vm);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2008-09-05 11:52:12 +00:00
|
|
|
|
2008-12-04 22:00:14 +00:00
|
|
|
void virDomainObjLock(virDomainObjPtr obj)
|
|
|
|
{
|
2009-01-15 19:56:05 +00:00
|
|
|
virMutexLock(&obj->lock);
|
2008-12-04 22:00:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void virDomainObjUnlock(virDomainObjPtr obj)
|
|
|
|
{
|
2009-01-15 19:56:05 +00:00
|
|
|
virMutexUnlock(&obj->lock);
|
2008-12-04 22:00:14 +00:00
|
|
|
}
|
|
|
|
|
Convert virDomainObjListPtr to use a hash of domain objects
The current virDomainObjListPtr object stores domain objects in
an array. This means that to find a particular objects requires
O(n) time, and more critically acquiring O(n) mutex locks.
The new impl replaces the array with a virHashTable, keyed off
UUID. Finding a object based on UUID is now O(1) time, and only
requires a single mutex lock. Finding by name/id is unchanged
in complexity.
In changing this, all code which iterates over the array had
to be updated to use a hash table iterator function callback.
Several of the functions which were identically duplicating
across all drivers were pulled into domain_conf.c
* src/conf/domain_conf.h, src/conf/domain_conf.c: Change
virDomainObjListPtr to use virHashTable. Add a initializer
method virDomainObjListInit, and rename virDomainObjListFree
to virDomainObjListDeinit, since its not actually freeing
the container, only its contents. Also add some convenient
methods virDomainObjListGetInactiveNames,
virDomainObjListGetActiveIDs and virDomainObjListNumOfDomains
which can be used to implement the correspondingly named
public API entry points in drivers
* src/libvirt_private.syms: Export new methods from domain_conf.h
* src/lxc/lxc_driver.c, src/opennebula/one_driver.c,
src/openvz/openvz_conf.c, src/openvz/openvz_driver.c,
src/qemu/qemu_driver.c, src/test/test_driver.c,
src/uml/uml_driver.c, src/vbox/vbox_tmpl.c: Update all code
to deal with hash tables instead of arrays for domains
2009-10-09 12:33:51 +01:00
|
|
|
|
|
|
|
static void virDomainObjListCountActive(void *payload, const char *name ATTRIBUTE_UNUSED, void *data)
|
|
|
|
{
|
|
|
|
virDomainObjPtr obj = payload;
|
|
|
|
int *count = data;
|
|
|
|
virDomainObjLock(obj);
|
Rename internal APis
Rename virDomainIsActive to virDomainObjIsActive, and
virInterfaceIsActive to virInterfaceObjIsActive and finally
virNetworkIsActive to virNetworkObjIsActive.
* src/conf/domain_conf.c, src/conf/domain_conf.h,
src/conf/interface_conf.h, src/conf/network_conf.c,
src/conf/network_conf.h, src/lxc/lxc_driver.c,
src/network/bridge_driver.c, src/opennebula/one_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_driver.c,
src/test/test_driver.c, src/uml/uml_driver.c: Update for
renamed APIs.
2009-10-20 15:51:03 +01:00
|
|
|
if (virDomainObjIsActive(obj))
|
Convert virDomainObjListPtr to use a hash of domain objects
The current virDomainObjListPtr object stores domain objects in
an array. This means that to find a particular objects requires
O(n) time, and more critically acquiring O(n) mutex locks.
The new impl replaces the array with a virHashTable, keyed off
UUID. Finding a object based on UUID is now O(1) time, and only
requires a single mutex lock. Finding by name/id is unchanged
in complexity.
In changing this, all code which iterates over the array had
to be updated to use a hash table iterator function callback.
Several of the functions which were identically duplicating
across all drivers were pulled into domain_conf.c
* src/conf/domain_conf.h, src/conf/domain_conf.c: Change
virDomainObjListPtr to use virHashTable. Add a initializer
method virDomainObjListInit, and rename virDomainObjListFree
to virDomainObjListDeinit, since its not actually freeing
the container, only its contents. Also add some convenient
methods virDomainObjListGetInactiveNames,
virDomainObjListGetActiveIDs and virDomainObjListNumOfDomains
which can be used to implement the correspondingly named
public API entry points in drivers
* src/libvirt_private.syms: Export new methods from domain_conf.h
* src/lxc/lxc_driver.c, src/opennebula/one_driver.c,
src/openvz/openvz_conf.c, src/openvz/openvz_driver.c,
src/qemu/qemu_driver.c, src/test/test_driver.c,
src/uml/uml_driver.c, src/vbox/vbox_tmpl.c: Update all code
to deal with hash tables instead of arrays for domains
2009-10-09 12:33:51 +01:00
|
|
|
(*count)++;
|
|
|
|
virDomainObjUnlock(obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void virDomainObjListCountInactive(void *payload, const char *name ATTRIBUTE_UNUSED, void *data)
|
|
|
|
{
|
|
|
|
virDomainObjPtr obj = payload;
|
|
|
|
int *count = data;
|
|
|
|
virDomainObjLock(obj);
|
Rename internal APis
Rename virDomainIsActive to virDomainObjIsActive, and
virInterfaceIsActive to virInterfaceObjIsActive and finally
virNetworkIsActive to virNetworkObjIsActive.
* src/conf/domain_conf.c, src/conf/domain_conf.h,
src/conf/interface_conf.h, src/conf/network_conf.c,
src/conf/network_conf.h, src/lxc/lxc_driver.c,
src/network/bridge_driver.c, src/opennebula/one_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_driver.c,
src/test/test_driver.c, src/uml/uml_driver.c: Update for
renamed APIs.
2009-10-20 15:51:03 +01:00
|
|
|
if (!virDomainObjIsActive(obj))
|
Convert virDomainObjListPtr to use a hash of domain objects
The current virDomainObjListPtr object stores domain objects in
an array. This means that to find a particular objects requires
O(n) time, and more critically acquiring O(n) mutex locks.
The new impl replaces the array with a virHashTable, keyed off
UUID. Finding a object based on UUID is now O(1) time, and only
requires a single mutex lock. Finding by name/id is unchanged
in complexity.
In changing this, all code which iterates over the array had
to be updated to use a hash table iterator function callback.
Several of the functions which were identically duplicating
across all drivers were pulled into domain_conf.c
* src/conf/domain_conf.h, src/conf/domain_conf.c: Change
virDomainObjListPtr to use virHashTable. Add a initializer
method virDomainObjListInit, and rename virDomainObjListFree
to virDomainObjListDeinit, since its not actually freeing
the container, only its contents. Also add some convenient
methods virDomainObjListGetInactiveNames,
virDomainObjListGetActiveIDs and virDomainObjListNumOfDomains
which can be used to implement the correspondingly named
public API entry points in drivers
* src/libvirt_private.syms: Export new methods from domain_conf.h
* src/lxc/lxc_driver.c, src/opennebula/one_driver.c,
src/openvz/openvz_conf.c, src/openvz/openvz_driver.c,
src/qemu/qemu_driver.c, src/test/test_driver.c,
src/uml/uml_driver.c, src/vbox/vbox_tmpl.c: Update all code
to deal with hash tables instead of arrays for domains
2009-10-09 12:33:51 +01:00
|
|
|
(*count)++;
|
|
|
|
virDomainObjUnlock(obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
int virDomainObjListNumOfDomains(virDomainObjListPtr doms, int active)
|
|
|
|
{
|
|
|
|
int count = 0;
|
|
|
|
if (active)
|
|
|
|
virHashForEach(doms->objs, virDomainObjListCountActive, &count);
|
|
|
|
else
|
|
|
|
virHashForEach(doms->objs, virDomainObjListCountInactive, &count);
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct virDomainIDData {
|
|
|
|
int numids;
|
|
|
|
int maxids;
|
|
|
|
int *ids;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void virDomainObjListCopyActiveIDs(void *payload, const char *name ATTRIBUTE_UNUSED, void *opaque)
|
|
|
|
{
|
|
|
|
virDomainObjPtr obj = payload;
|
|
|
|
struct virDomainIDData *data = opaque;
|
|
|
|
virDomainObjLock(obj);
|
Rename internal APis
Rename virDomainIsActive to virDomainObjIsActive, and
virInterfaceIsActive to virInterfaceObjIsActive and finally
virNetworkIsActive to virNetworkObjIsActive.
* src/conf/domain_conf.c, src/conf/domain_conf.h,
src/conf/interface_conf.h, src/conf/network_conf.c,
src/conf/network_conf.h, src/lxc/lxc_driver.c,
src/network/bridge_driver.c, src/opennebula/one_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_driver.c,
src/test/test_driver.c, src/uml/uml_driver.c: Update for
renamed APIs.
2009-10-20 15:51:03 +01:00
|
|
|
if (virDomainObjIsActive(obj) && data->numids < data->maxids)
|
Convert virDomainObjListPtr to use a hash of domain objects
The current virDomainObjListPtr object stores domain objects in
an array. This means that to find a particular objects requires
O(n) time, and more critically acquiring O(n) mutex locks.
The new impl replaces the array with a virHashTable, keyed off
UUID. Finding a object based on UUID is now O(1) time, and only
requires a single mutex lock. Finding by name/id is unchanged
in complexity.
In changing this, all code which iterates over the array had
to be updated to use a hash table iterator function callback.
Several of the functions which were identically duplicating
across all drivers were pulled into domain_conf.c
* src/conf/domain_conf.h, src/conf/domain_conf.c: Change
virDomainObjListPtr to use virHashTable. Add a initializer
method virDomainObjListInit, and rename virDomainObjListFree
to virDomainObjListDeinit, since its not actually freeing
the container, only its contents. Also add some convenient
methods virDomainObjListGetInactiveNames,
virDomainObjListGetActiveIDs and virDomainObjListNumOfDomains
which can be used to implement the correspondingly named
public API entry points in drivers
* src/libvirt_private.syms: Export new methods from domain_conf.h
* src/lxc/lxc_driver.c, src/opennebula/one_driver.c,
src/openvz/openvz_conf.c, src/openvz/openvz_driver.c,
src/qemu/qemu_driver.c, src/test/test_driver.c,
src/uml/uml_driver.c, src/vbox/vbox_tmpl.c: Update all code
to deal with hash tables instead of arrays for domains
2009-10-09 12:33:51 +01:00
|
|
|
data->ids[data->numids++] = obj->def->id;
|
|
|
|
virDomainObjUnlock(obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
int virDomainObjListGetActiveIDs(virDomainObjListPtr doms,
|
|
|
|
int *ids,
|
|
|
|
int maxids)
|
|
|
|
{
|
|
|
|
struct virDomainIDData data = { 0, maxids, ids };
|
|
|
|
virHashForEach(doms->objs, virDomainObjListCopyActiveIDs, &data);
|
|
|
|
return data.numids;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct virDomainNameData {
|
|
|
|
int oom;
|
|
|
|
int numnames;
|
|
|
|
int maxnames;
|
|
|
|
char **const names;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void virDomainObjListCopyInactiveNames(void *payload, const char *name ATTRIBUTE_UNUSED, void *opaque)
|
|
|
|
{
|
|
|
|
virDomainObjPtr obj = payload;
|
|
|
|
struct virDomainNameData *data = opaque;
|
|
|
|
|
|
|
|
if (data->oom)
|
|
|
|
return;
|
|
|
|
|
|
|
|
virDomainObjLock(obj);
|
Rename internal APis
Rename virDomainIsActive to virDomainObjIsActive, and
virInterfaceIsActive to virInterfaceObjIsActive and finally
virNetworkIsActive to virNetworkObjIsActive.
* src/conf/domain_conf.c, src/conf/domain_conf.h,
src/conf/interface_conf.h, src/conf/network_conf.c,
src/conf/network_conf.h, src/lxc/lxc_driver.c,
src/network/bridge_driver.c, src/opennebula/one_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_driver.c,
src/test/test_driver.c, src/uml/uml_driver.c: Update for
renamed APIs.
2009-10-20 15:51:03 +01:00
|
|
|
if (!virDomainObjIsActive(obj) && data->numnames < data->maxnames) {
|
Convert virDomainObjListPtr to use a hash of domain objects
The current virDomainObjListPtr object stores domain objects in
an array. This means that to find a particular objects requires
O(n) time, and more critically acquiring O(n) mutex locks.
The new impl replaces the array with a virHashTable, keyed off
UUID. Finding a object based on UUID is now O(1) time, and only
requires a single mutex lock. Finding by name/id is unchanged
in complexity.
In changing this, all code which iterates over the array had
to be updated to use a hash table iterator function callback.
Several of the functions which were identically duplicating
across all drivers were pulled into domain_conf.c
* src/conf/domain_conf.h, src/conf/domain_conf.c: Change
virDomainObjListPtr to use virHashTable. Add a initializer
method virDomainObjListInit, and rename virDomainObjListFree
to virDomainObjListDeinit, since its not actually freeing
the container, only its contents. Also add some convenient
methods virDomainObjListGetInactiveNames,
virDomainObjListGetActiveIDs and virDomainObjListNumOfDomains
which can be used to implement the correspondingly named
public API entry points in drivers
* src/libvirt_private.syms: Export new methods from domain_conf.h
* src/lxc/lxc_driver.c, src/opennebula/one_driver.c,
src/openvz/openvz_conf.c, src/openvz/openvz_driver.c,
src/qemu/qemu_driver.c, src/test/test_driver.c,
src/uml/uml_driver.c, src/vbox/vbox_tmpl.c: Update all code
to deal with hash tables instead of arrays for domains
2009-10-09 12:33:51 +01:00
|
|
|
if (!(data->names[data->numnames] = strdup(obj->def->name)))
|
|
|
|
data->oom = 1;
|
|
|
|
else
|
|
|
|
data->numnames++;
|
|
|
|
}
|
|
|
|
virDomainObjUnlock(obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int virDomainObjListGetInactiveNames(virDomainObjListPtr doms,
|
|
|
|
char **const names,
|
|
|
|
int maxnames)
|
|
|
|
{
|
|
|
|
struct virDomainNameData data = { 0, 0, maxnames, names };
|
|
|
|
int i;
|
|
|
|
virHashForEach(doms->objs, virDomainObjListCopyInactiveNames, &data);
|
|
|
|
if (data.oom) {
|
2010-02-04 19:19:08 +01:00
|
|
|
virReportOOMError();
|
Convert virDomainObjListPtr to use a hash of domain objects
The current virDomainObjListPtr object stores domain objects in
an array. This means that to find a particular objects requires
O(n) time, and more critically acquiring O(n) mutex locks.
The new impl replaces the array with a virHashTable, keyed off
UUID. Finding a object based on UUID is now O(1) time, and only
requires a single mutex lock. Finding by name/id is unchanged
in complexity.
In changing this, all code which iterates over the array had
to be updated to use a hash table iterator function callback.
Several of the functions which were identically duplicating
across all drivers were pulled into domain_conf.c
* src/conf/domain_conf.h, src/conf/domain_conf.c: Change
virDomainObjListPtr to use virHashTable. Add a initializer
method virDomainObjListInit, and rename virDomainObjListFree
to virDomainObjListDeinit, since its not actually freeing
the container, only its contents. Also add some convenient
methods virDomainObjListGetInactiveNames,
virDomainObjListGetActiveIDs and virDomainObjListNumOfDomains
which can be used to implement the correspondingly named
public API entry points in drivers
* src/libvirt_private.syms: Export new methods from domain_conf.h
* src/lxc/lxc_driver.c, src/opennebula/one_driver.c,
src/openvz/openvz_conf.c, src/openvz/openvz_driver.c,
src/qemu/qemu_driver.c, src/test/test_driver.c,
src/uml/uml_driver.c, src/vbox/vbox_tmpl.c: Update all code
to deal with hash tables instead of arrays for domains
2009-10-09 12:33:51 +01:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
return data.numnames;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
for (i = 0 ; i < data.numnames ; i++)
|
|
|
|
VIR_FREE(data.names[i]);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2010-04-02 10:41:30 -04:00
|
|
|
/* Snapshot Def functions */
|
|
|
|
void virDomainSnapshotDefFree(virDomainSnapshotDefPtr def)
|
|
|
|
{
|
|
|
|
if (!def)
|
|
|
|
return;
|
|
|
|
|
|
|
|
VIR_FREE(def->name);
|
|
|
|
VIR_FREE(def->description);
|
|
|
|
VIR_FREE(def->parent);
|
|
|
|
VIR_FREE(def);
|
|
|
|
}
|
|
|
|
|
|
|
|
virDomainSnapshotDefPtr virDomainSnapshotDefParseString(const char *xmlStr,
|
|
|
|
int newSnapshot)
|
|
|
|
{
|
|
|
|
xmlXPathContextPtr ctxt = NULL;
|
|
|
|
xmlDocPtr xml = NULL;
|
|
|
|
xmlNodePtr root;
|
|
|
|
virDomainSnapshotDefPtr def = NULL;
|
|
|
|
virDomainSnapshotDefPtr ret = NULL;
|
|
|
|
char *creation = NULL, *state = NULL;
|
|
|
|
struct timeval tv;
|
|
|
|
|
|
|
|
xml = virXMLParse(NULL, xmlStr, "domainsnapshot.xml");
|
|
|
|
if (!xml) {
|
|
|
|
virDomainReportError(VIR_ERR_XML_ERROR,
|
|
|
|
"%s",_("failed to parse snapshot xml document"));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((root = xmlDocGetRootElement(xml)) == NULL) {
|
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("missing root element"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!xmlStrEqual(root->name, BAD_CAST "domainsnapshot")) {
|
2010-04-23 11:58:14 -04:00
|
|
|
virDomainReportError(VIR_ERR_XML_ERROR, "%s", _("domainsnapshot"));
|
2010-04-02 10:41:30 -04:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctxt = xmlXPathNewContext(xml);
|
|
|
|
if (ctxt == NULL) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VIR_ALLOC(def) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctxt->node = root;
|
|
|
|
|
|
|
|
gettimeofday(&tv, NULL);
|
|
|
|
|
|
|
|
def->name = virXPathString("string(./name)", ctxt);
|
|
|
|
if (def->name == NULL)
|
|
|
|
ignore_value(virAsprintf(&def->name, "%ld", tv.tv_sec));
|
|
|
|
|
|
|
|
if (def->name == NULL) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
def->description = virXPathString("string(./description)", ctxt);
|
|
|
|
|
|
|
|
if (!newSnapshot) {
|
|
|
|
if (virXPathLong("string(./creationTime)", ctxt,
|
|
|
|
&def->creationTime) < 0) {
|
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("missing creationTime from existing snapshot"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
def->parent = virXPathString("string(./parent/name)", ctxt);
|
|
|
|
|
|
|
|
state = virXPathString("string(./state)", ctxt);
|
|
|
|
if (state == NULL) {
|
|
|
|
/* there was no state in an existing snapshot; this
|
|
|
|
* should never happen
|
|
|
|
*/
|
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("missing state from existing snapshot"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
def->state = virDomainStateTypeFromString(state);
|
|
|
|
if (def->state < 0) {
|
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Invalid state '%s' in domain snapshot XML"),
|
|
|
|
state);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virXPathLong("string(./active)", ctxt, &def->active) < 0) {
|
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Could not find 'active' element"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
def->creationTime = tv.tv_sec;
|
|
|
|
|
|
|
|
ret = def;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(creation);
|
|
|
|
VIR_FREE(state);
|
|
|
|
xmlXPathFreeContext(ctxt);
|
|
|
|
if (ret == NULL)
|
|
|
|
virDomainSnapshotDefFree(def);
|
|
|
|
xmlFreeDoc(xml);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *virDomainSnapshotDefFormat(char *domain_uuid,
|
|
|
|
virDomainSnapshotDefPtr def,
|
|
|
|
int internal)
|
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
|
|
|
|
virBufferAddLit(&buf, "<domainsnapshot>\n");
|
|
|
|
virBufferVSprintf(&buf, " <name>%s</name>\n", def->name);
|
|
|
|
if (def->description)
|
|
|
|
virBufferVSprintf(&buf, " <description>%s</description>\n",
|
|
|
|
def->description);
|
|
|
|
virBufferVSprintf(&buf, " <state>%s</state>\n",
|
|
|
|
virDomainStateTypeToString(def->state));
|
|
|
|
if (def->parent) {
|
|
|
|
virBufferAddLit(&buf, " <parent>\n");
|
|
|
|
virBufferVSprintf(&buf, " <name>%s</name>\n", def->parent);
|
|
|
|
virBufferAddLit(&buf, " </parent>\n");
|
|
|
|
}
|
|
|
|
virBufferVSprintf(&buf, " <creationTime>%ld</creationTime>\n",
|
|
|
|
def->creationTime);
|
|
|
|
virBufferAddLit(&buf, " <domain>\n");
|
|
|
|
virBufferVSprintf(&buf, " <uuid>%s</uuid>\n", domain_uuid);
|
|
|
|
virBufferAddLit(&buf, " </domain>\n");
|
|
|
|
if (internal)
|
|
|
|
virBufferVSprintf(&buf, " <active>%ld</active>\n", def->active);
|
|
|
|
virBufferAddLit(&buf, "</domainsnapshot>\n");
|
|
|
|
|
|
|
|
if (virBufferError(&buf)) {
|
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
virReportOOMError();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Snapshot Obj functions */
|
|
|
|
static virDomainSnapshotObjPtr virDomainSnapshotObjNew(void)
|
|
|
|
{
|
|
|
|
virDomainSnapshotObjPtr snapshot;
|
|
|
|
|
|
|
|
if (VIR_ALLOC(snapshot) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
snapshot->refs = 1;
|
|
|
|
|
|
|
|
VIR_DEBUG("obj=%p", snapshot);
|
|
|
|
|
|
|
|
return snapshot;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void virDomainSnapshotObjFree(virDomainSnapshotObjPtr snapshot)
|
|
|
|
{
|
|
|
|
if (!snapshot)
|
|
|
|
return;
|
|
|
|
|
|
|
|
VIR_DEBUG("obj=%p", snapshot);
|
|
|
|
|
|
|
|
virDomainSnapshotDefFree(snapshot->def);
|
2010-04-23 11:58:41 -04:00
|
|
|
VIR_FREE(snapshot);
|
2010-04-02 10:41:30 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
int virDomainSnapshotObjUnref(virDomainSnapshotObjPtr snapshot)
|
|
|
|
{
|
|
|
|
snapshot->refs--;
|
|
|
|
VIR_DEBUG("obj=%p refs=%d", snapshot, snapshot->refs);
|
|
|
|
if (snapshot->refs == 0) {
|
|
|
|
virDomainSnapshotObjFree(snapshot);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return snapshot->refs;
|
|
|
|
}
|
|
|
|
|
|
|
|
virDomainSnapshotObjPtr virDomainSnapshotAssignDef(virDomainSnapshotObjListPtr snapshots,
|
|
|
|
const virDomainSnapshotDefPtr def)
|
|
|
|
{
|
|
|
|
virDomainSnapshotObjPtr snap;
|
|
|
|
|
|
|
|
if (virHashLookup(snapshots->objs, def->name) != NULL) {
|
|
|
|
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unexpected domain snapshot %s already exists"),
|
|
|
|
def->name);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(snap = virDomainSnapshotObjNew()))
|
|
|
|
return NULL;
|
|
|
|
snap->def = def;
|
|
|
|
|
|
|
|
if (virHashAddEntry(snapshots->objs, snap->def->name, snap) < 0) {
|
|
|
|
VIR_FREE(snap);
|
|
|
|
virReportOOMError();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return snap;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Snapshot Obj List functions */
|
|
|
|
int virDomainSnapshotObjListInit(virDomainSnapshotObjListPtr snapshots)
|
|
|
|
{
|
|
|
|
snapshots->objs = virHashCreate(50);
|
|
|
|
if (!snapshots->objs) {
|
|
|
|
virReportOOMError();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void virDomainSnapshotObjListDeallocator(void *payload,
|
|
|
|
const char *name ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
virDomainSnapshotObjPtr obj = payload;
|
|
|
|
|
|
|
|
virDomainSnapshotObjUnref(obj);
|
|
|
|
}
|
|
|
|
|
2010-04-23 11:57:50 -04:00
|
|
|
static void virDomainSnapshotObjListDeinit(virDomainSnapshotObjListPtr snapshots)
|
2010-04-02 10:41:30 -04:00
|
|
|
{
|
|
|
|
if (snapshots->objs)
|
|
|
|
virHashFree(snapshots->objs, virDomainSnapshotObjListDeallocator);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct virDomainSnapshotNameData {
|
|
|
|
int oom;
|
|
|
|
int numnames;
|
|
|
|
int maxnames;
|
|
|
|
char **const names;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void virDomainSnapshotObjListCopyNames(void *payload,
|
|
|
|
const char *name ATTRIBUTE_UNUSED,
|
|
|
|
void *opaque)
|
|
|
|
{
|
|
|
|
virDomainSnapshotObjPtr obj = payload;
|
|
|
|
struct virDomainSnapshotNameData *data = opaque;
|
|
|
|
|
|
|
|
if (data->oom)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (data->numnames < data->maxnames) {
|
|
|
|
if (!(data->names[data->numnames] = strdup(obj->def->name)))
|
|
|
|
data->oom = 1;
|
|
|
|
else
|
|
|
|
data->numnames++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int virDomainSnapshotObjListGetNames(virDomainSnapshotObjListPtr snapshots,
|
|
|
|
char **const names, int maxnames)
|
|
|
|
{
|
|
|
|
struct virDomainSnapshotNameData data = { 0, 0, maxnames, names };
|
|
|
|
int i;
|
|
|
|
|
|
|
|
virHashForEach(snapshots->objs, virDomainSnapshotObjListCopyNames, &data);
|
|
|
|
if (data.oom) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
return data.numnames;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
for (i = 0; i < data.numnames; i++)
|
|
|
|
VIR_FREE(data.names[i]);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void virDomainSnapshotObjListCount(void *payload ATTRIBUTE_UNUSED,
|
|
|
|
const char *name ATTRIBUTE_UNUSED,
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
int *count = data;
|
|
|
|
|
|
|
|
(*count)++;
|
|
|
|
}
|
|
|
|
|
|
|
|
int virDomainSnapshotObjListNum(virDomainSnapshotObjListPtr snapshots)
|
|
|
|
{
|
|
|
|
int count = 0;
|
|
|
|
|
|
|
|
virHashForEach(snapshots->objs, virDomainSnapshotObjListCount, &count);
|
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int virDomainSnapshotObjListSearchName(const void *payload,
|
|
|
|
const char *name ATTRIBUTE_UNUSED,
|
|
|
|
const void *data)
|
|
|
|
{
|
|
|
|
virDomainSnapshotObjPtr obj = (virDomainSnapshotObjPtr)payload;
|
|
|
|
int want = 0;
|
|
|
|
|
|
|
|
if (STREQ(obj->def->name, (const char *)data))
|
|
|
|
want = 1;
|
|
|
|
|
|
|
|
return want;
|
|
|
|
}
|
|
|
|
|
|
|
|
virDomainSnapshotObjPtr virDomainSnapshotFindByName(const virDomainSnapshotObjListPtr snapshots,
|
|
|
|
const char *name)
|
|
|
|
{
|
|
|
|
return virHashSearch(snapshots->objs, virDomainSnapshotObjListSearchName, name);
|
|
|
|
}
|
|
|
|
|
|
|
|
void virDomainSnapshotObjListRemove(virDomainSnapshotObjListPtr snapshots,
|
|
|
|
virDomainSnapshotObjPtr snapshot)
|
|
|
|
{
|
|
|
|
virHashRemoveEntry(snapshots->objs, snapshot->def->name,
|
|
|
|
virDomainSnapshotObjListDeallocator);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct snapshot_has_children {
|
|
|
|
char *name;
|
|
|
|
int number;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void virDomainSnapshotCountChildren(void *payload,
|
|
|
|
const char *name ATTRIBUTE_UNUSED,
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
virDomainSnapshotObjPtr obj = payload;
|
|
|
|
struct snapshot_has_children *curr = data;
|
|
|
|
|
|
|
|
if (obj->def->parent && STREQ(obj->def->parent, curr->name))
|
|
|
|
curr->number++;
|
|
|
|
}
|
|
|
|
|
|
|
|
int virDomainSnapshotHasChildren(virDomainSnapshotObjPtr snap,
|
|
|
|
virDomainSnapshotObjListPtr snapshots)
|
|
|
|
{
|
|
|
|
struct snapshot_has_children children;
|
|
|
|
|
|
|
|
children.name = snap->def->name;
|
|
|
|
children.number = 0;
|
|
|
|
virHashForEach(snapshots->objs, virDomainSnapshotCountChildren, &children);
|
|
|
|
|
|
|
|
return children.number;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-07-25 10:49:33 +00:00
|
|
|
#endif /* ! PROXY */
|