2008-07-11 16:23:36 +00:00
|
|
|
/*
|
|
|
|
* domain_conf.c: domain XML processing
|
|
|
|
*
|
2009-01-30 17:15:39 +00:00
|
|
|
* Copyright (C) 2006-2009 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>
|
|
|
|
|
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 14:31:03 +00:00
|
|
|
#include "network.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 14:17:06 +00: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 13:54:44 +00:00
|
|
|
"video",
|
2009-10-21 12:26:38 +00:00
|
|
|
"hostdev",
|
|
|
|
"watchdog")
|
2009-03-02 17:39:43 +00:00
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
VIR_ENUM_IMPL(virDomainDisk, VIR_DOMAIN_DISK_TYPE_LAST,
|
|
|
|
"block",
|
|
|
|
"file")
|
|
|
|
|
|
|
|
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",
|
|
|
|
"uml")
|
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
|
|
|
|
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",
|
|
|
|
"internal")
|
2008-07-11 16:23:36 +00:00
|
|
|
|
2009-11-05 13:19:14 +00:00
|
|
|
VIR_ENUM_IMPL(virDomainChrTarget, VIR_DOMAIN_CHR_TARGET_TYPE_LAST,
|
|
|
|
"null",
|
|
|
|
"monitor",
|
|
|
|
"parallel",
|
|
|
|
"serial",
|
2009-11-05 14:31:03 +00:00
|
|
|
"console",
|
|
|
|
"guestfwd")
|
2009-11-05 13:19:14 +00: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 12:26:38 +00: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 13:54:44 +00: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")
|
|
|
|
|
2009-01-07 12:56:13 +00:00
|
|
|
#define virDomainReportError(conn, code, fmt...) \
|
2008-11-04 22:30:33 +00:00
|
|
|
virReportErrorHelper(conn, VIR_FROM_DOMAIN, code, __FILE__, \
|
2008-10-09 15:38:31 +00:00
|
|
|
__FUNCTION__, __LINE__, fmt)
|
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 11:33:51 +00: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 11:33:51 +00:00
|
|
|
doms->objs = virHashCreate(50);
|
|
|
|
if (!doms->objs) {
|
|
|
|
virReportOOMError(NULL);
|
|
|
|
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 11:33:51 +00: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 11:33:51 +00:00
|
|
|
|
|
|
|
static void virDomainObjListDeallocator(void *payload, const char *name ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
virDomainObjPtr obj = payload;
|
2009-10-15 11:30:26 +00:00
|
|
|
virDomainObjLock(obj);
|
|
|
|
if (!virDomainObjUnref(obj))
|
|
|
|
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 11:33:51 +00: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 14:51:03 +00: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 11:33:51 +00: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 11:33:51 +00: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 11:33:51 +00: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 11:33:51 +00: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 11:33:51 +00: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;
|
|
|
|
|
|
|
|
VIR_FREE(def);
|
|
|
|
}
|
|
|
|
|
|
|
|
void virDomainDiskDefFree(virDomainDiskDefPtr def)
|
|
|
|
{
|
|
|
|
if (!def)
|
|
|
|
return;
|
|
|
|
|
2009-08-14 11:22:01 +00: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 05:23:03 +00:00
|
|
|
virStorageEncryptionFree(def->encryption);
|
2008-07-11 16:23:36 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
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;
|
2008-07-11 16:23:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
VIR_FREE(def->ifname);
|
2009-07-17 21:08:33 +00:00
|
|
|
VIR_FREE(def->nic_name);
|
|
|
|
VIR_FREE(def->hostnet_name);
|
2008-07-11 16:23:36 +00:00
|
|
|
VIR_FREE(def);
|
|
|
|
}
|
|
|
|
|
|
|
|
void virDomainChrDefFree(virDomainChrDefPtr def)
|
|
|
|
{
|
|
|
|
if (!def)
|
|
|
|
return;
|
|
|
|
|
2009-11-05 14:31:03 +00:00
|
|
|
switch (def->targetType) {
|
|
|
|
case VIR_DOMAIN_CHR_TARGET_TYPE_GUESTFWD:
|
|
|
|
VIR_FREE(def->target.addr);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
VIR_FREE(def);
|
|
|
|
}
|
|
|
|
|
|
|
|
void virDomainSoundDefFree(virDomainSoundDefPtr def)
|
|
|
|
{
|
|
|
|
if (!def)
|
|
|
|
return;
|
|
|
|
|
|
|
|
VIR_FREE(def);
|
|
|
|
}
|
|
|
|
|
2009-10-21 12:26:38 +00:00
|
|
|
void virDomainWatchdogDefFree(virDomainWatchdogDefPtr def)
|
|
|
|
{
|
|
|
|
if (!def)
|
|
|
|
return;
|
|
|
|
|
|
|
|
VIR_FREE(def);
|
|
|
|
}
|
|
|
|
|
2009-07-06 13:54:44 +00:00
|
|
|
void virDomainVideoDefFree(virDomainVideoDefPtr def)
|
|
|
|
{
|
|
|
|
if (!def)
|
|
|
|
return;
|
|
|
|
|
2009-09-03 08:26:41 +00:00
|
|
|
VIR_FREE(def->accel);
|
2009-07-06 13:54:44 +00:00
|
|
|
VIR_FREE(def);
|
|
|
|
}
|
|
|
|
|
2008-08-08 14:27:05 +00:00
|
|
|
void virDomainHostdevDefFree(virDomainHostdevDefPtr def)
|
|
|
|
{
|
|
|
|
if (!def)
|
|
|
|
return;
|
|
|
|
|
|
|
|
VIR_FREE(def->target);
|
|
|
|
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 13:54:44 +00: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 12:26:38 +00:00
|
|
|
case VIR_DOMAIN_DEVICE_WATCHDOG:
|
|
|
|
virDomainWatchdogDefFree(def->data.watchdog);
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
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 14:31:03 +00: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 14:31:03 +00: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 13:54:44 +00: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);
|
|
|
|
|
|
|
|
VIR_FREE(def->name);
|
|
|
|
VIR_FREE(def->cpumask);
|
|
|
|
VIR_FREE(def->emulator);
|
2009-09-30 14:07:24 +00:00
|
|
|
VIR_FREE(def->description);
|
2008-07-11 16:23:36 +00:00
|
|
|
|
2009-10-21 12:26:38 +00:00
|
|
|
virDomainWatchdogDefFree(def->watchdog);
|
|
|
|
|
2009-03-03 09:44:41 +00:00
|
|
|
virSecurityLabelDefFree(def);
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
VIR_FREE(def);
|
|
|
|
}
|
|
|
|
|
2008-12-05 10:10:41 +00:00
|
|
|
#ifndef PROXY
|
|
|
|
|
2009-10-15 11:30:26 +00:00
|
|
|
static void virDomainObjFree(virDomainObjPtr dom)
|
2008-07-11 16:23:36 +00:00
|
|
|
{
|
|
|
|
if (!dom)
|
|
|
|
return;
|
|
|
|
|
2009-10-15 11:30:26 +00:00
|
|
|
VIR_DEBUG("obj=%p", dom);
|
2008-07-11 16:23:36 +00:00
|
|
|
virDomainDefFree(dom->def);
|
|
|
|
virDomainDefFree(dom->newDef);
|
|
|
|
|
2009-07-09 17:06:38 +00:00
|
|
|
virDomainChrDefFree(dom->monitor_chr);
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
VIR_FREE(dom->vcpupids);
|
|
|
|
|
2009-10-06 11:50:58 +00:00
|
|
|
if (dom->privateDataFreeFunc)
|
|
|
|
(dom->privateDataFreeFunc)(dom->privateData);
|
|
|
|
|
2009-01-15 19:56:05 +00:00
|
|
|
virMutexDestroy(&dom->lock);
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
VIR_FREE(dom);
|
|
|
|
}
|
|
|
|
|
2009-10-15 11:30:26 +00: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);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-10-06 11:50:58 +00:00
|
|
|
static virDomainObjPtr virDomainObjNew(virConnectPtr conn,
|
|
|
|
virCapsPtr caps)
|
2009-06-12 11:38:50 +00:00
|
|
|
{
|
|
|
|
virDomainObjPtr domain;
|
|
|
|
|
|
|
|
if (VIR_ALLOC(domain) < 0) {
|
|
|
|
virReportOOMError(conn);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2009-10-06 11:50:58 +00:00
|
|
|
if (caps->privateDataAllocFunc &&
|
|
|
|
!(domain->privateData = (caps->privateDataAllocFunc)())) {
|
|
|
|
virReportOOMError(conn);
|
|
|
|
VIR_FREE(domain);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
domain->privateDataFreeFunc = caps->privateDataFreeFunc;
|
|
|
|
|
2009-06-12 11:38:50 +00:00
|
|
|
if (virMutexInit(&domain->lock) < 0) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("cannot initialize mutex"));
|
2009-10-06 11:50:58 +00: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;
|
|
|
|
domain->monitorWatch = -1;
|
|
|
|
domain->monitor = -1;
|
2009-10-15 11:30:26 +00:00
|
|
|
domain->refs = 1;
|
2009-06-12 11:38:50 +00:00
|
|
|
|
2009-10-15 11:30:26 +00:00
|
|
|
VIR_DEBUG("obj=%p", domain);
|
2009-06-12 11:38:50 +00:00
|
|
|
return domain;
|
|
|
|
}
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
virDomainObjPtr virDomainAssignDef(virConnectPtr conn,
|
2009-10-06 11:50:58 +00:00
|
|
|
virCapsPtr caps,
|
2008-10-10 14:20:37 +00:00
|
|
|
virDomainObjListPtr doms,
|
2008-07-11 16:23:36 +00:00
|
|
|
const virDomainDefPtr def)
|
|
|
|
{
|
|
|
|
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 11:33:51 +00: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 14:51:03 +00:00
|
|
|
if (!virDomainObjIsActive(domain)) {
|
2008-07-11 16:23:36 +00:00
|
|
|
virDomainDefFree(domain->def);
|
|
|
|
domain->def = def;
|
|
|
|
} else {
|
|
|
|
if (domain->newDef)
|
|
|
|
virDomainDefFree(domain->newDef);
|
|
|
|
domain->newDef = def;
|
|
|
|
}
|
|
|
|
|
|
|
|
return domain;
|
|
|
|
}
|
|
|
|
|
2009-10-06 11:50:58 +00:00
|
|
|
if (!(domain = virDomainObjNew(conn, 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 11:33:51 +00:00
|
|
|
virUUIDFormat(def->uuid, uuidstr);
|
|
|
|
if (virHashAddEntry(doms->objs, uuidstr, domain) < 0) {
|
|
|
|
VIR_FREE(domain);
|
|
|
|
virReportOOMError(conn);
|
|
|
|
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 11:33:51 +00: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 11:33:51 +00: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 11:33:51 +00: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
|
|
|
|
|
|
|
/* Parse the XML definition for a disk
|
|
|
|
* @param node XML nodeset to parse for disk definition
|
|
|
|
*/
|
|
|
|
static virDomainDiskDefPtr
|
|
|
|
virDomainDiskDefParseXML(virConnectPtr conn,
|
2009-01-08 13:54:20 +00:00
|
|
|
xmlNodePtr node,
|
2009-07-17 21:08:33 +00: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;
|
2009-07-17 21:08:33 +00:00
|
|
|
char *devaddr = NULL;
|
2009-07-21 05:23:03 +00:00
|
|
|
virStorageEncryptionPtr encryption = NULL;
|
2009-08-14 11:22:01 +00:00
|
|
|
char *serial = NULL;
|
2008-07-11 16:23:36 +00:00
|
|
|
|
|
|
|
if (VIR_ALLOC(def) < 0) {
|
2009-01-29 12:10:32 +00:00
|
|
|
virReportOOMError(conn);
|
2008-07-11 16:23:36 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
type = virXMLPropString(node, "type");
|
|
|
|
if (type) {
|
|
|
|
if ((def->type = virDomainDiskTypeFromString(type)) < 0) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("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"))) {
|
|
|
|
|
|
|
|
if (def->type == VIR_DOMAIN_DISK_TYPE_FILE)
|
|
|
|
source = virXMLPropString(cur, "file");
|
|
|
|
else
|
|
|
|
source = virXMLPropString(cur, "dev");
|
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");
|
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 21:08:33 +00:00
|
|
|
} else if ((flags & VIR_DOMAIN_XML_INTERNAL_STATUS) &&
|
|
|
|
xmlStrEqual(cur->name, BAD_CAST "state")) {
|
|
|
|
devaddr = virXMLPropString(cur, "devaddr");
|
2009-07-21 05:23:03 +00:00
|
|
|
} else if (encryption == NULL &&
|
|
|
|
xmlStrEqual(cur->name, BAD_CAST "encryption")) {
|
|
|
|
encryption = virStorageEncryptionParseNode(conn, node->doc,
|
|
|
|
cur);
|
|
|
|
if (encryption == NULL)
|
|
|
|
goto error;
|
2009-08-14 11:22:01 +00: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) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("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) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_NO_SOURCE,
|
|
|
|
target ? "%s" : NULL, target);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (target == NULL) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_NO_TARGET,
|
|
|
|
source ? "%s" : NULL, source);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (def->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY &&
|
|
|
|
!STRPREFIX(target, "fd")) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("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")) {
|
2008-07-11 16:23:36 +00:00
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Invalid harddisk device name: %s"), target);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bus) {
|
|
|
|
if ((def->bus = virDomainDiskBusTypeFromString(bus)) < 0) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("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) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("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) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Invalid bus type '%s' for disk"), bus);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2009-01-30 17:15:39 +00:00
|
|
|
if (cachetag &&
|
|
|
|
(def->cachemode = virDomainDiskCacheTypeFromString(cachetag)) < 0) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unknown disk cache mode '%s'"), cachetag);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2009-07-17 21:08:33 +00:00
|
|
|
if (devaddr &&
|
|
|
|
sscanf(devaddr, "%x:%x:%x",
|
|
|
|
&def->pci_addr.domain,
|
|
|
|
&def->pci_addr.bus,
|
|
|
|
&def->pci_addr.slot) < 3) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Unable to parse devaddr parameter '%s'"),
|
|
|
|
devaddr);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
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 05:23:03 +00:00
|
|
|
def->encryption = encryption;
|
|
|
|
encryption = NULL;
|
2009-08-14 11:22:01 +00:00
|
|
|
def->serial = serial;
|
|
|
|
serial = NULL;
|
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);
|
2009-07-17 21:08:33 +00:00
|
|
|
VIR_FREE(devaddr);
|
2009-08-14 11:22:01 +00:00
|
|
|
VIR_FREE(serial);
|
2009-07-21 05:23:03 +00:00
|
|
|
virStorageEncryptionFree(encryption);
|
2008-07-11 16:23:36 +00:00
|
|
|
|
|
|
|
return def;
|
|
|
|
|
|
|
|
error:
|
|
|
|
virDomainDiskDefFree(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
|
|
|
|
virDomainFSDefParseXML(virConnectPtr conn,
|
2009-01-08 13:54:20 +00:00
|
|
|
xmlNodePtr node,
|
|
|
|
int flags ATTRIBUTE_UNUSED) {
|
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) {
|
2009-01-29 12:10:32 +00:00
|
|
|
virReportOOMError(conn);
|
2008-08-01 13:31:37 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
type = virXMLPropString(node, "type");
|
|
|
|
if (type) {
|
|
|
|
if ((def->type = virDomainFSTypeFromString(type)) < 0) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("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) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_NO_SOURCE,
|
|
|
|
target ? "%s" : NULL, target);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (target == NULL) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_NO_TARGET,
|
|
|
|
source ? "%s" : NULL, source);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
def->src = source;
|
|
|
|
source = NULL;
|
|
|
|
def->dst = target;
|
|
|
|
target = NULL;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(type);
|
|
|
|
VIR_FREE(target);
|
|
|
|
VIR_FREE(source);
|
|
|
|
|
|
|
|
return def;
|
|
|
|
|
|
|
|
error:
|
|
|
|
virDomainFSDefFree(def);
|
|
|
|
def = NULL;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
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
|
2008-07-11 16:23:36 +00:00
|
|
|
virDomainNetDefParseXML(virConnectPtr conn,
|
2008-10-24 11:20:08 +00:00
|
|
|
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;
|
2009-05-11 09:50:27 +00:00
|
|
|
char *internal = NULL;
|
2009-07-17 21:08:34 +00:00
|
|
|
char *nic_name = NULL;
|
|
|
|
char *hostnet_name = NULL;
|
2009-07-17 21:08:34 +00:00
|
|
|
char *devaddr = NULL;
|
2009-07-17 21:08:34 +00:00
|
|
|
char *vlan = NULL;
|
2008-07-11 16:23:36 +00:00
|
|
|
|
|
|
|
if (VIR_ALLOC(def) < 0) {
|
2009-01-29 12:10:32 +00:00
|
|
|
virReportOOMError(conn);
|
2008-07-11 16:23:36 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
type = virXMLPropString(node, "type");
|
|
|
|
if (type != NULL) {
|
|
|
|
if ((def->type = virDomainNetTypeFromString(type)) < 0) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("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) &&
|
|
|
|
(def->type == VIR_DOMAIN_NET_TYPE_ETHERNET) &&
|
|
|
|
xmlStrEqual(cur->name, BAD_CAST "source")) {
|
|
|
|
dev = virXMLPropString(cur, "dev");
|
|
|
|
} 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 09:54:38 +00:00
|
|
|
if ((ifname != NULL) &&
|
|
|
|
(STRPREFIX((const char*)ifname, "vnet"))) {
|
2008-07-11 16:23:36 +00:00
|
|
|
/* An auto-generated target name, blank it out */
|
|
|
|
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");
|
2009-07-17 21:08:34 +00:00
|
|
|
} else if ((flags & VIR_DOMAIN_XML_INTERNAL_STATUS) &&
|
|
|
|
xmlStrEqual(cur->name, BAD_CAST "state")) {
|
|
|
|
nic_name = virXMLPropString(cur, "nic");
|
|
|
|
hostnet_name = virXMLPropString(cur, "hostnet");
|
2009-07-17 21:08:34 +00:00
|
|
|
devaddr = virXMLPropString(cur, "devaddr");
|
2009-07-17 21:08:34 +00:00
|
|
|
vlan = virXMLPropString(cur, "vlan");
|
2008-07-11 16:23:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
cur = cur->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (macaddr) {
|
2009-10-16 10:09:13 +00:00
|
|
|
if (virParseMacAddr((const char *)macaddr, def->mac) < 0) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("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-07-17 21:08:34 +00:00
|
|
|
if (devaddr &&
|
|
|
|
sscanf(devaddr, "%x:%x:%x",
|
|
|
|
&def->pci_addr.domain,
|
|
|
|
&def->pci_addr.bus,
|
|
|
|
&def->pci_addr.slot) < 3) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Unable to parse devaddr parameter '%s'"),
|
|
|
|
devaddr);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2009-07-17 21:08:34 +00:00
|
|
|
def->nic_name = nic_name;
|
|
|
|
def->hostnet_name = hostnet_name;
|
|
|
|
nic_name = hostnet_name = NULL;
|
|
|
|
|
2009-07-17 21:08:34 +00:00
|
|
|
def->vlan = -1;
|
|
|
|
if (vlan && virStrToLong_i(vlan, NULL, 10, &def->vlan) < 0) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Cannot parse <state> 'vlan' attribute"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
switch (def->type) {
|
|
|
|
case VIR_DOMAIN_NET_TYPE_NETWORK:
|
|
|
|
if (network == NULL) {
|
2009-01-07 12:56:13 +00:00
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("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) {
|
2009-01-07 12:56:13 +00:00
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
|
2009-09-30 16:51:30 +00: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) {
|
2009-01-07 12:56:13 +00:00
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("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) {
|
2009-01-07 12:56:13 +00:00
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("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) {
|
2009-01-07 12:56:13 +00:00
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("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) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("No <source> 'name' attribute specified with <interface type='internal'/>"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
def->data.internal.name = internal;
|
|
|
|
internal = NULL;
|
|
|
|
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) {
|
|
|
|
virDomainReportError (conn, VIR_ERR_INVALID_ARG, "%s",
|
2009-01-07 12:56:13 +00:00
|
|
|
_("Model name contains invalid characters"));
|
2008-07-11 16:23:36 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
def->model = model;
|
|
|
|
model = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
VIR_FREE(type);
|
2009-05-11 09:50:27 +00:00
|
|
|
VIR_FREE(internal);
|
2009-07-17 21:08:34 +00:00
|
|
|
VIR_FREE(nic_name);
|
|
|
|
VIR_FREE(hostnet_name);
|
2009-07-17 21:08:34 +00:00
|
|
|
VIR_FREE(devaddr);
|
2009-07-17 21:08:34 +00:00
|
|
|
VIR_FREE(vlan);
|
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 21:59:23 +00: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
|
|
|
|
virDomainChrDefParseXML(virConnectPtr conn,
|
2009-01-08 13:54:20 +00:00
|
|
|
xmlNodePtr node,
|
|
|
|
int flags ATTRIBUTE_UNUSED) {
|
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 14:31:03 +00:00
|
|
|
const char *nodeName;
|
2009-11-05 13:19:14 +00:00
|
|
|
const char *targetType = NULL;
|
2009-11-05 14:31:03 +00:00
|
|
|
const char *addrStr = NULL;
|
|
|
|
const char *portStr = NULL;
|
2008-07-11 16:23:36 +00:00
|
|
|
virDomainChrDefPtr def;
|
|
|
|
|
|
|
|
if (VIR_ALLOC(def) < 0) {
|
2009-01-29 12:10:32 +00:00
|
|
|
virReportOOMError(conn);
|
2008-07-11 16:23:36 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
type = virXMLPropString(node, "type");
|
2009-07-10 08:33:34 +00: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 14:31:03 +00:00
|
|
|
nodeName = (const char *) node->name;
|
|
|
|
if ((def->targetType = virDomainChrTargetTypeFromString(nodeName)) < 0) {
|
|
|
|
/* channel is handled below */
|
2009-11-05 15:04:34 +00:00
|
|
|
if (STRNEQ(nodeName, "channel")) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_XML_ERROR,
|
2009-11-05 14:31:03 +00:00
|
|
|
_("unknown target type for character device: %s"),
|
|
|
|
nodeName);
|
|
|
|
return NULL;
|
|
|
|
}
|
2009-11-05 13:19:14 +00: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 21:59:23 +00: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 21:59:23 +00:00
|
|
|
} else {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("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 14:31:03 +00: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 15:04:34 +00:00
|
|
|
if (def->targetType == VIR_DOMAIN_CHR_TARGET_TYPE_NULL) {
|
2009-11-05 14:31:03 +00:00
|
|
|
targetType = virXMLPropString(cur, "type");
|
2009-11-05 15:04:34 +00:00
|
|
|
if (targetType == NULL) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_XML_ERROR, "%s",
|
2009-11-05 14:31:03 +00:00
|
|
|
_("character device target does "
|
|
|
|
"not define a type"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if ((def->targetType =
|
|
|
|
virDomainChrTargetTypeFromString(targetType)) < 0)
|
|
|
|
{
|
2009-11-05 15:04:34 +00:00
|
|
|
virDomainReportError(conn, VIR_ERR_XML_ERROR,
|
2009-11-05 14:31:03 +00: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 15:04:34 +00:00
|
|
|
if (portStr == NULL) {
|
2009-11-05 14:31:03 +00:00
|
|
|
/* Not required. It will be assigned automatically
|
|
|
|
* later */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2009-11-05 15:04:34 +00:00
|
|
|
if (virStrToLong_ui(portStr, NULL, 10, &port) < 0) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_XML_ERROR,
|
2009-11-05 14:31:03 +00: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 15:04:34 +00:00
|
|
|
if (addrStr == NULL) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_XML_ERROR, "%s",
|
2009-11-05 14:31:03 +00:00
|
|
|
_("guestfwd channel does not "
|
|
|
|
"define a target address"));
|
|
|
|
goto error;
|
|
|
|
}
|
2009-11-05 15:04:34 +00:00
|
|
|
if (VIR_ALLOC(def->target.addr) < 0) {
|
2009-11-05 14:31:03 +00:00
|
|
|
virReportOOMError(conn);
|
|
|
|
goto error;
|
|
|
|
}
|
2009-11-05 15:04:34 +00:00
|
|
|
if (virSocketParseAddr(addrStr, def->target.addr, 0) < 0)
|
2009-11-05 14:31:03 +00:00
|
|
|
{
|
2009-11-05 15:04:34 +00:00
|
|
|
virDomainReportError(conn, VIR_ERR_XML_ERROR,
|
2009-11-05 14:31:03 +00:00
|
|
|
_("%s is not a valid address"),
|
|
|
|
addrStr);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2009-11-05 15:04:34 +00:00
|
|
|
if (def->target.addr->stor.ss_family != AF_INET) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
"%s", _("guestfwd channel only supports "
|
|
|
|
"IPv4 addresses"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (portStr == NULL) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_XML_ERROR, "%s",
|
2009-11-05 14:31:03 +00:00
|
|
|
_("guestfwd channel does "
|
|
|
|
"not define a target port"));
|
|
|
|
goto error;
|
|
|
|
}
|
2009-11-05 15:04:34 +00:00
|
|
|
if (virStrToLong_ui(portStr, NULL, 10, &port) < 0) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_XML_ERROR,
|
2009-11-05 14:31:03 +00:00
|
|
|
_("Invalid port number: %s"),
|
|
|
|
portStr);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
virSocketSetPort(def->target.addr, port);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2009-11-05 15:04:34 +00:00
|
|
|
virDomainReportError(conn, VIR_ERR_XML_ERROR,
|
2009-11-05 14:31:03 +00: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) {
|
2009-01-07 12:56:13 +00:00
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("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) {
|
2009-01-07 12:56:13 +00:00
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Missing source host attribute for char device"));
|
2008-07-11 16:23:36 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (connectService == NULL) {
|
2009-01-07 12:56:13 +00:00
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("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) {
|
2009-01-07 12:56:13 +00:00
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Missing source host attribute for char device"));
|
2008-07-11 16:23:36 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (bindService == NULL) {
|
2009-01-07 12:56:13 +00:00
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("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 21:59:23 +00: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 21:59:23 +00:00
|
|
|
else if (STREQ(protocol, "telnet"))
|
|
|
|
def->data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET;
|
|
|
|
else {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Unknown protocol '%s'"), protocol);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_UDP:
|
|
|
|
if (connectService == NULL) {
|
2009-01-07 12:56:13 +00:00
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("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) {
|
2009-01-07 12:56:13 +00:00
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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 14:31:03 +00: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
|
|
|
|
virDomainInputDefParseXML(virConnectPtr conn,
|
|
|
|
const char *ostype,
|
2009-01-08 13:54:20 +00:00
|
|
|
xmlNodePtr node,
|
|
|
|
int flags ATTRIBUTE_UNUSED) {
|
2008-07-11 16:23:36 +00:00
|
|
|
virDomainInputDefPtr def;
|
|
|
|
char *type = NULL;
|
|
|
|
char *bus = NULL;
|
|
|
|
|
|
|
|
if (VIR_ALLOC(def) < 0) {
|
2009-01-29 12:10:32 +00:00
|
|
|
virReportOOMError(conn);
|
2008-07-11 16:23:36 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
type = virXMLPropString(node, "type");
|
|
|
|
bus = virXMLPropString(node, "bus");
|
|
|
|
|
|
|
|
if (!type) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("missing input device type"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((def->type = virDomainInputTypeFromString(type)) < 0) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unknown input device type '%s'"), type);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bus) {
|
|
|
|
if ((def->bus = virDomainInputBusTypeFromString(bus)) < 0) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("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) {
|
|
|
|
virDomainReportError(conn, 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) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unsupported input bus %s"),
|
|
|
|
bus);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (def->bus != VIR_DOMAIN_INPUT_BUS_XEN) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unsupported input bus %s"),
|
|
|
|
bus);
|
|
|
|
}
|
|
|
|
if (def->type != VIR_DOMAIN_INPUT_TYPE_MOUSE) {
|
|
|
|
virDomainReportError(conn, 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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(type);
|
|
|
|
VIR_FREE(bus);
|
|
|
|
|
|
|
|
return def;
|
|
|
|
|
|
|
|
error:
|
|
|
|
virDomainInputDefFree(def);
|
|
|
|
def = NULL;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Parse the XML definition for a graphics device */
|
|
|
|
static virDomainGraphicsDefPtr
|
|
|
|
virDomainGraphicsDefParseXML(virConnectPtr conn,
|
2008-12-04 12:02:59 +00:00
|
|
|
xmlNodePtr node, int flags) {
|
2008-07-11 16:23:36 +00:00
|
|
|
virDomainGraphicsDefPtr def;
|
|
|
|
char *type = NULL;
|
|
|
|
|
|
|
|
if (VIR_ALLOC(def) < 0) {
|
2009-01-29 12:10:32 +00:00
|
|
|
virReportOOMError(conn);
|
2008-07-11 16:23:36 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
type = virXMLPropString(node, "type");
|
|
|
|
|
|
|
|
if (!type) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("missing graphics device type"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((def->type = virDomainGraphicsTypeFromString(type)) < 0) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("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) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("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 {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("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) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("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 {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("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
|
|
|
|
virDomainSoundDefParseXML(virConnectPtr conn,
|
2009-01-08 13:54:20 +00:00
|
|
|
const xmlNodePtr node,
|
|
|
|
int flags ATTRIBUTE_UNUSED) {
|
2008-07-11 16:23:36 +00:00
|
|
|
|
|
|
|
char *model;
|
|
|
|
virDomainSoundDefPtr def;
|
|
|
|
|
|
|
|
if (VIR_ALLOC(def) < 0) {
|
2009-01-29 12:10:32 +00:00
|
|
|
virReportOOMError(conn);
|
2008-07-11 16:23:36 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
model = virXMLPropString(node, "model");
|
|
|
|
if ((def->model = virDomainSoundModelTypeFromString(model)) < 0) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unknown sound model '%s'"), model);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(model);
|
|
|
|
|
|
|
|
return def;
|
|
|
|
|
|
|
|
error:
|
|
|
|
virDomainSoundDefFree(def);
|
|
|
|
def = NULL;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2009-07-06 13:54:44 +00:00
|
|
|
|
2009-10-21 12:26:38 +00:00
|
|
|
static virDomainWatchdogDefPtr
|
|
|
|
virDomainWatchdogDefParseXML(virConnectPtr conn,
|
|
|
|
const xmlNodePtr node,
|
|
|
|
int flags ATTRIBUTE_UNUSED) {
|
|
|
|
|
|
|
|
char *model = NULL;
|
|
|
|
char *action = NULL;
|
|
|
|
virDomainWatchdogDefPtr def;
|
|
|
|
|
|
|
|
if (VIR_ALLOC (def) < 0) {
|
|
|
|
virReportOOMError (conn);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
model = virXMLPropString (node, "model");
|
|
|
|
if (model == NULL) {
|
2009-11-03 12:30:47 +00:00
|
|
|
virDomainReportError (conn, VIR_ERR_INTERNAL_ERROR, "%s",
|
2009-10-21 12:26:38 +00:00
|
|
|
_("watchdog must contain model name"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
def->model = virDomainWatchdogModelTypeFromString (model);
|
|
|
|
if (def->model < 0) {
|
|
|
|
virDomainReportError (conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unknown watchdog model '%s'"), model);
|
|
|
|
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) {
|
|
|
|
virDomainReportError (conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unknown watchdog action '%s'"), action);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE (action);
|
|
|
|
VIR_FREE (model);
|
|
|
|
|
|
|
|
return def;
|
|
|
|
|
|
|
|
error:
|
|
|
|
virDomainWatchdogDefFree (def);
|
|
|
|
def = NULL;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-07-06 13:54:44 +00: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;
|
|
|
|
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;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-09-03 08:26:41 +00:00
|
|
|
static virDomainVideoAccelDefPtr
|
|
|
|
virDomainVideoAccelDefParseXML(virConnectPtr conn, const xmlNodePtr node) {
|
|
|
|
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) {
|
|
|
|
virReportOOMError(conn);
|
|
|
|
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 13:54:44 +00:00
|
|
|
static virDomainVideoDefPtr
|
|
|
|
virDomainVideoDefParseXML(virConnectPtr conn,
|
|
|
|
const xmlNodePtr node,
|
|
|
|
virDomainDefPtr dom,
|
|
|
|
int flags ATTRIBUTE_UNUSED) {
|
|
|
|
virDomainVideoDefPtr def;
|
|
|
|
xmlNodePtr cur;
|
|
|
|
char *type = NULL;
|
|
|
|
char *heads = NULL;
|
|
|
|
char *vram = NULL;
|
|
|
|
|
|
|
|
if (VIR_ALLOC(def) < 0) {
|
|
|
|
virReportOOMError(conn);
|
|
|
|
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");
|
2009-09-03 08:26:41 +00:00
|
|
|
def->accel = virDomainVideoAccelDefParseXML(conn, cur);
|
2009-07-06 13:54:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
cur = cur->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (type) {
|
|
|
|
if ((def->type = virDomainVideoTypeFromString(type)) < 0) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unknown video model '%s'"), type);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if ((def->type = virDomainVideoDefaultType(dom)) < 0) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("missing video model and cannot determine default"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (vram) {
|
|
|
|
if (virStrToLong_ui(vram, NULL, 10, &def->vram) < 0) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("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) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot parse video heads '%s'"), heads);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
def->heads = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
virDomainHostdevSubsysUsbDefParseXML(virConnectPtr conn,
|
|
|
|
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) {
|
2008-08-08 14:27:05 +00:00
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot parse vendor id %s"), vendor);
|
|
|
|
VIR_FREE(vendor);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
VIR_FREE(vendor);
|
|
|
|
} else {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%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) {
|
2008-08-08 14:27:05 +00:00
|
|
|
virDomainReportError(conn, 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 {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%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) {
|
2008-08-08 14:27:05 +00:00
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot parse bus %s"), bus);
|
|
|
|
VIR_FREE(bus);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
VIR_FREE(bus);
|
|
|
|
} else {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%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) {
|
2008-08-08 14:27:05 +00:00
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot parse device %s"),
|
|
|
|
device);
|
|
|
|
VIR_FREE(device);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
VIR_FREE(device);
|
|
|
|
} else {
|
2009-01-07 12:56:13 +00:00
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("usb address needs device id"));
|
2008-08-08 14:27:05 +00:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
virDomainReportError(conn, 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) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("vendor cannot be 0."));
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!got_vendor && got_product) {
|
2008-08-08 14:27:05 +00:00
|
|
|
virDomainReportError(conn, 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) {
|
2008-08-08 14:27:05 +00:00
|
|
|
virDomainReportError(conn, 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
|
|
|
|
virDomainHostdevSubsysPciDefParseXML(virConnectPtr conn,
|
|
|
|
const xmlNodePtr node,
|
2009-08-14 07:31:10 +00:00
|
|
|
virDomainHostdevDefPtr def,
|
|
|
|
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")) {
|
|
|
|
|
|
|
|
char *domain = virXMLPropString(cur, "domain");
|
|
|
|
if (domain) {
|
|
|
|
if (virStrToLong_ui(domain, NULL, 0,
|
|
|
|
&def->source.subsys.u.pci.domain) < 0) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot parse domain %s"),
|
|
|
|
domain);
|
|
|
|
VIR_FREE(domain);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
VIR_FREE(domain);
|
|
|
|
}
|
|
|
|
|
|
|
|
char *bus = virXMLPropString(cur, "bus");
|
|
|
|
if (bus) {
|
|
|
|
if (virStrToLong_ui(bus, NULL, 0,
|
|
|
|
&def->source.subsys.u.pci.bus) < 0) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot parse bus %s"), bus);
|
|
|
|
VIR_FREE(bus);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
VIR_FREE(bus);
|
|
|
|
} else {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("pci address needs bus id"));
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *slot = virXMLPropString(cur, "slot");
|
|
|
|
if (slot) {
|
|
|
|
if (virStrToLong_ui(slot, NULL, 0,
|
|
|
|
&def->source.subsys.u.pci.slot) < 0) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot parse slot %s"),
|
|
|
|
slot);
|
|
|
|
VIR_FREE(slot);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
VIR_FREE(slot);
|
|
|
|
} else {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("pci address needs slot id"));
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *function = virXMLPropString(cur, "function");
|
|
|
|
if (function) {
|
|
|
|
if (virStrToLong_ui(function, NULL, 0,
|
|
|
|
&def->source.subsys.u.pci.function) < 0) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot parse function %s"),
|
|
|
|
function);
|
|
|
|
VIR_FREE(function);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
VIR_FREE(function);
|
|
|
|
} else {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("pci address needs function id"));
|
|
|
|
goto out;
|
|
|
|
}
|
2009-08-14 07:31:10 +00:00
|
|
|
} else if ((flags & VIR_DOMAIN_XML_INTERNAL_STATUS) &&
|
|
|
|
xmlStrEqual(cur->name, BAD_CAST "state")) {
|
|
|
|
char *devaddr = virXMLPropString(cur, "devaddr");
|
|
|
|
if (devaddr &&
|
|
|
|
sscanf(devaddr, "%x:%x:%x",
|
|
|
|
&def->source.subsys.u.pci.guest_addr.domain,
|
|
|
|
&def->source.subsys.u.pci.guest_addr.bus,
|
|
|
|
&def->source.subsys.u.pci.guest_addr.slot) < 3) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Unable to parse devaddr parameter '%s'"),
|
|
|
|
devaddr);
|
|
|
|
VIR_FREE(devaddr);
|
|
|
|
goto out;
|
|
|
|
}
|
2009-01-07 12:56:13 +00:00
|
|
|
} else {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("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
|
|
|
|
virDomainHostdevDefParseXML(virConnectPtr conn,
|
2009-01-08 13:54:20 +00:00
|
|
|
const xmlNodePtr node,
|
|
|
|
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) {
|
2009-01-29 12:10:32 +00:00
|
|
|
virReportOOMError(conn);
|
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) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("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) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unknown host device type '%s'"), type);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%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) {
|
2009-01-08 13:54:20 +00:00
|
|
|
if (virDomainHostdevSubsysUsbDefParseXML(conn, 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) {
|
2009-08-14 07:31:10 +00:00
|
|
|
if (virDomainHostdevSubsysPciDefParseXML(conn, cur, def, flags) < 0)
|
2009-01-07 12:56:13 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2008-08-08 14:27:05 +00:00
|
|
|
} else {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
2008-08-15 01:41:49 +00:00
|
|
|
_("unknown node %s"), cur->name);
|
2008-08-08 14:27:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
cur = cur->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(type);
|
|
|
|
VIR_FREE(mode);
|
|
|
|
return def;
|
|
|
|
|
|
|
|
error:
|
|
|
|
virDomainHostdevDefFree(def);
|
|
|
|
def = NULL;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
|
|
|
|
static int virDomainLifecycleParseXML(virConnectPtr conn,
|
|
|
|
xmlXPathContextPtr ctxt,
|
|
|
|
const char *xpath,
|
|
|
|
int *val,
|
|
|
|
int defaultVal)
|
|
|
|
{
|
2008-07-25 14:27:25 +00:00
|
|
|
char *tmp = virXPathString(conn, xpath, ctxt);
|
2008-07-11 16:23:36 +00:00
|
|
|
if (tmp == NULL) {
|
|
|
|
*val = defaultVal;
|
|
|
|
} else {
|
|
|
|
*val = virDomainLifecycleTypeFromString(tmp);
|
|
|
|
if (*val < 0) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("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
|
|
|
|
virSecurityLabelDefParseXML(virConnectPtr conn,
|
|
|
|
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;
|
|
|
|
|
|
|
|
if (virXPathNode(conn, "./seclabel", ctxt) == NULL)
|
|
|
|
return 0;
|
|
|
|
|
2009-03-03 16:53:13 +00:00
|
|
|
p = virXPathStringLimit(conn, "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) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_XML_ERROR,
|
|
|
|
"%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) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_XML_ERROR,
|
2009-07-23 16:27:47 +00: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)) {
|
2009-04-03 14:10:17 +00:00
|
|
|
p = virXPathStringLimit(conn, "string(./seclabel/@model)",
|
|
|
|
VIR_SECURITY_MODEL_BUFLEN-1, ctxt);
|
|
|
|
if (p == NULL) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_XML_ERROR,
|
|
|
|
"%s", _("missing security model"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
def->seclabel.model = p;
|
2009-03-03 16:53:13 +00:00
|
|
|
|
|
|
|
p = virXPathStringLimit(conn, "string(./seclabel/label[1])",
|
|
|
|
VIR_SECURITY_LABEL_BUFLEN-1, ctxt);
|
2009-04-03 10:55:51 +00:00
|
|
|
if (p == NULL) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_XML_ERROR,
|
2009-07-23 16:27:47 +00: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)) {
|
|
|
|
p = virXPathStringLimit(conn, "string(./seclabel/imagelabel[1])",
|
|
|
|
VIR_SECURITY_LABEL_BUFLEN-1, ctxt);
|
2009-04-03 14:10:17 +00:00
|
|
|
if (p == NULL) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_XML_ERROR,
|
2009-07-23 16:27:47 +00: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
|
|
|
|
|
|
|
virDomainDeviceDefPtr virDomainDeviceDefParse(virConnectPtr conn,
|
2008-10-24 11:20:08 +00:00
|
|
|
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))) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_XML_ERROR, NULL);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
node = xmlDocGetRootElement(xml);
|
|
|
|
if (node == NULL) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_XML_ERROR,
|
|
|
|
"%s", _("missing root element"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VIR_ALLOC(dev) < 0) {
|
2009-01-29 12:10:32 +00:00
|
|
|
virReportOOMError(conn);
|
2008-07-11 16:23:36 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (xmlStrEqual(node->name, BAD_CAST "disk")) {
|
|
|
|
dev->type = VIR_DOMAIN_DEVICE_DISK;
|
2009-01-08 13:54:20 +00:00
|
|
|
if (!(dev->data.disk = virDomainDiskDefParseXML(conn, 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;
|
2009-01-08 13:54:20 +00:00
|
|
|
if (!(dev->data.fs = virDomainFSDefParseXML(conn, 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;
|
2009-01-08 13:54:20 +00:00
|
|
|
if (!(dev->data.net = virDomainNetDefParseXML(conn, 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;
|
2009-01-08 13:54:20 +00:00
|
|
|
if (!(dev->data.input = virDomainInputDefParseXML(conn, def->os.type,
|
|
|
|
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;
|
2009-01-08 13:54:20 +00:00
|
|
|
if (!(dev->data.sound = virDomainSoundDefParseXML(conn, node, flags)))
|
2008-07-11 16:23:36 +00:00
|
|
|
goto error;
|
2009-10-21 12:26:38 +00:00
|
|
|
} else if (xmlStrEqual(node->name, BAD_CAST "watchdog")) {
|
|
|
|
dev->type = VIR_DOMAIN_DEVICE_WATCHDOG;
|
|
|
|
if (!(dev->data.watchdog = virDomainWatchdogDefParseXML(conn, node,
|
|
|
|
flags)))
|
|
|
|
goto error;
|
2009-07-06 13:54:44 +00:00
|
|
|
} else if (xmlStrEqual(node->name, BAD_CAST "video")) {
|
|
|
|
dev->type = VIR_DOMAIN_DEVICE_VIDEO;
|
|
|
|
if (!(dev->data.video = virDomainVideoDefParseXML(conn, node, def, flags)))
|
|
|
|
goto error;
|
2008-08-08 14:27:05 +00:00
|
|
|
} else if (xmlStrEqual(node->name, BAD_CAST "hostdev")) {
|
|
|
|
dev->type = VIR_DOMAIN_DEVICE_HOSTDEV;
|
2009-01-08 13:54:20 +00:00
|
|
|
if (!(dev->data.hostdev = virDomainHostdevDefParseXML(conn, node, flags)))
|
2008-08-08 14:27:05 +00:00
|
|
|
goto error;
|
2008-07-11 16:23:36 +00:00
|
|
|
} else {
|
|
|
|
virDomainReportError(conn, VIR_ERR_XML_ERROR,
|
|
|
|
"%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 09:31:36 +00:00
|
|
|
|
|
|
|
int virDomainDiskInsert(virDomainDefPtr def,
|
|
|
|
virDomainDiskDefPtr disk)
|
2008-10-10 16:08:01 +00:00
|
|
|
{
|
|
|
|
|
2009-08-14 09:31:36 +00: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 09:31:36 +00: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++;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-10-13 15:24:34 +00:00
|
|
|
#ifndef PROXY
|
2009-06-16 15:42:46 +00:00
|
|
|
static char *virDomainDefDefaultEmulator(virConnectPtr conn,
|
|
|
|
virDomainDefPtr def,
|
|
|
|
virCapsPtr caps) {
|
|
|
|
const char *type;
|
|
|
|
const char *emulator;
|
|
|
|
char *retemu;
|
|
|
|
|
|
|
|
type = virDomainVirtTypeToString(def->virtType);
|
|
|
|
if (!type) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("unknown virt type"));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
emulator = virCapabilitiesDefaultGuestEmulator(caps,
|
|
|
|
def->os.type,
|
|
|
|
def->os.arch,
|
|
|
|
type);
|
|
|
|
|
|
|
|
if (!emulator) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("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)
|
|
|
|
virReportOOMError(conn);
|
|
|
|
|
|
|
|
return retemu;
|
|
|
|
}
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
static virDomainDefPtr virDomainDefParseXML(virConnectPtr conn,
|
|
|
|
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) {
|
2009-01-29 12:10:32 +00:00
|
|
|
virReportOOMError(conn);
|
2008-07-11 16:23:36 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2008-12-04 12:02:59 +00:00
|
|
|
|
|
|
|
if (!(flags & VIR_DOMAIN_XML_INACTIVE))
|
2009-11-05 15:04:34 +00:00
|
|
|
if ((virXPathLong(conn, "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 */
|
2008-07-25 14:27:25 +00:00
|
|
|
if (!(tmp = virXPathString(conn, "string(./@type)", ctxt))) {
|
2008-07-11 16:23:36 +00:00
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("missing domain type attribute"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((def->virtType = virDomainVirtTypeFromString(tmp)) < 0) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("invalid domain type %s"), tmp);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
VIR_FREE(tmp);
|
|
|
|
|
|
|
|
/* Extract domain name */
|
2008-07-25 14:27:25 +00:00
|
|
|
if (!(def->name = virXPathString(conn, "string(./name[1])", ctxt))) {
|
2008-07-11 16:23:36 +00:00
|
|
|
virDomainReportError(conn, VIR_ERR_NO_NAME, NULL);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Extract domain uuid */
|
2008-07-25 14:27:25 +00:00
|
|
|
tmp = virXPathString(conn, "string(./uuid[1])", ctxt);
|
2008-07-11 16:23:36 +00:00
|
|
|
if (!tmp) {
|
2009-09-04 15:27:34 +00:00
|
|
|
if (virUUIDGenerate(def->uuid)) {
|
2008-07-11 16:23:36 +00:00
|
|
|
virDomainReportError(conn, 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) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("malformed uuid element"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
VIR_FREE(tmp);
|
|
|
|
}
|
|
|
|
|
2009-09-30 14:07:24 +00:00
|
|
|
/* Extract documentation if present */
|
|
|
|
def->description = virXPathString(conn, "string(./description[1])", ctxt);
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
/* Extract domain memory */
|
2008-07-25 14:27:25 +00:00
|
|
|
if (virXPathULong(conn, "string(./memory[1])", ctxt, &def->maxmem) < 0) {
|
2008-07-11 16:23:36 +00:00
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("missing memory element"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2008-07-25 14:27:25 +00:00
|
|
|
if (virXPathULong(conn, "string(./currentMemory[1])", ctxt, &def->memory) < 0)
|
2008-07-11 16:23:36 +00:00
|
|
|
def->memory = def->maxmem;
|
|
|
|
|
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 14:05:18 +00:00
|
|
|
node = virXPathNode(conn, "./memoryBacking/hugepages", ctxt);
|
|
|
|
if (node)
|
|
|
|
def->hugepage_backed = 1;
|
|
|
|
|
2008-07-25 14:27:25 +00:00
|
|
|
if (virXPathULong(conn, "string(./vcpu[1])", ctxt, &def->vcpus) < 0)
|
2008-07-11 16:23:36 +00:00
|
|
|
def->vcpus = 1;
|
|
|
|
|
2008-07-25 14:27:25 +00:00
|
|
|
tmp = virXPathString(conn, "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) {
|
2009-01-29 12:10:32 +00:00
|
|
|
virReportOOMError(conn);
|
2008-07-11 16:23:36 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (virDomainCpuSetParse(conn, (const char **)&set,
|
|
|
|
0, def->cpumask,
|
|
|
|
def->cpumasklen) < 0)
|
|
|
|
goto error;
|
|
|
|
VIR_FREE(tmp);
|
|
|
|
}
|
|
|
|
|
2009-04-01 10:31:01 +00:00
|
|
|
n = virXPathNodeSet(conn, "./features/*", ctxt, &nodes);
|
|
|
|
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) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("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
|
|
|
}
|
|
|
|
|
|
|
|
if (virDomainLifecycleParseXML(conn, ctxt, "string(./on_reboot[1])",
|
|
|
|
&def->onReboot, VIR_DOMAIN_LIFECYCLE_RESTART) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (virDomainLifecycleParseXML(conn, ctxt, "string(./on_poweroff[1])",
|
|
|
|
&def->onPoweroff, VIR_DOMAIN_LIFECYCLE_DESTROY) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (virDomainLifecycleParseXML(conn, ctxt, "string(./on_crash[1])",
|
|
|
|
&def->onCrash, VIR_DOMAIN_LIFECYCLE_DESTROY) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
|
2008-07-25 14:27:25 +00:00
|
|
|
tmp = virXPathString(conn, "string(./clock/@offset)", ctxt);
|
2008-07-11 16:23:36 +00:00
|
|
|
if (tmp && STREQ(tmp, "localtime"))
|
|
|
|
def->localtime = 1;
|
|
|
|
VIR_FREE(tmp);
|
|
|
|
|
2008-07-25 14:27:25 +00:00
|
|
|
def->os.bootloader = virXPathString(conn, "string(./bootloader)", ctxt);
|
|
|
|
def->os.bootloaderArgs = virXPathString(conn, "string(./bootloader_args)", ctxt);
|
2008-07-11 16:23:36 +00:00
|
|
|
|
2008-07-25 14:27:25 +00:00
|
|
|
def->os.type = virXPathString(conn, "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) {
|
2009-01-29 12:10:32 +00:00
|
|
|
virReportOOMError(conn);
|
2008-07-11 16:23:36 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
virDomainReportError(conn, VIR_ERR_OS_TYPE,
|
|
|
|
"%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"))) {
|
2009-01-29 12:10:32 +00:00
|
|
|
virReportOOMError(conn);
|
2008-07-11 16:23:36 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!virCapabilitiesSupportsGuestOSType(caps, def->os.type)) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_OS_TYPE,
|
|
|
|
"%s", def->os.type);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2008-07-25 14:27:25 +00:00
|
|
|
def->os.arch = virXPathString(conn, "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)) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("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) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("no supported architecture for os type '%s'"),
|
|
|
|
def->os.type);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (!(def->os.arch = strdup(defaultArch))) {
|
2009-01-29 12:10:32 +00:00
|
|
|
virReportOOMError(conn);
|
2008-07-11 16:23:36 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-07-25 14:27:25 +00:00
|
|
|
def->os.machine = virXPathString(conn, "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 09:52:13 +00:00
|
|
|
def->os.arch,
|
|
|
|
virDomainVirtTypeToString(def->virtType));
|
2008-07-11 16:23:36 +00:00
|
|
|
if (defaultMachine != NULL) {
|
|
|
|
if (!(def->os.machine = strdup(defaultMachine))) {
|
2009-01-29 12:10:32 +00:00
|
|
|
virReportOOMError(conn);
|
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")) {
|
|
|
|
def->os.init = virXPathString(conn, "string(./os/init[1])", ctxt);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (STREQ(def->os.type, "xen") ||
|
2008-11-19 16:58:23 +00:00
|
|
|
STREQ(def->os.type, "hvm") ||
|
|
|
|
STREQ(def->os.type, "uml")) {
|
2008-07-25 14:27:25 +00:00
|
|
|
def->os.kernel = virXPathString(conn, "string(./os/kernel[1])", ctxt);
|
|
|
|
def->os.initrd = virXPathString(conn, "string(./os/initrd[1])", ctxt);
|
|
|
|
def->os.cmdline = virXPathString(conn, "string(./os/cmdline[1])", ctxt);
|
|
|
|
def->os.root = virXPathString(conn, "string(./os/root[1])", ctxt);
|
|
|
|
def->os.loader = virXPathString(conn, "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 */
|
2008-07-25 14:27:25 +00:00
|
|
|
if ((n = virXPathNodeSet(conn, "./os/boot", ctxt, &nodes)) < 0) {
|
2008-07-11 16:23:36 +00:00
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%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) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("missing boot device"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if ((val = virDomainBootTypeFromString(dev)) < 0) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("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);
|
|
|
|
}
|
|
|
|
|
2008-07-25 14:27:25 +00:00
|
|
|
def->emulator = virXPathString(conn, "string(./devices/emulator[1])", ctxt);
|
2009-06-16 15:42:46 +00:00
|
|
|
if (!def->emulator && virCapabilitiesIsEmulatorRequired(caps)) {
|
|
|
|
def->emulator = virDomainDefDefaultEmulator(conn, def, caps);
|
|
|
|
if (!def->emulator)
|
|
|
|
goto error;
|
|
|
|
}
|
2008-07-11 16:23:36 +00:00
|
|
|
|
|
|
|
/* analysis of the disk devices */
|
2008-07-25 14:27:25 +00:00
|
|
|
if ((n = virXPathNodeSet(conn, "./devices/disk", ctxt, &nodes)) < 0) {
|
2008-07-11 16:23:36 +00:00
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%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++) {
|
|
|
|
virDomainDiskDefPtr disk = virDomainDiskDefParseXML(conn,
|
2009-01-08 13:54:20 +00:00
|
|
|
nodes[i],
|
|
|
|
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);
|
|
|
|
|
2008-08-01 13:31:37 +00:00
|
|
|
/* analysis of the filesystems */
|
|
|
|
if ((n = virXPathNodeSet(conn, "./devices/filesystem", ctxt, &nodes)) < 0) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%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++) {
|
2008-08-01 13:31:37 +00:00
|
|
|
virDomainFSDefPtr fs = virDomainFSDefParseXML(conn,
|
2009-01-08 13:54:20 +00:00
|
|
|
nodes[i],
|
|
|
|
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 */
|
2008-07-25 14:27:25 +00:00
|
|
|
if ((n = virXPathNodeSet(conn, "./devices/interface", ctxt, &nodes)) < 0) {
|
2008-07-11 16:23:36 +00:00
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%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++) {
|
2008-07-11 16:23:36 +00:00
|
|
|
virDomainNetDefPtr net = virDomainNetDefParseXML(conn,
|
2008-10-24 11:20:08 +00:00
|
|
|
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 */
|
2008-07-25 14:27:25 +00:00
|
|
|
if ((n = virXPathNodeSet(conn, "./devices/parallel", ctxt, &nodes)) < 0) {
|
2008-07-11 16:23:36 +00:00
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%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++) {
|
2008-07-11 16:23:36 +00:00
|
|
|
virDomainChrDefPtr chr = virDomainChrDefParseXML(conn,
|
2009-01-08 13:54:20 +00:00
|
|
|
nodes[i],
|
|
|
|
flags);
|
2008-07-11 16:23:36 +00:00
|
|
|
if (!chr)
|
|
|
|
goto error;
|
|
|
|
|
2009-11-05 13:19:14 +00: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);
|
|
|
|
|
2008-07-25 14:27:25 +00:00
|
|
|
if ((n = virXPathNodeSet(conn, "./devices/serial", ctxt, &nodes)) < 0) {
|
2008-07-11 16:23:36 +00:00
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%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++) {
|
2008-07-11 16:23:36 +00:00
|
|
|
virDomainChrDefPtr chr = virDomainChrDefParseXML(conn,
|
2009-01-08 13:54:20 +00:00
|
|
|
nodes[i],
|
|
|
|
flags);
|
2008-07-11 16:23:36 +00:00
|
|
|
if (!chr)
|
|
|
|
goto error;
|
|
|
|
|
2009-11-05 13:19:14 +00: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);
|
|
|
|
|
2008-11-19 16:58:23 +00:00
|
|
|
if ((node = virXPathNode(conn, "./devices/console[1]", ctxt)) != NULL) {
|
|
|
|
virDomainChrDefPtr chr = virDomainChrDefParseXML(conn,
|
2009-01-08 13:54:20 +00:00
|
|
|
node,
|
|
|
|
flags);
|
2008-11-19 16:58:23 +00:00
|
|
|
if (!chr)
|
|
|
|
goto error;
|
2008-07-11 16:23:36 +00:00
|
|
|
|
2009-11-05 13:19:14 +00: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;
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-05 14:31:03 +00:00
|
|
|
if ((n = virXPathNodeSet(conn, "./devices/channel", ctxt, &nodes)) < 0) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%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++) {
|
|
|
|
virDomainChrDefPtr chr = virDomainChrDefParseXML(conn,
|
|
|
|
nodes[i],
|
|
|
|
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 */
|
2008-07-25 14:27:25 +00:00
|
|
|
if ((n = virXPathNodeSet(conn, "./devices/input", ctxt, &nodes)) < 0) {
|
2008-07-11 16:23:36 +00:00
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%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++) {
|
2008-07-11 16:23:36 +00:00
|
|
|
virDomainInputDefPtr input = virDomainInputDefParseXML(conn,
|
|
|
|
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 */
|
2008-07-25 14:27:25 +00:00
|
|
|
if ((n = virXPathNodeSet(conn, "./devices/graphics", ctxt, &nodes)) < 0) {
|
2008-07-11 16:23:36 +00:00
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%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++) {
|
2008-07-11 16:23:36 +00:00
|
|
|
virDomainGraphicsDefPtr graphics = virDomainGraphicsDefParseXML(conn,
|
2009-05-07 07:27:49 +00:00
|
|
|
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) {
|
2009-01-29 12:10:32 +00:00
|
|
|
virReportOOMError(conn);
|
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 */
|
2008-07-25 14:27:25 +00:00
|
|
|
if ((n = virXPathNodeSet(conn, "./devices/sound", ctxt, &nodes)) < 0) {
|
2008-07-11 16:23:36 +00:00
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%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++) {
|
|
|
|
int collision = 0, j;
|
2008-07-11 16:23:36 +00:00
|
|
|
virDomainSoundDefPtr sound = virDomainSoundDefParseXML(conn,
|
2009-01-08 13:54:20 +00:00
|
|
|
nodes[i],
|
|
|
|
flags);
|
2008-07-11 16:23:36 +00:00
|
|
|
if (!sound)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
/* Verify there's no duplicated sound card */
|
2008-10-10 16:08:01 +00:00
|
|
|
for (j = 0 ; j < def->nsounds ; j++) {
|
|
|
|
if (def->sounds[j]->model == sound->model)
|
2008-07-11 16:23:36 +00:00
|
|
|
collision = 1;
|
|
|
|
}
|
|
|
|
if (collision) {
|
|
|
|
virDomainSoundDefFree(sound);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
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 13:54:44 +00:00
|
|
|
/* analysis of the video devices */
|
|
|
|
if ((n = virXPathNodeSet(conn, "./devices/video", ctxt, &nodes)) < 0) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%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++) {
|
|
|
|
virDomainVideoDefPtr video = virDomainVideoDefParseXML(conn,
|
|
|
|
nodes[i],
|
|
|
|
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) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("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 */
|
|
|
|
if ((n = virXPathNodeSet(conn, "./devices/hostdev", ctxt, &nodes)) < 0) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%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++) {
|
2009-01-08 13:54:20 +00:00
|
|
|
virDomainHostdevDefPtr hostdev = virDomainHostdevDefParseXML(conn,
|
|
|
|
nodes[i],
|
|
|
|
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 12:26:38 +00:00
|
|
|
/* analysis of the watchdog devices */
|
|
|
|
def->watchdog = NULL;
|
|
|
|
if ((n = virXPathNodeSet(conn, "./devices/watchdog", ctxt, &nodes)) < 0) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("cannot extract watchdog devices"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (n > 1) {
|
|
|
|
virDomainReportError (conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("only a single watchdog device is supported"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (n > 0) {
|
|
|
|
virDomainWatchdogDefPtr watchdog =
|
|
|
|
virDomainWatchdogDefParseXML (conn, nodes[0], flags);
|
|
|
|
if (!watchdog)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
def->watchdog = watchdog;
|
|
|
|
VIR_FREE(nodes);
|
|
|
|
}
|
|
|
|
|
2009-03-03 09:44:41 +00:00
|
|
|
/* analysis of security label */
|
2009-03-03 16:53:13 +00:00
|
|
|
if (virSecurityLabelDefParseXML(conn, def, ctxt, flags) == -1)
|
2009-03-03 09:44:41 +00:00
|
|
|
goto error;
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
return def;
|
|
|
|
|
2008-10-10 16:08:01 +00:00
|
|
|
no_memory:
|
2009-01-29 12:10:32 +00:00
|
|
|
virReportOOMError(conn);
|
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
|
|
|
|
|
|
|
static virDomainObjPtr virDomainObjParseXML(virConnectPtr conn,
|
|
|
|
virCapsPtr caps,
|
|
|
|
xmlXPathContextPtr ctxt)
|
|
|
|
{
|
|
|
|
char *tmp = NULL;
|
|
|
|
long val;
|
|
|
|
xmlNodePtr config;
|
|
|
|
xmlNodePtr oldnode;
|
|
|
|
virDomainObjPtr obj;
|
2009-07-09 17:06:38 +00:00
|
|
|
char *monitorpath;
|
2009-09-11 15:26:40 +00:00
|
|
|
xmlNodePtr *nodes = NULL;
|
|
|
|
int n, i;
|
2009-06-12 11:38:50 +00:00
|
|
|
|
2009-10-06 11:50:58 +00:00
|
|
|
if (!(obj = virDomainObjNew(conn, caps)))
|
2009-06-12 11:38:50 +00:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (!(config = virXPathNode(conn, "./domain", ctxt))) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("no domain config"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
oldnode = ctxt->node;
|
|
|
|
ctxt->node = config;
|
2009-07-17 21:08:33 +00:00
|
|
|
obj->def = virDomainDefParseXML(conn, caps, ctxt,
|
|
|
|
VIR_DOMAIN_XML_INTERNAL_STATUS);
|
2009-06-12 11:38:50 +00:00
|
|
|
ctxt->node = oldnode;
|
|
|
|
if (!obj->def)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (!(tmp = virXPathString(conn, "string(./@state)", ctxt))) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("missing domain state"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if ((obj->state = virDomainStateTypeFromString(tmp)) < 0) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("invalid domain state '%s'"), tmp);
|
|
|
|
VIR_FREE(tmp);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
VIR_FREE(tmp);
|
|
|
|
|
|
|
|
if ((virXPathLong(conn, "string(./@pid)", ctxt, &val)) < 0) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("invalid pid"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
obj->pid = (pid_t)val;
|
|
|
|
|
2009-07-09 17:06:38 +00:00
|
|
|
if (VIR_ALLOC(obj->monitor_chr) < 0) {
|
|
|
|
virReportOOMError(conn);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(monitorpath =
|
|
|
|
virXPathString(conn, "string(./monitor[1]/@path)", ctxt))) {
|
2009-06-12 11:38:50 +00:00
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("no monitor path"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2009-07-09 17:06:38 +00:00
|
|
|
tmp = virXPathString(conn, "string(./monitor[1]/@type)", ctxt);
|
|
|
|
if (tmp)
|
|
|
|
obj->monitor_chr->type = virDomainChrTypeFromString(tmp);
|
|
|
|
else
|
|
|
|
obj->monitor_chr->type = VIR_DOMAIN_CHR_TYPE_PTY;
|
|
|
|
VIR_FREE(tmp);
|
|
|
|
|
|
|
|
switch (obj->monitor_chr->type) {
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_PTY:
|
|
|
|
obj->monitor_chr->data.file.path = monitorpath;
|
|
|
|
break;
|
2009-07-09 17:33:40 +00:00
|
|
|
case VIR_DOMAIN_CHR_TYPE_UNIX:
|
|
|
|
obj->monitor_chr->data.nix.path = monitorpath;
|
|
|
|
break;
|
2009-07-09 17:06:38 +00:00
|
|
|
default:
|
|
|
|
VIR_FREE(monitorpath);
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unsupported monitor type '%s'"),
|
|
|
|
virDomainChrTypeToString(obj->monitor_chr->type));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2009-09-11 15:26:40 +00:00
|
|
|
n = virXPathNodeSet(conn, "./vcpus/vcpu", ctxt, &nodes);
|
|
|
|
if (n < 0)
|
|
|
|
goto error;
|
|
|
|
if (n) {
|
|
|
|
obj->nvcpupids = n;
|
2009-11-08 21:08:54 +00:00
|
|
|
if (VIR_REALLOC_N(obj->vcpupids, obj->nvcpupids) < 0) {
|
|
|
|
virReportOOMError(conn);
|
2009-09-11 15:26:40 +00:00
|
|
|
goto error;
|
2009-11-08 21:08:54 +00:00
|
|
|
}
|
2009-09-11 15:26:40 +00:00
|
|
|
|
|
|
|
for (i = 0 ; i < n ; i++) {
|
|
|
|
char *pidstr = virXMLPropString(nodes[i], "pid");
|
|
|
|
if (!pidstr)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (virStrToLong_i(pidstr, NULL, 10, &(obj->vcpupids[i])) < 0) {
|
|
|
|
VIR_FREE(pidstr);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
VIR_FREE(pidstr);
|
|
|
|
}
|
|
|
|
VIR_FREE(nodes);
|
|
|
|
}
|
|
|
|
|
2009-06-12 11:38:50 +00:00
|
|
|
return obj;
|
|
|
|
|
|
|
|
error:
|
2009-09-11 15:26:40 +00:00
|
|
|
VIR_FREE(nodes);
|
2009-07-09 17:06:38 +00:00
|
|
|
virDomainChrDefFree(obj->monitor_chr);
|
2009-10-15 11:30:26 +00:00
|
|
|
virDomainObjUnref(obj);
|
2009-06-12 11:38:50 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-08-01 09:39:44 +00:00
|
|
|
/* Called from SAX on parsing errors in the XML. */
|
|
|
|
static void
|
|
|
|
catchXMLError (void *ctx, const char *msg ATTRIBUTE_UNUSED, ...)
|
|
|
|
{
|
|
|
|
xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
|
|
|
|
|
|
|
|
if (ctxt) {
|
|
|
|
virConnectPtr conn = ctxt->_private;
|
|
|
|
|
2009-02-05 19:29:37 +00:00
|
|
|
if (virGetLastError() == NULL &&
|
2008-08-01 09:39:44 +00:00
|
|
|
ctxt->lastError.level == XML_ERR_FATAL &&
|
|
|
|
ctxt->lastError.message != NULL) {
|
|
|
|
virDomainReportError (conn, VIR_ERR_XML_DETAIL,
|
|
|
|
_("at line %d: %s"),
|
|
|
|
ctxt->lastError.line,
|
|
|
|
ctxt->lastError.message);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-07-11 16:23:36 +00:00
|
|
|
|
|
|
|
virDomainDefPtr virDomainDefParseString(virConnectPtr conn,
|
|
|
|
virCapsPtr caps,
|
2009-01-08 13:54:20 +00:00
|
|
|
const char *xmlStr,
|
|
|
|
int flags)
|
2008-07-11 16:23:36 +00:00
|
|
|
{
|
2008-08-01 09:39:44 +00:00
|
|
|
xmlParserCtxtPtr pctxt;
|
|
|
|
xmlDocPtr xml = NULL;
|
2008-07-11 16:23:36 +00:00
|
|
|
xmlNodePtr root;
|
|
|
|
virDomainDefPtr def = NULL;
|
|
|
|
|
2008-08-01 09:39:44 +00:00
|
|
|
/* Set up a parser context so we can catch the details of XML errors. */
|
|
|
|
pctxt = xmlNewParserCtxt ();
|
|
|
|
if (!pctxt || !pctxt->sax)
|
|
|
|
goto cleanup;
|
|
|
|
pctxt->sax->error = catchXMLError;
|
|
|
|
pctxt->_private = conn;
|
|
|
|
|
|
|
|
if (conn) virResetError (&conn->err);
|
|
|
|
xml = xmlCtxtReadDoc (pctxt, BAD_CAST xmlStr, "domain.xml", NULL,
|
|
|
|
XML_PARSE_NOENT | XML_PARSE_NONET |
|
|
|
|
XML_PARSE_NOWARNING);
|
|
|
|
if (!xml) {
|
2009-02-05 19:29:37 +00:00
|
|
|
if (virGetLastError() == NULL)
|
2008-08-01 09:39:44 +00:00
|
|
|
virDomainReportError(conn, VIR_ERR_XML_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", _("failed to parse xml document"));
|
2008-08-01 09:39:44 +00:00
|
|
|
goto cleanup;
|
2008-07-11 16:23:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((root = xmlDocGetRootElement(xml)) == NULL) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("missing root element"));
|
2008-08-01 09:39:44 +00:00
|
|
|
goto cleanup;
|
2008-07-11 16:23:36 +00:00
|
|
|
}
|
|
|
|
|
2009-01-08 13:54:20 +00:00
|
|
|
def = virDomainDefParseNode(conn, caps, xml, root, flags);
|
2008-07-11 16:23:36 +00:00
|
|
|
|
2008-08-01 09:39:44 +00:00
|
|
|
cleanup:
|
|
|
|
xmlFreeParserCtxt (pctxt);
|
|
|
|
xmlFreeDoc (xml);
|
2008-07-11 16:23:36 +00:00
|
|
|
return def;
|
|
|
|
}
|
|
|
|
|
|
|
|
virDomainDefPtr virDomainDefParseFile(virConnectPtr conn,
|
|
|
|
virCapsPtr caps,
|
2008-12-04 12:02:59 +00:00
|
|
|
const char *filename, int flags)
|
2008-07-11 16:23:36 +00:00
|
|
|
{
|
2008-08-01 09:39:44 +00:00
|
|
|
xmlParserCtxtPtr pctxt;
|
|
|
|
xmlDocPtr xml = NULL;
|
2008-07-11 16:23:36 +00:00
|
|
|
xmlNodePtr root;
|
|
|
|
virDomainDefPtr def = NULL;
|
|
|
|
|
2008-08-01 09:39:44 +00:00
|
|
|
/* Set up a parser context so we can catch the details of XML errors. */
|
|
|
|
pctxt = xmlNewParserCtxt ();
|
|
|
|
if (!pctxt || !pctxt->sax)
|
|
|
|
goto cleanup;
|
|
|
|
pctxt->sax->error = catchXMLError;
|
|
|
|
pctxt->_private = conn;
|
|
|
|
|
|
|
|
if (conn) virResetError (&conn->err);
|
|
|
|
xml = xmlCtxtReadFile (pctxt, filename, NULL,
|
|
|
|
XML_PARSE_NOENT | XML_PARSE_NONET |
|
|
|
|
XML_PARSE_NOWARNING);
|
|
|
|
if (!xml) {
|
2009-02-05 19:29:37 +00:00
|
|
|
if (virGetLastError() == NULL)
|
2008-08-01 09:39:44 +00:00
|
|
|
virDomainReportError(conn, VIR_ERR_XML_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", _("failed to parse xml document"));
|
2008-08-01 09:39:44 +00:00
|
|
|
goto cleanup;
|
2008-07-11 16:23:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((root = xmlDocGetRootElement(xml)) == NULL) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("missing root element"));
|
2008-08-01 09:39:44 +00:00
|
|
|
goto cleanup;
|
2008-07-11 16:23:36 +00:00
|
|
|
}
|
|
|
|
|
2008-12-04 12:02:59 +00:00
|
|
|
def = virDomainDefParseNode(conn, caps, xml, root, flags);
|
2008-07-11 16:23:36 +00:00
|
|
|
|
2008-08-01 09:39:44 +00:00
|
|
|
cleanup:
|
|
|
|
xmlFreeParserCtxt (pctxt);
|
|
|
|
xmlFreeDoc (xml);
|
2008-07-11 16:23:36 +00:00
|
|
|
return def;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
virDomainDefPtr virDomainDefParseNode(virConnectPtr conn,
|
|
|
|
virCapsPtr caps,
|
|
|
|
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")) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("incorrect root element"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctxt = xmlXPathNewContext(xml);
|
|
|
|
if (ctxt == NULL) {
|
2009-01-29 12:10:32 +00:00
|
|
|
virReportOOMError(conn);
|
2008-07-11 16:23:36 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctxt->node = root;
|
2008-12-04 12:02:59 +00:00
|
|
|
def = virDomainDefParseXML(conn, caps, ctxt, flags);
|
2008-07-11 16:23:36 +00:00
|
|
|
|
|
|
|
cleanup:
|
|
|
|
xmlXPathFreeContext(ctxt);
|
|
|
|
return def;
|
|
|
|
}
|
2009-06-12 11:38:50 +00:00
|
|
|
|
|
|
|
|
|
|
|
virDomainObjPtr virDomainObjParseFile(virConnectPtr conn,
|
|
|
|
virCapsPtr caps,
|
|
|
|
const char *filename)
|
|
|
|
{
|
|
|
|
xmlParserCtxtPtr pctxt;
|
|
|
|
xmlDocPtr xml = NULL;
|
|
|
|
xmlNodePtr root;
|
|
|
|
virDomainObjPtr obj = NULL;
|
|
|
|
|
|
|
|
/* Set up a parser context so we can catch the details of XML errors. */
|
|
|
|
pctxt = xmlNewParserCtxt ();
|
|
|
|
if (!pctxt || !pctxt->sax)
|
|
|
|
goto cleanup;
|
|
|
|
pctxt->sax->error = catchXMLError;
|
|
|
|
pctxt->_private = conn;
|
|
|
|
|
|
|
|
if (conn) virResetError (&conn->err);
|
|
|
|
xml = xmlCtxtReadFile (pctxt, filename, NULL,
|
|
|
|
XML_PARSE_NOENT | XML_PARSE_NONET |
|
|
|
|
XML_PARSE_NOWARNING);
|
|
|
|
if (!xml) {
|
|
|
|
if (virGetLastError() == NULL)
|
|
|
|
virDomainReportError(conn, VIR_ERR_XML_ERROR,
|
|
|
|
"%s", _("failed to parse xml document"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((root = xmlDocGetRootElement(xml)) == NULL) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("missing root element"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
obj = virDomainObjParseNode(conn, caps, xml, root);
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
xmlFreeParserCtxt (pctxt);
|
|
|
|
xmlFreeDoc (xml);
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
virDomainObjPtr virDomainObjParseNode(virConnectPtr conn,
|
|
|
|
virCapsPtr caps,
|
|
|
|
xmlDocPtr xml,
|
|
|
|
xmlNodePtr root)
|
|
|
|
{
|
|
|
|
xmlXPathContextPtr ctxt = NULL;
|
|
|
|
virDomainObjPtr obj = NULL;
|
|
|
|
|
|
|
|
if (!xmlStrEqual(root->name, BAD_CAST "domstatus")) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("incorrect root element"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctxt = xmlXPathNewContext(xml);
|
|
|
|
if (ctxt == NULL) {
|
|
|
|
virReportOOMError(conn);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctxt->node = root;
|
|
|
|
obj = virDomainObjParseXML(conn, caps, ctxt);
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
xmlXPathFreeContext(ctxt);
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
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 *
|
|
|
|
virDomainCpuSetFormat(virConnectPtr conn, char *cpuset, int maxcpu)
|
|
|
|
{
|
|
|
|
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-01-29 12:10:32 +00:00
|
|
|
virReportOOMError(conn);
|
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
|
|
|
|
virDomainCpuSetParse(virConnectPtr conn, const char **str, char sep,
|
|
|
|
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:
|
2009-10-27 16:20:22 +00:00
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 16:23:36 +00:00
|
|
|
"%s", _("topology cpuset syntax error"));
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
virDomainLifecycleDefFormat(virConnectPtr conn,
|
|
|
|
virBufferPtr buf,
|
|
|
|
int type,
|
|
|
|
const char *name)
|
|
|
|
{
|
|
|
|
const char *typeStr = virDomainLifecycleTypeToString(type);
|
|
|
|
if (!typeStr) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unexpected lifecycle type %d"), type);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferVSprintf(buf, " <%s>%s</%s>\n", name, typeStr, name);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
virDomainDiskDefFormat(virConnectPtr conn,
|
|
|
|
virBufferPtr buf,
|
2009-07-17 21:08:33 +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);
|
2008-07-11 16:23:36 +00:00
|
|
|
|
|
|
|
if (!type) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unexpected disk type %d"), def->type);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (!device) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unexpected disk device %d"), def->device);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (!bus) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unexpected disk bus %d"), def->bus);
|
|
|
|
return -1;
|
|
|
|
}
|
2009-01-30 17:15:39 +00:00
|
|
|
if (!cachemode) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("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);
|
|
|
|
|
|
|
|
if (def->driverName) {
|
2009-01-30 17:15:39 +00:00
|
|
|
virBufferVSprintf(buf, " <driver 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);
|
|
|
|
virBufferVSprintf(buf, "/>\n");
|
2008-07-11 16:23:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (def->src) {
|
|
|
|
if (def->type == VIR_DOMAIN_DISK_TYPE_FILE)
|
|
|
|
virBufferEscapeString(buf, " <source file='%s'/>\n",
|
|
|
|
def->src);
|
|
|
|
else
|
|
|
|
virBufferEscapeString(buf, " <source dev='%s'/>\n",
|
|
|
|
def->src);
|
|
|
|
}
|
|
|
|
|
|
|
|
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 11:22:01 +00:00
|
|
|
if (def->serial)
|
|
|
|
virBufferEscapeString(buf, " <serial>%s</serial>\n",
|
|
|
|
def->serial);
|
2009-07-21 05:23:03 +00:00
|
|
|
if (def->encryption != NULL &&
|
|
|
|
virStorageEncryptionFormat(conn, buf, def->encryption) < 0)
|
|
|
|
return -1;
|
2008-07-11 16:23:36 +00:00
|
|
|
|
2009-07-17 21:08:33 +00:00
|
|
|
if (flags & VIR_DOMAIN_XML_INTERNAL_STATUS) {
|
|
|
|
virBufferAddLit(buf, " <state");
|
|
|
|
if (virDiskHasValidPciAddr(def))
|
|
|
|
virBufferVSprintf(buf, " devaddr='%.4x:%.2x:%.2x'",
|
|
|
|
def->pci_addr.domain,
|
|
|
|
def->pci_addr.bus,
|
|
|
|
def->pci_addr.slot);
|
|
|
|
virBufferAddLit(buf, "/>\n");
|
|
|
|
}
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
virBufferAddLit(buf, " </disk>\n");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-08-01 13:31:37 +00:00
|
|
|
static int
|
|
|
|
virDomainFSDefFormat(virConnectPtr conn,
|
|
|
|
virBufferPtr buf,
|
|
|
|
virDomainFSDefPtr def)
|
|
|
|
{
|
|
|
|
const char *type = virDomainFSTypeToString(def->type);
|
|
|
|
|
|
|
|
if (!type) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("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");
|
|
|
|
|
|
|
|
virBufferAddLit(buf, " </filesystem>\n");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
static int
|
|
|
|
virDomainNetDefFormat(virConnectPtr conn,
|
|
|
|
virBufferPtr buf,
|
2009-07-17 21:08:34 +00:00
|
|
|
virDomainNetDefPtr def,
|
|
|
|
int flags)
|
2008-07-11 16:23:36 +00:00
|
|
|
{
|
|
|
|
const char *type = virDomainNetTypeToString(def->type);
|
|
|
|
|
|
|
|
if (!type) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("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;
|
|
|
|
|
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);
|
|
|
|
|
2009-07-17 21:08:34 +00:00
|
|
|
if (flags & VIR_DOMAIN_XML_INTERNAL_STATUS) {
|
|
|
|
virBufferAddLit(buf, " <state");
|
|
|
|
if (def->nic_name)
|
|
|
|
virBufferEscapeString(buf, " nic='%s'", def->nic_name);
|
|
|
|
if (def->hostnet_name)
|
|
|
|
virBufferEscapeString(buf, " hostnet='%s'", def->hostnet_name);
|
2009-07-17 21:08:34 +00:00
|
|
|
if (virNetHasValidPciAddr(def))
|
|
|
|
virBufferVSprintf(buf, " devaddr='%.4x:%.2x:%.2x'",
|
|
|
|
def->pci_addr.domain,
|
|
|
|
def->pci_addr.bus,
|
|
|
|
def->pci_addr.slot);
|
2009-07-17 21:08:34 +00:00
|
|
|
if (def->vlan > 0)
|
|
|
|
virBufferVSprintf(buf, " vlan='%d'", def->vlan);
|
2009-07-17 21:08:34 +00:00
|
|
|
virBufferAddLit(buf, "/>\n");
|
|
|
|
}
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
virBufferAddLit(buf, " </interface>\n");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
virDomainChrDefFormat(virConnectPtr conn,
|
|
|
|
virBufferPtr buf,
|
|
|
|
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 13:19:14 +00:00
|
|
|
const char *targetName = virDomainChrTargetTypeToString(def->targetType);
|
2009-11-05 14:31:03 +00:00
|
|
|
const char *elementName;
|
|
|
|
|
|
|
|
const char *addr = NULL;
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
switch (def->targetType) {
|
|
|
|
/* channel types are in a common channel element */
|
|
|
|
case VIR_DOMAIN_CHR_TARGET_TYPE_GUESTFWD:
|
|
|
|
elementName = "channel";
|
|
|
|
break;
|
2009-11-05 13:19:14 +00:00
|
|
|
|
2009-11-05 14:31:03 +00:00
|
|
|
default:
|
|
|
|
elementName = targetName;
|
|
|
|
}
|
2008-07-11 16:23:36 +00:00
|
|
|
|
|
|
|
if (!type) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unexpected char type %d"), def->type);
|
2009-11-05 14:31:03 +00:00
|
|
|
ret = -1;
|
|
|
|
goto cleanup;
|
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 13:19:14 +00: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 13:19:14 +00:00
|
|
|
switch (def->targetType) {
|
2009-11-05 14:31:03 +00:00
|
|
|
case VIR_DOMAIN_CHR_TARGET_TYPE_GUESTFWD:
|
|
|
|
addr = virSocketFormatAddr(def->target.addr);
|
|
|
|
if (addr == NULL) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Unable to format guestfwd address"));
|
|
|
|
ret = -1;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
int port = virSocketGetPort(def->target.addr);
|
|
|
|
if (port < 0) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Unable to format guestfwd port"));
|
|
|
|
ret = -1;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
virBufferVSprintf(buf, " <target type='guestfwd' address='%s' port='%d'/>\n",
|
|
|
|
addr, port);
|
|
|
|
break;
|
|
|
|
|
2009-11-05 13:19:14 +00:00
|
|
|
case VIR_DOMAIN_CHR_TARGET_TYPE_PARALLEL:
|
|
|
|
case VIR_DOMAIN_CHR_TARGET_TYPE_SERIAL:
|
|
|
|
case VIR_DOMAIN_CHR_TARGET_TYPE_CONSOLE:
|
|
|
|
virBufferVSprintf(buf, " <target port='%d'/>\n",
|
|
|
|
def->target.port);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unexpected character destination type %d"),
|
|
|
|
def->targetType);
|
|
|
|
return -1;
|
|
|
|
}
|
2008-07-11 16:23:36 +00:00
|
|
|
|
|
|
|
virBufferVSprintf(buf, " </%s>\n",
|
2009-11-05 13:19:14 +00:00
|
|
|
elementName);
|
2008-07-11 16:23:36 +00:00
|
|
|
|
2009-11-05 14:31:03 +00:00
|
|
|
cleanup:
|
|
|
|
VIR_FREE(addr);
|
|
|
|
|
|
|
|
return ret;
|
2008-07-11 16:23:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
virDomainSoundDefFormat(virConnectPtr conn,
|
|
|
|
virBufferPtr buf,
|
|
|
|
virDomainSoundDefPtr def)
|
|
|
|
{
|
|
|
|
const char *model = virDomainSoundModelTypeToString(def->model);
|
|
|
|
|
|
|
|
if (!model) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unexpected sound model %d"), def->model);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferVSprintf(buf, " <sound model='%s'/>\n",
|
|
|
|
model);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-09-03 08:26:41 +00:00
|
|
|
|
2009-10-21 12:26:38 +00:00
|
|
|
static int
|
|
|
|
virDomainWatchdogDefFormat(virConnectPtr conn,
|
|
|
|
virBufferPtr buf,
|
|
|
|
virDomainWatchdogDefPtr def)
|
|
|
|
{
|
|
|
|
const char *model = virDomainWatchdogModelTypeToString (def->model);
|
|
|
|
const char *action = virDomainWatchdogActionTypeToString (def->action);
|
|
|
|
|
|
|
|
if (!model) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unexpected watchdog model %d"), def->model);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!action) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unexpected watchdog action %d"), def->action);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferVSprintf(buf, " <watchdog model='%s' action='%s'/>\n",
|
|
|
|
model, action);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-09-03 08:26:41 +00: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 13:54:44 +00:00
|
|
|
static int
|
|
|
|
virDomainVideoDefFormat(virConnectPtr conn,
|
|
|
|
virBufferPtr buf,
|
|
|
|
virDomainVideoDefPtr def)
|
|
|
|
{
|
|
|
|
const char *model = virDomainVideoTypeToString(def->type);
|
|
|
|
|
|
|
|
if (!model) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("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 08:26:41 +00:00
|
|
|
if (def->accel) {
|
|
|
|
virBufferAddLit(buf, ">\n");
|
|
|
|
virDomainVideoAccelDefFormat(buf, def->accel);
|
|
|
|
virBufferAddLit(buf, " </model>\n");
|
|
|
|
} else {
|
|
|
|
virBufferAddLit(buf, "/>\n");
|
|
|
|
}
|
|
|
|
|
2009-07-06 13:54:44 +00:00
|
|
|
virBufferAddLit(buf, " </video>\n");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
static int
|
|
|
|
virDomainInputDefFormat(virConnectPtr conn,
|
|
|
|
virBufferPtr buf,
|
|
|
|
virDomainInputDefPtr def)
|
|
|
|
{
|
|
|
|
const char *type = virDomainInputTypeToString(def->type);
|
|
|
|
const char *bus = virDomainInputBusTypeToString(def->bus);
|
|
|
|
|
|
|
|
if (!type) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unexpected input type %d"), def->type);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (!bus) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unexpected input bus type %d"), def->bus);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferVSprintf(buf, " <input type='%s' bus='%s'/>\n",
|
|
|
|
type, bus);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
virDomainGraphicsDefFormat(virConnectPtr conn,
|
|
|
|
virBufferPtr buf,
|
2008-07-31 14:39:30 +00:00
|
|
|
virDomainDefPtr vm,
|
2008-07-11 16:23:36 +00:00
|
|
|
virDomainGraphicsDefPtr def,
|
|
|
|
int flags)
|
|
|
|
{
|
|
|
|
const char *type = virDomainGraphicsTypeToString(def->type);
|
|
|
|
|
|
|
|
if (!type) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("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 &&
|
|
|
|
(!def->data.vnc.autoport || vm->id != -1))
|
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
|
|
|
|
virDomainHostdevDefFormat(virConnectPtr conn,
|
|
|
|
virBufferPtr buf,
|
2009-08-14 07:31:10 +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) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("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) ) {
|
2008-08-08 14:27:05 +00:00
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("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);
|
|
|
|
} else {
|
|
|
|
virBufferVSprintf(buf, " <address bus='%d' device='%d'/>\n",
|
|
|
|
def->source.subsys.u.usb.bus,
|
|
|
|
def->source.subsys.u.usb.device);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) {
|
|
|
|
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);
|
2009-08-14 07:31:10 +00:00
|
|
|
if (flags & VIR_DOMAIN_XML_INTERNAL_STATUS) {
|
|
|
|
virBufferAddLit(buf, " <state");
|
|
|
|
if (virHostdevHasValidGuestAddr(def))
|
|
|
|
virBufferVSprintf(buf, " devaddr='%.4x:%.2x:%.2x'",
|
|
|
|
def->source.subsys.u.pci.guest_addr.domain,
|
|
|
|
def->source.subsys.u.pci.guest_addr.bus,
|
|
|
|
def->source.subsys.u.pci.guest_addr.slot);
|
|
|
|
virBufferAddLit(buf, "/>\n");
|
|
|
|
}
|
2008-08-08 14:27:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virBufferAddLit(buf, " </source>\n");
|
|
|
|
virBufferAddLit(buf, " </hostdev>\n");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
char *virDomainDefFormat(virConnectPtr conn,
|
|
|
|
virDomainDefPtr def,
|
|
|
|
int flags)
|
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
unsigned char *uuid;
|
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
|
|
|
const char *type = NULL, *tmp;
|
|
|
|
int n, allones = 1;
|
|
|
|
|
|
|
|
if (!(type = virDomainVirtTypeToString(def->virtType))) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unexpected domain type %d"), def->virtType);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (def->id >= 0)
|
|
|
|
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 14:07:24 +00: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 14:05:18 +00: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 =
|
|
|
|
virDomainCpuSetFormat(conn, def->cpumask, def->cpumasklen)) == NULL)
|
|
|
|
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) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("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) {
|
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unexpected feature %d"), i);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
virBufferVSprintf(&buf, " <%s/>\n", name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
virBufferAddLit(&buf, " </features>\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferVSprintf(&buf, " <clock offset='%s'/>\n",
|
|
|
|
def->localtime ? "localtime" : "utc");
|
|
|
|
|
|
|
|
if (virDomainLifecycleDefFormat(conn, &buf, def->onPoweroff,
|
|
|
|
"on_poweroff") < 0)
|
|
|
|
goto cleanup;
|
|
|
|
if (virDomainLifecycleDefFormat(conn, &buf, def->onReboot,
|
|
|
|
"on_reboot") < 0)
|
|
|
|
goto cleanup;
|
|
|
|
if (virDomainLifecycleDefFormat(conn, &buf, def->onCrash,
|
|
|
|
"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++)
|
2009-07-17 21:08:33 +00:00
|
|
|
if (virDomainDiskDefFormat(conn, &buf, def->disks[n], flags) < 0)
|
2008-07-11 16:23:36 +00:00
|
|
|
goto cleanup;
|
2008-08-01 13:31:37 +00:00
|
|
|
|
2008-10-10 16:08:01 +00:00
|
|
|
for (n = 0 ; n < def->nfss ; n++)
|
|
|
|
if (virDomainFSDefFormat(conn, &buf, def->fss[n]) < 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++)
|
2009-07-17 21:08:34 +00:00
|
|
|
if (virDomainNetDefFormat(conn, &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++)
|
2009-11-05 13:19:14 +00:00
|
|
|
if (virDomainChrDefFormat(conn, &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++)
|
2009-11-05 13:19:14 +00:00
|
|
|
if (virDomainChrDefFormat(conn, &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) {
|
2009-11-05 13:19:14 +00:00
|
|
|
if (virDomainChrDefFormat(conn, &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 13:19:14 +00:00
|
|
|
virDomainChrDef console;
|
|
|
|
memcpy(&console, def->serials[0], sizeof(console));
|
|
|
|
console.targetType = VIR_DOMAIN_CHR_TARGET_TYPE_CONSOLE;
|
|
|
|
if (virDomainChrDefFormat(conn, &buf, &console, flags) < 0)
|
2008-07-11 16:23:36 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2009-11-05 14:31:03 +00:00
|
|
|
for (n = 0 ; n < def->nchannels ; n++)
|
|
|
|
if (virDomainChrDefFormat(conn, &buf, def->channels[n], flags) < 0)
|
|
|
|
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 &&
|
|
|
|
virDomainInputDefFormat(conn, &buf, def->inputs[n]) < 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") ?
|
2008-10-10 16:08:01 +00:00
|
|
|
VIR_DOMAIN_INPUT_BUS_PS2 : VIR_DOMAIN_INPUT_BUS_XEN
|
|
|
|
};
|
2008-07-11 16:23:36 +00:00
|
|
|
|
|
|
|
if (virDomainInputDefFormat(conn, &buf, &autoInput) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2009-05-07 07:27:49 +00:00
|
|
|
for (n = 0 ; n < def->ngraphics ; n++)
|
|
|
|
if (virDomainGraphicsDefFormat(conn, &buf, def, def->graphics[n], flags) < 0)
|
|
|
|
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++)
|
|
|
|
if (virDomainSoundDefFormat(conn, &buf, def->sounds[n]) < 0)
|
2008-07-11 16:23:36 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2009-07-06 13:54:44 +00:00
|
|
|
for (n = 0 ; n < def->nvideos ; n++)
|
|
|
|
if (virDomainVideoDefFormat(conn, &buf, def->videos[n]) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2008-10-10 16:08:01 +00:00
|
|
|
for (n = 0 ; n < def->nhostdevs ; n++)
|
2009-08-14 07:31:10 +00:00
|
|
|
if (virDomainHostdevDefFormat(conn, &buf, def->hostdevs[n], flags) < 0)
|
2008-08-08 14:27:05 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2009-10-21 12:26:38 +00:00
|
|
|
if (def->watchdog)
|
|
|
|
virDomainWatchdogDefFormat (conn, &buf, def->watchdog);
|
|
|
|
|
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:
|
2009-01-29 12:10:32 +00:00
|
|
|
virReportOOMError(conn);
|
2008-07-11 16:23:36 +00:00
|
|
|
cleanup:
|
|
|
|
tmp = virBufferContentAndReset(&buf);
|
|
|
|
VIR_FREE(tmp);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2009-06-12 11:38:50 +00:00
|
|
|
char *virDomainObjFormat(virConnectPtr conn,
|
|
|
|
virDomainObjPtr obj,
|
|
|
|
int flags)
|
|
|
|
{
|
|
|
|
char *config_xml = NULL, *xml = NULL;
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
2009-07-09 17:06:38 +00:00
|
|
|
const char *monitorpath;
|
2009-06-12 11:38:50 +00:00
|
|
|
|
|
|
|
virBufferVSprintf(&buf, "<domstatus state='%s' pid='%d'>\n",
|
|
|
|
virDomainStateTypeToString(obj->state),
|
|
|
|
obj->pid);
|
2009-07-09 17:06:38 +00:00
|
|
|
|
2009-09-21 14:31:22 +00:00
|
|
|
/* obj->monitor_chr is set only for qemu */
|
|
|
|
if (obj->monitor_chr) {
|
|
|
|
switch (obj->monitor_chr->type) {
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_UNIX:
|
|
|
|
monitorpath = obj->monitor_chr->data.nix.path;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
case VIR_DOMAIN_CHR_TYPE_PTY:
|
|
|
|
monitorpath = obj->monitor_chr->data.file.path;
|
|
|
|
break;
|
|
|
|
}
|
2009-07-09 17:06:38 +00:00
|
|
|
|
2009-09-21 14:31:22 +00:00
|
|
|
virBufferEscapeString(&buf, " <monitor path='%s'", monitorpath);
|
|
|
|
virBufferVSprintf(&buf, " type='%s'/>\n",
|
|
|
|
virDomainChrTypeToString(obj->monitor_chr->type));
|
|
|
|
}
|
2009-06-12 11:38:50 +00:00
|
|
|
|
2009-09-11 15:26:40 +00:00
|
|
|
|
|
|
|
if (obj->nvcpupids) {
|
|
|
|
int i;
|
|
|
|
virBufferAddLit(&buf, " <vcpus>\n");
|
|
|
|
for (i = 0 ; i < obj->nvcpupids ; i++) {
|
|
|
|
virBufferVSprintf(&buf, " <vcpu pid='%d'/>\n", obj->vcpupids[i]);
|
|
|
|
}
|
|
|
|
virBufferAddLit(&buf, " </vcpus>\n");
|
|
|
|
}
|
|
|
|
|
2009-06-12 11:38:50 +00:00
|
|
|
if (!(config_xml = virDomainDefFormat(conn,
|
|
|
|
obj->def,
|
|
|
|
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:
|
|
|
|
virReportOOMError(conn);
|
|
|
|
error:
|
|
|
|
xml = virBufferContentAndReset(&buf);
|
|
|
|
VIR_FREE(xml);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
|
2008-07-25 10:49:33 +00:00
|
|
|
#ifndef PROXY
|
|
|
|
|
2008-12-20 13:09:45 +00:00
|
|
|
int virDomainSaveXML(virConnectPtr conn,
|
|
|
|
const char *configDir,
|
|
|
|
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;
|
|
|
|
|
2008-08-20 19:42:36 +00:00
|
|
|
if ((configFile = virDomainConfigFile(conn, configDir, def->name)) == NULL)
|
2008-07-11 16:23:36 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2009-09-04 15:27:34 +00:00
|
|
|
if (virFileMakePath(configDir)) {
|
2009-01-20 17:13:33 +00:00
|
|
|
virReportSystemError(conn, errno,
|
|
|
|
_("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) {
|
2009-01-20 17:13:33 +00:00
|
|
|
virReportSystemError(conn, errno,
|
|
|
|
_("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) {
|
2009-01-20 17:13:33 +00:00
|
|
|
virReportSystemError(conn, errno,
|
|
|
|
_("cannot write config file '%s'"),
|
|
|
|
configFile);
|
2008-07-11 16:23:36 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (close(fd) < 0) {
|
2009-01-20 17:13:33 +00:00
|
|
|
virReportSystemError(conn, errno,
|
|
|
|
_("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 13:56:32 +00:00
|
|
|
VIR_FREE(configFile);
|
2008-12-20 13:09:45 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int virDomainSaveConfig(virConnectPtr conn,
|
|
|
|
const char *configDir,
|
|
|
|
virDomainDefPtr def)
|
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
char *xml;
|
2008-07-11 16:23:36 +00:00
|
|
|
|
2008-12-20 13:09:45 +00:00
|
|
|
if (!(xml = virDomainDefFormat(conn,
|
|
|
|
def,
|
|
|
|
VIR_DOMAIN_XML_SECURE)))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (virDomainSaveXML(conn, configDir, def, xml))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(xml);
|
2008-07-11 16:23:36 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2009-06-12 11:38:50 +00:00
|
|
|
int virDomainSaveStatus(virConnectPtr conn,
|
|
|
|
const char *statusDir,
|
|
|
|
virDomainObjPtr obj)
|
|
|
|
{
|
2009-07-17 21:08:33 +00: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;
|
|
|
|
|
2009-07-17 21:08:33 +00:00
|
|
|
if (!(xml = virDomainObjFormat(conn, obj, flags)))
|
2009-06-12 11:38:50 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (virDomainSaveXML(conn, statusDir, obj->def, xml))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(xml);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2008-07-25 10:49:33 +00:00
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
virDomainObjPtr virDomainLoadConfig(virConnectPtr conn,
|
|
|
|
virCapsPtr caps,
|
2008-10-10 14:20:37 +00:00
|
|
|
virDomainObjListPtr doms,
|
2008-07-11 16:23:36 +00:00
|
|
|
const char *configDir,
|
|
|
|
const char *autostartDir,
|
2008-11-17 16:52:32 +00:00
|
|
|
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
|
|
|
|
2008-08-20 19:42:36 +00:00
|
|
|
if ((configFile = virDomainConfigFile(conn, configDir, name)) == NULL)
|
2008-07-11 16:23:36 +00:00
|
|
|
goto error;
|
2008-08-20 19:42:36 +00:00
|
|
|
if ((autostartLink = virDomainConfigFile(conn, autostartDir, name)) == NULL)
|
2008-07-11 16:23:36 +00:00
|
|
|
goto error;
|
2008-08-20 19:42:36 +00:00
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
if ((autostart = virFileLinkPointsTo(autostartLink, configFile)) < 0)
|
|
|
|
goto error;
|
|
|
|
|
2008-12-04 12:02:59 +00:00
|
|
|
if (!(def = virDomainDefParseFile(conn, caps, configFile,
|
|
|
|
VIR_DOMAIN_XML_INACTIVE)))
|
2008-07-11 16:23:36 +00:00
|
|
|
goto error;
|
|
|
|
|
2008-12-15 11:00:11 +00:00
|
|
|
if ((dom = virDomainFindByName(doms, def->name))) {
|
|
|
|
virDomainObjUnlock(dom);
|
|
|
|
dom = NULL;
|
2008-11-17 16:52:32 +00:00
|
|
|
newVM = 0;
|
2008-12-15 11:00:11 +00:00
|
|
|
}
|
2008-11-17 16:52:32 +00:00
|
|
|
|
2009-10-06 11:50:58 +00:00
|
|
|
if (!(dom = virDomainAssignDef(conn, caps, doms, def)))
|
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;
|
|
|
|
}
|
|
|
|
|
2009-06-12 11:38:50 +00:00
|
|
|
static virDomainObjPtr virDomainLoadStatus(virConnectPtr conn,
|
|
|
|
virCapsPtr caps,
|
|
|
|
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 11:33:51 +00:00
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
2009-06-12 11:38:50 +00:00
|
|
|
|
|
|
|
if ((statusFile = virDomainConfigFile(conn, statusDir, name)) == NULL)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (!(obj = virDomainObjParseFile(conn, caps, statusFile)))
|
|
|
|
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 11:33:51 +00:00
|
|
|
virUUIDFormat(obj->def->uuid, uuidstr);
|
|
|
|
|
|
|
|
if (virHashLookup(doms->objs, uuidstr) != NULL) {
|
2009-06-12 11:38:50 +00:00
|
|
|
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("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 11:33:51 +00:00
|
|
|
if (virHashAddEntry(doms->objs, uuidstr, obj) < 0) {
|
2009-06-12 11:38:50 +00:00
|
|
|
virReportOOMError(conn);
|
|
|
|
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 17:40:51 +00:00
|
|
|
if (obj)
|
|
|
|
virDomainObjUnref(obj);
|
2009-06-12 11:38:50 +00:00
|
|
|
VIR_FREE(statusFile);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2008-07-11 16:23:36 +00:00
|
|
|
int virDomainLoadAllConfigs(virConnectPtr conn,
|
|
|
|
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;
|
2009-01-20 17:13:33 +00:00
|
|
|
virReportSystemError(conn, errno,
|
|
|
|
_("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)
|
|
|
|
dom = virDomainLoadStatus(conn,
|
|
|
|
caps,
|
|
|
|
doms,
|
|
|
|
configDir,
|
|
|
|
entry->d_name,
|
|
|
|
notify,
|
|
|
|
opaque);
|
|
|
|
else
|
|
|
|
dom = virDomainLoadConfig(conn,
|
|
|
|
caps,
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
int virDomainDeleteConfig(virConnectPtr conn,
|
2008-08-20 19:42:36 +00:00
|
|
|
const char *configDir,
|
|
|
|
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;
|
|
|
|
|
|
|
|
if ((configFile = virDomainConfigFile(conn, configDir, dom->def->name)) == NULL)
|
|
|
|
goto cleanup;
|
|
|
|
if ((autostartLink = virDomainConfigFile(conn, autostartDir, dom->def->name)) == NULL)
|
|
|
|
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) {
|
2009-01-20 17:13:33 +00:00
|
|
|
virReportSystemError(conn, errno,
|
|
|
|
_("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
|
|
|
|
2008-08-20 19:42:36 +00:00
|
|
|
char *virDomainConfigFile(virConnectPtr conn,
|
|
|
|
const char *dir,
|
|
|
|
const char *name)
|
|
|
|
{
|
|
|
|
char *ret = NULL;
|
|
|
|
|
2008-12-23 13:03:29 +00:00
|
|
|
if (virAsprintf(&ret, "%s/%s.xml", dir, name) < 0) {
|
2009-01-29 12:10:32 +00:00
|
|
|
virReportOOMError(conn);
|
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 18:37:38 +00: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);
|
|
|
|
virDomainReportError(NULL, VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("domain '%s' is already defined with uuid %s"),
|
|
|
|
vm->def->name, uuidstr);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (check_active) {
|
|
|
|
/* UUID & name match, but if VM is already active, refuse it */
|
|
|
|
if (virDomainObjIsActive(vm)) {
|
|
|
|
virDomainReportError(NULL, VIR_ERR_OPERATION_INVALID,
|
|
|
|
_("domain is already active as '%s'"),
|
|
|
|
vm->def->name);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
dupVM = 1;
|
|
|
|
virDomainObjUnlock(vm);
|
|
|
|
} 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);
|
|
|
|
virDomainReportError(NULL, VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("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 11:33:51 +00: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 14:51:03 +00: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 11:33:51 +00: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 14:51:03 +00: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 11:33:51 +00: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 14:51:03 +00: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 11:33:51 +00: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 14:51:03 +00: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 11:33:51 +00: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) {
|
|
|
|
virReportOOMError(NULL);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
return data.numnames;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
for (i = 0 ; i < data.numnames ; i++)
|
|
|
|
VIR_FREE(data.names[i]);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2008-07-25 10:49:33 +00:00
|
|
|
#endif /* ! PROXY */
|