-I$(top_srcdir)/gnulib/lib -I../gnulib/lib \
-I$(top_srcdir)/include -I$(top_builddir)/include \
-I$(top_srcdir)/src \
+ -I$(top_srcdir)/src/util \
-I$(top_srcdir)/src/conf \
$(LIBXML_CFLAGS) $(GNUTLS_CFLAGS) $(SASL_CFLAGS) \
$(POLKIT_CFLAGS) \
libvirt-api.xml libvirt-refs.xml: apibuild.py \
$(srcdir)/../include/libvirt/*.h \
- $(srcdir)/../src/*.h $(srcdir)/../src/*.c
+ $(srcdir)/../src/libvirt.c $(srcdir)/../src/util/virterror.c
-(./apibuild.py)
$(top_builddir)/NEWS: $(top_srcdir)/docs/news.xsl $(top_srcdir)/docs/news.html.in
builder = None
if glob.glob("../src/libvirt.c") != [] :
print "Rebuilding API description for libvirt"
- builder = docBuilder("libvirt", ["../src", "../include/libvirt"],
+ builder = docBuilder("libvirt", ["../src", "../src/util", "../include/libvirt"],
[])
elif glob.glob("src/libvirt.c") != [] :
print "Rebuilding API description for libvir"
- builder = docBuilder("libvirt", ["src", "include/libvirt"],
+ builder = docBuilder("libvirt", ["src", "src/util", "include/libvirt"],
[])
else:
print "rebuild() failed, unable to guess the module"
INCLUDES = -I$(top_srcdir)/gnulib/lib -I../gnulib/lib \
-I$(top_builddir)/include -I@top_srcdir@/include \
-I@top_srcdir@/proxy -I@top_srcdir@/src \
+ -I@top_srcdir@/src/util \
-I@top_srcdir@/src/conf \
-I@top_srcdir@/src/xen \
@LIBXML_CFLAGS@ \
libexec_PROGRAMS = libvirt_proxy
-libvirt_proxy_SOURCES = libvirt_proxy.c @top_srcdir@/src/xen/xend_internal.c \
- @top_srcdir@/src/xen/xen_hypervisor.c @top_srcdir@/src/virterror.c \
- @top_srcdir@/src/xen/sexpr.c \
- @top_srcdir@/src/threads.c \
- @top_srcdir@/src/xen/xs_internal.c @top_srcdir@/src/buf.c \
+libvirt_proxy_SOURCES = libvirt_proxy.c \
+ @top_srcdir@/src/util/buf.c \
+ @top_srcdir@/src/util/logging.c \
+ @top_srcdir@/src/util/memory.c \
+ @top_srcdir@/src/util/threads.c \
+ @top_srcdir@/src/util/util.c \
+ @top_srcdir@/src/util/uuid.c \
+ @top_srcdir@/src/util/virterror.c \
@top_srcdir@/src/conf/capabilities.c \
- @top_srcdir@/src/memory.c \
@top_srcdir@/src/conf/storage_encryption_conf.c \
@top_srcdir@/src/conf/domain_conf.c \
- @top_srcdir@/src/util.c \
- @top_srcdir@/src/event.c \
- @top_srcdir@/src/uuid.c \
- @top_srcdir@/src/logging.c
+ @top_srcdir@/src/xen/xend_internal.c \
+ @top_srcdir@/src/xen/xen_hypervisor.c \
+ @top_srcdir@/src/xen/sexpr.c \
+ @top_srcdir@/src/xen/xs_internal.c
libvirt_proxy_LDFLAGS = $(WARN_CFLAGS) $(XEN_LIBS)
libvirt_proxy_DEPENDENCIES =
libvirt_proxy_LDADD = ../gnulib/lib/libgnu.la
-I$(top_srcdir)/gnulib/lib \
-I../gnulib/lib \
-I../include \
+ -I@top_srcdir@/src/util \
-I@top_srcdir@/include \
$(DRIVER_MODULE_CFLAGS) \
$(LIBXML_CFLAGS) \
# These files are not related to driver APIs. Simply generic
# helper APIs for various purposes
UTIL_SOURCES = \
- bridge.c bridge.h \
- buf.c buf.h \
- conf.c conf.h \
- event.c event.h \
- hash.c hash.h \
- iptables.c iptables.h \
- logging.c logging.h \
- memory.c memory.h \
- pci.c pci.h \
- hostusb.c hostusb.h \
- qparams.c qparams.h \
- threads.c threads.h \
- threads-pthread.h \
- threads-win32.h \
- uuid.c uuid.h \
- util.c util.h \
- virterror.c virterror_internal.h \
- xml.c xml.h
-
-EXTRA_DIST += threads-pthread.c threads-win32.c
+ util/bridge.c util/bridge.h \
+ util/buf.c util/buf.h \
+ util/conf.c util/conf.h \
+ util/cgroup.c util/cgroup.h \
+ util/event.c util/event.h \
+ util/hash.c util/hash.h \
+ util/iptables.c util/iptables.h \
+ util/logging.c util/logging.h \
+ util/memory.c util/memory.h \
+ util/pci.c util/pci.h \
+ util/hostusb.c util/hostusb.h \
+ util/qparams.c util/qparams.h \
+ util/stats_linux.c util/stats_linux.h \
+ util/threads.c util/threads.h \
+ util/threads-pthread.h \
+ util/threads-win32.h \
+ util/uuid.c util/uuid.h \
+ util/util.c util/util.h \
+ util/xml.c util/xml.h \
+ util/virterror.c util/virterror_internal.h
+
+EXTRA_DIST += util/threads-pthread.c util/threads-win32.c
# Internal generic driver infrastructure
NODE_INFO_SOURCES = nodeinfo.h nodeinfo.c
driver.c driver.h \
internal.h \
datatypes.c datatypes.h \
- stats_linux.c stats_linux.h \
$(NODE_INFO_SOURCES) \
libvirt.c libvirt_internal.h
lxc/lxc_conf.c lxc/lxc_conf.h \
lxc/lxc_container.c lxc/lxc_container.h \
lxc/lxc_driver.c lxc/lxc_driver.h \
- lxc/veth.c lxc/veth.h \
- cgroup.c cgroup.h
+ lxc/veth.c lxc/veth.h
LXC_CONTROLLER_SOURCES = \
lxc/lxc_conf.c lxc/lxc_conf.h \
lxc/lxc_container.c lxc/lxc_container.h \
lxc/lxc_controller.c \
- lxc/veth.c lxc/veth.h \
- cgroup.c cgroup.h
+ lxc/veth.c lxc/veth.h
PHYP_DRIVER_SOURCES = \
phyp/phyp_driver.c phyp/phyp_driver.h
VBOX_DRIVER_EXTRA_DIST = vbox/vbox_tmpl.c vbox/README
QEMU_DRIVER_SOURCES = \
- qemu/qemu_conf.c qemu/qemu_conf.h \
- qemu/qemu_driver.c qemu/qemu_driver.h \
- cgroup.c cgroup.h
+ qemu/qemu_conf.c qemu/qemu_conf.h \
+ qemu/qemu_driver.c qemu/qemu_driver.h
UML_DRIVER_SOURCES = \
uml/uml_conf.c uml/uml_conf.h \
libvirt_driver_storage_la_SOURCES =
libvirt_driver_storage_la_CFLAGS = \
-I@top_srcdir@/src/conf
+libvirt_driver_storage_la_LDFLAGS =
if WITH_STORAGE_DIR
if WITH_DRIVER_MODULES
mod_LTLIBRARIES += libvirt_driver_storage.la
#libvirt_la_LIBADD += libvirt_driver_storage.la
endif
if WITH_DRIVER_MODULES
-libvirt_driver_storage_la_LDFLAGS = -module -avoid-version
+libvirt_driver_storage_la_LDFLAGS += -module -avoid-version
endif
libvirt_driver_storage_la_SOURCES += $(STORAGE_DRIVER_SOURCES)
libvirt_driver_storage_la_SOURCES += $(STORAGE_DRIVER_FS_SOURCES)
if WITH_STORAGE_MPATH
libvirt_driver_storage_la_SOURCES += $(STORAGE_DRIVER_MPATH_SOURCES)
libvirt_driver_storage_la_CFLAGS += $(DEVMAPPER_CFLAGS)
+libvirt_driver_storage_la_LDFLAGS += $(DEVMAPPER_LIBS)
endif
if WITH_STORAGE_DISK
+++ /dev/null
-/*
- * Copyright (C) 2007, 2009 Red Hat, Inc.
- *
- * 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
- *
- * Authors:
- * Mark McLoughlin <markmc@redhat.com>
- */
-
-#include <config.h>
-
-#if defined(WITH_BRIDGE)
-
-#include "bridge.h"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <arpa/inet.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <paths.h>
-#include <sys/wait.h>
-
-#include <linux/param.h> /* HZ */
-#include <linux/sockios.h> /* SIOCBRADDBR etc. */
-#include <linux/if_bridge.h> /* SYSFS_BRIDGE_ATTR */
-#include <linux/if_tun.h> /* IFF_TUN, IFF_NO_PI */
-#include <net/if_arp.h> /* ARPHRD_ETHER */
-
-#include "internal.h"
-#include "memory.h"
-#include "util.h"
-#include "logging.h"
-
-#define JIFFIES_TO_MS(j) (((j)*1000)/HZ)
-#define MS_TO_JIFFIES(ms) (((ms)*HZ)/1000)
-
-struct _brControl {
- int fd;
-};
-
-/**
- * brInit:
- * @ctlp: pointer to bridge control return value
- *
- * Initialize a new bridge layer. In case of success
- * @ctlp will contain a pointer to the new bridge structure.
- *
- * Returns 0 in case of success, an error code otherwise.
- */
-int
-brInit(brControl **ctlp)
-{
- int fd;
- int flags;
-
- if (!ctlp || *ctlp)
- return EINVAL;
-
- fd = socket(AF_INET, SOCK_STREAM, 0);
- if (fd < 0)
- return errno;
-
- if ((flags = fcntl(fd, F_GETFD)) < 0 ||
- fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) {
- int err = errno;
- close(fd);
- return err;
- }
-
- if (VIR_ALLOC(*ctlp) < 0) {
- close(fd);
- return ENOMEM;
- }
-
- (*ctlp)->fd = fd;
-
- return 0;
-}
-
-/**
- * brShutdown:
- * @ctl: pointer to a bridge control
- *
- * Shutdown the bridge layer and deallocate the associated structures
- */
-void
-brShutdown(brControl *ctl)
-{
- if (!ctl)
- return;
-
- close(ctl->fd);
- ctl->fd = 0;
-
- VIR_FREE(ctl);
-}
-
-/**
- * brAddBridge:
- * @ctl: bridge control pointer
- * @name: the bridge name
- *
- * This function register a new bridge
- *
- * Returns 0 in case of success or an errno code in case of failure.
- */
-#ifdef SIOCBRADDBR
-int
-brAddBridge(brControl *ctl,
- const char *name)
-{
- if (!ctl || !ctl->fd || !name)
- return EINVAL;
-
- if (ioctl(ctl->fd, SIOCBRADDBR, name) == 0)
- return 0;
-
- return errno;
-}
-#else
-int brAddBridge (brControl *ctl ATTRIBUTE_UNUSED,
- const char *name ATTRIBUTE_UNUSED)
-{
- return EINVAL;
-}
-#endif
-
-#ifdef SIOCBRDELBR
-int
-brHasBridge(brControl *ctl,
- const char *name)
-{
- struct ifreq ifr;
- int len;
-
- if (!ctl || !name) {
- errno = EINVAL;
- return -1;
- }
-
- if ((len = strlen(name)) >= BR_IFNAME_MAXLEN) {
- errno = EINVAL;
- return -1;
- }
-
- memset(&ifr, 0, sizeof(struct ifreq));
-
- strncpy(ifr.ifr_name, name, len);
- ifr.ifr_name[len] = '\0';
-
- if (ioctl(ctl->fd, SIOCGIFFLAGS, &ifr))
- return -1;
-
- return 0;
-}
-#else
-int
-brHasBridge(brControl *ctl ATTRIBUTE_UNUSED,
- const char *name ATTRIBUTE_UNUSED)
-{
- return EINVAL;
-}
-#endif
-
-/**
- * brDeleteBridge:
- * @ctl: bridge control pointer
- * @name: the bridge name
- *
- * Remove a bridge from the layer.
- *
- * Returns 0 in case of success or an errno code in case of failure.
- */
-#ifdef SIOCBRDELBR
-int
-brDeleteBridge(brControl *ctl,
- const char *name)
-{
- if (!ctl || !ctl->fd || !name)
- return EINVAL;
-
- return ioctl(ctl->fd, SIOCBRDELBR, name) == 0 ? 0 : errno;
-}
-#else
-int
-brDeleteBridge(brControl *ctl ATTRIBUTE_UNUSED,
- const char *name ATTRIBUTE_UNUSED)
-{
- return EINVAL;
-}
-#endif
-
-#if defined(SIOCBRADDIF) && defined(SIOCBRDELIF)
-static int
-brAddDelInterface(brControl *ctl,
- int cmd,
- const char *bridge,
- const char *iface)
-{
- struct ifreq ifr;
- int len;
-
- if (!ctl || !ctl->fd || !bridge || !iface)
- return EINVAL;
-
- if ((len = strlen(bridge)) >= BR_IFNAME_MAXLEN)
- return EINVAL;
-
- memset(&ifr, 0, sizeof(struct ifreq));
-
- strncpy(ifr.ifr_name, bridge, len);
- ifr.ifr_name[len] = '\0';
-
- if (!(ifr.ifr_ifindex = if_nametoindex(iface)))
- return ENODEV;
-
- return ioctl(ctl->fd, cmd, &ifr) == 0 ? 0 : errno;
-}
-#endif
-
-/**
- * brAddInterface:
- * @ctl: bridge control pointer
- * @bridge: the bridge name
- * @iface: the network interface name
- *
- * Adds an interface to a bridge
- *
- * Returns 0 in case of success or an errno code in case of failure.
- */
-#ifdef SIOCBRADDIF
-int
-brAddInterface(brControl *ctl,
- const char *bridge,
- const char *iface)
-{
- return brAddDelInterface(ctl, SIOCBRADDIF, bridge, iface);
-}
-#else
-int
-brAddInterface(brControl *ctl ATTRIBUTE_UNUSED,
- const char *bridge ATTRIBUTE_UNUSED,
- const char *iface ATTRIBUTE_UNUSED)
-{
- return EINVAL;
-}
-#endif
-
-/**
- * brDeleteInterface:
- * @ctl: bridge control pointer
- * @bridge: the bridge name
- * @iface: the network interface name
- *
- * Removes an interface from a bridge
- *
- * Returns 0 in case of success or an errno code in case of failure.
- */
-#ifdef SIOCBRDELIF
-int
-brDeleteInterface(brControl *ctl,
- const char *bridge,
- const char *iface)
-{
- return brAddDelInterface(ctl, SIOCBRDELIF, bridge, iface);
-}
-#else
-int
-brDeleteInterface(brControl *ctl ATTRIBUTE_UNUSED,
- const char *bridge ATTRIBUTE_UNUSED,
- const char *iface ATTRIBUTE_UNUSED)
-{
- return EINVAL;
-}
-#endif
-
-/**
- * ifGetMtu
- * @ctl: bridge control pointer
- * @ifname: interface name get MTU for
- *
- * This function gets the @mtu value set for a given interface @ifname.
- *
- * Returns the MTU value in case of success.
- * On error, returns -1 and sets errno accordingly
- */
-static int ifGetMtu(brControl *ctl, const char *ifname)
-{
- struct ifreq ifr;
- int len;
-
- if (!ctl || !ifname) {
- errno = EINVAL;
- return -1;
- }
-
- if ((len = strlen(ifname)) >= BR_IFNAME_MAXLEN) {
- errno = EINVAL;
- return -1;
- }
-
- memset(&ifr, 0, sizeof(struct ifreq));
-
- strncpy(ifr.ifr_name, ifname, len);
- ifr.ifr_name[len] = '\0';
-
- if (ioctl(ctl->fd, SIOCGIFMTU, &ifr))
- return -1;
-
- return ifr.ifr_mtu;
-
-}
-
-/**
- * ifSetMtu:
- * @ctl: bridge control pointer
- * @ifname: interface name to set MTU for
- * @mtu: MTU value
- *
- * This function sets the @mtu for a given interface @ifname. Typically
- * used on a tap device to set up for Jumbo Frames.
- *
- * Returns 0 in case of success or an errno code in case of failure.
- */
-static int ifSetMtu(brControl *ctl, const char *ifname, int mtu)
-{
- struct ifreq ifr;
- int len;
-
- if (!ctl || !ifname)
- return EINVAL;
-
- if ((len = strlen(ifname)) >= BR_IFNAME_MAXLEN)
- return EINVAL;
-
- memset(&ifr, 0, sizeof(struct ifreq));
-
- strncpy(ifr.ifr_name, ifname, len);
- ifr.ifr_name[len] = '\0';
- ifr.ifr_mtu = mtu;
-
- return ioctl(ctl->fd, SIOCSIFMTU, &ifr) == 0 ? 0 : errno;
-}
-
-/**
- * brSetInterfaceMtu
- * @ctl: bridge control pointer
- * @bridge: name of the bridge interface
- * @ifname: name of the interface whose MTU we want to set
- *
- * Sets the interface mtu to the same MTU of the bridge
- *
- * Returns 0 in case of success or an errno code in case of failure.
- */
-static int brSetInterfaceMtu(brControl *ctl,
- const char *bridge,
- const char *ifname)
-{
- int mtu = ifGetMtu(ctl, bridge);
-
- if (mtu < 0)
- return errno;
-
- return ifSetMtu(ctl, ifname, mtu);
-}
-
-/**
- * brProbeVnetHdr:
- * @tapfd: a tun/tap file descriptor
- *
- * Check whether it is safe to enable the IFF_VNET_HDR flag on the
- * tap interface.
- *
- * Setting IFF_VNET_HDR enables QEMU's virtio_net driver to allow
- * guests to pass larger (GSO) packets, with partial checksums, to
- * the host. This greatly increases the achievable throughput.
- *
- * It is only useful to enable this when we're setting up a virtio
- * interface. And it is only *safe* to enable it when we know for
- * sure that a) qemu has support for IFF_VNET_HDR and b) the running
- * kernel implements the TUNGETIFF ioctl(), which qemu needs to query
- * the supplied tapfd.
- *
- * Returns 0 in case of success or an errno code in case of failure.
- */
-#ifdef IFF_VNET_HDR
-static int
-brProbeVnetHdr(int tapfd)
-{
-#if defined(IFF_VNET_HDR) && defined(TUNGETFEATURES) && defined(TUNGETIFF)
- unsigned int features;
- struct ifreq dummy;
-
- if (ioctl(tapfd, TUNGETFEATURES, &features) != 0) {
- VIR_INFO0(_("Not enabling IFF_VNET_HDR; "
- "TUNGETFEATURES ioctl() not implemented"));
- return 0;
- }
-
- if (!(features & IFF_VNET_HDR)) {
- VIR_INFO0(_("Not enabling IFF_VNET_HDR; "
- "TUNGETFEATURES ioctl() reports no IFF_VNET_HDR"));
- return 0;
- }
-
- /* The kernel will always return -1 at this point.
- * If TUNGETIFF is not implemented then errno == EBADFD.
- */
- if (ioctl(tapfd, TUNGETIFF, &dummy) != -1 || errno != EBADFD) {
- VIR_INFO0(_("Not enabling IFF_VNET_HDR; "
- "TUNGETIFF ioctl() not implemented"));
- return 0;
- }
-
- VIR_INFO0(_("Enabling IFF_VNET_HDR"));
-
- return 1;
-#else
- (void) tapfd;
- VIR_INFO0(_("Not enabling IFF_VNET_HDR; disabled at build time"));
- return 0;
-#endif
-}
-#endif
-
-/**
- * brAddTap:
- * @ctl: bridge control pointer
- * @bridge: the bridge name
- * @ifname: the interface name (or name template)
- * @vnet_hdr: whether to try enabling IFF_VNET_HDR
- * @tapfd: file descriptor return value for the new tap device
- *
- * This function creates a new tap device on a bridge. @ifname can be either
- * a fixed name or a name template with '%d' for dynamic name allocation.
- * in either case the final name for the bridge will be stored in @ifname.
- * If the @tapfd parameter is supplied, the open tap device file
- * descriptor will be returned, otherwise the TAP device will be made
- * persistent and closed. The caller must use brDeleteTap to remove
- * a persistent TAP devices when it is no longer needed.
- *
- * Returns 0 in case of success or an errno code in case of failure.
- */
-int
-brAddTap(brControl *ctl,
- const char *bridge,
- char **ifname,
- int vnet_hdr,
- int *tapfd)
-{
- int fd, len;
- struct ifreq ifr;
-
- if (!ctl || !ctl->fd || !bridge || !ifname)
- return EINVAL;
-
- if ((fd = open("/dev/net/tun", O_RDWR)) < 0)
- return errno;
-
- memset(&ifr, 0, sizeof(ifr));
-
- ifr.ifr_flags = IFF_TAP|IFF_NO_PI;
-
-#ifdef IFF_VNET_HDR
- if (vnet_hdr && brProbeVnetHdr(fd))
- ifr.ifr_flags |= IFF_VNET_HDR;
-#else
- (void) vnet_hdr;
-#endif
-
- strncpy(ifr.ifr_name, *ifname, IFNAMSIZ-1);
-
- if (ioctl(fd, TUNSETIFF, &ifr) < 0)
- goto error;
-
- len = strlen(ifr.ifr_name);
- if (len >= BR_IFNAME_MAXLEN - 1) {
- errno = EINVAL;
- goto error;
- }
-
- /* We need to set the interface MTU before adding it
- * to the bridge, because the bridge will have its
- * MTU adjusted automatically when we add the new interface.
- */
- if ((errno = brSetInterfaceMtu(ctl, bridge, ifr.ifr_name)))
- goto error;
- if ((errno = brAddInterface(ctl, bridge, ifr.ifr_name)))
- goto error;
- if ((errno = brSetInterfaceUp(ctl, ifr.ifr_name, 1)))
- goto error;
- if (!tapfd &&
- (errno = ioctl(fd, TUNSETPERSIST, 1)))
- goto error;
- VIR_FREE(*ifname);
- if (!(*ifname = strdup(ifr.ifr_name)))
- goto error;
- if (tapfd)
- *tapfd = fd;
- return 0;
-
- error:
- close(fd);
-
- return errno;
-}
-
-int brDeleteTap(brControl *ctl,
- const char *ifname)
-{
- struct ifreq try;
- int len;
- int fd;
-
- if (!ctl || !ctl->fd || !ifname)
- return EINVAL;
-
- if ((fd = open("/dev/net/tun", O_RDWR)) < 0)
- return errno;
-
- memset(&try, 0, sizeof(struct ifreq));
- try.ifr_flags = IFF_TAP|IFF_NO_PI;
-
- len = strlen(ifname);
- if (len >= BR_IFNAME_MAXLEN - 1) {
- errno = EINVAL;
- goto error;
- }
-
- strncpy(try.ifr_name, ifname, len);
- try.ifr_name[len] = '\0';
-
- if (ioctl(fd, TUNSETIFF, &try) == 0) {
- if ((errno = ioctl(fd, TUNSETPERSIST, 0)))
- goto error;
- }
-
- error:
- close(fd);
-
- return errno;
-}
-
-
-/**
- * brSetInterfaceUp:
- * @ctl: bridge control pointer
- * @ifname: the interface name
- * @up: 1 for up, 0 for down
- *
- * Function to control if an interface is activated (up, 1) or not (down, 0)
- *
- * Returns 0 in case of success or an errno code in case of failure.
- */
-int
-brSetInterfaceUp(brControl *ctl,
- const char *ifname,
- int up)
-{
- struct ifreq ifr;
- int len;
- int flags;
-
- if (!ctl || !ifname)
- return EINVAL;
-
- if ((len = strlen(ifname)) >= BR_IFNAME_MAXLEN)
- return EINVAL;
-
- memset(&ifr, 0, sizeof(struct ifreq));
-
- strncpy(ifr.ifr_name, ifname, len);
- ifr.ifr_name[len] = '\0';
-
- if (ioctl(ctl->fd, SIOCGIFFLAGS, &ifr) < 0)
- return errno;
-
- flags = up ? (ifr.ifr_flags | IFF_UP) : (ifr.ifr_flags & ~IFF_UP);
-
- if (ifr.ifr_flags != flags) {
- ifr.ifr_flags = flags;
-
- if (ioctl(ctl->fd, SIOCSIFFLAGS, &ifr) < 0)
- return errno;
- }
-
- return 0;
-}
-
-/**
- * brGetInterfaceUp:
- * @ctl: bridge control pointer
- * @ifname: the interface name
- * @up: where to store the status
- *
- * Function to query if an interface is activated (1) or not (0)
- *
- * Returns 0 in case of success or an errno code in case of failure.
- */
-int
-brGetInterfaceUp(brControl *ctl,
- const char *ifname,
- int *up)
-{
- struct ifreq ifr;
- int len;
-
- if (!ctl || !ifname || !up)
- return EINVAL;
-
- if ((len = strlen(ifname)) >= BR_IFNAME_MAXLEN)
- return EINVAL;
-
- memset(&ifr, 0, sizeof(struct ifreq));
-
- strncpy(ifr.ifr_name, ifname, len);
- ifr.ifr_name[len] = '\0';
-
- if (ioctl(ctl->fd, SIOCGIFFLAGS, &ifr) < 0)
- return errno;
-
- *up = (ifr.ifr_flags & IFF_UP) ? 1 : 0;
-
- return 0;
-}
-
-static int
-brSetInetAddr(brControl *ctl,
- const char *ifname,
- int cmd,
- const char *addr)
-{
- union {
- struct sockaddr sa;
- struct sockaddr_in sa_in;
- } s;
- struct ifreq ifr;
- struct in_addr inaddr;
- int len, ret;
-
- if (!ctl || !ctl->fd || !ifname || !addr)
- return EINVAL;
-
- if ((len = strlen(ifname)) >= BR_IFNAME_MAXLEN)
- return EINVAL;
-
- memset(&ifr, 0, sizeof(struct ifreq));
-
- strncpy(ifr.ifr_name, ifname, len);
- ifr.ifr_name[len] = '\0';
-
- if ((ret = inet_pton(AF_INET, addr, &inaddr)) < 0)
- return errno;
- else if (ret == 0)
- return EINVAL;
-
- s.sa_in.sin_family = AF_INET;
- s.sa_in.sin_addr = inaddr;
-
- ifr.ifr_addr = s.sa;
-
- if (ioctl(ctl->fd, cmd, &ifr) < 0)
- return errno;
-
- return 0;
-}
-
-static int
-brGetInetAddr(brControl *ctl,
- const char *ifname,
- int cmd,
- char *addr,
- int maxlen)
-{
- struct ifreq ifr;
- struct in_addr *inaddr;
- int len;
-
- if (!ctl || !ctl->fd || !ifname || !addr)
- return EINVAL;
-
- if ((len = strlen(ifname)) >= BR_IFNAME_MAXLEN)
- return EINVAL;
-
- memset(&ifr, 0, sizeof(struct ifreq));
-
- strncpy(ifr.ifr_name, ifname, len);
- ifr.ifr_name[len] = '\0';
-
- if (ioctl(ctl->fd, cmd, &ifr) < 0)
- return errno;
-
- if (maxlen < BR_INET_ADDR_MAXLEN || ifr.ifr_addr.sa_family != AF_INET)
- return EFAULT;
-
- inaddr = &((struct sockaddr_in *)&ifr.ifr_data)->sin_addr;
-
- if (!inet_ntop(AF_INET, inaddr, addr, maxlen))
- return errno;
-
- return 0;
-}
-
-/**
- * brSetInetAddress:
- * @ctl: bridge control pointer
- * @ifname: the interface name
- * @addr: the string representation of the IP address
- *
- * Function to bind the interface to an IP address, it should handle
- * IPV4 and IPv6. The string for addr would be of the form
- * "ddd.ddd.ddd.ddd" assuming the common IPv4 format.
- *
- * Returns 0 in case of success or an errno code in case of failure.
- */
-
-int
-brSetInetAddress(brControl *ctl,
- const char *ifname,
- const char *addr)
-{
- return brSetInetAddr(ctl, ifname, SIOCSIFADDR, addr);
-}
-
-/**
- * brGetInetAddress:
- * @ctl: bridge control pointer
- * @ifname: the interface name
- * @addr: the array for the string representation of the IP address
- * @maxlen: size of @addr in bytes
- *
- * Function to get the IP address of an interface, it should handle
- * IPV4 and IPv6. The returned string for addr would be of the form
- * "ddd.ddd.ddd.ddd" assuming the common IPv4 format.
- *
- * Returns 0 in case of success or an errno code in case of failure.
- */
-
-int
-brGetInetAddress(brControl *ctl,
- const char *ifname,
- char *addr,
- int maxlen)
-{
- return brGetInetAddr(ctl, ifname, SIOCGIFADDR, addr, maxlen);
-}
-
-/**
- * brSetInetNetmask:
- * @ctl: bridge control pointer
- * @ifname: the interface name
- * @addr: the string representation of the netmask
- *
- * Function to set the netmask of an interface, it should handle
- * IPV4 and IPv6 forms. The string for addr would be of the form
- * "ddd.ddd.ddd.ddd" assuming the common IPv4 format.
- *
- * Returns 0 in case of success or an errno code in case of failure.
- */
-
-int
-brSetInetNetmask(brControl *ctl,
- const char *ifname,
- const char *addr)
-{
- return brSetInetAddr(ctl, ifname, SIOCSIFNETMASK, addr);
-}
-
-/**
- * brGetInetNetmask:
- * @ctl: bridge control pointer
- * @ifname: the interface name
- * @addr: the array for the string representation of the netmask
- * @maxlen: size of @addr in bytes
- *
- * Function to get the netmask of an interface, it should handle
- * IPV4 and IPv6. The returned string for addr would be of the form
- * "ddd.ddd.ddd.ddd" assuming the common IPv4 format.
- *
- * Returns 0 in case of success or an errno code in case of failure.
- */
-
-int
-brGetInetNetmask(brControl *ctl,
- const char *ifname,
- char *addr,
- int maxlen)
-{
- return brGetInetAddr(ctl, ifname, SIOCGIFNETMASK, addr, maxlen);
-}
-
-
-/**
- * brSetForwardDelay:
- * @ctl: bridge control pointer
- * @bridge: the bridge name
- * @delay: delay in seconds
- *
- * Set the bridge forward delay
- *
- * Returns 0 in case of success or -1 on failure
- */
-
-int
-brSetForwardDelay(brControl *ctl ATTRIBUTE_UNUSED,
- const char *bridge,
- int delay)
-{
- char delayStr[30];
- const char *const progargv[] = {
- BRCTL, "setfd", bridge, delayStr, NULL
- };
-
- snprintf(delayStr, sizeof(delayStr), "%d", delay);
-
- if (virRun(NULL, progargv, NULL) < 0)
- return -1;
-
- return 0;
-}
-
-/**
- * brSetEnableSTP:
- * @ctl: bridge control pointer
- * @bridge: the bridge name
- * @enable: 1 to enable, 0 to disable
- *
- * Control whether the bridge participates in the spanning tree protocol,
- * in general don't disable it without good reasons.
- *
- * Returns 0 in case of success or -1 on failure
- */
-int
-brSetEnableSTP(brControl *ctl ATTRIBUTE_UNUSED,
- const char *bridge,
- int enable)
-{
- const char *setting = enable ? "on" : "off";
- const char *const progargv[] = {
- BRCTL, "stp", bridge, setting, NULL
- };
-
- if (virRun(NULL, progargv, NULL) < 0)
- return -1;
-
- return 0;
-}
-
-#endif /* WITH_BRIDGE */
+++ /dev/null
-/*
- * Copyright (C) 2007 Red Hat, Inc.
- *
- * 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
- *
- * Authors:
- * Mark McLoughlin <markmc@redhat.com>
- */
-
-#ifndef __QEMUD_BRIDGE_H__
-#define __QEMUD_BRIDGE_H__
-
-#include <config.h>
-
-#if defined(WITH_BRIDGE)
-
-#include <net/if.h>
-#include <netinet/in.h>
-
-/**
- * BR_IFNAME_MAXLEN:
- * maximum size in byte of the name for an interface
- */
-#define BR_IFNAME_MAXLEN IF_NAMESIZE
-
-/**
- * BR_INET_ADDR_MAXLEN:
- * maximum size in bytes for an inet addess name
- */
-#define BR_INET_ADDR_MAXLEN INET_ADDRSTRLEN
-
-typedef struct _brControl brControl;
-
-int brInit (brControl **ctl);
-void brShutdown (brControl *ctl);
-
-int brAddBridge (brControl *ctl,
- const char *name);
-int brDeleteBridge (brControl *ctl,
- const char *name);
-int brHasBridge (brControl *ctl,
- const char *name);
-
-int brAddInterface (brControl *ctl,
- const char *bridge,
- const char *iface);
-int brDeleteInterface (brControl *ctl,
- const char *bridge,
- const char *iface);
-
-enum {
- BR_TAP_VNET_HDR = (1 << 0),
- BR_TAP_PERSIST = (1 << 1),
-};
-
-int brAddTap (brControl *ctl,
- const char *bridge,
- char **ifname,
- int features,
- int *tapfd);
-
-int brDeleteTap (brControl *ctl,
- const char *ifname);
-
-int brSetInterfaceUp (brControl *ctl,
- const char *ifname,
- int up);
-int brGetInterfaceUp (brControl *ctl,
- const char *ifname,
- int *up);
-
-int brSetInetAddress (brControl *ctl,
- const char *ifname,
- const char *addr);
-int brGetInetAddress (brControl *ctl,
- const char *ifname,
- char *addr,
- int maxlen);
-int brSetInetNetmask (brControl *ctl,
- const char *ifname,
- const char *netmask);
-int brGetInetNetmask (brControl *ctl,
- const char *ifname,
- char *netmask,
- int maxlen);
-
-int brSetForwardDelay (brControl *ctl,
- const char *bridge,
- int delay);
-int brGetForwardDelay (brControl *ctl,
- const char *bridge,
- int *delay);
-int brSetEnableSTP (brControl *ctl,
- const char *bridge,
- int enable);
-int brGetEnableSTP (brControl *ctl,
- const char *bridge,
- int *enable);
-
-#endif /* WITH_BRIDGE */
-
-#endif /* __QEMUD_BRIDGE_H__ */
+++ /dev/null
-/*
- * buf.c: buffers for libvirt
- *
- * Copyright (C) 2005-2008 Red Hat, Inc.
- *
- * See COPYING.LIB for the License of this software
- *
- * Daniel Veillard <veillard@redhat.com>
- */
-
-#include <config.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdarg.h>
-#include "c-ctype.h"
-
-#define __VIR_BUFFER_C__
-
-#include "buf.h"
-#include "memory.h"
-
-
-/* If adding more fields, ensure to edit buf.h to match
- the number of fields */
-struct _virBuffer {
- unsigned int size;
- unsigned int use;
- unsigned int error;
- char *content;
-};
-
-/**
- * virBufferFail
- * @buf: the buffer
- *
- * Mark the buffer has having failed a memory allocation,
- * freeing the content and setting the error flag.
- */
-static void
-virBufferNoMemory(const virBufferPtr buf)
-{
- VIR_FREE(buf->content);
- buf->size = 0;
- buf->use = 0;
- buf->error = 1;
-}
-
-/**
- * virBufferGrow:
- * @buf: the buffer
- * @len: the minimum free size to allocate on top of existing used space
- *
- * Grow the available space of a buffer to at least @len bytes.
- *
- * Returns zero on success or -1 on error
- */
-static int
-virBufferGrow(virBufferPtr buf, unsigned int len)
-{
- int size;
-
- if (buf->error)
- return -1;
-
- if ((len + buf->use) < buf->size)
- return 0;
-
- size = buf->use + len + 1000;
-
- if (VIR_REALLOC_N(buf->content, size) < 0) {
- virBufferNoMemory(buf);
- return -1;
- }
- buf->size = size;
- return 0;
-}
-
-/**
- * virBufferAdd:
- * @buf: the buffer to add to
- * @str: the string
- * @len: the number of bytes to add
- *
- * Add a string range to an XML buffer. if len == -1, the length of
- * str is recomputed to the full string.
- *
- */
-void
-virBufferAdd(const virBufferPtr buf, const char *str, int len)
-{
- unsigned int needSize;
-
- if ((str == NULL) || (buf == NULL) || (len == 0))
- return;
-
- if (buf->error)
- return;
-
- if (len < 0)
- len = strlen(str);
-
- needSize = buf->use + len + 2;
- if (needSize > buf->size &&
- virBufferGrow(buf, needSize - buf->use) < 0)
- return;
-
- memcpy (&buf->content[buf->use], str, len);
- buf->use += len;
- buf->content[buf->use] = '\0';
-}
-
-/**
- * virBufferAddChar:
- * @buf: the buffer to add to
- * @c: the character to add
- *
- * Add a single character 'c' to a buffer.
- *
- */
-void
-virBufferAddChar (virBufferPtr buf, char c)
-{
- unsigned int needSize;
-
- if (buf == NULL)
- return;
-
- if (buf->error)
- return;
-
- needSize = buf->use + 2;
- if (needSize > buf->size &&
- virBufferGrow (buf, needSize - buf->use) < 0)
- return;
-
- buf->content[buf->use++] = c;
- buf->content[buf->use] = '\0';
-}
-
-/**
- * virBufferContentAndReset:
- * @buf: Buffer
- *
- * Get the content from the buffer and free (only) the buffer structure.
- * The caller owns the returned string & should free it when no longer
- * required. The buffer object is reset to its initial state.
- *
- * Returns the buffer content or NULL in case of error.
- */
-char *
-virBufferContentAndReset(const virBufferPtr buf)
-{
- char *str;
- if (buf == NULL)
- return NULL;
-
- if (buf->error) {
- memset(buf, 0, sizeof(*buf));
- return NULL;
- }
-
- str = buf->content;
- memset(buf, 0, sizeof(*buf));
- return str;
-}
-
-/**
- * virBufferError:
- * @buf: the buffer
- *
- * Check to see if the buffer is in an error state due
- * to failed memory allocation
- *
- * Return true if in error, 0 if normal
- */
-int
-virBufferError(const virBufferPtr buf)
-{
- if (buf == NULL)
- return 1;
-
- return buf->error;
-}
-
-/**
- * virBufferUse:
- * @buf: the usage of the string in the buffer
- *
- * Return the string usage in bytes
- */
-unsigned int
-virBufferUse(const virBufferPtr buf)
-{
- if (buf == NULL)
- return 0;
-
- return buf->use;
-}
-
-/**
- * virBufferVSprintf:
- * @buf: the buffer to dump
- * @format: the format
- * @...: the variable list of arguments
- *
- * Do a formatted print to an XML buffer.
- */
-void
-virBufferVSprintf(const virBufferPtr buf, const char *format, ...)
-{
- int size, count, grow_size;
- va_list locarg, argptr;
-
- if ((format == NULL) || (buf == NULL))
- return;
-
- if (buf->error)
- return;
-
- if (buf->size == 0 &&
- virBufferGrow(buf, 100) < 0)
- return;
-
- size = buf->size - buf->use - 1;
- va_start(argptr, format);
- va_copy(locarg, argptr);
- while (((count = vsnprintf(&buf->content[buf->use], size, format,
- locarg)) < 0) || (count >= size - 1)) {
- buf->content[buf->use] = 0;
- va_end(locarg);
-
- grow_size = (count > 1000) ? count : 1000;
- if (virBufferGrow(buf, grow_size) < 0)
- return;
-
- size = buf->size - buf->use - 1;
- va_copy(locarg, argptr);
- }
- va_end(locarg);
- buf->use += count;
- buf->content[buf->use] = '\0';
-}
-
-/**
- * virBufferEscapeString:
- * @buf: the buffer to dump
- * @format: a printf like format string but with only one %s parameter
- * @str: the string argument which need to be escaped
- *
- * Do a formatted print with a single string to an XML buffer. The string
- * is escaped to avoid generating a not well-formed XML instance.
- */
-void
-virBufferEscapeString(const virBufferPtr buf, const char *format, const char *str)
-{
- int size, count, len, grow_size;
- char *escaped, *out;
- const char *cur;
-
- if ((format == NULL) || (buf == NULL) || (str == NULL))
- return;
-
- if (buf->error)
- return;
-
- len = strlen(str);
- if (VIR_ALLOC_N(escaped, 6 * len + 1) < 0) {
- virBufferNoMemory(buf);
- return;
- }
-
- cur = str;
- out = escaped;
- while (*cur != 0) {
- if (*cur == '<') {
- *out++ = '&';
- *out++ = 'l';
- *out++ = 't';
- *out++ = ';';
- } else if (*cur == '>') {
- *out++ = '&';
- *out++ = 'g';
- *out++ = 't';
- *out++ = ';';
- } else if (*cur == '&') {
- *out++ = '&';
- *out++ = 'a';
- *out++ = 'm';
- *out++ = 'p';
- *out++ = ';';
- } else if (*cur == '"') {
- *out++ = '&';
- *out++ = 'q';
- *out++ = 'u';
- *out++ = 'o';
- *out++ = 't';
- *out++ = ';';
- } else if (*cur == '\'') {
- *out++ = '&';
- *out++ = 'a';
- *out++ = 'p';
- *out++ = 'o';
- *out++ = 's';
- *out++ = ';';
- } else if (((unsigned char)*cur >= 0x20) || (*cur == '\n') || (*cur == '\t') ||
- (*cur == '\r')) {
- /*
- * default case, just copy !
- * Note that character over 0x80 are likely to give problem
- * with UTF-8 XML, but since our string don't have an encoding
- * it's hard to handle properly we have to assume it's UTF-8 too
- */
- *out++ = *cur;
- }
- cur++;
- }
- *out = 0;
-
- size = buf->size - buf->use - 1;
- while (((count = snprintf(&buf->content[buf->use], size, format,
- (char *)escaped)) < 0) || (count >= size - 1)) {
- buf->content[buf->use] = 0;
- grow_size = (count > 1000) ? count : 1000;
- if (virBufferGrow(buf, grow_size) < 0) {
- VIR_FREE(escaped);
- return;
- }
- size = buf->size - buf->use - 1;
- }
- buf->use += count;
- buf->content[buf->use] = '\0';
- VIR_FREE(escaped);
-}
-
-/**
- * virBufferURIEncodeString:
- * @buf: the buffer to append to
- * @str: the string argument which will be URI-encoded
- *
- * Append the string to the buffer. The string will be URI-encoded
- * during the append (ie any non alpha-numeric characters are replaced
- * with '%xx' hex sequences).
- */
-void
-virBufferURIEncodeString (virBufferPtr buf, const char *str)
-{
- int grow_size = 0;
- const char *p;
- unsigned char uc;
- const char *hex = "0123456789abcdef";
-
- if ((buf == NULL) || (str == NULL))
- return;
-
- if (buf->error)
- return;
-
- for (p = str; *p; ++p) {
- if (c_isalnum(*p))
- grow_size++;
- else
- grow_size += 3; /* %ab */
- }
-
- if (virBufferGrow (buf, grow_size) < 0)
- return;
-
- for (p = str; *p; ++p) {
- if (c_isalnum(*p))
- buf->content[buf->use++] = *p;
- else {
- uc = (unsigned char) *p;
- buf->content[buf->use++] = '%';
- buf->content[buf->use++] = hex[uc >> 4];
- buf->content[buf->use++] = hex[uc & 0xf];
- }
- }
-
- buf->content[buf->use] = '\0';
-}
-
-/**
- * virBufferStrcat:
- * @buf: the buffer to dump
- * @...: the variable list of strings, the last argument must be NULL
- *
- * Concatenate strings to an XML buffer.
- */
-void
-virBufferStrcat(virBufferPtr buf, ...)
-{
- va_list ap;
- char *str;
-
- if (buf->error)
- return;
-
- va_start(ap, buf);
-
- while ((str = va_arg(ap, char *)) != NULL) {
- unsigned int len = strlen(str);
- unsigned int needSize = buf->use + len + 2;
-
- if (needSize > buf->size) {
- if (virBufferGrow(buf, needSize - buf->use) < 0)
- return;
- }
- memcpy(&buf->content[buf->use], str, len);
- buf->use += len;
- buf->content[buf->use] = 0;
- }
- va_end(ap);
-}
+++ /dev/null
-/*
- * buf.h: buffers for libvirt
- *
- * Copyright (C) 2005-2008 Red Hat, Inc.
- *
- * See COPYING.LIB for the License of this software
- *
- * Daniel Veillard <veillard@redhat.com>
- */
-
-#ifndef __VIR_BUFFER_H__
-#define __VIR_BUFFER_H__
-
-#include "internal.h"
-
-/**
- * virBuffer:
- *
- * A buffer structure.
- */
-typedef struct _virBuffer virBuffer;
-typedef virBuffer *virBufferPtr;
-
-#ifndef __VIR_BUFFER_C__
-#define VIR_BUFFER_INITIALIZER { 0, 0, 0, NULL }
-
-/* This struct must be kept in syn with the real struct
- in the buf.c impl file */
-struct _virBuffer {
- unsigned int a;
- unsigned int b;
- unsigned int c;
- char *d;
-};
-#endif
-
-char *virBufferContentAndReset(const virBufferPtr buf);
-int virBufferError(const virBufferPtr buf);
-unsigned int virBufferUse(const virBufferPtr buf);
-void virBufferAdd(const virBufferPtr buf, const char *str, int len);
-void virBufferAddChar(const virBufferPtr buf, char c);
-void virBufferVSprintf(const virBufferPtr buf, const char *format, ...)
- ATTRIBUTE_FMT_PRINTF(2, 3);
-void virBufferStrcat(const virBufferPtr buf, ...);
-void virBufferEscapeString(const virBufferPtr buf, const char *format, const char *str);
-void virBufferURIEncodeString (const virBufferPtr buf, const char *str);
-
-#define virBufferAddLit(buf_, literal_string_) \
- virBufferAdd (buf_, "" literal_string_ "", sizeof literal_string_ - 1)
-
-#endif /* __VIR_BUFFER_H__ */
+++ /dev/null
-/*
- * cgroup.c: Tools for managing cgroups
- *
- * Copyright IBM Corp. 2008
- *
- * See COPYING.LIB for the License of this software
- *
- * Authors:
- * Dan Smith <danms@us.ibm.com>
- */
-#include <config.h>
-
-#include <stdio.h>
-#include <stdint.h>
-#include <inttypes.h>
-#include <mntent.h>
-#include <fcntl.h>
-#include <string.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <stdbool.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <libgen.h>
-
-#include "internal.h"
-#include "util.h"
-#include "memory.h"
-#include "cgroup.h"
-#include "logging.h"
-
-#define CGROUP_MAX_VAL 512
-
-VIR_ENUM_IMPL(virCgroupController, VIR_CGROUP_CONTROLLER_LAST,
- "cpu", "cpuacct", "cpuset", "memory", "devices");
-
-struct virCgroupController {
- int type;
- char *mountPoint;
- char *placement;
-};
-
-struct virCgroup {
- char *path;
-
- struct virCgroupController controllers[VIR_CGROUP_CONTROLLER_LAST];
-};
-
-/**
- * virCgroupFree:
- *
- * @group: The group structure to free
- */
-void virCgroupFree(virCgroupPtr *group)
-{
- int i;
-
- if (*group == NULL)
- return;
-
- for (i = 0 ; i < VIR_CGROUP_CONTROLLER_LAST ; i++) {
- VIR_FREE((*group)->controllers[i].mountPoint);
- VIR_FREE((*group)->controllers[i].placement);
- }
-
- VIR_FREE((*group)->path);
- VIR_FREE(*group);
-}
-
-
-/*
- * Process /proc/mounts figuring out what controllers are
- * mounted and where
- */
-static int virCgroupDetectMounts(virCgroupPtr group)
-{
- int i;
- FILE *mounts = NULL;
- struct mntent entry;
- char buf[CGROUP_MAX_VAL];
-
- mounts = fopen("/proc/mounts", "r");
- if (mounts == NULL) {
- VIR_ERROR0("Unable to open /proc/mounts");
- return -ENOENT;
- }
-
- while (getmntent_r(mounts, &entry, buf, sizeof(buf)) != NULL) {
- if (STRNEQ(entry.mnt_type, "cgroup"))
- continue;
-
- for (i = 0 ; i < VIR_CGROUP_CONTROLLER_LAST ; i++) {
- const char *typestr = virCgroupControllerTypeToString(i);
- int typelen = strlen(typestr);
- char *tmp = entry.mnt_opts;
- while (tmp) {
- char *next = strchr(tmp, ',');
- int len;
- if (next) {
- len = next-tmp;
- next++;
- } else {
- len = strlen(tmp);
- }
- if (typelen == len && STREQLEN(typestr, tmp, len) &&
- !(group->controllers[i].mountPoint = strdup(entry.mnt_dir)))
- goto no_memory;
- tmp = next;
- }
- }
- }
-
- fclose(mounts);
-
- return 0;
-
-no_memory:
- if (mounts)
- fclose(mounts);
- return -ENOMEM;
-}
-
-
-/*
- * Process /proc/self/cgroup figuring out what cgroup
- * sub-path the current process is assigned to. ie not
- * neccessarily in the root
- */
-static int virCgroupDetectPlacement(virCgroupPtr group)
-{
- int i;
- FILE *mapping = NULL;
- char line[1024];
-
- mapping = fopen("/proc/self/cgroup", "r");
- if (mapping == NULL) {
- VIR_ERROR0("Unable to open /proc/self/cgroup");
- return -ENOENT;
- }
-
- while (fgets(line, sizeof(line), mapping) != NULL) {
- char *controllers = strchr(line, ':');
- char *path = controllers ? strchr(controllers+1, ':') : NULL;
- char *nl = path ? strchr(path, '\n') : NULL;
-
- if (!controllers || !path)
- continue;
-
- if (nl)
- *nl = '\0';
-
- *path = '\0';
- controllers++;
- path++;
-
- for (i = 0 ; i < VIR_CGROUP_CONTROLLER_LAST ; i++) {
- const char *typestr = virCgroupControllerTypeToString(i);
- int typelen = strlen(typestr);
- char *tmp = controllers;
- while (tmp) {
- char *next = strchr(tmp, ',');
- int len;
- if (next) {
- len = next-tmp;
- next++;
- } else {
- len = strlen(tmp);
- }
- if (typelen == len && STREQLEN(typestr, tmp, len) &&
- !(group->controllers[i].placement = strdup(STREQ(path, "/") ? "" : path)))
- goto no_memory;
-
- tmp = next;
- }
- }
- }
-
- fclose(mapping);
-
- return 0;
-
-no_memory:
- return -ENOMEM;
-
-}
-
-static int virCgroupDetect(virCgroupPtr group)
-{
- int any = 0;
- int rc;
- int i;
-
- rc = virCgroupDetectMounts(group);
- if (rc < 0) {
- VIR_ERROR("Failed to detect mounts for %s", group->path);
- return rc;
- }
-
- /* Check that at least 1 controller is available */
- for (i = 0 ; i < VIR_CGROUP_CONTROLLER_LAST ; i++) {
- if (group->controllers[i].mountPoint != NULL)
- any = 1;
- }
- if (!any)
- return -ENXIO;
-
-
- rc = virCgroupDetectPlacement(group);
-
- if (rc == 0) {
- /* Check that for every mounted controller, we found our placement */
- for (i = 0 ; i < VIR_CGROUP_CONTROLLER_LAST ; i++) {
- if (!group->controllers[i].mountPoint)
- continue;
-
- if (!group->controllers[i].placement) {
- VIR_ERROR("Could not find placement for controller %s at %s",
- virCgroupControllerTypeToString(i),
- group->controllers[i].placement);
- rc = -ENOENT;
- break;
- }
-
- VIR_DEBUG("Detected mount/mapping %i:%s at %s in %s", i,
- virCgroupControllerTypeToString(i),
- group->controllers[i].mountPoint,
- group->controllers[i].placement);
- }
- } else {
- VIR_ERROR("Failed to detect mapping for %s", group->path);
- }
-
- return rc;
-}
-
-
-static int virCgroupPathOfController(virCgroupPtr group,
- int controller,
- const char *key,
- char **path)
-{
- if (group->controllers[controller].mountPoint == NULL)
- return -ENOENT;
-
- if (group->controllers[controller].placement == NULL)
- return -ENOENT;
-
- if (virAsprintf(path, "%s%s%s/%s",
- group->controllers[controller].mountPoint,
- group->controllers[controller].placement,
- STREQ(group->path, "/") ? "" : group->path,
- key ? key : "") == -1)
- return -ENOMEM;
-
- return 0;
-}
-
-
-static int virCgroupSetValueStr(virCgroupPtr group,
- int controller,
- const char *key,
- const char *value)
-{
- int rc = 0;
- char *keypath = NULL;
-
- rc = virCgroupPathOfController(group, controller, key, &keypath);
- if (rc != 0)
- return rc;
-
- VIR_DEBUG("Set value %s", keypath);
- rc = virFileWriteStr(keypath, value);
- if (rc < 0) {
- DEBUG("Failed to write value '%s': %m", value);
- rc = -errno;
- } else {
- rc = 0;
- }
-
- VIR_FREE(keypath);
-
- return rc;
-}
-
-static int virCgroupGetValueStr(virCgroupPtr group,
- int controller,
- const char *key,
- char **value)
-{
- int rc;
- char *keypath = NULL;
-
- *value = NULL;
-
- rc = virCgroupPathOfController(group, controller, key, &keypath);
- if (rc != 0) {
- DEBUG("No path of %s, %s", group->path, key);
- return rc;
- }
-
- VIR_DEBUG("Get value %s", keypath);
-
- rc = virFileReadAll(keypath, 1024, value);
- if (rc < 0) {
- DEBUG("Failed to read %s: %m\n", keypath);
- rc = -errno;
- } else {
- rc = 0;
- }
-
- VIR_FREE(keypath);
-
- return rc;
-}
-
-static int virCgroupSetValueU64(virCgroupPtr group,
- int controller,
- const char *key,
- uint64_t value)
-{
- char *strval = NULL;
- int rc;
-
- if (virAsprintf(&strval, "%" PRIu64, value) == -1)
- return -ENOMEM;
-
- rc = virCgroupSetValueStr(group, controller, key, strval);
-
- VIR_FREE(strval);
-
- return rc;
-}
-
-
-#if 0
-/* This is included for completeness, but not yet used */
-
-static int virCgroupSetValueI64(virCgroupPtr group,
- int controller,
- const char *key,
- int64_t value)
-{
- char *strval = NULL;
- int rc;
-
- if (virAsprintf(&strval, "%" PRIi64, value) == -1)
- return -ENOMEM;
-
- rc = virCgroupSetValueStr(group, controller, key, strval);
-
- VIR_FREE(strval);
-
- return rc;
-}
-
-static int virCgroupGetValueI64(virCgroupPtr group,
- int controller,
- const char *key,
- int64_t *value)
-{
- char *strval = NULL;
- int rc = 0;
-
- rc = virCgroupGetValueStr(group, controller, key, &strval);
- if (rc != 0)
- goto out;
-
- if (sscanf(strval, "%" SCNi64, value) != 1)
- rc = -EINVAL;
-out:
- VIR_FREE(strval);
-
- return rc;
-}
-#endif
-
-static int virCgroupGetValueU64(virCgroupPtr group,
- int controller,
- const char *key,
- uint64_t *value)
-{
- char *strval = NULL;
- int rc = 0;
-
- rc = virCgroupGetValueStr(group, controller, key, &strval);
- if (rc != 0)
- goto out;
-
- if (sscanf(strval, "%" SCNu64, value) != 1)
- rc = -EINVAL;
-out:
- VIR_FREE(strval);
-
- return rc;
-}
-
-
-static int virCgroupCpuSetInherit(virCgroupPtr parent, virCgroupPtr group)
-{
- int i;
- int rc = 0;
- const char *inherit_values[] = {
- "cpuset.cpus",
- "cpuset.mems",
- };
-
- VIR_DEBUG("Setting up inheritance %s -> %s", parent->path, group->path);
- for (i = 0; i < ARRAY_CARDINALITY(inherit_values) ; i++) {
- char *value;
-
- rc = virCgroupGetValueStr(parent,
- VIR_CGROUP_CONTROLLER_CPUSET,
- inherit_values[i],
- &value);
- if (rc != 0) {
- VIR_ERROR("Failed to get %s %d", inherit_values[i], rc);
- break;
- }
-
- VIR_DEBUG("Inherit %s = %s", inherit_values[i], value);
-
- rc = virCgroupSetValueStr(group,
- VIR_CGROUP_CONTROLLER_CPUSET,
- inherit_values[i],
- value);
-
- if (rc != 0) {
- VIR_ERROR("Failed to set %s %d", inherit_values[i], rc);
- break;
- }
- }
-
- return rc;
-}
-
-static int virCgroupMakeGroup(virCgroupPtr parent, virCgroupPtr group)
-{
- int i;
- int rc = 0;
-
- VIR_DEBUG("Make group %s", group->path);
- for (i = 0 ; i < VIR_CGROUP_CONTROLLER_LAST ; i++) {
- char *path = NULL;
-
- /* Skip over controllers that aren't mounted */
- if (!group->controllers[i].mountPoint)
- continue;
-
- rc = virCgroupPathOfController(group, i, "", &path);
- if (rc < 0)
- return rc;
-
- VIR_DEBUG("Make controller %s", path);
- if (access(path, F_OK) != 0) {
- if (mkdir(path, 0755) < 0) {
- rc = -errno;
- VIR_FREE(path);
- break;
- }
- if (group->controllers[VIR_CGROUP_CONTROLLER_CPUSET].mountPoint != NULL &&
- (i == VIR_CGROUP_CONTROLLER_CPUSET ||
- STREQ(group->controllers[i].mountPoint, group->controllers[VIR_CGROUP_CONTROLLER_CPUSET].mountPoint))) {
- rc = virCgroupCpuSetInherit(parent, group);
- if (rc != 0)
- break;
- }
- }
-
- VIR_FREE(path);
- }
-
- return rc;
-}
-
-
-static int virCgroupNew(const char *path,
- virCgroupPtr *group)
-{
- int rc = 0;
- char *typpath = NULL;
-
- VIR_DEBUG("New group %s", path);
- *group = NULL;
-
- if (VIR_ALLOC((*group)) != 0) {
- rc = -ENOMEM;
- goto err;
- }
-
- if (!((*group)->path = strdup(path))) {
- rc = -ENOMEM;
- goto err;
- }
-
- rc = virCgroupDetect(*group);
- if (rc < 0)
- goto err;
-
- return rc;
-err:
- virCgroupFree(group);
- *group = NULL;
-
- VIR_FREE(typpath);
-
- return rc;
-}
-
-static int virCgroupAppRoot(int privileged,
- virCgroupPtr *group)
-{
- virCgroupPtr rootgrp = NULL;
- int rc;
-
- rc = virCgroupNew("/", &rootgrp);
- if (rc != 0)
- return rc;
-
- if (privileged) {
- rc = virCgroupNew("/libvirt", group);
- } else {
- char *rootname;
- char *username;
- username = virGetUserName(NULL, getuid());
- if (!username) {
- rc = -ENOMEM;
- goto cleanup;
- }
- rc = virAsprintf(&rootname, "/libvirt-%s", username);
- VIR_FREE(username);
- if (rc < 0) {
- rc = -ENOMEM;
- goto cleanup;
- }
-
- rc = virCgroupNew(rootname, group);
- VIR_FREE(rootname);
- }
- if (rc != 0)
- goto cleanup;
-
- rc = virCgroupMakeGroup(rootgrp, *group);
-
-cleanup:
- virCgroupFree(&rootgrp);
- return rc;
-}
-
-
-/**
- * virCgroupRemove:
- *
- * @group: The group to be removed
- *
- * Returns: 0 on success
- */
-int virCgroupRemove(virCgroupPtr group)
-{
- int rc = 0;
- int i;
- char *grppath = NULL;
-
- for (i = 0 ; i < VIR_CGROUP_CONTROLLER_LAST ; i++) {
- /* Skip over controllers not mounted */
- if (!group->controllers[i].mountPoint)
- continue;
-
- if (virCgroupPathOfController(group,
- i,
- NULL,
- &grppath) != 0)
- continue;
-
- DEBUG("Removing cgroup %s", grppath);
- if (rmdir(grppath) != 0 && errno != ENOENT) {
- rc = -errno;
- }
- VIR_FREE(grppath);
- }
-
- return rc;
-}
-
-/**
- * virCgroupAddTask:
- *
- * @group: The cgroup to add a task to
- * @pid: The pid of the task to add
- *
- * Returns: 0 on success
- */
-int virCgroupAddTask(virCgroupPtr group, pid_t pid)
-{
- int rc = 0;
- int i;
-
- for (i = 0 ; i < VIR_CGROUP_CONTROLLER_LAST ; i++) {
- /* Skip over controllers not mounted */
- if (!group->controllers[i].mountPoint)
- continue;
-
- rc = virCgroupSetValueU64(group, i, "tasks", (unsigned long long)pid);
- if (rc != 0)
- break;
- }
-
- return rc;
-}
-
-
-/**
- * virCgroupForDriver:
- *
- * @name: name of this driver (e.g., xen, qemu, lxc)
- * @group: Pointer to returned virCgroupPtr
- *
- * Returns 0 on success
- */
-int virCgroupForDriver(const char *name,
- virCgroupPtr *group,
- int privileged,
- int create)
-{
- int rc;
- char *path = NULL;
- virCgroupPtr rootgrp = NULL;
-
- rc = virCgroupAppRoot(privileged, &rootgrp);
- if (rc != 0)
- goto out;
-
- if (virAsprintf(&path, "%s/%s", rootgrp->path, name) < 0) {
- rc = -ENOMEM;
- goto out;
- }
-
- rc = virCgroupNew(path, group);
- VIR_FREE(path);
-
- if (rc == 0 &&
- create) {
- rc = virCgroupMakeGroup(rootgrp, *group);
- if (rc != 0)
- virCgroupFree(group);
- }
-
-out:
- virCgroupFree(&rootgrp);
-
- return rc;
-}
-
-
-/**
- * virCgroupForDomain:
- *
- * @driver: group for driver owning the domain
- * @name: name of the domain
- * @group: Pointer to returned virCgroupPtr
- *
- * Returns 0 on success
- */
-int virCgroupForDomain(virCgroupPtr driver,
- const char *name,
- virCgroupPtr *group,
- int create)
-{
- int rc;
- char *path;
-
- if (virAsprintf(&path, "%s/%s", driver->path, name) < 0)
- return -ENOMEM;
-
- rc = virCgroupNew(path, group);
- VIR_FREE(path);
-
- if (rc == 0 &&
- create) {
- rc = virCgroupMakeGroup(driver, *group);
- if (rc != 0)
- virCgroupFree(group);
- }
-
- return rc;
-}
-
-/**
- * virCgroupSetMemory:
- *
- * @group: The cgroup to change memory for
- * @kb: The memory amount in kilobytes
- *
- * Returns: 0 on success
- */
-int virCgroupSetMemory(virCgroupPtr group, unsigned long kb)
-{
- return virCgroupSetValueU64(group,
- VIR_CGROUP_CONTROLLER_MEMORY,
- "memory.limit_in_bytes",
- kb << 10);
-}
-
-/**
- * virCgroupDenyAllDevices:
- *
- * @group: The cgroup to deny devices for
- *
- * Returns: 0 on success
- */
-int virCgroupDenyAllDevices(virCgroupPtr group)
-{
- return virCgroupSetValueStr(group,
- VIR_CGROUP_CONTROLLER_DEVICES,
- "devices.deny",
- "a");
-}
-
-/**
- * virCgroupAllowDevice:
- *
- * @group: The cgroup to allow a device for
- * @type: The device type (i.e., 'c' or 'b')
- * @major: The major number of the device
- * @minor: The minor number of the device
- *
- * Returns: 0 on success
- */
-int virCgroupAllowDevice(virCgroupPtr group, char type, int major, int minor)
-{
- int rc;
- char *devstr = NULL;
-
- if (virAsprintf(&devstr, "%c %i:%i rwm", type, major, minor) == -1) {
- rc = -ENOMEM;
- goto out;
- }
-
- rc = virCgroupSetValueStr(group,
- VIR_CGROUP_CONTROLLER_DEVICES,
- "devices.allow",
- devstr);
-out:
- VIR_FREE(devstr);
-
- return rc;
-}
-
-/**
- * virCgroupAllowDeviceMajor:
- *
- * @group: The cgroup to allow an entire device major type for
- * @type: The device type (i.e., 'c' or 'b')
- * @major: The major number of the device type
- *
- * Returns: 0 on success
- */
-int virCgroupAllowDeviceMajor(virCgroupPtr group, char type, int major)
-{
- int rc;
- char *devstr = NULL;
-
- if (virAsprintf(&devstr, "%c %i:* rwm", type, major) == -1) {
- rc = -ENOMEM;
- goto out;
- }
-
- rc = virCgroupSetValueStr(group,
- VIR_CGROUP_CONTROLLER_DEVICES,
- "devices.allow",
- devstr);
- out:
- VIR_FREE(devstr);
-
- return rc;
-}
-
-/**
- * virCgroupAllowDevicePath:
- *
- * @group: The cgroup to allow the device for
- * @path: the device to allow
- *
- * Queries the type of device and its major/minor number, and
- * adds that to the cgroup ACL
- *
- * Returns: 0 on success
- */
-int virCgroupAllowDevicePath(virCgroupPtr group, const char *path)
-{
- struct stat sb;
-
- if (stat(path, &sb) < 0)
- return -errno;
-
- if (!S_ISCHR(sb.st_mode) && !S_ISBLK(sb.st_mode))
- return -EINVAL;
-
- return virCgroupAllowDevice(group,
- S_ISCHR(sb.st_mode) ? 'c' : 'b',
- major(sb.st_rdev),
- minor(sb.st_rdev));
-}
-
-/**
- * virCgroupDenyDevice:
- *
- * @group: The cgroup to deny a device for
- * @type: The device type (i.e., 'c' or 'b')
- * @major: The major number of the device
- * @minor: The minor number of the device
- *
- * Returns: 0 on success
- */
-int virCgroupDenyDevice(virCgroupPtr group, char type, int major, int minor)
-{
- int rc;
- char *devstr = NULL;
-
- if (virAsprintf(&devstr, "%c %i:%i rwm", type, major, minor) == -1) {
- rc = -ENOMEM;
- goto out;
- }
-
- rc = virCgroupSetValueStr(group,
- VIR_CGROUP_CONTROLLER_DEVICES,
- "devices.deny",
- devstr);
-out:
- VIR_FREE(devstr);
-
- return rc;
-}
-
-/**
- * virCgroupDenyDeviceMajor:
- *
- * @group: The cgroup to deny an entire device major type for
- * @type: The device type (i.e., 'c' or 'b')
- * @major: The major number of the device type
- *
- * Returns: 0 on success
- */
-int virCgroupDenyDeviceMajor(virCgroupPtr group, char type, int major)
-{
- int rc;
- char *devstr = NULL;
-
- if (virAsprintf(&devstr, "%c %i:* rwm", type, major) == -1) {
- rc = -ENOMEM;
- goto out;
- }
-
- rc = virCgroupSetValueStr(group,
- VIR_CGROUP_CONTROLLER_DEVICES,
- "devices.deny",
- devstr);
- out:
- VIR_FREE(devstr);
-
- return rc;
-}
-
-int virCgroupDenyDevicePath(virCgroupPtr group, const char *path)
-{
- struct stat sb;
-
- if (stat(path, &sb) < 0)
- return -errno;
-
- if (!S_ISCHR(sb.st_mode) && !S_ISBLK(sb.st_mode))
- return -EINVAL;
-
- return virCgroupDenyDevice(group,
- S_ISCHR(sb.st_mode) ? 'c' : 'b',
- major(sb.st_rdev),
- minor(sb.st_rdev));
-}
-
-int virCgroupSetCpuShares(virCgroupPtr group, unsigned long long shares)
-{
- return virCgroupSetValueU64(group,
- VIR_CGROUP_CONTROLLER_CPU,
- "cpu.shares", (uint64_t)shares);
-}
-
-int virCgroupGetCpuShares(virCgroupPtr group, unsigned long long *shares)
-{
- return virCgroupGetValueU64(group,
- VIR_CGROUP_CONTROLLER_CPU,
- "cpu.shares", (uint64_t *)shares);
-}
-
-int virCgroupGetCpuacctUsage(virCgroupPtr group, unsigned long long *usage)
-{
- return virCgroupGetValueU64(group,
- VIR_CGROUP_CONTROLLER_CPUACCT,
- "cpuacct.usage", (uint64_t *)usage);
-}
+++ /dev/null
-/*
- * cgroup.h: Interface to tools for managing cgroups
- *
- * Copyright IBM Corp. 2008
- *
- * See COPYING.LIB for the License of this software
- *
- * Authors:
- * Dan Smith <danms@us.ibm.com>
- */
-
-#ifndef CGROUP_H
-#define CGROUP_H
-
-struct virCgroup;
-typedef struct virCgroup *virCgroupPtr;
-
-enum {
- VIR_CGROUP_CONTROLLER_CPU,
- VIR_CGROUP_CONTROLLER_CPUACCT,
- VIR_CGROUP_CONTROLLER_CPUSET,
- VIR_CGROUP_CONTROLLER_MEMORY,
- VIR_CGROUP_CONTROLLER_DEVICES,
-
- VIR_CGROUP_CONTROLLER_LAST
-};
-
-VIR_ENUM_DECL(virCgroupController);
-
-int virCgroupForDriver(const char *name,
- virCgroupPtr *group,
- int privileged,
- int create);
-
-int virCgroupForDomain(virCgroupPtr driver,
- const char *name,
- virCgroupPtr *group,
- int create);
-
-int virCgroupAddTask(virCgroupPtr group, pid_t pid);
-
-int virCgroupSetMemory(virCgroupPtr group, unsigned long kb);
-
-int virCgroupDenyAllDevices(virCgroupPtr group);
-
-int virCgroupAllowDevice(virCgroupPtr group,
- char type,
- int major,
- int minor);
-int virCgroupAllowDeviceMajor(virCgroupPtr group,
- char type,
- int major);
-int virCgroupAllowDevicePath(virCgroupPtr group,
- const char *path);
-
-int virCgroupDenyDevice(virCgroupPtr group,
- char type,
- int major,
- int minor);
-int virCgroupDenyDeviceMajor(virCgroupPtr group,
- char type,
- int major);
-int virCgroupDenyDevicePath(virCgroupPtr group,
- const char *path);
-
-int virCgroupSetCpuShares(virCgroupPtr group, unsigned long long shares);
-int virCgroupGetCpuShares(virCgroupPtr group, unsigned long long *shares);
-
-int virCgroupGetCpuacctUsage(virCgroupPtr group, unsigned long long *usage);
-
-int virCgroupRemove(virCgroupPtr group);
-
-void virCgroupFree(virCgroupPtr *group);
-
-#endif /* CGROUP_H */
+++ /dev/null
-/**
- * conf.c: parser for a subset of the Python encoded Xen configuration files
- *
- * Copyright (C) 2006, 2007, 2008, 2009 Red Hat, Inc.
- *
- * See COPYING.LIB for the License of this software
- *
- * Daniel Veillard <veillard@redhat.com>
- */
-
-#include <config.h>
-
-#include <string.h>
-
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-#include "virterror_internal.h"
-#include "buf.h"
-#include "conf.h"
-#include "util.h"
-#include "c-ctype.h"
-#include "memory.h"
-
-#define VIR_FROM_THIS VIR_FROM_CONF
-
-/************************************************************************
- * *
- * Structures and macros used by the mini parser *
- * *
- ************************************************************************/
-
-typedef struct _virConfParserCtxt virConfParserCtxt;
-typedef virConfParserCtxt *virConfParserCtxtPtr;
-
-struct _virConfParserCtxt {
- const char* filename;
- const char* base;
- const char* cur;
- const char *end;
- int line;
-
- virConfPtr conf;
-};
-
-#define CUR (*ctxt->cur)
-#define NEXT if (ctxt->cur < ctxt->end) ctxt->cur++;
-#define IS_EOL(c) (((c) == '\n') || ((c) == '\r'))
-
-#define SKIP_BLANKS_AND_EOL \
- do { while ((ctxt->cur < ctxt->end) && (c_isblank(CUR) || IS_EOL(CUR))) { \
- if (CUR == '\n') ctxt->line++; \
- ctxt->cur++;}} while (0)
-#define SKIP_BLANKS \
- do { while ((ctxt->cur < ctxt->end) && (c_isblank(CUR))) \
- ctxt->cur++; } while (0)
-
-/************************************************************************
- * *
- * Structures used by configuration data *
- * *
- ************************************************************************/
-
-typedef struct _virConfEntry virConfEntry;
-typedef virConfEntry *virConfEntryPtr;
-
-struct _virConfEntry {
- virConfEntryPtr next;
- char* name;
- char* comment;
- virConfValuePtr value;
-};
-
-struct _virConf {
- const char* filename;
- unsigned int flags;
- virConfEntryPtr entries;
-};
-
-/**
- * virConfError:
- * @ctxt: the parser context if available or NULL
- * @error: the error number
- * @info: extra information string
- *
- * Handle an error at the xend daemon interface
- */
-static void
-virConfError(virConfParserCtxtPtr ctxt,
- virErrorNumber error, const char *info)
-{
- const char *format;
-
- if (error == VIR_ERR_OK)
- return;
-
- /* Construct the string 'filename:line: info' if we have that. */
- if (ctxt && ctxt->filename) {
- virRaiseError(NULL, NULL, NULL, VIR_FROM_CONF, error, VIR_ERR_ERROR,
- info, ctxt->filename, NULL,
- ctxt->line, 0,
- "%s:%d: %s", ctxt->filename, ctxt->line, info);
- } else {
- format = virErrorMsg(error, info);
- virRaiseError(NULL, NULL, NULL, VIR_FROM_CONF, error, VIR_ERR_ERROR,
- info, NULL, NULL,
- ctxt ? ctxt->line : 0, 0,
- format, info);
- }
-}
-
-
-/************************************************************************
- * *
- * Structures allocations and deallocations *
- * *
- ************************************************************************/
-
-/**
- * virConfFreeList:
- * @list: the list to free
- *
- * Free a list
- */
-static void
-virConfFreeList(virConfValuePtr list)
-{
- virConfValuePtr next;
-
- while (list != NULL) {
- next = list->next;
- list->next = NULL;
- virConfFreeValue(list);
- list = next;
- }
-}
-
-/**
- * virConfFreeValue:
- * @val: the value to free
- *
- * Free a value
- */
-void
-virConfFreeValue(virConfValuePtr val)
-{
- if (val == NULL)
- return;
- if (val->type == VIR_CONF_STRING &&
- val->str != NULL)
- VIR_FREE(val->str);
- if (val->type == VIR_CONF_LIST &&
- val->list != NULL)
- virConfFreeList(val->list);
- VIR_FREE(val);
-}
-
-virConfPtr
-virConfNew(void)
-{
- virConfPtr ret;
-
- if (VIR_ALLOC(ret) < 0) {
- virReportOOMError(NULL);
- return(NULL);
- }
- ret->filename = NULL;
- ret->flags = 0;
-
- return(ret);
-}
-
-/**
- * virConfCreate:
- * @filename: the name to report errors
- * @flags: combination of virConfFlag(s)
- *
- * Create a configuration internal structure
- *
- * Returns a pointer or NULL in case of error.
- */
-static virConfPtr
-virConfCreate(const char *filename, unsigned int flags)
-{
- virConfPtr ret = virConfNew();
- if (ret) {
- ret->filename = filename;
- ret->flags = flags;
- }
- return(ret);
-}
-
-/**
- * virConfAddEntry:
- * @conf: the conf structure
- * @name: name of the entry or NULL for comment
- * @value: the value if any
- * @comm: extra comment for that entry if any
- *
- * add one entry to the conf, the parameters are included in the conf
- * if successful and freed on virConfFree()
- *
- * Returns a pointer to the entry or NULL in case of failure
- */
-static virConfEntryPtr
-virConfAddEntry(virConfPtr conf, char *name, virConfValuePtr value, char *comm)
-{
- virConfEntryPtr ret, prev;
-
- if (conf == NULL)
- return(NULL);
- if ((comm == NULL) && (name == NULL))
- return(NULL);
-
- if (VIR_ALLOC(ret) < 0) {
- virReportOOMError(NULL);
- return(NULL);
- }
-
- ret->name = name;
- ret->value = value;
- ret->comment = comm;
-
- if (conf->entries == NULL) {
- conf->entries = ret;
- } else {
- prev = conf->entries;
- while (prev->next != NULL)
- prev = prev->next;
- prev->next = ret;
- }
- return(ret);
-}
-
-/************************************************************************
- * *
- * Serialization *
- * *
- ************************************************************************/
-
-/**
- * virConfSaveValue:
- * @buf: output buffer
- * @val: a value
- *
- * Serialize the value to the buffer
- *
- * Returns 0 in case of success, -1 in case of error.
- */
-static int
-virConfSaveValue(virBufferPtr buf, virConfValuePtr val)
-{
- if (val == NULL)
- return(-1);
- switch (val->type) {
- case VIR_CONF_NONE:
- return(-1);
- case VIR_CONF_LONG:
- virBufferVSprintf(buf, "%ld", val->l);
- break;
- case VIR_CONF_STRING:
- if (strchr(val->str, '\n') != NULL) {
- virBufferVSprintf(buf, "\"\"\"%s\"\"\"", val->str);
- } else if (strchr(val->str, '"') == NULL) {
- virBufferVSprintf(buf, "\"%s\"", val->str);
- } else if (strchr(val->str, '\'') == NULL) {
- virBufferVSprintf(buf, "'%s'", val->str);
- } else {
- virBufferVSprintf(buf, "\"\"\"%s\"\"\"", val->str);
- }
- break;
- case VIR_CONF_LIST: {
- virConfValuePtr cur;
-
- cur = val->list;
- virBufferAddLit(buf, "[ ");
- if (cur != NULL) {
- virConfSaveValue(buf, cur);
- cur = cur->next;
- while (cur != NULL) {
- virBufferAddLit(buf, ", ");
- virConfSaveValue(buf, cur);
- cur = cur->next;
- }
- }
- virBufferAddLit(buf, " ]");
- break;
- }
- default:
- return(-1);
- }
- return(0);
-}
-
-/**
- * virConfSaveEntry:
- * @buf: output buffer
- * @cur: a conf entry
- *
- * Serialize the entry to the buffer
- *
- * Returns 0 in case of success, -1 in case of error.
- */
-static int
-virConfSaveEntry(virBufferPtr buf, virConfEntryPtr cur)
-{
- if (cur->name != NULL) {
- virBufferAdd(buf, cur->name, -1);
- virBufferAddLit(buf, " = ");
- virConfSaveValue(buf, cur->value);
- if (cur->comment != NULL) {
- virBufferAddLit(buf, " #");
- virBufferAdd(buf, cur->comment, -1);
- }
- } else if (cur->comment != NULL) {
- virBufferAddLit(buf, "#");
- virBufferAdd(buf, cur->comment, -1);
- }
- virBufferAddLit(buf, "\n");
- return(0);
-}
-
-/************************************************************************
- * *
- * The parser core *
- * *
- ************************************************************************/
-
-/**
- * virConfParseLong:
- * @ctxt: the parsing context
- * @val: the result
- *
- * Parse one long int value
- *
- * Returns 0 in case of success and -1 in case of error
- */
-static int
-virConfParseLong(virConfParserCtxtPtr ctxt, long *val)
-{
- long l = 0;
- int neg = 0;
-
- if (CUR == '-') {
- neg = 1;
- NEXT;
- } else if (CUR == '+') {
- NEXT;
- }
- if ((ctxt->cur >= ctxt->end) || (!c_isdigit(CUR))) {
- virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated number"));
- return(-1);
- }
- while ((ctxt->cur < ctxt->end) && (c_isdigit(CUR))) {
- l = l * 10 + (CUR - '0');
- NEXT;
- }
- if (neg)
- l = -l;
- *val = l;
- return(0);
-}
-
-/**
- * virConfParseString:
- * @ctxt: the parsing context
- *
- * Parse one string
- *
- * Returns a pointer to the string or NULL in case of error
- */
-static char *
-virConfParseString(virConfParserCtxtPtr ctxt)
-{
- const char *base;
- char *ret = NULL;
-
- if (CUR == '\'') {
- NEXT;
- base = ctxt->cur;
- while ((ctxt->cur < ctxt->end) && (CUR != '\'') && (!IS_EOL(CUR)))
- NEXT;
- if (CUR != '\'') {
- virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated string"));
- return(NULL);
- }
- ret = strndup(base, ctxt->cur - base);
- NEXT;
- } else if ((ctxt->cur + 6 < ctxt->end) && (ctxt->cur[0] == '"') &&
- (ctxt->cur[1] == '"') && (ctxt->cur[2] == '"')) {
- ctxt->cur += 3;
- base = ctxt->cur;
- while ((ctxt->cur + 2 < ctxt->end) && (ctxt->cur[0] == '"') &&
- (ctxt->cur[1] == '"') && (ctxt->cur[2] == '"')) {
- if (CUR == '\n') ctxt->line++;
- NEXT;
- }
- if ((ctxt->cur[0] != '"') || (ctxt->cur[1] != '"') ||
- (ctxt->cur[2] != '"')) {
- virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated string"));
- return(NULL);
- }
- ret = strndup(base, ctxt->cur - base);
- ctxt->cur += 3;
- } else if (CUR == '"') {
- NEXT;
- base = ctxt->cur;
- while ((ctxt->cur < ctxt->end) && (CUR != '"') && (!IS_EOL(CUR)))
- NEXT;
- if (CUR != '"') {
- virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated string"));
- return(NULL);
- }
- ret = strndup(base, ctxt->cur - base);
- NEXT;
- }
- return(ret);
-}
-
-/**
- * virConfParseValue:
- * @ctxt: the parsing context
- *
- * Parse one value
- *
- * Returns a pointer to the value or NULL in case of error
- */
-static virConfValuePtr
-virConfParseValue(virConfParserCtxtPtr ctxt)
-{
- virConfValuePtr ret, lst = NULL, tmp, prev;
- virConfType type = VIR_CONF_NONE;
- char *str = NULL;
- long l = 0;
-
- SKIP_BLANKS;
- if (ctxt->cur >= ctxt->end) {
- virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting a value"));
- return(NULL);
- }
- if ((CUR == '"') || (CUR == '\'')) {
- type = VIR_CONF_STRING;
- str = virConfParseString(ctxt);
- if (str == NULL)
- return(NULL);
- } else if (CUR == '[') {
- if (ctxt->conf->flags & VIR_CONF_FLAG_VMX_FORMAT) {
- virConfError(ctxt, VIR_ERR_CONF_SYNTAX,
- _("lists not allowed in VMX format"));
- return(NULL);
- }
- type = VIR_CONF_LIST;
- NEXT;
- SKIP_BLANKS_AND_EOL;
- if ((ctxt->cur < ctxt->end) && (CUR != ']')) {
- if ((lst = virConfParseValue(ctxt)) == NULL)
- return(NULL);
- SKIP_BLANKS_AND_EOL;
- }
- while ((ctxt->cur < ctxt->end) && (CUR != ']')) {
- if (CUR != ',') {
- virConfError(ctxt, VIR_ERR_CONF_SYNTAX,
- _("expecting a separator in list"));
- virConfFreeList(lst);
- return(NULL);
- }
- NEXT;
- SKIP_BLANKS_AND_EOL;
- if (CUR == ']') {
- break;
- }
- tmp = virConfParseValue(ctxt);
- if (tmp == NULL) {
- virConfFreeList(lst);
- return(NULL);
- }
- prev = lst;
- while (prev->next != NULL) prev = prev->next;
- prev->next = tmp;
- SKIP_BLANKS_AND_EOL;
- }
- if (CUR == ']') {
- NEXT;
- } else {
- virConfError(ctxt, VIR_ERR_CONF_SYNTAX,
- _("list is not closed with ]"));
- virConfFreeList(lst);
- return(NULL);
- }
- } else if (c_isdigit(CUR) || (CUR == '-') || (CUR == '+')) {
- if (ctxt->conf->flags & VIR_CONF_FLAG_VMX_FORMAT) {
- virConfError(ctxt, VIR_ERR_CONF_SYNTAX,
- _("numbers not allowed in VMX format"));
- return(NULL);
- }
- if (virConfParseLong(ctxt, &l) < 0) {
- return(NULL);
- }
- type = VIR_CONF_LONG;
- } else {
- virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting a value"));
- return(NULL);
- }
- if (VIR_ALLOC(ret) < 0) {
- virReportOOMError(NULL);
- virConfFreeList(lst);
- VIR_FREE(str);
- return(NULL);
- }
- ret->type = type;
- ret->l = l;
- ret->str = str;
- ret->list = lst;
- return(ret);
-}
-
-/**
- * virConfParseName:
- * @ctxt: the parsing context
- *
- * Parse one name
- *
- * Returns a copy of the new string, NULL in case of error
- */
-static char *
-virConfParseName(virConfParserCtxtPtr ctxt)
-{
- const char *base;
- char *ret;
-
- SKIP_BLANKS;
- base = ctxt->cur;
- /* TODO: probably need encoding support and UTF-8 parsing ! */
- if (!c_isalpha(CUR) &&
- !((ctxt->conf->flags & VIR_CONF_FLAG_VMX_FORMAT) && (CUR == '.'))) {
- virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting a name"));
- return(NULL);
- }
- while ((ctxt->cur < ctxt->end) &&
- (c_isalnum(CUR) || (CUR == '_') ||
- ((ctxt->conf->flags & VIR_CONF_FLAG_VMX_FORMAT) &&
- ((CUR == ':') || (CUR == '.')))))
- NEXT;
- ret = strndup(base, ctxt->cur - base);
- if (ret == NULL) {
- virReportOOMError(NULL);
- return(NULL);
- }
- return(ret);
-}
-
-/**
- * virConfParseComment:
- * @ctxt: the parsing context
- *
- * Parse one standalone comment in the configuration file
- *
- * Returns 0 in case of success and -1 in case of error
- */
-static int
-virConfParseComment(virConfParserCtxtPtr ctxt)
-{
- const char *base;
- char *comm;
-
- if (CUR != '#')
- return(-1);
- NEXT;
- base = ctxt->cur;
- while ((ctxt->cur < ctxt->end) && (!IS_EOL(CUR))) NEXT;
- comm = strndup(base, ctxt->cur - base);
- if (comm == NULL) {
- virReportOOMError(NULL);
- return(-1);
- }
- virConfAddEntry(ctxt->conf, NULL, NULL, comm);
- return(0);
-}
-
-/**
- * virConfParseSeparator:
- * @ctxt: the parsing context
- *
- * Parse one separator between statement if not at the end.
- *
- * Returns 0 in case of success and -1 in case of error
- */
-static int
-virConfParseSeparator(virConfParserCtxtPtr ctxt)
-{
- SKIP_BLANKS;
- if (ctxt->cur >= ctxt->end)
- return(0);
- if (IS_EOL(CUR)) {
- SKIP_BLANKS_AND_EOL;
- } else if (CUR == ';') {
- NEXT;
- SKIP_BLANKS_AND_EOL;
- } else {
- virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting a separator"));
- return(-1);
- }
- return(0);
-}
-
-/**
- * virConfParseStatement:
- * @ctxt: the parsing context
- *
- * Parse one statement in the conf file
- *
- * Returns 0 in case of success and -1 in case of error
- */
-static int
-virConfParseStatement(virConfParserCtxtPtr ctxt)
-{
- const char *base;
- char *name;
- virConfValuePtr value;
- char *comm = NULL;
-
- SKIP_BLANKS_AND_EOL;
- if (CUR == '#') {
- return(virConfParseComment(ctxt));
- }
- name = virConfParseName(ctxt);
- if (name == NULL)
- return(-1);
- SKIP_BLANKS;
- if (CUR != '=') {
- virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting an assignment"));
- return(-1);
- }
- NEXT;
- SKIP_BLANKS;
- value = virConfParseValue(ctxt);
- if (value == NULL) {
- VIR_FREE(name);
- return(-1);
- }
- SKIP_BLANKS;
- if (CUR == '#') {
- NEXT;
- base = ctxt->cur;
- while ((ctxt->cur < ctxt->end) && (!IS_EOL(CUR))) NEXT;
- comm = strndup(base, ctxt->cur - base);
- if (comm == NULL) {
- virReportOOMError(NULL);
- VIR_FREE(name);
- virConfFreeValue(value);
- return(-1);
- }
- }
- if (virConfAddEntry(ctxt->conf, name, value, comm) == NULL) {
- VIR_FREE(name);
- virConfFreeValue(value);
- VIR_FREE(comm);
- return(-1);
- }
- return(0);
-}
-
-/**
- * virConfParse:
- * @filename: the name to report errors
- * @content: the configuration content in memory
- * @len: the length in bytes
- * @flags: combination of virConfFlag(s)
- *
- * Parse the subset of the Python language needed to handle simple
- * Xen configuration files.
- *
- * Returns an handle to lookup settings or NULL if it failed to
- * read or parse the file, use virConfFree() to free the data.
- */
-static virConfPtr
-virConfParse(const char *filename, const char *content, int len,
- unsigned int flags) {
- virConfParserCtxt ctxt;
-
- ctxt.filename = filename;
- ctxt.base = ctxt.cur = content;
- ctxt.end = content + len - 1;
- ctxt.line = 1;
-
- ctxt.conf = virConfCreate(filename, flags);
- if (ctxt.conf == NULL)
- return(NULL);
-
- while (ctxt.cur < ctxt.end) {
- if (virConfParseStatement(&ctxt) < 0)
- goto error;
- if (virConfParseSeparator(&ctxt) < 0)
- goto error;
- }
-
- return(ctxt.conf);
-
-error:
- virConfFree(ctxt.conf);
- return(NULL);
-}
-
-/************************************************************************
- * *
- * The module entry points *
- * *
- ************************************************************************/
-
-/* 10 MB limit on config file size as a sanity check */
-#define MAX_CONFIG_FILE_SIZE (1024*1024*10)
-
-/**
- * virConfReadFile:
- * @filename: the path to the configuration file.
- * @flags: combination of virConfFlag(s)
- *
- * Reads a configuration file.
- *
- * Returns an handle to lookup settings or NULL if it failed to
- * read or parse the file, use virConfFree() to free the data.
- */
-virConfPtr
-virConfReadFile(const char *filename, unsigned int flags)
-{
- char *content;
- int len;
- virConfPtr conf;
-
- if (filename == NULL) {
- virConfError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
- return(NULL);
- }
-
- if ((len = virFileReadAll(filename, MAX_CONFIG_FILE_SIZE, &content)) < 0) {
- return NULL;
- }
-
- conf = virConfParse(filename, content, len, flags);
-
- VIR_FREE(content);
-
- return conf;
-}
-
-/**
- * virConfReadMem:
- * @memory: pointer to the content of the configuration file
- * @len: length in byte
- * @flags: combination of virConfFlag(s)
- *
- * Reads a configuration file loaded in memory. The string can be
- * zero terminated in which case @len can be 0
- *
- * Returns an handle to lookup settings or NULL if it failed to
- * parse the content, use virConfFree() to free the data.
- */
-virConfPtr
-virConfReadMem(const char *memory, int len, unsigned int flags)
-{
- if ((memory == NULL) || (len < 0)) {
- virConfError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
- return(NULL);
- }
- if (len == 0)
- len = strlen(memory);
-
- return(virConfParse("memory conf", memory, len, flags));
-}
-
-/**
- * virConfFree:
- * @conf: a configuration file handle
- *
- * Frees all data associated to the handle
- *
- * Returns 0 in case of success, -1 in case of error.
- */
-int
-virConfFree(virConfPtr conf)
-{
- virConfEntryPtr tmp;
- if (conf == NULL) {
- virConfError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
- return(-1);
- }
-
- tmp = conf->entries;
- while (tmp) {
- virConfEntryPtr next;
- VIR_FREE(tmp->name);
- virConfFreeValue(tmp->value);
- VIR_FREE(tmp->comment);
- next = tmp->next;
- VIR_FREE(tmp);
- tmp = next;
- }
- VIR_FREE(conf);
- return(0);
-}
-
-/**
- * virConfGetValue:
- * @conf: a configuration file handle
- * @entry: the name of the entry
- *
- * Lookup the value associated to this entry in the configuration file
- *
- * Returns a pointer to the value or NULL if the lookup failed, the data
- * associated will be freed when virConfFree() is called
- */
-virConfValuePtr
-virConfGetValue(virConfPtr conf, const char *setting)
-{
- virConfEntryPtr cur;
-
- cur = conf->entries;
- while (cur != NULL) {
- if ((cur->name != NULL) && (STREQ(cur->name, setting)))
- return(cur->value);
- cur = cur->next;
- }
- return(NULL);
-}
-
-/**
- * virConfSetValue:
- * @conf: a configuration file handle
- * @entry: the name of the entry
- * @value: the new configuration value
- *
- * Set (or replace) the value associated to this entry in the configuration
- * file. The passed in 'value' will be owned by the conf object upon return
- * of this method, even in case of error. It should not be referenced again
- * by the caller.
- *
- * Returns 0 on success, or -1 on failure.
- */
-int
-virConfSetValue (virConfPtr conf,
- const char *setting,
- virConfValuePtr value)
-{
- virConfEntryPtr cur, prev = NULL;
-
- cur = conf->entries;
- while (cur != NULL) {
- if ((cur->name != NULL) && (STREQ(cur->name, setting))) {
- break;
- }
- prev = cur;
- cur = cur->next;
- }
-
- if (!cur) {
- if (VIR_ALLOC(cur) < 0) {
- virConfFreeValue(value);
- return (-1);
- }
- cur->comment = NULL;
- if (!(cur->name = strdup(setting))) {
- virConfFreeValue(value);
- VIR_FREE(cur);
- return (-1);
- }
- cur->value = value;
- if (prev) {
- cur->next = prev->next;
- prev->next = cur;
- } else {
- cur->next = conf->entries;
- conf->entries = cur;
- }
- } else {
- if (cur->value) {
- virConfFreeValue(cur->value);
- }
- cur->value = value;
- }
- return (0);
-}
-
-
-/**
- * virConfWriteFile:
- * @filename: the path to the configuration file.
- * @conf: the conf
- *
- * Writes a configuration file back to a file.
- *
- * Returns the number of bytes written or -1 in case of error.
- */
-int
-virConfWriteFile(const char *filename, virConfPtr conf)
-{
- virBuffer buf = VIR_BUFFER_INITIALIZER;
- virConfEntryPtr cur;
- int ret;
- int fd;
- char *content;
- unsigned int use;
-
- if (conf == NULL)
- return(-1);
-
- cur = conf->entries;
- while (cur != NULL) {
- virConfSaveEntry(&buf, cur);
- cur = cur->next;
- }
-
- if (virBufferError(&buf)) {
- virReportOOMError(NULL);
- return -1;
- }
-
- fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR );
- if (fd < 0) {
- char *tmp = virBufferContentAndReset(&buf);
- virConfError(NULL, VIR_ERR_WRITE_FAILED, _("failed to open file"));
- VIR_FREE(tmp);
- return -1;
- }
-
- use = virBufferUse(&buf);
- content = virBufferContentAndReset(&buf);
- ret = safewrite(fd, content, use);
- VIR_FREE(content);
- close(fd);
- if (ret != (int)use) {
- virConfError(NULL, VIR_ERR_WRITE_FAILED, _("failed to save content"));
- return -1;
- }
-
- return ret;
-}
-
-/**
- * virConfWriteMem:
- * @memory: pointer to the memory to store the config file
- * @len: pointer to the length in bytes of the store, on output the size
- * @conf: the conf
- *
- * Writes a configuration file back to a memory area. @len is an IN/OUT
- * parameter, it indicates the size available in bytes, and on output the
- * size required for the configuration file (even if the call fails due to
- * insufficient space).
- *
- * Returns the number of bytes written or -1 in case of error.
- */
-int
-virConfWriteMem(char *memory, int *len, virConfPtr conf)
-{
- virBuffer buf = VIR_BUFFER_INITIALIZER;
- virConfEntryPtr cur;
- char *content;
- unsigned int use;
-
- if ((memory == NULL) || (len == NULL) || (*len <= 0) || (conf == NULL))
- return(-1);
-
- cur = conf->entries;
- while (cur != NULL) {
- virConfSaveEntry(&buf, cur);
- cur = cur->next;
- }
-
- if (virBufferError(&buf)) {
- virReportOOMError(NULL);
- return -1;
- }
-
- use = virBufferUse(&buf);
- content = virBufferContentAndReset(&buf);
-
- if ((int)use >= *len) {
- *len = (int)use;
- VIR_FREE(content);
- return -1;
- }
- memcpy(memory, content, use);
- VIR_FREE(content);
- *len = use;
- return use;
-}
+++ /dev/null
-/**
- * conf.h: parser for a subset of the Python encoded Xen configuration files
- *
- * Copyright (C) 2006, 2007 Red Hat, Inc.
- *
- * See COPYING.LIB for the License of this software
- *
- * Daniel Veillard <veillard@redhat.com>
- */
-
-#ifndef __VIR_CONF_H__
-#define __VIR_CONF_H__
-
-/**
- * virConfType:
- * one of the possible type for a value from the configuration file
- *
- * TODO: we probably need a float too.
- */
-typedef enum {
- VIR_CONF_NONE = 0, /* undefined */
- VIR_CONF_LONG = 1, /* a long int */
- VIR_CONF_STRING = 2, /* a string */
- VIR_CONF_LIST = 3 /* a list */
-} virConfType;
-
-typedef enum {
- VIR_CONF_FLAG_VMX_FORMAT = 1, /* allow : and . in names for compatibility with
- VMware VMX configuration file, but restrict
- allowed value types to string only */
-} virConfFlags;
-
-static inline const char *
-virConfTypeName (virConfType t)
-{
- switch (t) {
- case VIR_CONF_LONG:
- return "long";
- case VIR_CONF_STRING:
- return "string";
- case VIR_CONF_LIST:
- return "list";
- default:
- return "*unexpected*";
- }
-}
-
-/**
- * virConfValue:
- * a value from the configuration file
- */
-typedef struct _virConfValue virConfValue;
-typedef virConfValue *virConfValuePtr;
-
-struct _virConfValue {
- virConfType type; /* the virConfType */
- virConfValuePtr next; /* next element if in a list */
- long l; /* long integer */
- char *str; /* pointer to 0 terminated string */
- virConfValuePtr list; /* list of a list */
-};
-
-/**
- * virConfPtr:
- * a pointer to a parsed configuration file
- */
-typedef struct _virConf virConf;
-typedef virConf *virConfPtr;
-
-virConfPtr virConfNew (void);
-virConfPtr virConfReadFile (const char *filename, unsigned int flags);
-virConfPtr virConfReadMem (const char *memory,
- int len, unsigned int flags);
-int virConfFree (virConfPtr conf);
-void virConfFreeValue (virConfValuePtr val);
-
-virConfValuePtr virConfGetValue (virConfPtr conf,
- const char *setting);
-int virConfSetValue (virConfPtr conf,
- const char *setting,
- virConfValuePtr value);
-int virConfWriteFile (const char *filename,
- virConfPtr conf);
-int virConfWriteMem (char *memory,
- int *len,
- virConfPtr conf);
-
-#endif /* __VIR_CONF_H__ */
+++ /dev/null
-/*
- * event.c: event loop for monitoring file handles
- *
- * Copyright (C) 2007 Daniel P. Berrange
- * Copyright (C) 2007 Red Hat, Inc.
- *
- * 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 "event.h"
-
-#include <stdlib.h>
-
-static virEventAddHandleFunc addHandleImpl = NULL;
-static virEventUpdateHandleFunc updateHandleImpl = NULL;
-static virEventRemoveHandleFunc removeHandleImpl = NULL;
-static virEventAddTimeoutFunc addTimeoutImpl = NULL;
-static virEventUpdateTimeoutFunc updateTimeoutImpl = NULL;
-static virEventRemoveTimeoutFunc removeTimeoutImpl = NULL;
-
-int virEventAddHandle(int fd,
- int events,
- virEventHandleCallback cb,
- void *opaque,
- virFreeCallback ff) {
- if (!addHandleImpl)
- return -1;
-
- return addHandleImpl(fd, events, cb, opaque, ff);
-}
-
-void virEventUpdateHandle(int watch, int events) {
- updateHandleImpl(watch, events);
-}
-
-int virEventRemoveHandle(int watch) {
- if (!removeHandleImpl)
- return -1;
-
- return removeHandleImpl(watch);
-}
-
-int virEventAddTimeout(int timeout,
- virEventTimeoutCallback cb,
- void *opaque,
- virFreeCallback ff) {
- if (!addTimeoutImpl)
- return -1;
-
- return addTimeoutImpl(timeout, cb, opaque, ff);
-}
-
-void virEventUpdateTimeout(int timer, int timeout) {
- updateTimeoutImpl(timer, timeout);
-}
-
-int virEventRemoveTimeout(int timer) {
- if (!removeTimeoutImpl)
- return -1;
-
- return removeTimeoutImpl(timer);
-}
-
-/**
- * virEventRegisterImpl:
- * Register an EventImpl
- * @addHandle: the callback to add fd handles
- * @updateHandle: the callback to update fd handles
- * @removeHandle: the callback to remove fd handles
- * @addTimeout: the callback to add a timeout
- * @updateTimeout: the callback to update a timeout
- * @removeTimeout: the callback to remove a timeout
- */
-void virEventRegisterImpl(virEventAddHandleFunc addHandle,
- virEventUpdateHandleFunc updateHandle,
- virEventRemoveHandleFunc removeHandle,
- virEventAddTimeoutFunc addTimeout,
- virEventUpdateTimeoutFunc updateTimeout,
- virEventRemoveTimeoutFunc removeTimeout) {
- addHandleImpl = addHandle;
- updateHandleImpl = updateHandle;
- removeHandleImpl = removeHandle;
- addTimeoutImpl = addTimeout;
- updateTimeoutImpl = updateTimeout;
- removeTimeoutImpl = removeTimeout;
-}
+++ /dev/null
-/*
- * event.h: event loop for monitoring file handles
- *
- * Copyright (C) 2007 Daniel P. Berrange
- * Copyright (C) 2007 Red Hat, Inc.
- *
- * 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>
- */
-
-#ifndef __VIR_EVENT_H__
-#define __VIR_EVENT_H__
-#include "internal.h"
-/**
- * virEventAddHandle: register a callback for monitoring file handle events
- *
- * @fd: file handle to monitor for events
- * @events: bitset of events to watch from virEventHandleType constants
- * @cb: callback to invoke when an event occurs
- * @opaque: user data to pass to callback
- *
- * returns -1 if the file handle cannot be registered, 0 upon success
- */
-int virEventAddHandle(int fd, int events,
- virEventHandleCallback cb,
- void *opaque,
- virFreeCallback ff);
-
-/**
- * virEventUpdateHandle: change event set for a monitored file handle
- *
- * @watch: watch whose file handle to update
- * @events: bitset of events to watch from virEventHandleType constants
- *
- * Will not fail if fd exists
- */
-void virEventUpdateHandle(int watch, int events);
-
-/**
- * virEventRemoveHandle: unregister a callback from a file handle
- *
- * @watch: watch whose file handle to remove
- *
- * returns -1 if the file handle was not registered, 0 upon success
- */
-int virEventRemoveHandle(int watch);
-
-/**
- * virEventAddTimeout: register a callback for a timer event
- *
- * @frequency: time between events in milliseconds
- * @cb: callback to invoke when an event occurs
- * @opaque: user data to pass to callback
- *
- * Setting frequency to -1 will disable the timer. Setting the frequency
- * to zero will cause it to fire on every event loop iteration.
- *
- * returns -1 if the file handle cannot be registered, a positive
- * integer timer id upon success
- */
-int virEventAddTimeout(int frequency,
- virEventTimeoutCallback cb,
- void *opaque,
- virFreeCallback ff);
-
-/**
- * virEventUpdateTimeoutImpl: change frequency for a timer
- *
- * @timer: timer id to change
- * @frequency: time between events in milliseconds
- *
- * Setting frequency to -1 will disable the timer. Setting the frequency
- * to zero will cause it to fire on every event loop iteration.
- *
- * Will not fail if timer exists
- */
-void virEventUpdateTimeout(int timer, int frequency);
-
-/**
- * virEventRemoveTimeout: unregister a callback for a timer
- *
- * @timer: the timer id to remove
- *
- * returns -1 if the timer was not registered, 0 upon success
- */
-int virEventRemoveTimeout(int timer);
-
-#endif /* __VIR_EVENT_H__ */
+++ /dev/null
-/*
- * hash.c: chained hash tables for domain and domain/connection deallocations
- *
- * Reference: Your favorite introductory book on algorithms
- *
- * Copyright (C) 2000 Bjorn Reese and Daniel Veillard.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
- * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
- * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
- *
- * Author: breese@users.sourceforge.net
- * Daniel Veillard <veillard@redhat.com>
- */
-
-#include <config.h>
-
-#include <string.h>
-#include <stdlib.h>
-
-#include "virterror_internal.h"
-#include "hash.h"
-#include "memory.h"
-
-#define MAX_HASH_LEN 8
-
-/* #define DEBUG_GROW */
-
-/*
- * A single entry in the hash table
- */
-typedef struct _virHashEntry virHashEntry;
-typedef virHashEntry *virHashEntryPtr;
-struct _virHashEntry {
- struct _virHashEntry *next;
- char *name;
- void *payload;
- int valid;
-};
-
-/*
- * The entire hash table
- */
-struct _virHashTable {
- struct _virHashEntry *table;
- int size;
- int nbElems;
-};
-
-/*
- * virHashComputeKey:
- * Calculate the hash key
- */
-static unsigned long
-virHashComputeKey(virHashTablePtr table, const char *name)
-{
- unsigned long value = 0L;
- char ch;
-
- if (name != NULL) {
- value += 30 * (*name);
- while ((ch = *name++) != 0) {
- value =
- value ^ ((value << 5) + (value >> 3) + (unsigned long) ch);
- }
- }
- return (value % table->size);
-}
-
-/**
- * virHashCreate:
- * @size: the size of the hash table
- *
- * Create a new virHashTablePtr.
- *
- * Returns the newly created object, or NULL if an error occured.
- */
-virHashTablePtr
-virHashCreate(int size)
-{
- virHashTablePtr table = NULL;
-
- if (size <= 0)
- size = 256;
-
- if (VIR_ALLOC(table) < 0)
- return NULL;
-
- table->size = size;
- table->nbElems = 0;
- if (VIR_ALLOC_N(table->table, size) < 0) {
- VIR_FREE(table);
- return NULL;
- }
-
- return table;
-}
-
-/**
- * virHashGrow:
- * @table: the hash table
- * @size: the new size of the hash table
- *
- * resize the hash table
- *
- * Returns 0 in case of success, -1 in case of failure
- */
-static int
-virHashGrow(virHashTablePtr table, int size)
-{
- unsigned long key;
- int oldsize, i;
- virHashEntryPtr iter, next;
- struct _virHashEntry *oldtable;
-
-#ifdef DEBUG_GROW
- unsigned long nbElem = 0;
-#endif
-
- if (table == NULL)
- return (-1);
- if (size < 8)
- return (-1);
- if (size > 8 * 2048)
- return (-1);
-
- oldsize = table->size;
- oldtable = table->table;
- if (oldtable == NULL)
- return (-1);
-
- if (VIR_ALLOC_N(table->table, size) < 0) {
- table->table = oldtable;
- return (-1);
- }
- table->size = size;
-
- /* If the two loops are merged, there would be situations where
- * a new entry needs to allocated and data copied into it from
- * the main table. So instead, we run through the array twice, first
- * copying all the elements in the main array (where we can't get
- * conflicts) and then the rest, so we only free (and don't allocate)
- */
- for (i = 0; i < oldsize; i++) {
- if (oldtable[i].valid == 0)
- continue;
- key = virHashComputeKey(table, oldtable[i].name);
- memcpy(&(table->table[key]), &(oldtable[i]), sizeof(virHashEntry));
- table->table[key].next = NULL;
- }
-
- for (i = 0; i < oldsize; i++) {
- iter = oldtable[i].next;
- while (iter) {
- next = iter->next;
-
- /*
- * put back the entry in the new table
- */
-
- key = virHashComputeKey(table, iter->name);
- if (table->table[key].valid == 0) {
- memcpy(&(table->table[key]), iter, sizeof(virHashEntry));
- table->table[key].next = NULL;
- VIR_FREE(iter);
- } else {
- iter->next = table->table[key].next;
- table->table[key].next = iter;
- }
-
-#ifdef DEBUG_GROW
- nbElem++;
-#endif
-
- iter = next;
- }
- }
-
- VIR_FREE(oldtable);
-
-#ifdef DEBUG_GROW
- xmlGenericError(xmlGenericErrorContext,
- "virHashGrow : from %d to %d, %d elems\n", oldsize,
- size, nbElem);
-#endif
-
- return (0);
-}
-
-/**
- * virHashFree:
- * @table: the hash table
- * @f: the deallocator function for items in the hash
- *
- * Free the hash @table and its contents. The userdata is
- * deallocated with @f if provided.
- */
-void
-virHashFree(virHashTablePtr table, virHashDeallocator f)
-{
- int i;
- virHashEntryPtr iter;
- virHashEntryPtr next;
- int inside_table = 0;
- int nbElems;
-
- if (table == NULL)
- return;
- if (table->table) {
- nbElems = table->nbElems;
- for (i = 0; (i < table->size) && (nbElems > 0); i++) {
- iter = &(table->table[i]);
- if (iter->valid == 0)
- continue;
- inside_table = 1;
- while (iter) {
- next = iter->next;
- if ((f != NULL) && (iter->payload != NULL))
- f(iter->payload, iter->name);
- VIR_FREE(iter->name);
- iter->payload = NULL;
- if (!inside_table)
- VIR_FREE(iter);
- nbElems--;
- inside_table = 0;
- iter = next;
- }
- }
- VIR_FREE(table->table);
- }
- VIR_FREE(table);
-}
-
-/**
- * virHashAddEntry3:
- * @table: the hash table
- * @name: the name of the userdata
- * @userdata: a pointer to the userdata
- *
- * Add the @userdata to the hash @table. This can later be retrieved
- * by using @name. Duplicate entries generate errors.
- *
- * Returns 0 the addition succeeded and -1 in case of error.
- */
-int
-virHashAddEntry(virHashTablePtr table, const char *name, void *userdata)
-{
- unsigned long key, len = 0;
- virHashEntryPtr entry;
- virHashEntryPtr insert;
-
- if ((table == NULL) || (name == NULL))
- return (-1);
-
- /*
- * Check for duplicate and insertion location.
- */
- key = virHashComputeKey(table, name);
- if (table->table[key].valid == 0) {
- insert = NULL;
- } else {
- for (insert = &(table->table[key]); insert->next != NULL;
- insert = insert->next) {
- if (STREQ(insert->name, name))
- return (-1);
- len++;
- }
- if (STREQ(insert->name, name))
- return (-1);
- }
-
- if (insert == NULL) {
- entry = &(table->table[key]);
- } else {
- if (VIR_ALLOC(entry) < 0)
- return (-1);
- }
-
- entry->name = strdup(name);
- entry->payload = userdata;
- entry->next = NULL;
- entry->valid = 1;
-
-
- if (insert != NULL)
- insert->next = entry;
-
- table->nbElems++;
-
- if (len > MAX_HASH_LEN)
- virHashGrow(table, MAX_HASH_LEN * table->size);
-
- return (0);
-}
-
-/**
- * virHashUpdateEntry:
- * @table: the hash table
- * @name: the name of the userdata
- * @userdata: a pointer to the userdata
- * @f: the deallocator function for replaced item (if any)
- *
- * Add the @userdata to the hash @table. This can later be retrieved
- * by using @name. Existing entry for this tuple
- * will be removed and freed with @f if found.
- *
- * Returns 0 the addition succeeded and -1 in case of error.
- */
-int
-virHashUpdateEntry(virHashTablePtr table, const char *name,
- void *userdata, virHashDeallocator f)
-{
- unsigned long key;
- virHashEntryPtr entry;
- virHashEntryPtr insert;
-
- if ((table == NULL) || name == NULL)
- return (-1);
-
- /*
- * Check for duplicate and insertion location.
- */
- key = virHashComputeKey(table, name);
- if (table->table[key].valid == 0) {
- insert = NULL;
- } else {
- for (insert = &(table->table[key]); insert->next != NULL;
- insert = insert->next) {
- if (STREQ(insert->name, name)) {
- if (f)
- f(insert->payload, insert->name);
- insert->payload = userdata;
- return (0);
- }
- }
- if (STREQ(insert->name, name)) {
- if (f)
- f(insert->payload, insert->name);
- insert->payload = userdata;
- return (0);
- }
- }
-
- if (insert == NULL) {
- entry = &(table->table[key]);
- } else {
- if (VIR_ALLOC(entry) < 0)
- return (-1);
- }
-
- entry->name = strdup(name);
- entry->payload = userdata;
- entry->next = NULL;
- entry->valid = 1;
- table->nbElems++;
-
-
- if (insert != NULL) {
- insert->next = entry;
- }
- return (0);
-}
-
-/**
- * virHashLookup:
- * @table: the hash table
- * @name: the name of the userdata
- *
- * Find the userdata specified by the (@name, @name2, @name3) tuple.
- *
- * Returns the a pointer to the userdata
- */
-void *
-virHashLookup(virHashTablePtr table, const char *name)
-{
- unsigned long key;
- virHashEntryPtr entry;
-
- if (table == NULL)
- return (NULL);
- if (name == NULL)
- return (NULL);
- key = virHashComputeKey(table, name);
- if (table->table[key].valid == 0)
- return (NULL);
- for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
- if (STREQ(entry->name, name))
- return (entry->payload);
- }
- return (NULL);
-}
-
-/**
- * virHashSize:
- * @table: the hash table
- *
- * Query the number of elements installed in the hash @table.
- *
- * Returns the number of elements in the hash table or
- * -1 in case of error
- */
-int
-virHashSize(virHashTablePtr table)
-{
- if (table == NULL)
- return (-1);
- return (table->nbElems);
-}
-
-/**
- * virHashRemoveEntry:
- * @table: the hash table
- * @name: the name of the userdata
- * @f: the deallocator function for removed item (if any)
- *
- * Find the userdata specified by the @name and remove
- * it from the hash @table. Existing userdata for this tuple will be removed
- * and freed with @f.
- *
- * Returns 0 if the removal succeeded and -1 in case of error or not found.
- */
-int
-virHashRemoveEntry(virHashTablePtr table, const char *name,
- virHashDeallocator f)
-{
- unsigned long key;
- virHashEntryPtr entry;
- virHashEntryPtr prev = NULL;
-
- if (table == NULL || name == NULL)
- return (-1);
-
- key = virHashComputeKey(table, name);
- if (table->table[key].valid == 0) {
- return (-1);
- } else {
- for (entry = &(table->table[key]); entry != NULL;
- entry = entry->next) {
- if (STREQ(entry->name, name)) {
- if ((f != NULL) && (entry->payload != NULL))
- f(entry->payload, entry->name);
- entry->payload = NULL;
- VIR_FREE(entry->name);
- if (prev) {
- prev->next = entry->next;
- VIR_FREE(entry);
- } else {
- if (entry->next == NULL) {
- entry->valid = 0;
- } else {
- entry = entry->next;
- memcpy(&(table->table[key]), entry,
- sizeof(virHashEntry));
- VIR_FREE(entry);
- }
- }
- table->nbElems--;
- return (0);
- }
- prev = entry;
- }
- return (-1);
- }
-}
-
-
-/**
- * virHashForEach
- * @table: the hash table to process
- * @iter: callback to process each element
- * @data: opaque data to pass to the iterator
- *
- * Iterates over every element in the hash table, invoking the
- * 'iter' callback. The callback must not call any other virHash*
- * functions, and in particular must not attempt to remove the
- * element.
- *
- * Returns number of items iterated over upon completion, -1 on failure
- */
-int virHashForEach(virHashTablePtr table, virHashIterator iter, const void *data) {
- int i, count = 0;
-
- if (table == NULL || iter == NULL)
- return (-1);
-
- for (i = 0 ; i < table->size ; i++) {
- virHashEntryPtr entry = table->table + i;
- while (entry) {
- if (entry->valid) {
- iter(entry->payload, entry->name, data);
- count++;
- }
- entry = entry->next;
- }
- }
- return (count);
-}
-
-/**
- * virHashRemoveSet
- * @table: the hash table to process
- * @iter: callback to identify elements for removal
- * @f: callback to free memory from element payload
- * @data: opaque data to pass to the iterator
- *
- * Iterates over all elements in the hash table, invoking the 'iter'
- * callback. If the callback returns a non-zero value, the element
- * will be removed from the hash table & its payload passed to the
- * callback 'f' for de-allocation.
- *
- * Returns number of items removed on success, -1 on failure
- */
-int virHashRemoveSet(virHashTablePtr table, virHashSearcher iter, virHashDeallocator f, const void *data) {
- int i, count = 0;
-
- if (table == NULL || iter == NULL)
- return (-1);
-
- for (i = 0 ; i < table->size ; i++) {
- virHashEntryPtr prev = NULL;
- virHashEntryPtr entry = &(table->table[i]);
-
- while (entry && entry->valid) {
- if (iter(entry->payload, entry->name, data)) {
- count++;
- f(entry->payload, entry->name);
- VIR_FREE(entry->name);
- table->nbElems--;
- if (prev) {
- prev->next = entry->next;
- VIR_FREE(entry);
- entry = prev;
- } else {
- if (entry->next == NULL) {
- entry->valid = 0;
- entry->name = NULL;
- } else {
- entry = entry->next;
- memcpy(&(table->table[i]), entry,
- sizeof(virHashEntry));
- VIR_FREE(entry);
- entry = &(table->table[i]);
- continue;
- }
- }
- }
- prev = entry;
- if (entry) {
- entry = entry->next;
- }
- }
- }
- return (count);
-}
-
-/**
- * virHashSearch:
- * @table: the hash table to search
- * @iter: an iterator to identify the desired element
- * @data: extra opaque information passed to the iter
- *
- * Iterates over the hash table calling the 'iter' callback
- * for each element. The first element for which the iter
- * returns non-zero will be returned by this function.
- * The elements are processed in a undefined order
- */
-void *virHashSearch(virHashTablePtr table, virHashSearcher iter, const void *data) {
- int i;
-
- if (table == NULL || iter == NULL)
- return (NULL);
-
- for (i = 0 ; i < table->size ; i++) {
- virHashEntryPtr entry = table->table + i;
- while (entry) {
- if (entry->valid) {
- if (iter(entry->payload, entry->name, data))
- return entry->payload;
- }
- entry = entry->next;
- }
- }
- return (NULL);
-}
+++ /dev/null
-/*
- * Summary: Chained hash tables and domain/connections handling
- * Description: This module implements the hash table and allocation and
- * deallocation of domains and connections
- *
- * Copy: Copyright (C) 2005 Red Hat, Inc.
- *
- * Author: Bjorn Reese <bjorn.reese@systematic.dk>
- * Daniel Veillard <veillard@redhat.com>
- */
-
-#ifndef __VIR_HASH_H__
-#define __VIR_HASH_H__
-
-/*
- * The hash table.
- */
-typedef struct _virHashTable virHashTable;
-typedef virHashTable *virHashTablePtr;
-
-/*
- * function types:
- */
-
-/**
- * virHashDeallocator:
- * @payload: the data in the hash
- * @name: the name associated
- *
- * Callback to free data from a hash.
- */
-typedef void (*virHashDeallocator) (void *payload, const char *name);
-/**
- * virHashIterator:
- * @payload: the data in the hash
- * @name: the name associated
- * @data: user supplied data blob
- *
- * Callback to process a hash entry during iteration
- */
-typedef void (*virHashIterator) (const void *payload, const char *name, const void *data);
-/**
- * virHashSearcher
- * @payload: the data in the hash
- * @name: the name associated
- * @data: user supplied data blob
- *
- * Callback to identify hash entry desired
- * Returns 1 if the hash entry is desired, 0 to move
- * to next entry
- */
-typedef int (*virHashSearcher) (const void *payload, const char *name, const void *data);
-
-/*
- * Constructor and destructor.
- */
-virHashTablePtr virHashCreate(int size);
-void virHashFree(virHashTablePtr table, virHashDeallocator f);
-int virHashSize(virHashTablePtr table);
-
-/*
- * Add a new entry to the hash table.
- */
-int virHashAddEntry(virHashTablePtr table,
- const char *name, void *userdata);
-int virHashUpdateEntry(virHashTablePtr table,
- const char *name,
- void *userdata, virHashDeallocator f);
-
-/*
- * Remove an entry from the hash table.
- */
-int virHashRemoveEntry(virHashTablePtr table,
- const char *name, virHashDeallocator f);
-
-/*
- * Retrieve the userdata.
- */
-void *virHashLookup(virHashTablePtr table, const char *name);
-
-
-/*
- * Iterators
- */
-int virHashForEach(virHashTablePtr table, virHashIterator iter, const void *data);
-int virHashRemoveSet(virHashTablePtr table, virHashSearcher iter, virHashDeallocator f, const void *data);
-void *virHashSearch(virHashTablePtr table, virHashSearcher iter, const void *data);
-
-#endif /* ! __VIR_HASH_H__ */
+++ /dev/null
-/*
- * Copyright (C) 2009 Red Hat, Inc.
- *
- * 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
- *
- * Authors:
- * Daniel P. Berrange <berrange@redhat.com>
- */
-
-#include <config.h>
-
-#include <dirent.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <limits.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include "hostusb.h"
-#include "logging.h"
-#include "memory.h"
-#include "util.h"
-#include "virterror_internal.h"
-
-#define USB_DEVFS "/dev/bus/usb/"
-#define USB_ID_LEN 10 /* "XXXX XXXX" */
-#define USB_ADDR_LEN 8 /* "XXX:XXX" */
-
-struct _usbDevice {
- unsigned bus;
- unsigned dev;
-
- char name[USB_ADDR_LEN]; /* domain:bus:slot.function */
- char id[USB_ID_LEN]; /* product vendor */
- char path[PATH_MAX];
-};
-
-/* For virReportOOMError() and virReportSystemError() */
-#define VIR_FROM_THIS VIR_FROM_NONE
-
-#define usbReportError(conn, code, fmt...) \
- virReportErrorHelper(conn, VIR_FROM_NONE, code, __FILE__, \
- __FUNCTION__, __LINE__, fmt)
-
-
-usbDevice *
-usbGetDevice(virConnectPtr conn,
- unsigned bus,
- unsigned devno)
-{
- usbDevice *dev;
-
- if (VIR_ALLOC(dev) < 0) {
- virReportOOMError(conn);
- return NULL;
- }
-
- dev->bus = bus;
- dev->dev = devno;
-
- snprintf(dev->name, sizeof(dev->name), "%.3o:%.3o",
- dev->bus, dev->dev);
- snprintf(dev->path, sizeof(dev->path),
- USB_DEVFS "%03o/%03o", dev->bus, dev->dev);
-
- /* XXX fixme. this should be product/vendor */
- snprintf(dev->id, sizeof(dev->id), "%d %d", dev->bus, dev->dev);
-
- VIR_DEBUG("%s %s: initialized", dev->id, dev->name);
-
- return dev;
-}
-
-void
-usbFreeDevice(virConnectPtr conn ATTRIBUTE_UNUSED, usbDevice *dev)
-{
- VIR_DEBUG("%s %s: freeing", dev->id, dev->name);
- VIR_FREE(dev);
-}
-
-
-int usbDeviceFileIterate(virConnectPtr conn,
- usbDevice *dev,
- usbDeviceFileActor actor,
- void *opaque)
-{
- return (actor)(conn, dev, dev->path, opaque);
-}
+++ /dev/null
-/*
- * Copyright (C) 2009 Red Hat, Inc.
- *
- * 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
- *
- * Authors:
- * Daniel P. Berrange <berrange@redhat.com>
- */
-
-#ifndef __VIR_USB_H__
-#define __VIR_USB_H__
-
-#include "internal.h"
-
-typedef struct _usbDevice usbDevice;
-
-usbDevice *usbGetDevice (virConnectPtr conn,
- unsigned bus,
- unsigned devno);
-void usbFreeDevice (virConnectPtr conn,
- usbDevice *dev);
-
-/*
- * Callback that will be invoked once for each file
- * associated with / used for USB host device access.
- *
- * Should return 0 if successfully processed, or
- * -1 to indicate error and abort iteration
- */
-typedef int (*usbDeviceFileActor)(virConnectPtr conn, usbDevice *dev,
- const char *path, void *opaque);
-
-int usbDeviceFileIterate(virConnectPtr conn,
- usbDevice *dev,
- usbDeviceFileActor actor,
- void *opaque);
-
-
-#endif /* __VIR_USB_H__ */
+++ /dev/null
-/*
- * Copyright (C) 2007-2009 Red Hat, Inc.
- *
- * 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
- *
- * Authors:
- * Mark McLoughlin <markmc@redhat.com>
- */
-
-#include <config.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <errno.h>
-#include <limits.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#ifdef HAVE_SYS_WAIT_H
-#include <sys/wait.h>
-#endif
-
-#ifdef HAVE_PATHS_H
-#include <paths.h>
-#endif
-
-#include "internal.h"
-#include "iptables.h"
-#include "util.h"
-#include "memory.h"
-#include "virterror_internal.h"
-#include "logging.h"
-
-enum {
- ADD = 0,
- REMOVE
-};
-
-typedef struct
-{
- char *rule;
- const char **argv;
- int command_idx;
-} iptRule;
-
-typedef struct
-{
- char *table;
- char *chain;
-
- int nrules;
- iptRule *rules;
-
-#ifdef ENABLE_IPTABLES_LOKKIT
-
- char dir[PATH_MAX];
- char path[PATH_MAX];
-
-#endif /* ENABLE_IPTABLES_LOKKIT */
-
-} iptRules;
-
-struct _iptablesContext
-{
- iptRules *input_filter;
- iptRules *forward_filter;
- iptRules *nat_postrouting;
-};
-
-#ifdef ENABLE_IPTABLES_LOKKIT
-static void
-notifyRulesUpdated(const char *table,
- const char *path)
-{
- char arg[PATH_MAX];
- const char *argv[4];
-
- snprintf(arg, sizeof(arg), "--custom-rules=ipv4:%s:%s", table, path);
-
- argv[0] = (char *) LOKKIT_PATH;
- argv[1] = (char *) "--nostart";
- argv[2] = arg;
- argv[3] = NULL;
-
- char ebuf[1024];
- if (virRun(NULL, argv, NULL) < 0)
- VIR_WARN(_("Failed to run '%s %s': %s"),
- LOKKIT_PATH, arg, virStrerror(errno, ebuf, sizeof ebuf));
-}
-
-static int
-stripLine(char *str, int len, const char *line)
-{
- char *s, *p;
- int changed;
-
- changed = 0;
- s = str;
-
- while ((p = strchr(s, '\n'))) {
- if (p == s || STRNEQLEN(s, line, p - s)) {
- s = ++p;
- continue;
- }
-
- ++p;
- memmove(s, p, len - (p - str) + 1);
- len -= p - s;
- changed = 1;
- }
-
- if (STREQ(s, line)) {
- *s = '\0';
- changed = 1;
- }
-
- return changed;
-}
-
-static void
-notifyRulesRemoved(const char *table,
- const char *path)
-{
-/* 10 MB limit on config file size as a sanity check */
-#define MAX_FILE_LEN (1024*1024*10)
-
- char arg[PATH_MAX];
- char *content;
- int len;
- FILE *f = NULL;
-
- len = virFileReadAll(SYSCONF_DIR "/sysconfig/system-config-firewall",
- MAX_FILE_LEN, &content);
- if (len < 0) {
- VIR_WARN("%s", _("Failed to read " SYSCONF_DIR
- "/sysconfig/system-config-firewall"));
- return;
- }
-
- snprintf(arg, sizeof(arg), "--custom-rules=ipv4:%s:%s", table, path);
-
- if (!stripLine(content, len, arg)) {
- VIR_FREE(content);
- return;
- }
-
- if (!(f = fopen(SYSCONF_DIR "/sysconfig/system-config-firewall", "w")))
- goto write_error;
-
- if (fputs(content, f) == EOF)
- goto write_error;
-
- if (fclose(f) == EOF) {
- f = NULL;
- goto write_error;
- }
-
- VIR_FREE(content);
-
- return;
-
- write_error:;
- char ebuf[1024];
- VIR_WARN(_("Failed to write to " SYSCONF_DIR
- "/sysconfig/system-config-firewall : %s"),
- virStrerror(errno, ebuf, sizeof ebuf));
- if (f)
- fclose(f);
- VIR_FREE(content);
-
-#undef MAX_FILE_LEN
-}
-
-static int
-writeRules(const char *path,
- const iptRule *rules,
- int nrules)
-{
- char tmp[PATH_MAX];
- FILE *f;
- int istmp;
- int i;
-
- if (nrules == 0 && unlink(path) == 0)
- return 0;
-
- if (snprintf(tmp, PATH_MAX, "%s.new", path) >= PATH_MAX)
- return EINVAL;
-
- istmp = 1;
-
- if (!(f = fopen(tmp, "w"))) {
- istmp = 0;
- if (!(f = fopen(path, "w")))
- return errno;
- }
-
- for (i = 0; i < nrules; i++) {
- if (fputs(rules[i].rule, f) == EOF ||
- fputc('\n', f) == EOF) {
- fclose(f);
- if (istmp)
- unlink(tmp);
- return errno;
- }
- }
-
- fclose(f);
-
- if (istmp && rename(tmp, path) < 0) {
- unlink(tmp);
- return errno;
- }
-
- if (istmp)
- unlink(tmp);
-
- return 0;
-}
-#endif /* ENABLE_IPTABLES_LOKKIT */
-
-static void
-iptRulesSave(iptRules *rules)
-{
-#ifdef ENABLE_IPTABLES_LOKKIT
- int err;
-
- char ebuf[1024];
- if ((err = virFileMakePath(rules->dir))) {
- VIR_WARN(_("Failed to create directory %s : %s"),
- rules->dir, virStrerror(err, ebuf, sizeof ebuf));
- return;
- }
-
- if ((err = writeRules(rules->path, rules->rules, rules->nrules))) {
- VIR_WARN(_("Failed to saves iptables rules to %s : %s"),
- rules->path, virStrerror(err, ebuf, sizeof ebuf));
- return;
- }
-
- if (rules->nrules > 0)
- notifyRulesUpdated(rules->table, rules->path);
- else
- notifyRulesRemoved(rules->table, rules->path);
-#else
- (void) rules;
-#endif /* ENABLE_IPTABLES_LOKKIT */
-}
-
-static void
-iptRuleFree(iptRule *rule)
-{
- VIR_FREE(rule->rule);
-
- if (rule->argv) {
- int i = 0;
- while (rule->argv[i])
- VIR_FREE(rule->argv[i++]);
- VIR_FREE(rule->argv);
- }
-}
-
-static int
-iptRulesAppend(iptRules *rules,
- char *rule,
- const char **argv,
- int command_idx)
-{
- if (VIR_REALLOC_N(rules->rules, rules->nrules+1) < 0) {
- int i = 0;
- while (argv[i])
- VIR_FREE(argv[i++]);
- VIR_FREE(argv);
- return ENOMEM;
- }
-
- rules->rules[rules->nrules].rule = rule;
- rules->rules[rules->nrules].argv = argv;
- rules->rules[rules->nrules].command_idx = command_idx;
-
- rules->nrules++;
-
- return 0;
-}
-
-static int
-iptRulesRemove(iptRules *rules,
- char *rule)
-{
- int i;
-
- for (i = 0; i < rules->nrules; i++)
- if (STREQ(rules->rules[i].rule, rule))
- break;
-
- if (i >= rules->nrules)
- return EINVAL;
-
- iptRuleFree(&rules->rules[i]);
-
- memmove(&rules->rules[i],
- &rules->rules[i+1],
- (rules->nrules - i - 1) * sizeof (iptRule));
-
- rules->nrules--;
-
- return 0;
-}
-
-static void
-iptRulesFree(iptRules *rules)
-{
- int i;
-
- VIR_FREE(rules->table);
- VIR_FREE(rules->chain);
-
- if (rules->rules) {
- for (i = 0; i < rules->nrules; i++)
- iptRuleFree(&rules->rules[i]);
-
- VIR_FREE(rules->rules);
-
- rules->nrules = 0;
- }
-
-#ifdef ENABLE_IPTABLES_LOKKIT
- rules->dir[0] = '\0';
- rules->path[0] = '\0';
-#endif /* ENABLE_IPTABLES_LOKKIT */
-
- VIR_FREE(rules);
-}
-
-static iptRules *
-iptRulesNew(const char *table,
- const char *chain)
-{
- iptRules *rules;
-
- if (VIR_ALLOC(rules) < 0)
- return NULL;
-
- if (!(rules->table = strdup(table)))
- goto error;
-
- if (!(rules->chain = strdup(chain)))
- goto error;
-
- rules->rules = NULL;
- rules->nrules = 0;
-
-#ifdef ENABLE_IPTABLES_LOKKIT
- if (virFileBuildPath(LOCAL_STATE_DIR "/lib/libvirt/iptables", table, NULL,
- rules->dir, sizeof(rules->dir)) < 0)
- goto error;
-
- if (virFileBuildPath(rules->dir, chain, ".chain", rules->path, sizeof(rules->path)) < 0)
- goto error;
-#endif /* ENABLE_IPTABLES_LOKKIT */
-
- return rules;
-
- error:
- iptRulesFree(rules);
- return NULL;
-}
-
-static int
-iptablesAddRemoveRule(iptRules *rules, int action, const char *arg, ...)
-{
- va_list args;
- int retval = ENOMEM;
- const char **argv;
- char *rule = NULL;
- const char *s;
- int n, command_idx;
-
- n = 1 + /* /sbin/iptables */
- 2 + /* --table foo */
- 2 + /* --insert bar */
- 1; /* arg */
-
- va_start(args, arg);
- while (va_arg(args, const char *))
- n++;
-
- va_end(args);
-
- if (VIR_ALLOC_N(argv, n + 1) < 0)
- goto error;
-
- n = 0;
-
- if (!(argv[n++] = strdup(IPTABLES_PATH)))
- goto error;
-
- if (!(argv[n++] = strdup("--table")))
- goto error;
-
- if (!(argv[n++] = strdup(rules->table)))
- goto error;
-
- command_idx = n;
-
- if (!(argv[n++] = strdup("--insert")))
- goto error;
-
- if (!(argv[n++] = strdup(rules->chain)))
- goto error;
-
- if (!(argv[n++] = strdup(arg)))
- goto error;
-
- va_start(args, arg);
-
- while ((s = va_arg(args, const char *)))
- if (!(argv[n++] = strdup(s)))
- goto error;
-
- va_end(args);
-
- if (!(rule = virArgvToString(&argv[command_idx])))
- goto error;
-
- if (action == REMOVE) {
- VIR_FREE(argv[command_idx]);
- if (!(argv[command_idx] = strdup("--delete")))
- goto error;
- }
-
- if (virRun(NULL, argv, NULL) < 0) {
- retval = errno;
- goto error;
- }
-
- if (action == ADD) {
- retval = iptRulesAppend(rules, rule, argv, command_idx);
- rule = NULL;
- argv = NULL;
- } else {
- retval = iptRulesRemove(rules, rule);
- }
-
- error:
- VIR_FREE(rule);
-
- if (argv) {
- n = 0;
- while (argv[n])
- VIR_FREE(argv[n++]);
- VIR_FREE(argv);
- }
-
- return retval;
-}
-
-/**
- * iptablesContextNew:
- *
- * Create a new IPtable context
- *
- * Returns a pointer to the new structure or NULL in case of error
- */
-iptablesContext *
-iptablesContextNew(void)
-{
- iptablesContext *ctx;
-
- if (VIR_ALLOC(ctx) < 0)
- return NULL;
-
- if (!(ctx->input_filter = iptRulesNew("filter", "INPUT")))
- goto error;
-
- if (!(ctx->forward_filter = iptRulesNew("filter", "FORWARD")))
- goto error;
-
- if (!(ctx->nat_postrouting = iptRulesNew("nat", "POSTROUTING")))
- goto error;
-
- return ctx;
-
- error:
- iptablesContextFree(ctx);
- return NULL;
-}
-
-/**
- * iptablesContextFree:
- * @ctx: pointer to the IP table context
- *
- * Free the resources associated with an IP table context
- */
-void
-iptablesContextFree(iptablesContext *ctx)
-{
- if (ctx->input_filter)
- iptRulesFree(ctx->input_filter);
- if (ctx->forward_filter)
- iptRulesFree(ctx->forward_filter);
- if (ctx->nat_postrouting)
- iptRulesFree(ctx->nat_postrouting);
- VIR_FREE(ctx);
-}
-
-/**
- * iptablesSaveRules:
- * @ctx: pointer to the IP table context
- *
- * Saves all the IP table rules associated with a context
- * to disk so that if iptables is restarted, the rules
- * will automatically be reload.
- */
-void
-iptablesSaveRules(iptablesContext *ctx)
-{
- iptRulesSave(ctx->input_filter);
- iptRulesSave(ctx->forward_filter);
- iptRulesSave(ctx->nat_postrouting);
-}
-
-static void
-iptRulesReload(iptRules *rules)
-{
- int i;
- char ebuf[1024];
-
- for (i = 0; i < rules->nrules; i++) {
- iptRule *rule = &rules->rules[i];
- const char *orig;
-
- orig = rule->argv[rule->command_idx];
- rule->argv[rule->command_idx] = (char *) "--delete";
-
- if (virRun(NULL, rule->argv, NULL) < 0)
- VIR_WARN(_("Failed to remove iptables rule '%s'"
- " from chain '%s' in table '%s': %s"),
- rule->rule, rules->chain, rules->table,
- virStrerror(errno, ebuf, sizeof ebuf));
-
- rule->argv[rule->command_idx] = orig;
- }
-
- for (i = 0; i < rules->nrules; i++)
- if (virRun(NULL, rules->rules[i].argv, NULL) < 0)
- VIR_WARN(_("Failed to add iptables rule '%s'"
- " to chain '%s' in table '%s': %s"),
- rules->rules[i].rule, rules->chain, rules->table,
- virStrerror(errno, ebuf, sizeof ebuf));
-}
-
-/**
- * iptablesReloadRules:
- * @ctx: pointer to the IP table context
- *
- * Reloads all the IP table rules associated to a context
- */
-void
-iptablesReloadRules(iptablesContext *ctx)
-{
- iptRulesReload(ctx->input_filter);
- iptRulesReload(ctx->forward_filter);
- iptRulesReload(ctx->nat_postrouting);
-}
-
-static int
-iptablesInput(iptablesContext *ctx,
- const char *iface,
- int port,
- int action,
- int tcp)
-{
- char portstr[32];
-
- snprintf(portstr, sizeof(portstr), "%d", port);
- portstr[sizeof(portstr) - 1] = '\0';
-
- return iptablesAddRemoveRule(ctx->input_filter,
- action,
- "--in-interface", iface,
- "--protocol", tcp ? "tcp" : "udp",
- "--destination-port", portstr,
- "--jump", "ACCEPT",
- NULL);
-}
-
-/**
- * iptablesAddTcpInput:
- * @ctx: pointer to the IP table context
- * @iface: the interface name
- * @port: the TCP port to add
- *
- * Add an input to the IP table allowing access to the given @port on
- * the given @iface interface for TCP packets
- *
- * Returns 0 in case of success or an error code in case of error
- */
-
-int
-iptablesAddTcpInput(iptablesContext *ctx,
- const char *iface,
- int port)
-{
- return iptablesInput(ctx, iface, port, ADD, 1);
-}
-
-/**
- * iptablesRemoveTcpInput:
- * @ctx: pointer to the IP table context
- * @iface: the interface name
- * @port: the TCP port to remove
- *
- * Removes an input from the IP table, hence forbidding access to the given
- * @port on the given @iface interface for TCP packets
- *
- * Returns 0 in case of success or an error code in case of error
- */
-int
-iptablesRemoveTcpInput(iptablesContext *ctx,
- const char *iface,
- int port)
-{
- return iptablesInput(ctx, iface, port, REMOVE, 1);
-}
-
-/**
- * iptablesAddUdpInput:
- * @ctx: pointer to the IP table context
- * @iface: the interface name
- * @port: the UDP port to add
- *
- * Add an input to the IP table allowing access to the given @port on
- * the given @iface interface for UDP packets
- *
- * Returns 0 in case of success or an error code in case of error
- */
-
-int
-iptablesAddUdpInput(iptablesContext *ctx,
- const char *iface,
- int port)
-{
- return iptablesInput(ctx, iface, port, ADD, 0);
-}
-
-/**
- * iptablesRemoveUdpInput:
- * @ctx: pointer to the IP table context
- * @iface: the interface name
- * @port: the UDP port to remove
- *
- * Removes an input from the IP table, hence forbidding access to the given
- * @port on the given @iface interface for UDP packets
- *
- * Returns 0 in case of success or an error code in case of error
- */
-int
-iptablesRemoveUdpInput(iptablesContext *ctx,
- const char *iface,
- int port)
-{
- return iptablesInput(ctx, iface, port, REMOVE, 0);
-}
-
-
-/* Allow all traffic coming from the bridge, with a valid network address
- * to proceed to WAN
- */
-static int
-iptablesForwardAllowOut(iptablesContext *ctx,
- const char *network,
- const char *iface,
- const char *physdev,
- int action)
-{
- if (physdev && physdev[0]) {
- return iptablesAddRemoveRule(ctx->forward_filter,
- action,
- "--source", network,
- "--in-interface", iface,
- "--out-interface", physdev,
- "--jump", "ACCEPT",
- NULL);
- } else {
- return iptablesAddRemoveRule(ctx->forward_filter,
- action,
- "--source", network,
- "--in-interface", iface,
- "--jump", "ACCEPT",
- NULL);
- }
-}
-
-/**
- * iptablesAddForwardAllowOut:
- * @ctx: pointer to the IP table context
- * @network: the source network name
- * @iface: the source interface name
- * @physdev: the physical output device
- *
- * Add a rule to the IP table context to allow the traffic for the
- * network @network via interface @iface to be forwarded to
- * @physdev device. This allow the outbound traffic on a bridge.
- *
- * Returns 0 in case of success or an error code otherwise
- */
-int
-iptablesAddForwardAllowOut(iptablesContext *ctx,
- const char *network,
- const char *iface,
- const char *physdev)
-{
- return iptablesForwardAllowOut(ctx, network, iface, physdev, ADD);
-}
-
-/**
- * iptablesRemoveForwardAllowOut:
- * @ctx: pointer to the IP table context
- * @network: the source network name
- * @iface: the source interface name
- * @physdev: the physical output device
- *
- * Remove a rule from the IP table context hence forbidding forwarding
- * of the traffic for the network @network via interface @iface
- * to the @physdev device output. This stops the outbound traffic on a bridge.
- *
- * Returns 0 in case of success or an error code otherwise
- */
-int
-iptablesRemoveForwardAllowOut(iptablesContext *ctx,
- const char *network,
- const char *iface,
- const char *physdev)
-{
- return iptablesForwardAllowOut(ctx, network, iface, physdev, REMOVE);
-}
-
-
-/* Allow all traffic destined to the bridge, with a valid network address
- * and associated with an existing connection
- */
-static int
-iptablesForwardAllowRelatedIn(iptablesContext *ctx,
- const char *network,
- const char *iface,
- const char *physdev,
- int action)
-{
- if (physdev && physdev[0]) {
- return iptablesAddRemoveRule(ctx->forward_filter,
- action,
- "--destination", network,
- "--in-interface", physdev,
- "--out-interface", iface,
- "--match", "state",
- "--state", "ESTABLISHED,RELATED",
- "--jump", "ACCEPT",
- NULL);
- } else {
- return iptablesAddRemoveRule(ctx->forward_filter,
- action,
- "--destination", network,
- "--out-interface", iface,
- "--match", "state",
- "--state", "ESTABLISHED,RELATED",
- "--jump", "ACCEPT",
- NULL);
- }
-}
-
-/**
- * iptablesAddForwardAllowRelatedIn:
- * @ctx: pointer to the IP table context
- * @network: the source network name
- * @iface: the output interface name
- * @physdev: the physical input device or NULL
- *
- * Add rules to the IP table context to allow the traffic for the
- * network @network on @physdev device to be forwarded to
- * interface @iface, if it is part of an existing connection.
- *
- * Returns 0 in case of success or an error code otherwise
- */
-int
-iptablesAddForwardAllowRelatedIn(iptablesContext *ctx,
- const char *network,
- const char *iface,
- const char *physdev)
-{
- return iptablesForwardAllowRelatedIn(ctx, network, iface, physdev, ADD);
-}
-
-/**
- * iptablesRemoveForwardAllowRelatedIn:
- * @ctx: pointer to the IP table context
- * @network: the source network name
- * @iface: the output interface name
- * @physdev: the physical input device or NULL
- *
- * Remove rules from the IP table context hence forbidding the traffic for
- * network @network on @physdev device to be forwarded to
- * interface @iface, if it is part of an existing connection.
- *
- * Returns 0 in case of success or an error code otherwise
- */
-int
-iptablesRemoveForwardAllowRelatedIn(iptablesContext *ctx,
- const char *network,
- const char *iface,
- const char *physdev)
-{
- return iptablesForwardAllowRelatedIn(ctx, network, iface, physdev, REMOVE);
-}
-
-/* Allow all traffic destined to the bridge, with a valid network address
- */
-static int
-iptablesForwardAllowIn(iptablesContext *ctx,
- const char *network,
- const char *iface,
- const char *physdev,
- int action)
-{
- if (physdev && physdev[0]) {
- return iptablesAddRemoveRule(ctx->forward_filter,
- action,
- "--destination", network,
- "--in-interface", physdev,
- "--out-interface", iface,
- "--jump", "ACCEPT",
- NULL);
- } else {
- return iptablesAddRemoveRule(ctx->forward_filter,
- action,
- "--destination", network,
- "--out-interface", iface,
- "--jump", "ACCEPT",
- NULL);
- }
-}
-
-/**
- * iptablesAddForwardAllowIn:
- * @ctx: pointer to the IP table context
- * @network: the source network name
- * @iface: the output interface name
- * @physdev: the physical input device or NULL
- *
- * Add rules to the IP table context to allow the traffic for the
- * network @network on @physdev device to be forwarded to
- * interface @iface. This allow the inbound traffic on a bridge.
- *
- * Returns 0 in case of success or an error code otherwise
- */
-int
-iptablesAddForwardAllowIn(iptablesContext *ctx,
- const char *network,
- const char *iface,
- const char *physdev)
-{
- return iptablesForwardAllowIn(ctx, network, iface, physdev, ADD);
-}
-
-/**
- * iptablesRemoveForwardAllowIn:
- * @ctx: pointer to the IP table context
- * @network: the source network name
- * @iface: the output interface name
- * @physdev: the physical input device or NULL
- *
- * Remove rules from the IP table context hence forbidding the traffic for
- * network @network on @physdev device to be forwarded to
- * interface @iface. This stops the inbound traffic on a bridge.
- *
- * Returns 0 in case of success or an error code otherwise
- */
-int
-iptablesRemoveForwardAllowIn(iptablesContext *ctx,
- const char *network,
- const char *iface,
- const char *physdev)
-{
- return iptablesForwardAllowIn(ctx, network, iface, physdev, REMOVE);
-}
-
-
-/* Allow all traffic between guests on the same bridge,
- * with a valid network address
- */
-static int
-iptablesForwardAllowCross(iptablesContext *ctx,
- const char *iface,
- int action)
-{
- return iptablesAddRemoveRule(ctx->forward_filter,
- action,
- "--in-interface", iface,
- "--out-interface", iface,
- "--jump", "ACCEPT",
- NULL);
-}
-
-/**
- * iptablesAddForwardAllowCross:
- * @ctx: pointer to the IP table context
- * @iface: the input/output interface name
- *
- * Add rules to the IP table context to allow traffic to cross that
- * interface. It allows all traffic between guests on the same bridge
- * represented by that interface.
- *
- * Returns 0 in case of success or an error code otherwise
- */
-int
-iptablesAddForwardAllowCross(iptablesContext *ctx,
- const char *iface) {
- return iptablesForwardAllowCross(ctx, iface, ADD);
-}
-
-/**
- * iptablesRemoveForwardAllowCross:
- * @ctx: pointer to the IP table context
- * @iface: the input/output interface name
- *
- * Remove rules to the IP table context to block traffic to cross that
- * interface. It forbids traffic between guests on the same bridge
- * represented by that interface.
- *
- * Returns 0 in case of success or an error code otherwise
- */
-int
-iptablesRemoveForwardAllowCross(iptablesContext *ctx,
- const char *iface) {
- return iptablesForwardAllowCross(ctx, iface, REMOVE);
-}
-
-
-/* Drop all traffic trying to forward from the bridge.
- * ie the bridge is the in interface
- */
-static int
-iptablesForwardRejectOut(iptablesContext *ctx,
- const char *iface,
- int action)
-{
- return iptablesAddRemoveRule(ctx->forward_filter,
- action,
- "--in-interface", iface,
- "--jump", "REJECT",
- NULL);
-}
-
-/**
- * iptablesAddForwardRejectOut:
- * @ctx: pointer to the IP table context
- * @iface: the output interface name
- *
- * Add rules to the IP table context to forbid all traffic to that
- * interface. It forbids forwarding from the bridge to that interface.
- *
- * Returns 0 in case of success or an error code otherwise
- */
-int
-iptablesAddForwardRejectOut(iptablesContext *ctx,
- const char *iface)
-{
- return iptablesForwardRejectOut(ctx, iface, ADD);
-}
-
-/**
- * iptablesRemoveForwardRejectOut:
- * @ctx: pointer to the IP table context
- * @iface: the output interface name
- *
- * Remove rules from the IP table context forbidding all traffic to that
- * interface. It reallow forwarding from the bridge to that interface.
- *
- * Returns 0 in case of success or an error code otherwise
- */
-int
-iptablesRemoveForwardRejectOut(iptablesContext *ctx,
- const char *iface)
-{
- return iptablesForwardRejectOut(ctx, iface, REMOVE);
-}
-
-
-
-
-/* Drop all traffic trying to forward to the bridge.
- * ie the bridge is the out interface
- */
-static int
-iptablesForwardRejectIn(iptablesContext *ctx,
- const char *iface,
- int action)
-{
- return iptablesAddRemoveRule(ctx->forward_filter,
- action,
- "--out-interface", iface,
- "--jump", "REJECT",
- NULL);
-}
-
-/**
- * iptablesAddForwardRejectIn:
- * @ctx: pointer to the IP table context
- * @iface: the input interface name
- *
- * Add rules to the IP table context to forbid all traffic from that
- * interface. It forbids forwarding from that interface to the bridge.
- *
- * Returns 0 in case of success or an error code otherwise
- */
-int
-iptablesAddForwardRejectIn(iptablesContext *ctx,
- const char *iface)
-{
- return iptablesForwardRejectIn(ctx, iface, ADD);
-}
-
-/**
- * iptablesRemoveForwardRejectIn:
- * @ctx: pointer to the IP table context
- * @iface: the input interface name
- *
- * Remove rules from the IP table context forbidding all traffic from that
- * interface. It allows forwarding from that interface to the bridge.
- *
- * Returns 0 in case of success or an error code otherwise
- */
-int
-iptablesRemoveForwardRejectIn(iptablesContext *ctx,
- const char *iface)
-{
- return iptablesForwardRejectIn(ctx, iface, REMOVE);
-}
-
-
-/* Masquerade all traffic coming from the network associated
- * with the bridge
- */
-static int
-iptablesForwardMasquerade(iptablesContext *ctx,
- const char *network,
- const char *physdev,
- int action)
-{
- if (physdev && physdev[0]) {
- return iptablesAddRemoveRule(ctx->nat_postrouting,
- action,
- "--source", network,
- "--destination", "!", network,
- "--out-interface", physdev,
- "--jump", "MASQUERADE",
- NULL);
- } else {
- return iptablesAddRemoveRule(ctx->nat_postrouting,
- action,
- "--source", network,
- "--destination", "!", network,
- "--jump", "MASQUERADE",
- NULL);
- }
-}
-
-/**
- * iptablesAddForwardMasquerade:
- * @ctx: pointer to the IP table context
- * @network: the source network name
- * @physdev: the physical input device or NULL
- *
- * Add rules to the IP table context to allow masquerading
- * network @network on @physdev. This allow the bridge to
- * masquerade for that network (on @physdev).
- *
- * Returns 0 in case of success or an error code otherwise
- */
-int
-iptablesAddForwardMasquerade(iptablesContext *ctx,
- const char *network,
- const char *physdev)
-{
- return iptablesForwardMasquerade(ctx, network, physdev, ADD);
-}
-
-/**
- * iptablesRemoveForwardMasquerade:
- * @ctx: pointer to the IP table context
- * @network: the source network name
- * @physdev: the physical input device or NULL
- *
- * Remove rules from the IP table context to stop masquerading
- * network @network on @physdev. This stops the bridge from
- * masquerading for that network (on @physdev).
- *
- * Returns 0 in case of success or an error code otherwise
- */
-int
-iptablesRemoveForwardMasquerade(iptablesContext *ctx,
- const char *network,
- const char *physdev)
-{
- return iptablesForwardMasquerade(ctx, network, physdev, REMOVE);
-}
+++ /dev/null
-/*
- * Copyright (C) 2007, 2008 Red Hat, Inc.
- *
- * 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
- *
- * Authors:
- * Mark McLoughlin <markmc@redhat.com>
- */
-
-#ifndef __QEMUD_IPTABLES_H__
-#define __QEMUD_IPTABLES_H__
-
-typedef struct _iptablesContext iptablesContext;
-
-iptablesContext *iptablesContextNew (void);
-void iptablesContextFree (iptablesContext *ctx);
-
-void iptablesSaveRules (iptablesContext *ctx);
-void iptablesReloadRules (iptablesContext *ctx);
-
-int iptablesAddTcpInput (iptablesContext *ctx,
- const char *iface,
- int port);
-int iptablesRemoveTcpInput (iptablesContext *ctx,
- const char *iface,
- int port);
-
-int iptablesAddUdpInput (iptablesContext *ctx,
- const char *iface,
- int port);
-int iptablesRemoveUdpInput (iptablesContext *ctx,
- const char *iface,
- int port);
-
-int iptablesAddForwardAllowOut (iptablesContext *ctx,
- const char *network,
- const char *iface,
- const char *physdev);
-int iptablesRemoveForwardAllowOut (iptablesContext *ctx,
- const char *network,
- const char *iface,
- const char *physdev);
-
-int iptablesAddForwardAllowRelatedIn(iptablesContext *ctx,
- const char *network,
- const char *iface,
- const char *physdev);
-int iptablesRemoveForwardAllowRelatedIn(iptablesContext *ctx,
- const char *network,
- const char *iface,
- const char *physdev);
-
-int iptablesAddForwardAllowIn (iptablesContext *ctx,
- const char *network,
- const char *iface,
- const char *physdev);
-int iptablesRemoveForwardAllowIn (iptablesContext *ctx,
- const char *network,
- const char *iface,
- const char *physdev);
-
-int iptablesAddForwardAllowCross (iptablesContext *ctx,
- const char *iface);
-int iptablesRemoveForwardAllowCross (iptablesContext *ctx,
- const char *iface);
-
-int iptablesAddForwardRejectOut (iptablesContext *ctx,
- const char *iface);
-int iptablesRemoveForwardRejectOut (iptablesContext *ctx,
- const char *iface);
-
-int iptablesAddForwardRejectIn (iptablesContext *ctx,
- const char *iface);
-int iptablesRemoveForwardRejectIn (iptablesContext *ctx,
- const char *iface);
-
-int iptablesAddForwardMasquerade (iptablesContext *ctx,
- const char *network,
- const char *physdev);
-int iptablesRemoveForwardMasquerade (iptablesContext *ctx,
- const char *network,
- const char *physdev);
-
-#endif /* __QEMUD_IPTABLES_H__ */
virConfWriteMem;
+# cgroup.h
+virCgroupForDomain;
+virCgroupForDriver;
+virCgroupRemove;
+virCgroupFree;
+virCgroupAddTask;
+virCgroupSetCpuShares;
+virCgroupGetCpuShares;
+virCgroupDenyDevicePath;
+virCgroupAllowDevicePath;
+virCgroupDenyAllDevices;
+virCgroupAllowDeviceMajor;
+virCgroupControllerTypeToString;
+virCgroupControllerTypeFromString;
+virCgroupGetCpuacctUsage;
+
+
# datatypes.h
virGetDomain;
virGetInterface;
+++ /dev/null
-/*
- * logging.c: internal logging and debugging
- *
- * Copyright (C) 2008 Red Hat, Inc.
- *
- * 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
- *
- */
-
-#include <config.h>
-
-#include <stdio.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <time.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#if HAVE_SYSLOG_H
-#include <syslog.h>
-#endif
-
-#include "logging.h"
-#include "memory.h"
-#include "util.h"
-#include "threads.h"
-
-/*
- * Macro used to format the message as a string in virLogMessage
- * and borrowed from libxml2 (also used in virRaiseError)
- */
-#define VIR_GET_VAR_STR(msg, str) { \
- int size, prev_size = -1; \
- int chars; \
- char *larger; \
- va_list ap; \
- \
- str = (char *) malloc(150); \
- if (str != NULL) { \
- \
- size = 150; \
- \
- while (1) { \
- va_start(ap, msg); \
- chars = vsnprintf(str, size, msg, ap); \
- va_end(ap); \
- if ((chars > -1) && (chars < size)) { \
- if (prev_size == chars) { \
- break; \
- } else { \
- prev_size = chars; \
- } \
- } \
- if (chars > -1) \
- size += chars + 1; \
- else \
- size += 100; \
- if ((larger = (char *) realloc(str, size)) == NULL) { \
- break; \
- } \
- str = larger; \
- }} \
-}
-
-/*
- * A logging buffer to keep some history over logs
- */
-#define LOG_BUFFER_SIZE 64000
-
-static char virLogBuffer[LOG_BUFFER_SIZE + 1];
-static int virLogLen = 0;
-static int virLogStart = 0;
-static int virLogEnd = 0;
-
-/*
- * Filters are used to refine the rules on what to keep or drop
- * based on a matching pattern (currently a substring)
- */
-struct _virLogFilter {
- const char *match;
- int priority;
-};
-typedef struct _virLogFilter virLogFilter;
-typedef virLogFilter *virLogFilterPtr;
-
-static virLogFilterPtr virLogFilters = NULL;
-static int virLogNbFilters = 0;
-
-/*
- * Outputs are used to emit the messages retained
- * after filtering, multiple output can be used simultaneously
- */
-struct _virLogOutput {
- void *data;
- virLogOutputFunc f;
- virLogCloseFunc c;
- int priority;
-};
-typedef struct _virLogOutput virLogOutput;
-typedef virLogOutput *virLogOutputPtr;
-
-static virLogOutputPtr virLogOutputs = NULL;
-static int virLogNbOutputs = 0;
-
-/*
- * Default priorities
- */
-static virLogPriority virLogDefaultPriority = VIR_LOG_DEFAULT;
-
-static int virLogResetFilters(void);
-static int virLogResetOutputs(void);
-
-/*
- * Logs accesses must be serialized though a mutex
- */
-virMutex virLogMutex;
-
-static void virLogLock(void)
-{
- virMutexLock(&virLogMutex);
-}
-static void virLogUnlock(void)
-{
- virMutexUnlock(&virLogMutex);
-}
-
-
-static const char *virLogPriorityString(virLogPriority lvl) {
- switch (lvl) {
- case VIR_LOG_DEBUG:
- return("debug");
- case VIR_LOG_INFO:
- return("info");
- case VIR_LOG_WARN:
- return("warning");
- case VIR_LOG_ERROR:
- return("error");
- }
- return("unknown");
-}
-
-static int virLogInitialized = 0;
-
-/**
- * virLogStartup:
- *
- * Initialize the logging module
- *
- * Returns 0 if successful, and -1 in case or error
- */
-int virLogStartup(void) {
- if (virLogInitialized)
- return(-1);
-
- if (virMutexInit(&virLogMutex) < 0)
- return -1;
-
- virLogInitialized = 1;
- virLogLock();
- virLogLen = 0;
- virLogStart = 0;
- virLogEnd = 0;
- virLogDefaultPriority = VIR_LOG_DEFAULT;
- virLogUnlock();
- return(0);
-}
-
-/**
- * virLogReset:
- *
- * Reset the logging module to its default initial state
- *
- * Returns 0 if successful, and -1 in case or error
- */
-int virLogReset(void) {
- if (!virLogInitialized)
- return(virLogStartup());
-
- virLogLock();
- virLogResetFilters();
- virLogResetOutputs();
- virLogLen = 0;
- virLogStart = 0;
- virLogEnd = 0;
- virLogDefaultPriority = VIR_LOG_DEFAULT;
- virLogUnlock();
- return(0);
-}
-/**
- * virLogShutdown:
- *
- * Shutdown the logging module
- */
-void virLogShutdown(void) {
- if (!virLogInitialized)
- return;
- virLogLock();
- virLogResetFilters();
- virLogResetOutputs();
- virLogLen = 0;
- virLogStart = 0;
- virLogEnd = 0;
- virLogUnlock();
- virMutexDestroy(&virLogMutex);
- virLogInitialized = 0;
-}
-
-/*
- * Store a string in the ring buffer
- */
-static void virLogStr(const char *str, int len) {
- int tmp;
-
- if (str == NULL)
- return;
- if (len <= 0)
- len = strlen(str);
- if (len > LOG_BUFFER_SIZE)
- return;
- virLogLock();
-
- /*
- * copy the data and reset the end, we cycle over the end of the buffer
- */
- if (virLogEnd + len >= LOG_BUFFER_SIZE) {
- tmp = LOG_BUFFER_SIZE - virLogEnd;
- memcpy(&virLogBuffer[virLogEnd], str, tmp);
- virLogBuffer[LOG_BUFFER_SIZE] = 0;
- memcpy(&virLogBuffer[0], &str[tmp], len - tmp);
- virLogEnd = len - tmp;
- } else {
- memcpy(&virLogBuffer[virLogEnd], str, len);
- virLogEnd += len;
- }
- /*
- * Update the log length, and if full move the start index
- */
- virLogLen += len;
- if (virLogLen > LOG_BUFFER_SIZE) {
- tmp = virLogLen - LOG_BUFFER_SIZE;
- virLogLen = LOG_BUFFER_SIZE;
- virLogStart += tmp;
- }
- virLogUnlock();
-}
-
-#if 0
-/*
- * Output the ring buffer
- */
-static int virLogDump(void *data, virLogOutputFunc f) {
- int ret = 0, tmp;
-
- if ((virLogLen == 0) || (f == NULL))
- return(0);
- virLogLock();
- if (virLogStart + virLogLen < LOG_BUFFER_SIZE) {
-push_end:
- virLogBuffer[virLogStart + virLogLen] = 0;
- tmp = f(data, &virLogBuffer[virLogStart], virLogLen);
- if (tmp < 0) {
- ret = -1;
- goto error;
- }
- ret += tmp;
- virLogStart += tmp;
- virLogLen -= tmp;
- } else {
- tmp = LOG_BUFFER_SIZE - virLogStart;
- ret = f(data, &virLogBuffer[virLogStart], tmp);
- if (ret < 0) {
- ret = -1;
- goto error;
- }
- if (ret < tmp) {
- virLogStart += ret;
- virLogLen -= ret;
- } else {
- virLogStart = 0;
- virLogLen -= tmp;
- /* dump the second part */
- if (virLogLen > 0)
- goto push_end;
- }
- }
-error:
- virLogUnlock();
- return(ret);
-}
-#endif
-
-/**
- * virLogSetDefaultPriority:
- * @priority: the default priority level
- *
- * Set the default priority level, i.e. any logged data of a priority
- * equal or superior to this level will be logged, unless a specific rule
- * was defined for the log category of the message.
- *
- * Returns 0 if successful, -1 in case of error.
- */
-int virLogSetDefaultPriority(int priority) {
- if ((priority < VIR_LOG_DEBUG) || (priority > VIR_LOG_ERROR)) {
- VIR_WARN0(_("Ignoring invalid log level setting."));
- return(-1);
- }
- if (!virLogInitialized)
- virLogStartup();
- virLogDefaultPriority = priority;
- return(0);
-}
-
-/**
- * virLogResetFilters:
- *
- * Removes the set of logging filters defined.
- *
- * Returns the number of filters removed
- */
-static int virLogResetFilters(void) {
- int i;
-
- for (i = 0; i < virLogNbFilters;i++)
- VIR_FREE(virLogFilters[i].match);
- VIR_FREE(virLogFilters);
- virLogNbFilters = 0;
- return(i);
-}
-
-/**
- * virLogDefineFilter:
- * @match: the pattern to match
- * @priority: the priority to give to messages matching the pattern
- * @flags: extra flag, currently unused
- *
- * Defines a pattern used for log filtering, it allow to select or
- * reject messages independently of the default priority.
- * The filter defines a rules that will apply only to messages matching
- * the pattern (currently if @match is a substring of the message category)
- *
- * Returns -1 in case of failure or the filter number if successful
- */
-int virLogDefineFilter(const char *match, int priority,
- int flags ATTRIBUTE_UNUSED) {
- int i;
- char *mdup = NULL;
-
- if ((match == NULL) || (priority < VIR_LOG_DEBUG) ||
- (priority > VIR_LOG_ERROR))
- return(-1);
-
- virLogLock();
- for (i = 0;i < virLogNbFilters;i++) {
- if (STREQ(virLogFilters[i].match, match)) {
- virLogFilters[i].priority = priority;
- goto cleanup;
- }
- }
-
- mdup = strdup(match);
- if (dup == NULL) {
- i = -1;
- goto cleanup;
- }
- i = virLogNbFilters;
- if (VIR_REALLOC_N(virLogFilters, virLogNbFilters + 1)) {
- i = -1;
- VIR_FREE(mdup);
- goto cleanup;
- }
- virLogFilters[i].match = mdup;
- virLogFilters[i].priority = priority;
- virLogNbFilters++;
-cleanup:
- virLogUnlock();
- return(i);
-}
-
-/**
- * virLogFiltersCheck:
- * @input: the input string
- *
- * Check the input of the message against the existing filters. Currently
- * the match is just a substring check of the category used as the input
- * string, a more subtle approach could be used instead
- *
- * Returns 0 if not matched or the new priority if found.
- */
-static int virLogFiltersCheck(const char *input) {
- int ret = 0;
- int i;
-
- virLogLock();
- for (i = 0;i < virLogNbFilters;i++) {
- if (strstr(input, virLogFilters[i].match)) {
- ret = virLogFilters[i].priority;
- break;
- }
- }
- virLogUnlock();
- return(ret);
-}
-
-/**
- * virLogResetOutputs:
- *
- * Removes the set of logging output defined.
- *
- * Returns the number of output removed
- */
-static int virLogResetOutputs(void) {
- int i;
-
- for (i = 0;i < virLogNbOutputs;i++) {
- if (virLogOutputs[i].c != NULL)
- virLogOutputs[i].c(virLogOutputs[i].data);
- }
- VIR_FREE(virLogOutputs);
- i = virLogNbOutputs;
- virLogNbOutputs = 0;
- return(i);
-}
-
-/**
- * virLogDefineOutput:
- * @f: the function to call to output a message
- * @f: the function to call to close the output (or NULL)
- * @data: extra data passed as first arg to the function
- * @priority: minimal priority for this filter, use 0 for none
- * @flags: extra flag, currently unused
- *
- * Defines an output function for log messages. Each message once
- * gone though filtering is emitted through each registered output.
- *
- * Returns -1 in case of failure or the output number if successful
- */
-int virLogDefineOutput(virLogOutputFunc f, virLogCloseFunc c, void *data,
- int priority, int flags ATTRIBUTE_UNUSED) {
- int ret = -1;
-
- if (f == NULL)
- return(-1);
-
- virLogLock();
- if (VIR_REALLOC_N(virLogOutputs, virLogNbOutputs + 1)) {
- goto cleanup;
- }
- ret = virLogNbOutputs++;
- virLogOutputs[ret].f = f;
- virLogOutputs[ret].c = c;
- virLogOutputs[ret].data = data;
- virLogOutputs[ret].priority = priority;
-cleanup:
- virLogUnlock();
- return(ret);
-}
-
-/**
- * virLogMessage:
- * @category: where is that message coming from
- * @priority: the priority level
- * @funcname: the function emitting the (debug) message
- * @linenr: line where the message was emitted
- * @flags: extra flags, 1 if coming from the error handler
- * @fmt: the string format
- * @...: the arguments
- *
- * Call the libvirt logger with some informations. Based on the configuration
- * the message may be stored, sent to output or just discarded
- */
-void virLogMessage(const char *category, int priority, const char *funcname,
- long long linenr, int flags, const char *fmt, ...) {
- char *str = NULL;
- char *msg;
- struct timeval cur_time;
- struct tm time_info;
- int len, fprio, i, ret;
-
- if (!virLogInitialized)
- virLogStartup();
-
- if (fmt == NULL)
- return;
-
- /*
- * check against list of specific logging patterns
- */
- fprio = virLogFiltersCheck(category);
- if (fprio == 0) {
- if (priority < virLogDefaultPriority)
- return;
- } else if (priority < fprio)
- return;
-
- /*
- * serialize the error message, add level and timestamp
- */
- VIR_GET_VAR_STR(fmt, str);
- if (str == NULL)
- return;
- gettimeofday(&cur_time, NULL);
- localtime_r(&cur_time.tv_sec, &time_info);
-
- if ((funcname != NULL)) {
- ret = virAsprintf(&msg, "%02d:%02d:%02d.%03d: %s : %s:%lld : %s\n",
- time_info.tm_hour, time_info.tm_min,
- time_info.tm_sec, (int) cur_time.tv_usec / 1000,
- virLogPriorityString(priority), funcname, linenr, str);
- } else {
- ret = virAsprintf(&msg, "%02d:%02d:%02d.%03d: %s : %s\n",
- time_info.tm_hour, time_info.tm_min,
- time_info.tm_sec, (int) cur_time.tv_usec / 1000,
- virLogPriorityString(priority), str);
- }
- VIR_FREE(str);
- if (ret < 0) {
- /* apparently we're running out of memory */
- return;
- }
-
- /*
- * Log based on defaults, first store in the history buffer
- * then push the message on the outputs defined, if none
- * use stderr.
- * NOTE: the locking is a single point of contention for multiple
- * threads, but avoid intermixing. Maybe set up locks per output
- * to improve paralellism.
- */
- len = strlen(msg);
- virLogStr(msg, len);
- virLogLock();
- for (i = 0; i < virLogNbOutputs;i++) {
- if (priority >= virLogOutputs[i].priority)
- virLogOutputs[i].f(category, priority, funcname, linenr,
- msg, len, virLogOutputs[i].data);
- }
- if ((virLogNbOutputs == 0) && (flags != 1))
- safewrite(2, msg, len);
- virLogUnlock();
-
- VIR_FREE(msg);
-}
-
-static int virLogOutputToFd(const char *category ATTRIBUTE_UNUSED,
- int priority ATTRIBUTE_UNUSED,
- const char *funcname ATTRIBUTE_UNUSED,
- long long linenr ATTRIBUTE_UNUSED,
- const char *str, int len, void *data) {
- int fd = (long) data;
- int ret;
-
- if (fd < 0)
- return(-1);
- ret = safewrite(fd, str, len);
- return(ret);
-}
-
-static void virLogCloseFd(void *data) {
- int fd = (long) data;
-
- if (fd >= 0)
- close(fd);
-}
-
-static int virLogAddOutputToStderr(int priority) {
- if (virLogDefineOutput(virLogOutputToFd, NULL, (void *)2L, priority, 0) < 0)
- return(-1);
- return(0);
-}
-
-static int virLogAddOutputToFile(int priority, const char *file) {
- int fd;
-
- fd = open(file, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR);
- if (fd < 0)
- return(-1);
- if (virLogDefineOutput(virLogOutputToFd, virLogCloseFd, (void *)(long)fd,
- priority, 0) < 0) {
- close(fd);
- return(-1);
- }
- return(0);
-}
-
-#if HAVE_SYSLOG_H
-static int virLogOutputToSyslog(const char *category ATTRIBUTE_UNUSED,
- int priority,
- const char *funcname ATTRIBUTE_UNUSED,
- long long linenr ATTRIBUTE_UNUSED,
- const char *str, int len ATTRIBUTE_UNUSED,
- void *data ATTRIBUTE_UNUSED) {
- int prio;
-
- switch (priority) {
- case VIR_LOG_DEBUG:
- prio = LOG_DEBUG;
- break;
- case VIR_LOG_INFO:
- prio = LOG_INFO;
- break;
- case VIR_LOG_WARN:
- prio = LOG_WARNING;
- break;
- case VIR_LOG_ERROR:
- prio = LOG_ERR;
- break;
- default:
- prio = LOG_ERR;
- }
- syslog(prio, "%s", str);
- return(len);
-}
-
-static char *current_ident = NULL;
-
-static void virLogCloseSyslog(void *data ATTRIBUTE_UNUSED) {
- closelog();
- VIR_FREE(current_ident);
-}
-
-static int virLogAddOutputToSyslog(int priority, const char *ident) {
- /*
- * ident needs to be kept around on Solaris
- */
- VIR_FREE(current_ident);
- current_ident = strdup(ident);
- if (current_ident == NULL)
- return(-1);
-
- openlog(current_ident, 0, 0);
- if (virLogDefineOutput(virLogOutputToSyslog, virLogCloseSyslog, NULL,
- priority, 0) < 0) {
- closelog();
- VIR_FREE(current_ident);
- return(-1);
- }
- return(0);
-}
-#endif /* HAVE_SYSLOG_H */
-
-#define IS_SPACE(cur) \
- ((*cur == ' ') || (*cur == '\t') || (*cur == '\n') || \
- (*cur == '\r') || (*cur == '\\'))
-
-/**
- * virLogParseOutputs:
- * @outputs: string defining a (set of) output(s)
- *
- * The format for an output can be:
- * x:stderr
- * output goes to stderr
- * x:syslog:name
- * use syslog for the output and use the given name as the ident
- * x:file:file_path
- * output to a file, with the given filepath
- * In all case the x prefix is the minimal level, acting as a filter
- * 0: everything
- * 1: DEBUG
- * 2: INFO
- * 3: WARNING
- * 4: ERROR
- *
- * Multiple output can be defined in a single @output, they just need to be
- * separated by spaces.
- *
- * Returns the number of output parsed and installed or -1 in case of error
- */
-int virLogParseOutputs(const char *outputs) {
- const char *cur = outputs, *str;
- char *name;
- int prio;
- int ret = -1;
- int count = 0;
-
- if (cur == NULL)
- return(-1);
-
- virSkipSpaces(&cur);
- while (*cur != 0) {
- prio= virParseNumber(&cur);
- if ((prio < VIR_LOG_DEBUG) || (prio > VIR_LOG_ERROR))
- goto cleanup;
- if (*cur != ':')
- goto cleanup;
- cur++;
- if (STREQLEN(cur, "stderr", 6)) {
- cur += 6;
- if (virLogAddOutputToStderr(prio) == 0)
- count++;
- } else if (STREQLEN(cur, "syslog", 6)) {
- cur += 6;
- if (*cur != ':')
- goto cleanup;
- cur++;
- str = cur;
- while ((*cur != 0) && (!IS_SPACE(cur)))
- cur++;
- if (str == cur)
- goto cleanup;
-#if HAVE_SYSLOG_H
- name = strndup(str, cur - str);
- if (name == NULL)
- goto cleanup;
- if (virLogAddOutputToSyslog(prio, name) == 0)
- count++;
- VIR_FREE(name);
-#endif /* HAVE_SYSLOG_H */
- } else if (STREQLEN(cur, "file", 4)) {
- cur += 4;
- if (*cur != ':')
- goto cleanup;
- cur++;
- str = cur;
- while ((*cur != 0) && (!IS_SPACE(cur)))
- cur++;
- if (str == cur)
- goto cleanup;
- name = strndup(str, cur - str);
- if (name == NULL)
- goto cleanup;
- if (virLogAddOutputToFile(prio, name) == 0)
- count++;
- VIR_FREE(name);
- } else {
- goto cleanup;
- }
- virSkipSpaces(&cur);
- }
- ret = count;
-cleanup:
- if (ret == -1)
- VIR_WARN0(_("Ignoring invalid log output setting."));
- return(ret);
-}
-
-/**
- * virLogParseFilters:
- * @filters: string defining a (set of) filter(s)
- *
- * The format for a filter is:
- * x:name
- * where name is a match string
- * the x prefix is the minimal level where the messages should be logged
- * 1: DEBUG
- * 2: INFO
- * 3: WARNING
- * 4: ERROR
- *
- * Multiple filter can be defined in a single @filters, they just need to be
- * separated by spaces.
- *
- * Returns the number of filter parsed and installed or -1 in case of error
- */
-int virLogParseFilters(const char *filters) {
- const char *cur = filters, *str;
- char *name;
- int prio;
- int ret = -1;
- int count = 0;
-
- if (cur == NULL)
- return(-1);
-
- virSkipSpaces(&cur);
- while (*cur != 0) {
- prio= virParseNumber(&cur);
- if ((prio < VIR_LOG_DEBUG) || (prio > VIR_LOG_ERROR))
- goto cleanup;
- if (*cur != ':')
- goto cleanup;
- cur++;
- str = cur;
- while ((*cur != 0) && (!IS_SPACE(cur)))
- cur++;
- if (str == cur)
- goto cleanup;
- name = strndup(str, cur - str);
- if (name == NULL)
- goto cleanup;
- if (virLogDefineFilter(name, prio, 0) >= 0)
- count++;
- VIR_FREE(name);
- virSkipSpaces(&cur);
- }
- ret = count;
-cleanup:
- if (ret == -1)
- VIR_WARN0(_("Ignoring invalid log filter setting."));
- return(ret);
-}
-
-/**
- * virLogGetDefaultPriority:
- *
- * Returns the current logging priority level.
- */
-int virLogGetDefaultPriority(void) {
- return (virLogDefaultPriority);
-}
-
-/**
- * virLogGetNbFilters:
- *
- * Returns the current number of defined log filters.
- */
-int virLogGetNbFilters(void) {
- return (virLogNbFilters);
-}
-
-/**
- * virLogGetNbOutputs:
- *
- * Returns the current number of defined log outputs.
- */
-int virLogGetNbOutputs(void) {
- return (virLogNbOutputs);
-}
-
-/**
- * virLogParseDefaultPriority:
- * @priority: string defining the desired logging level
- *
- * Parses and sets the default log priority level. It can take a string or
- * number corresponding to the following levels:
- * 1: DEBUG
- * 2: INFO
- * 3: WARNING
- * 4: ERROR
- *
- * Returns the parsed log level or -1 on error.
- */
-int virLogParseDefaultPriority(const char *priority) {
- int ret = -1;
-
- if (STREQ(priority, "1") || STREQ(priority, "debug"))
- ret = virLogSetDefaultPriority(VIR_LOG_DEBUG);
- else if (STREQ(priority, "2") || STREQ(priority, "info"))
- ret = virLogSetDefaultPriority(VIR_LOG_INFO);
- else if (STREQ(priority, "3") || STREQ(priority, "warning"))
- ret = virLogSetDefaultPriority(VIR_LOG_WARN);
- else if (STREQ(priority, "4") || STREQ(priority, "error"))
- ret = virLogSetDefaultPriority(VIR_LOG_ERROR);
- else
- VIR_WARN0(_("Ignoring invalid log level setting"));
-
- return ret;
-}
-
-/**
- * virLogSetFromEnv:
- *
- * Sets virLogDefaultPriority, virLogFilters and virLogOutputs based on
- * environment variables.
- */
-void virLogSetFromEnv(void) {
- char *debugEnv;
-
- debugEnv = getenv("LIBVIRT_DEBUG");
- if (debugEnv && *debugEnv)
- virLogParseDefaultPriority(debugEnv);
- debugEnv = getenv("LIBVIRT_LOG_FILTERS");
- if (debugEnv && *debugEnv)
- virLogParseFilters(strdup(debugEnv));
- debugEnv = getenv("LIBVIRT_LOG_OUTPUTS");
- if (debugEnv && *debugEnv)
- virLogParseOutputs(strdup(debugEnv));
-}
+++ /dev/null
-/*
- * logging.h: internal logging and debugging
- *
- * Copyright (C) 2006-2008 Red Hat, Inc.
- *
- * 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
- *
- */
-
-#ifndef __VIRTLOG_H_
-#define __VIRTLOG_H_
-
-#include "internal.h"
-
-/*
- * If configured with --enable-debug=yes then library calls
- * are printed to stderr for debugging or to an appropriate channel
- * defined at runtime of from the libvirt daemon configuration file
- */
-#ifdef ENABLE_DEBUG
-#define VIR_DEBUG_INT(category, f, l, fmt,...) \
- virLogMessage(category, VIR_LOG_DEBUG, f, l, 0, fmt, __VA_ARGS__)
-#else
-#define VIR_DEBUG_INT(category, f, l, fmt,...) \
- do { } while (0)
-#endif /* !ENABLE_DEBUG */
-
-#define VIR_INFO_INT(category, f, l, fmt,...) \
- virLogMessage(category, VIR_LOG_INFO, f, l, 0, fmt, __VA_ARGS__)
-#define VIR_WARN_INT(category, f, l, fmt,...) \
- virLogMessage(category, VIR_LOG_WARN, f, l, 0, fmt, __VA_ARGS__)
-#define VIR_ERROR_INT(category, f, l, fmt,...) \
- virLogMessage(category, VIR_LOG_ERROR, f, l, 0, fmt, __VA_ARGS__)
-
-#define VIR_DEBUG(fmt,...) \
- VIR_DEBUG_INT("file." __FILE__, __func__, __LINE__, fmt, __VA_ARGS__)
-#define VIR_DEBUG0(msg) \
- VIR_DEBUG_INT("file." __FILE__, __func__, __LINE__, "%s", msg)
-#define VIR_INFO(fmt,...) \
- VIR_INFO_INT("file." __FILE__, __func__, __LINE__, fmt, __VA_ARGS__)
-#define VIR_INFO0(msg) \
- VIR_INFO_INT("file." __FILE__, __func__, __LINE__, "%s", msg)
-#define VIR_WARN(fmt,...) \
- VIR_WARN_INT("file." __FILE__, __func__, __LINE__, fmt, __VA_ARGS__)
-#define VIR_WARN0(msg) \
- VIR_WARN_INT("file." __FILE__, __func__, __LINE__, "%s", msg)
-#define VIR_ERROR(fmt,...) \
- VIR_ERROR_INT("file." __FILE__, __func__, __LINE__, fmt, __VA_ARGS__)
-#define VIR_ERROR0(msg) \
- VIR_ERROR_INT("file." __FILE__, __func__, __LINE__, "%s", msg)
-
-/* Legacy compat */
-#define DEBUG(fmt,...) \
- VIR_DEBUG_INT("file." __FILE__, __func__, __LINE__, fmt, __VA_ARGS__)
-#define DEBUG0(msg) \
- VIR_DEBUG_INT("file." __FILE__, __func__, __LINE__, "%s", msg)
-
-/*
- * To be made public
- */
-typedef enum {
- VIR_LOG_DEBUG = 1,
- VIR_LOG_INFO,
- VIR_LOG_WARN,
- VIR_LOG_ERROR,
-} virLogPriority;
-
-#define VIR_LOG_DEFAULT VIR_LOG_WARN
-
-/**
- * virLogOutputFunc:
- * @category: the category for the message
- * @priority: the priority for the message
- * @funcname: the function emitting the message
- * @linenr: line where the message was emitted
- * @msg: the message to log, preformatted and zero terminated
- * @len: the lenght of the message in bytes without the terminating zero
- * @data: extra output logging data
- *
- * Callback function used to output messages
- *
- * Returns the number of bytes written or -1 in case of error
- */
-typedef int (*virLogOutputFunc) (const char *category, int priority,
- const char *funcname, long long lineno,
- const char *str, int len, void *data);
-
-/**
- * virLogCloseFunc:
- * @data: extra output logging data
- *
- * Callback function used to close a log output
- */
-typedef void (*virLogCloseFunc) (void *data);
-
-extern int virLogGetNbFilters(void);
-extern int virLogGetNbOutputs(void);
-extern int virLogGetDefaultPriority(void);
-extern int virLogSetDefaultPriority(int priority);
-extern void virLogSetFromEnv(void);
-extern int virLogDefineFilter(const char *match, int priority, int flags);
-extern int virLogDefineOutput(virLogOutputFunc f, virLogCloseFunc c,
- void *data, int priority, int flags);
-
-/*
- * Internal logging API
- */
-
-extern int virLogStartup(void);
-extern int virLogReset(void);
-extern void virLogShutdown(void);
-extern int virLogParseDefaultPriority(const char *priority);
-extern int virLogParseFilters(const char *filters);
-extern int virLogParseOutputs(const char *output);
-extern void virLogMessage(const char *category, int priority,
- const char *funcname, long long linenr, int flags,
- const char *fmt, ...) ATTRIBUTE_FMT_PRINTF(6, 7);
-
-#endif
+++ /dev/null
-/*
- * memory.c: safer memory allocation
- *
- * Copyright (C) 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
- *
- */
-
-#include <config.h>
-#include <stdlib.h>
-#include <stddef.h>
-
-#include "memory.h"
-
-
-#if TEST_OOM
-static int testMallocNext = 0;
-static int testMallocFailFirst = 0;
-static int testMallocFailLast = 0;
-static void (*testMallocHook)(int, void*) = NULL;
-static void *testMallocHookData = NULL;
-
-void virAllocTestInit(void)
-{
- testMallocNext = 1;
- testMallocFailFirst = 0;
- testMallocFailLast = 0;
-}
-
-int virAllocTestCount(void)
-{
- return testMallocNext - 1;
-}
-
-void virAllocTestHook(void (*func)(int, void*), void *data)
-{
- testMallocHook = func;
- testMallocHookData = data;
-}
-
-void virAllocTestOOM(int n, int m)
-{
- testMallocNext = 1;
- testMallocFailFirst = n;
- testMallocFailLast = n + m - 1;
-}
-
-static int virAllocTestFail(void)
-{
- int fail = 0;
- if (testMallocNext == 0)
- return 0;
-
- fail =
- testMallocNext >= testMallocFailFirst &&
- testMallocNext <= testMallocFailLast;
-
- if (fail && testMallocHook)
- (testMallocHook)(testMallocNext, testMallocHookData);
-
- testMallocNext++;
- return fail;
-}
-#endif
-
-
-/**
- * virAlloc:
- * @ptrptr: pointer to pointer for address of allocated memory
- * @size: number of bytes to allocate
- *
- * Allocate 'size' bytes of memory. Return the address of the
- * allocated memory in 'ptrptr'. The newly allocated memory is
- * filled with zeros.
- *
- * Returns -1 on failure to allocate, zero on success
- */
-int virAlloc(void *ptrptr, size_t size)
-{
-#if TEST_OOM
- if (virAllocTestFail()) {
- *(void **)ptrptr = NULL;
- return -1;
- }
-#endif
-
- *(void **)ptrptr = calloc(1, size);
- if (*(void **)ptrptr == NULL)
- return -1;
- return 0;
-}
-
-/**
- * virAllocN:
- * @ptrptr: pointer to pointer for address of allocated memory
- * @size: number of bytes to allocate
- * @count: number of elements to allocate
- *
- * Allocate an array of memory 'count' elements long,
- * each with 'size' bytes. Return the address of the
- * allocated memory in 'ptrptr'. The newly allocated
- * memory is filled with zeros.
- *
- * Returns -1 on failure to allocate, zero on success
- */
-int virAllocN(void *ptrptr, size_t size, size_t count)
-{
-#if TEST_OOM
- if (virAllocTestFail()) {
- *(void **)ptrptr = NULL;
- return -1;
- }
-#endif
-
- *(void**)ptrptr = calloc(count, size);
- if (*(void**)ptrptr == NULL)
- return -1;
- return 0;
-}
-
-/**
- * virReallocN:
- * @ptrptr: pointer to pointer for address of allocated memory
- * @size: number of bytes to allocate
- * @count: number of elements in array
- *
- * Resize the block of memory in 'ptrptr' to be an array of
- * 'count' elements, each 'size' bytes in length. Update 'ptrptr'
- * with the address of the newly allocated memory. On failure,
- * 'ptrptr' is not changed and still points to the original memory
- * block. The newly allocated memory is filled with zeros.
- *
- * Returns -1 on failure to allocate, zero on success
- */
-int virReallocN(void *ptrptr, size_t size, size_t count)
-{
- void *tmp;
-#if TEST_OOM
- if (virAllocTestFail())
- return -1;
-#endif
-
- if (xalloc_oversized(count, size)) {
- errno = ENOMEM;
- return -1;
- }
- tmp = realloc(*(void**)ptrptr, size * count);
- if (!tmp && (size * count))
- return -1;
- *(void**)ptrptr = tmp;
- return 0;
-}
-
-/**
- * virFree:
- * @ptrptr: pointer to pointer for address of memory to be freed
- *
- * Release the chunk of memory in the pointer pointed to by
- * the 'ptrptr' variable. After release, 'ptrptr' will be
- * updated to point to NULL.
- */
-void virFree(void *ptrptr)
-{
- free(*(void**)ptrptr);
- *(void**)ptrptr = NULL;
-}
+++ /dev/null
-/*
- * memory.c: safer memory allocation
- *
- * Copyright (C) 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
- *
- */
-
-
-#ifndef __VIR_MEMORY_H_
-#define __VIR_MEMORY_H_
-
-#include "internal.h"
-
-/* Return 1 if an array of N objects, each of size S, cannot exist due
- to size arithmetic overflow. S must be positive and N must be
- nonnegative. This is a macro, not an inline function, so that it
- works correctly even when SIZE_MAX < N.
-
- By gnulib convention, SIZE_MAX represents overflow in size
- calculations, so the conservative dividend to use here is
- SIZE_MAX - 1, since SIZE_MAX might represent an overflowed value.
- However, malloc (SIZE_MAX) fails on all known hosts where
- sizeof (ptrdiff_t) <= sizeof (size_t), so do not bother to test for
- exactly-SIZE_MAX allocations on such hosts; this avoids a test and
- branch when S is known to be 1. */
-#ifndef xalloc_oversized
-# define xalloc_oversized(n, s) \
- ((size_t) (sizeof (ptrdiff_t) <= sizeof (size_t) ? -1 : -2) / (s) < (n))
-#endif
-
-
-
-/* Don't call these directly - use the macros below */
-int virAlloc(void *ptrptr, size_t size) ATTRIBUTE_RETURN_CHECK;
-int virAllocN(void *ptrptr, size_t size, size_t count) ATTRIBUTE_RETURN_CHECK;
-int virReallocN(void *ptrptr, size_t size, size_t count) ATTRIBUTE_RETURN_CHECK;
-void virFree(void *ptrptr);
-
-/**
- * VIR_ALLOC:
- * @ptr: pointer to hold address of allocated memory
- *
- * Allocate sizeof(*ptr) bytes of memory and store
- * the address of allocated memory in 'ptr'. Fill the
- * newly allocated memory with zeros.
- *
- * Returns -1 on failure, 0 on success
- */
-#define VIR_ALLOC(ptr) virAlloc(&(ptr), sizeof(*(ptr)))
-
-/**
- * VIR_ALLOC_N:
- * @ptr: pointer to hold address of allocated memory
- * @count: number of elements to allocate
- *
- * Allocate an array of 'count' elements, each sizeof(*ptr)
- * bytes long and store the address of allocated memory in
- * 'ptr'. Fill the newly allocated memory with zeros.
- *
- * Returns -1 on failure, 0 on success
- */
-#define VIR_ALLOC_N(ptr, count) virAllocN(&(ptr), sizeof(*(ptr)), (count))
-
-/**
- * VIR_REALLOC_N:
- * @ptr: pointer to hold address of allocated memory
- * @count: number of elements to allocate
- *
- * Re-allocate an array of 'count' elements, each sizeof(*ptr)
- * bytes long and store the address of allocated memory in
- * 'ptr'. Fill the newly allocated memory with zeros
- *
- * Returns -1 on failure, 0 on success
- */
-#define VIR_REALLOC_N(ptr, count) virReallocN(&(ptr), sizeof(*(ptr)), (count))
-
-/**
- * VIR_FREE:
- * @ptr: pointer holding address to be freed
- *
- * Free the memory stored in 'ptr' and update to point
- * to NULL.
- */
-#define VIR_FREE(ptr) virFree(&(ptr))
-
-
-#if TEST_OOM
-void virAllocTestInit(void);
-int virAllocTestCount(void);
-void virAllocTestOOM(int n, int m);
-void virAllocTestHook(void (*func)(int, void*), void *data);
-#endif
-
-
-
-#endif /* __VIR_MEMORY_H_ */
+++ /dev/null
-/*
- * Copyright (C) 2009 Red Hat, Inc.
- *
- * 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
- *
- * Authors:
- * Mark McLoughlin <markmc@redhat.com>
- */
-
-#include <config.h>
-
-#include "pci.h"
-
-#include <dirent.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <limits.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include "logging.h"
-#include "memory.h"
-#include "util.h"
-#include "virterror_internal.h"
-
-/* avoid compilation breakage on some systems */
-#ifndef MODPROBE
-#define MODPROBE "modprobe"
-#endif
-
-#define PCI_SYSFS "/sys/bus/pci/"
-#define PCI_ID_LEN 10 /* "XXXX XXXX" */
-#define PCI_ADDR_LEN 13 /* "XXXX:XX:XX.X" */
-
-struct _pciDevice {
- unsigned domain;
- unsigned bus;
- unsigned slot;
- unsigned function;
-
- char name[PCI_ADDR_LEN]; /* domain:bus:slot.function */
- char id[PCI_ID_LEN]; /* product vendor */
- char path[PATH_MAX];
- int fd;
-
- unsigned initted;
- unsigned pcie_cap_pos;
- unsigned pci_pm_cap_pos;
- unsigned has_flr : 1;
- unsigned has_pm_reset : 1;
- unsigned managed : 1;
-};
-
-/* For virReportOOMError() and virReportSystemError() */
-#define VIR_FROM_THIS VIR_FROM_NONE
-
-#define pciReportError(conn, code, fmt...) \
- virReportErrorHelper(conn, VIR_FROM_NONE, code, __FILE__, \
- __FUNCTION__, __LINE__, fmt)
-
-/* Specifications referenced in comments:
- * PCI30 - PCI Local Bus Specification 3.0
- * PCIe20 - PCI Express Base Specification 2.0
- * BR12 - PCI-to-PCI Bridge Architecture Specification 1.2
- * PM12 - PCI Bus Power Management Interface Specification 1.2
- * ECN_AF - Advanced Capabilities for Conventional PCI ECN
- */
-
-/* Type 0 config space header length; PCI30 Section 6.1 Configuration Space Organization */
-#define PCI_CONF_LEN 0x100
-#define PCI_CONF_HEADER_LEN 0x40
-
-/* PCI30 6.2.1 */
-#define PCI_HEADER_TYPE 0x0e /* Header type */
-#define PCI_HEADER_TYPE_BRIDGE 0x1
-#define PCI_HEADER_TYPE_MASK 0x7f
-#define PCI_HEADER_TYPE_MULTI 0x80
-
-/* PCI30 6.2.1 Device Identification */
-#define PCI_CLASS_DEVICE 0x0a /* Device class */
-
-/* Class Code for bridge; PCI30 D.7 Base Class 06h */
-#define PCI_CLASS_BRIDGE_PCI 0x0604
-
-/* PCI30 6.2.3 Device Status */
-#define PCI_STATUS 0x06 /* 16 bits */
-#define PCI_STATUS_CAP_LIST 0x10 /* Support Capability List */
-
-/* PCI30 6.7 Capabilities List */
-#define PCI_CAPABILITY_LIST 0x34 /* Offset of first capability list entry */
-
-/* PM12 3.2.1 Capability Identifier */
-#define PCI_CAP_ID_PM 0x01 /* Power Management */
-/* PCI30 H Capability IDs */
-#define PCI_CAP_ID_EXP 0x10 /* PCI Express */
-/* ECN_AF 6.x.1.1 Capability ID for AF */
-#define PCI_CAP_ID_AF 0x13 /* Advanced Features */
-
-/* PCIe20 7.8.3 Device Capabilities Register (Offset 04h) */
-#define PCI_EXP_DEVCAP 0x4 /* Device capabilities */
-#define PCI_EXP_DEVCAP_FLR (1<<28) /* Function Level Reset */
-
-/* Header type 1 BR12 3.2 PCI-to-PCI Bridge Configuration Space Header Format */
-#define PCI_PRIMARY_BUS 0x18 /* BR12 3.2.5.2 Primary bus number */
-#define PCI_SECONDARY_BUS 0x19 /* BR12 3.2.5.3 Secondary bus number */
-#define PCI_SUBORDINATE_BUS 0x1a /* BR12 3.2.5.4 Highest bus number behind the bridge */
-#define PCI_BRIDGE_CONTROL 0x3e
-/* BR12 3.2.5.18 Bridge Control Register */
-#define PCI_BRIDGE_CTL_RESET 0x40 /* Secondary bus reset */
-
-/* PM12 3.2.4 Power Management Control/Status (Offset = 4) */
-#define PCI_PM_CTRL 4 /* PM control and status register */
-#define PCI_PM_CTRL_STATE_MASK 0x3 /* Current power state (D0 to D3) */
-#define PCI_PM_CTRL_STATE_D0 0x0 /* D0 state */
-#define PCI_PM_CTRL_STATE_D3hot 0x3 /* D3 state */
-#define PCI_PM_CTRL_NO_SOFT_RESET 0x8 /* No reset for D3hot->D0 */
-
-/* ECN_AF 6.x.1 Advanced Features Capability Structure */
-#define PCI_AF_CAP 0x3 /* Advanced features capabilities */
-#define PCI_AF_CAP_FLR 0x2 /* Function Level Reset */
-
-static int
-pciOpenConfig(pciDevice *dev)
-{
- int fd;
-
- if (dev->fd > 0)
- return 0;
-
- fd = open(dev->path, O_RDWR);
- if (fd < 0) {
- char ebuf[1024];
- VIR_WARN(_("Failed to open config space file '%s': %s"),
- dev->path, virStrerror(errno, ebuf, sizeof(ebuf)));
- return -1;
- }
- VIR_DEBUG("%s %s: opened %s", dev->id, dev->name, dev->path);
- dev->fd = fd;
- return 0;
-}
-
-static int
-pciRead(pciDevice *dev, unsigned pos, uint8_t *buf, unsigned buflen)
-{
- memset(buf, 0, buflen);
-
- if (pciOpenConfig(dev) < 0)
- return -1;
-
- if (lseek(dev->fd, pos, SEEK_SET) != pos ||
- saferead(dev->fd, buf, buflen) != buflen) {
- char ebuf[1024];
- VIR_WARN(_("Failed to read from '%s' : %s"), dev->path,
- virStrerror(errno, ebuf, sizeof(ebuf)));
- return -1;
- }
- return 0;
-}
-
-static uint8_t
-pciRead8(pciDevice *dev, unsigned pos)
-{
- uint8_t buf;
- pciRead(dev, pos, &buf, sizeof(buf));
- return buf;
-}
-
-static uint16_t
-pciRead16(pciDevice *dev, unsigned pos)
-{
- uint8_t buf[2];
- pciRead(dev, pos, &buf[0], sizeof(buf));
- return (buf[0] << 0) | (buf[1] << 8);
-}
-
-static uint32_t
-pciRead32(pciDevice *dev, unsigned pos)
-{
- uint8_t buf[4];
- pciRead(dev, pos, &buf[0], sizeof(buf));
- return (buf[0] << 0) | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
-}
-
-static int
-pciWrite(pciDevice *dev, unsigned pos, uint8_t *buf, unsigned buflen)
-{
- if (pciOpenConfig(dev) < 0)
- return -1;
-
- if (lseek(dev->fd, pos, SEEK_SET) != pos ||
- safewrite(dev->fd, buf, buflen) != buflen) {
- char ebuf[1024];
- VIR_WARN(_("Failed to write to '%s' : %s"), dev->path,
- virStrerror(errno, ebuf, sizeof(ebuf)));
- return -1;
- }
- return 0;
-}
-
-static void
-pciWrite16(pciDevice *dev, unsigned pos, uint16_t val)
-{
- uint8_t buf[2] = { (val >> 0), (val >> 8) };
- pciWrite(dev, pos, &buf[0], sizeof(buf));
-}
-
-static void
-pciWrite32(pciDevice *dev, unsigned pos, uint32_t val)
-{
- uint8_t buf[4] = { (val >> 0), (val >> 8), (val >> 16), (val >> 14) };
- pciWrite(dev, pos, &buf[0], sizeof(buf));
-}
-
-typedef int (*pciIterPredicate)(pciDevice *, pciDevice *, void *);
-
-/* Iterate over available PCI devices calling @predicate
- * to compare each one to @dev.
- * Return -1 on error since we don't want to assume it is
- * safe to reset if there is an error.
- */
-static int
-pciIterDevices(virConnectPtr conn,
- pciIterPredicate predicate,
- pciDevice *dev,
- pciDevice **matched,
- void *data)
-{
- DIR *dir;
- struct dirent *entry;
- int ret = 0;
-
- *matched = NULL;
-
- VIR_DEBUG("%s %s: iterating over " PCI_SYSFS "devices", dev->id, dev->name);
-
- dir = opendir(PCI_SYSFS "devices");
- if (!dir) {
- VIR_WARN0("Failed to open " PCI_SYSFS "devices");
- return -1;
- }
-
- while ((entry = readdir(dir))) {
- unsigned domain, bus, slot, function;
- pciDevice *check;
-
- /* Ignore '.' and '..' */
- if (entry->d_name[0] == '.')
- continue;
-
- if (sscanf(entry->d_name, "%x:%x:%x.%x",
- &domain, &bus, &slot, &function) < 4) {
- VIR_WARN("Unusual entry in " PCI_SYSFS "devices: %s", entry->d_name);
- continue;
- }
-
- check = pciGetDevice(conn, domain, bus, slot, function);
- if (!check) {
- ret = -1;
- break;
- }
-
- if (predicate(dev, check, data)) {
- VIR_DEBUG("%s %s: iter matched on %s", dev->id, dev->name, check->name);
- *matched = check;
- break;
- }
- pciFreeDevice(conn, check);
- }
- closedir(dir);
- return ret;
-}
-
-static uint8_t
-pciFindCapabilityOffset(pciDevice *dev, unsigned capability)
-{
- uint16_t status;
- uint8_t pos;
-
- status = pciRead16(dev, PCI_STATUS);
- if (!(status & PCI_STATUS_CAP_LIST))
- return 0;
-
- pos = pciRead8(dev, PCI_CAPABILITY_LIST);
-
- /* Zero indicates last capability, capabilities can't
- * be in the config space header and 0xff is returned
- * by the kernel if we don't have access to this region
- *
- * Note: we're not handling loops or extended
- * capabilities here.
- */
- while (pos >= PCI_CONF_HEADER_LEN && pos != 0xff) {
- uint8_t capid = pciRead8(dev, pos);
- if (capid == capability) {
- VIR_DEBUG("%s %s: found cap 0x%.2x at 0x%.2x",
- dev->id, dev->name, capability, pos);
- return pos;
- }
-
- pos = pciRead8(dev, pos + 1);
- }
-
- VIR_DEBUG("%s %s: failed to find cap 0x%.2x", dev->id, dev->name, capability);
-
- return 0;
-}
-
-static unsigned
-pciDetectFunctionLevelReset(pciDevice *dev)
-{
- uint32_t caps;
- uint8_t pos;
-
- /* The PCIe Function Level Reset capability allows
- * individual device functions to be reset without
- * affecting any other functions on the device or
- * any other devices on the bus. This is only common
- * on SR-IOV NICs at the moment.
- */
- if (dev->pcie_cap_pos) {
- caps = pciRead32(dev, dev->pcie_cap_pos + PCI_EXP_DEVCAP);
- if (caps & PCI_EXP_DEVCAP_FLR) {
- VIR_DEBUG("%s %s: detected PCIe FLR capability", dev->id, dev->name);
- return 1;
- }
- }
-
- /* The PCI AF Function Level Reset capability is
- * the same thing, except for conventional PCI
- * devices. This is not common yet.
- */
- pos = pciFindCapabilityOffset(dev, PCI_CAP_ID_AF);
- if (pos) {
- caps = pciRead16(dev, pos + PCI_AF_CAP);
- if (caps & PCI_AF_CAP_FLR) {
- VIR_DEBUG("%s %s: detected PCI FLR capability", dev->id, dev->name);
- return 1;
- }
- }
-
- VIR_DEBUG("%s %s: no FLR capability found", dev->id, dev->name);
-
- return 0;
-}
-
-/* Require the device has the PCI Power Management capability
- * and that a D3hot->D0 transition will results in a full
- * internal reset, not just a soft reset.
- */
-static unsigned
-pciDetectPowerManagementReset(pciDevice *dev)
-{
- if (dev->pci_pm_cap_pos) {
- uint32_t ctl;
-
- /* require the NO_SOFT_RESET bit is clear */
- ctl = pciRead32(dev, dev->pci_pm_cap_pos + PCI_PM_CTRL);
- if (!(ctl & PCI_PM_CTRL_NO_SOFT_RESET)) {
- VIR_DEBUG("%s %s: detected PM reset capability", dev->id, dev->name);
- return 1;
- }
- }
-
- VIR_DEBUG("%s %s: no PM reset capability found", dev->id, dev->name);
-
- return 0;
-}
-
-/* Any active devices other than the one supplied on the same domain/bus ? */
-static int
-pciSharesBusWithActive(pciDevice *dev, pciDevice *check, void *data)
-{
- pciDeviceList *activeDevs = data;
-
- if (dev->domain != check->domain ||
- dev->bus != check->bus ||
- (check->slot == check->slot &&
- check->function == check->function))
- return 0;
-
- if (activeDevs && !pciDeviceListFind(activeDevs, check))
- return 0;
-
- return 1;
-}
-
-static pciDevice *
-pciBusContainsActiveDevices(virConnectPtr conn,
- pciDevice *dev,
- pciDeviceList *activeDevs)
-{
- pciDevice *active = NULL;
- if (pciIterDevices(conn, pciSharesBusWithActive,
- dev, &active, activeDevs) < 0)
- return NULL;
- return active;
-}
-
-/* Is @check the parent of @dev ? */
-static int
-pciIsParent(pciDevice *dev, pciDevice *check, void *data ATTRIBUTE_UNUSED)
-{
- uint16_t device_class;
- uint8_t header_type, secondary, subordinate;
-
- if (dev->domain != check->domain)
- return 0;
-
- /* Is it a bridge? */
- device_class = pciRead16(check, PCI_CLASS_DEVICE);
- if (device_class != PCI_CLASS_BRIDGE_PCI)
- return 0;
-
- /* Is it a plane? */
- header_type = pciRead8(check, PCI_HEADER_TYPE);
- if ((header_type & PCI_HEADER_TYPE_MASK) != PCI_HEADER_TYPE_BRIDGE)
- return 0;
-
- secondary = pciRead8(check, PCI_SECONDARY_BUS);
- subordinate = pciRead8(check, PCI_SUBORDINATE_BUS);
-
- VIR_DEBUG("%s %s: found parent device %s\n", dev->id, dev->name, check->name);
-
- /* No, it's superman! */
- return (dev->bus >= secondary && dev->bus <= subordinate);
-}
-
-static pciDevice *
-pciGetParentDevice(virConnectPtr conn, pciDevice *dev)
-{
- pciDevice *parent = NULL;
- pciIterDevices(conn, pciIsParent, dev, &parent, NULL);
- return parent;
-}
-
-/* Secondary Bus Reset is our sledgehammer - it resets all
- * devices behind a bus.
- */
-static int
-pciTrySecondaryBusReset(virConnectPtr conn,
- pciDevice *dev,
- pciDeviceList *activeDevs)
-{
- pciDevice *parent, *conflict;
- uint8_t config_space[PCI_CONF_LEN];
- uint16_t ctl;
- int ret = -1;
-
- /* For now, we just refuse to do a secondary bus reset
- * if there are other devices/functions behind the bus.
- * In future, we could allow it so long as those devices
- * are not in use by the host or other guests.
- */
- if ((conflict = pciBusContainsActiveDevices(conn, dev, activeDevs))) {
- pciReportError(conn, VIR_ERR_NO_SUPPORT,
- _("Active %s devices on bus with %s, not doing bus reset"),
- conflict->name, dev->name);
- return -1;
- }
-
- /* Find the parent bus */
- parent = pciGetParentDevice(conn, dev);
- if (!parent) {
- pciReportError(conn, VIR_ERR_NO_SUPPORT,
- _("Failed to find parent device for %s"),
- dev->name);
- return -1;
- }
-
- VIR_DEBUG("%s %s: doing a secondary bus reset", dev->id, dev->name);
-
- /* Save and restore the device's config space; we only do this
- * for the supplied device since we refuse to do a reset if there
- * are multiple devices/functions
- */
- if (pciRead(dev, 0, config_space, PCI_CONF_LEN) < 0) {
- pciReportError(conn, VIR_ERR_NO_SUPPORT,
- _("Failed to save PCI config space for %s"),
- dev->name);
- goto out;
- }
-
- /* Read the control register, set the reset flag, wait 200ms,
- * unset the reset flag and wait 200ms.
- */
- ctl = pciRead16(dev, PCI_BRIDGE_CONTROL);
-
- pciWrite16(parent, PCI_BRIDGE_CONTROL, ctl | PCI_BRIDGE_CTL_RESET);
-
- usleep(200 * 1000); /* sleep 200ms */
-
- pciWrite16(parent, PCI_BRIDGE_CONTROL, ctl);
-
- usleep(200 * 1000); /* sleep 200ms */
-
- if (pciWrite(dev, 0, config_space, PCI_CONF_LEN) < 0) {
- pciReportError(conn, VIR_ERR_NO_SUPPORT,
- _("Failed to restore PCI config space for %s"),
- dev->name);
- goto out;
- }
- ret = 0;
-out:
- pciFreeDevice(conn, parent);
- return ret;
-}
-
-/* Power management reset attempts to reset a device using a
- * D-state transition from D3hot to D0. Note, in detect_pm_reset()
- * above we require the device supports a full internal reset.
- */
-static int
-pciTryPowerManagementReset(virConnectPtr conn ATTRIBUTE_UNUSED, pciDevice *dev)
-{
- uint8_t config_space[PCI_CONF_LEN];
- uint32_t ctl;
-
- if (!dev->pci_pm_cap_pos)
- return -1;
-
- /* Save and restore the device's config space. */
- if (pciRead(dev, 0, &config_space[0], PCI_CONF_LEN) < 0) {
- pciReportError(conn, VIR_ERR_NO_SUPPORT,
- _("Failed to save PCI config space for %s"),
- dev->name);
- return -1;
- }
-
- VIR_DEBUG("%s %s: doing a power management reset", dev->id, dev->name);
-
- ctl = pciRead32(dev, dev->pci_pm_cap_pos + PCI_PM_CTRL);
- ctl &= ~PCI_PM_CTRL_STATE_MASK;
-
- pciWrite32(dev, dev->pci_pm_cap_pos + PCI_PM_CTRL, ctl|PCI_PM_CTRL_STATE_D3hot);
-
- usleep(10 * 1000); /* sleep 10ms */
-
- pciWrite32(dev, dev->pci_pm_cap_pos + PCI_PM_CTRL, ctl|PCI_PM_CTRL_STATE_D0);
-
- usleep(10 * 1000); /* sleep 10ms */
-
- if (pciWrite(dev, 0, &config_space[0], PCI_CONF_LEN) < 0) {
- pciReportError(conn, VIR_ERR_NO_SUPPORT,
- _("Failed to restore PCI config space for %s"),
- dev->name);
- return -1;
- }
-
- return 0;
-}
-
-static int
-pciInitDevice(virConnectPtr conn, pciDevice *dev)
-{
- if (pciOpenConfig(dev) < 0) {
- virReportSystemError(conn, errno,
- _("Failed to open config space file '%s'"),
- dev->path);
- return -1;
- }
-
- dev->pcie_cap_pos = pciFindCapabilityOffset(dev, PCI_CAP_ID_EXP);
- dev->pci_pm_cap_pos = pciFindCapabilityOffset(dev, PCI_CAP_ID_PM);
- dev->has_flr = pciDetectFunctionLevelReset(dev);
- dev->has_pm_reset = pciDetectPowerManagementReset(dev);
- dev->initted = 1;
- return 0;
-}
-
-int
-pciResetDevice(virConnectPtr conn,
- pciDevice *dev,
- pciDeviceList *activeDevs)
-{
- int ret = -1;
-
- if (activeDevs && pciDeviceListFind(activeDevs, dev)) {
- pciReportError(conn, VIR_ERR_INTERNAL_ERROR,
- _("Not resetting active device %s"), dev->name);
- return -1;
- }
-
- if (!dev->initted && pciInitDevice(conn, dev) < 0)
- return -1;
-
- /* KVM will perform FLR when starting and stopping
- * a guest, so there is no need for us to do it here.
- */
- if (dev->has_flr)
- return 0;
-
- /* If the device supports PCI power management reset,
- * that's the next best thing because it only resets
- * the function, not the whole device.
- */
- if (dev->has_pm_reset)
- ret = pciTryPowerManagementReset(conn, dev);
-
- /* Bus reset is not an option with the root bus */
- if (ret < 0 && dev->bus != 0)
- ret = pciTrySecondaryBusReset(conn, dev, activeDevs);
-
- if (ret < 0) {
- virErrorPtr err = virGetLastError();
- pciReportError(conn, VIR_ERR_NO_SUPPORT,
- _("Unable to reset PCI device %s: %s"),
- dev->name,
- err ? err->message : _("no FLR, PM reset or bus reset available"));
- }
-
- return ret;
-}
-
-
-static void
-pciDriverDir(char *buf, size_t buflen, const char *driver)
-{
- snprintf(buf, buflen, PCI_SYSFS "drivers/%s", driver);
-}
-
-static void
-pciDriverFile(char *buf, size_t buflen, const char *driver, const char *file)
-{
- snprintf(buf, buflen, PCI_SYSFS "drivers/%s/%s", driver, file);
-}
-
-static void
-pciDeviceFile(char *buf, size_t buflen, const char *device, const char *file)
-{
- snprintf(buf, buflen, PCI_SYSFS "devices/%s/%s", device, file);
-}
-
-
-static const char *
-pciFindStubDriver(virConnectPtr conn)
-{
- char drvpath[PATH_MAX];
- int probed = 0;
-
-recheck:
- pciDriverDir(drvpath, sizeof(drvpath), "pci-stub");
- if (virFileExists(drvpath))
- return "pci-stub";
- pciDriverDir(drvpath, sizeof(drvpath), "pciback");
- if (virFileExists(drvpath))
- return "pciback";
-
- if (!probed) {
- const char *const stubprobe[] = { MODPROBE, "pci-stub", NULL };
- const char *const backprobe[] = { MODPROBE, "pciback", NULL };
-
- probed = 1;
- /*
- * Probing for pci-stub will succeed regardless of whether
- * on native or Xen kernels.
- * On Xen though, we want to prefer pciback, so probe
- * for that first, because that will only work on Xen
- */
- if (virRun(conn, backprobe, NULL) < 0 &&
- virRun(conn, stubprobe, NULL) < 0) {
- char ebuf[1024];
- VIR_WARN(_("failed to load pci-stub or pciback drivers: %s"),
- virStrerror(errno, ebuf, sizeof ebuf));
- return 0;
- }
-
- goto recheck;
- }
-
- return NULL;
-}
-
-
-static int
-pciBindDeviceToStub(virConnectPtr conn, pciDevice *dev, const char *driver)
-{
- char drvdir[PATH_MAX];
- char path[PATH_MAX];
-
- /* Add the PCI device ID to the stub's dynamic ID table;
- * this is needed to allow us to bind the device to the stub.
- * Note: if the device is not currently bound to any driver,
- * stub will immediately be bound to the device. Also, note
- * that if a new device with this ID is hotplugged, or if a probe
- * is triggered for such a device, it will also be immediately
- * bound by the stub.
- */
- pciDriverFile(path, sizeof(path), driver, "new_id");
- if (virFileWriteStr(path, dev->id) < 0) {
- virReportSystemError(conn, errno,
- _("Failed to add PCI device ID '%s' to %s"),
- dev->id, driver);
- return -1;
- }
-
- /* If the device is already bound to a driver, unbind it.
- * Note, this will have rather unpleasant side effects if this
- * PCI device happens to be IDE controller for the disk hosting
- * your root filesystem.
- */
- pciDeviceFile(path, sizeof(path), dev->name, "driver/unbind");
- if (virFileExists(path) && virFileWriteStr(path, dev->name) < 0) {
- virReportSystemError(conn, errno,
- _("Failed to unbind PCI device '%s'"), dev->name);
- return -1;
- }
-
- /* If the device isn't already bound to pci-stub, try binding it now.
- */
- pciDriverDir(drvdir, sizeof(drvdir), driver);
- pciDeviceFile(path, sizeof(path), dev->name, "driver");
- if (!virFileLinkPointsTo(path, drvdir)) {
- /* Xen's pciback.ko wants you to use new_slot first */
- pciDriverFile(path, sizeof(path), driver, "new_slot");
- if (virFileExists(path) && virFileWriteStr(path, dev->name) < 0) {
- virReportSystemError(conn, errno,
- _("Failed to add slot for PCI device '%s' to %s"),
- dev->name, driver);
- return -1;
- }
-
- pciDriverFile(path, sizeof(path), driver, "bind");
- if (virFileWriteStr(path, dev->name) < 0) {
- virReportSystemError(conn, errno,
- _("Failed to bind PCI device '%s' to %s"),
- dev->name, driver);
- return -1;
- }
- }
-
- /* If 'remove_id' exists, remove the device id from pci-stub's dynamic
- * ID table so that 'drivers_probe' works below.
- */
- pciDriverFile(path, sizeof(path), driver, "remove_id");
- if (virFileExists(path) && virFileWriteStr(path, dev->id) < 0) {
- virReportSystemError(conn, errno,
- _("Failed to remove PCI ID '%s' from %s"),
- dev->id, driver);
- return -1;
- }
-
- return 0;
-}
-
-int
-pciDettachDevice(virConnectPtr conn, pciDevice *dev)
-{
- const char *driver = pciFindStubDriver(conn);
- if (!driver) {
- pciReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
- _("cannot find any PCI stub module"));
- return -1;
- }
-
- return pciBindDeviceToStub(conn, dev, driver);
-}
-
-static int
-pciUnBindDeviceFromStub(virConnectPtr conn, pciDevice *dev, const char *driver)
-{
- char drvdir[PATH_MAX];
- char path[PATH_MAX];
-
- /* If the device is bound to stub, unbind it.
- */
- pciDriverDir(drvdir, sizeof(drvdir), driver);
- pciDeviceFile(path, sizeof(path), dev->name, "driver");
- if (virFileExists(drvdir) && virFileLinkPointsTo(path, drvdir)) {
- pciDriverFile(path, sizeof(path), driver, "unbind");
- if (virFileWriteStr(path, dev->name) < 0) {
- virReportSystemError(conn, errno,
- _("Failed to bind PCI device '%s' to %s"),
- dev->name, driver);
- return -1;
- }
- }
-
- /* Xen's pciback.ko wants you to use remove_slot on the specific device */
- pciDriverFile(path, sizeof(path), driver, "remove_slot");
- if (virFileExists(path) && virFileWriteStr(path, dev->name) < 0) {
- virReportSystemError(conn, errno,
- _("Failed to remove slot for PCI device '%s' to %s"),
- dev->name, driver);
- return -1;
- }
-
-
- /* Trigger a re-probe of the device is not in the stub's dynamic
- * ID table. If the stub is available, but 'remove_id' isn't
- * available, then re-probing would just cause the device to be
- * re-bound to the stub.
- */
- pciDriverFile(path, sizeof(path), driver, "remove_id");
- if (!virFileExists(drvdir) || virFileExists(path)) {
- if (virFileWriteStr(PCI_SYSFS "drivers_probe", dev->name) < 0) {
- virReportSystemError(conn, errno,
- _("Failed to trigger a re-probe for PCI device '%s'"),
- dev->name);
- return -1;
- }
- }
-
- return 0;
-}
-
-int
-pciReAttachDevice(virConnectPtr conn, pciDevice *dev)
-{
- const char *driver = pciFindStubDriver(conn);
- if (!driver) {
- pciReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
- _("cannot find any PCI stub module"));
- return -1;
- }
-
- return pciUnBindDeviceFromStub(conn, dev, driver);
-}
-
-static char *
-pciReadDeviceID(pciDevice *dev, const char *id_name)
-{
- char path[PATH_MAX];
- char *id_str;
-
- snprintf(path, sizeof(path), PCI_SYSFS "devices/%s/%s",
- dev->name, id_name);
-
- /* ID string is '0xNNNN\n' ... i.e. 7 bytes */
- if (virFileReadAll(path, 7, &id_str) < 0)
- return NULL;
-
- /* Check for 0x suffix */
- if (id_str[0] != '0' || id_str[1] != 'x') {
- VIR_FREE(id_str);
- return NULL;
- }
-
- /* Chop off the newline; we know the string is 7 bytes */
- id_str[6] = '\0';
-
- return id_str;
-}
-
-pciDevice *
-pciGetDevice(virConnectPtr conn,
- unsigned domain,
- unsigned bus,
- unsigned slot,
- unsigned function)
-{
- pciDevice *dev;
- char *vendor, *product;
-
- if (VIR_ALLOC(dev) < 0) {
- virReportOOMError(conn);
- return NULL;
- }
-
- dev->fd = -1;
- dev->domain = domain;
- dev->bus = bus;
- dev->slot = slot;
- dev->function = function;
-
- snprintf(dev->name, sizeof(dev->name), "%.4x:%.2x:%.2x.%.1x",
- dev->domain, dev->bus, dev->slot, dev->function);
- snprintf(dev->path, sizeof(dev->path),
- PCI_SYSFS "devices/%s/config", dev->name);
-
- vendor = pciReadDeviceID(dev, "vendor");
- product = pciReadDeviceID(dev, "device");
-
- if (!vendor || !product) {
- pciReportError(conn, VIR_ERR_NO_SUPPORT,
- _("Failed to read product/vendor ID for %s"),
- dev->name);
- VIR_FREE(product);
- VIR_FREE(vendor);
- pciFreeDevice(conn, dev);
- return NULL;
- }
-
- /* strings contain '0x' prefix */
- snprintf(dev->id, sizeof(dev->id), "%s %s", &vendor[2], &product[2]);
-
- VIR_FREE(product);
- VIR_FREE(vendor);
-
- VIR_DEBUG("%s %s: initialized", dev->id, dev->name);
-
- return dev;
-}
-
-void
-pciFreeDevice(virConnectPtr conn ATTRIBUTE_UNUSED, pciDevice *dev)
-{
- if (!dev)
- return;
- VIR_DEBUG("%s %s: freeing", dev->id, dev->name);
- if (dev->fd >= 0)
- close(dev->fd);
- VIR_FREE(dev);
-}
-
-void pciDeviceSetManaged(pciDevice *dev, unsigned managed)
-{
- dev->managed = !!managed;
-}
-
-unsigned pciDeviceGetManaged(pciDevice *dev)
-{
- return dev->managed;
-}
-
-pciDeviceList *
-pciDeviceListNew(virConnectPtr conn)
-{
- pciDeviceList *list;
-
- if (VIR_ALLOC(list) < 0) {
- virReportOOMError(conn);
- return NULL;
- }
-
- return list;
-}
-
-void
-pciDeviceListFree(virConnectPtr conn,
- pciDeviceList *list)
-{
- int i;
-
- if (!list)
- return;
-
- for (i = 0; i < list->count; i++) {
- pciFreeDevice(conn, list->devs[i]);
- list->devs[i] = NULL;
- }
-
- list->count = 0;
- VIR_FREE(list->devs);
- VIR_FREE(list);
-}
-
-int
-pciDeviceListAdd(virConnectPtr conn,
- pciDeviceList *list,
- pciDevice *dev)
-{
- if (pciDeviceListFind(list, dev)) {
- pciReportError(conn, VIR_ERR_INTERNAL_ERROR,
- _("Device %s is already in use"), dev->name);
- return -1;
- }
-
- if (VIR_REALLOC_N(list->devs, list->count+1) < 0) {
- virReportOOMError(conn);
- return -1;
- }
-
- list->devs[list->count++] = dev;
-
- return 0;
-}
-
-void
-pciDeviceListDel(virConnectPtr conn ATTRIBUTE_UNUSED,
- pciDeviceList *list,
- pciDevice *dev)
-{
- int i;
-
- for (i = 0; i < list->count; i++) {
- if (list->devs[i]->domain != dev->domain ||
- list->devs[i]->bus != dev->bus ||
- list->devs[i]->slot != dev->slot ||
- list->devs[i]->function != dev->function)
- continue;
-
- pciFreeDevice(conn, list->devs[i]);
-
- if (i != --list->count)
- memmove(&list->devs[i],
- &list->devs[i+1],
- sizeof(*list->devs) * (list->count-i));
-
- if (VIR_REALLOC_N(list->devs, list->count) < 0) {
- ; /* not fatal */
- }
-
- break;
- }
-}
-
-pciDevice *
-pciDeviceListFind(pciDeviceList *list, pciDevice *dev)
-{
- int i;
-
- for (i = 0; i < list->count; i++)
- if (list->devs[i]->domain == dev->domain &&
- list->devs[i]->bus == dev->bus &&
- list->devs[i]->slot == dev->slot &&
- list->devs[i]->function == dev->function)
- return list->devs[i];
- return NULL;
-}
-
-
-int pciDeviceFileIterate(virConnectPtr conn,
- pciDevice *dev,
- pciDeviceFileActor actor,
- void *opaque)
-{
- char *pcidir = NULL;
- char *file = NULL;
- DIR *dir = NULL;
- int ret = -1;
- struct dirent *ent;
-
- if (virAsprintf(&pcidir, "/sys/bus/pci/devices/%04x:%02x:%02x.%x",
- dev->domain, dev->bus, dev->slot, dev->function) < 0) {
- virReportOOMError(conn);
- goto cleanup;
- }
-
- if (!(dir = opendir(pcidir))) {
- virReportSystemError(conn, errno,
- _("cannot open %s"), pcidir);
- goto cleanup;
- }
-
- while ((ent = readdir(dir)) != NULL) {
- /* Device assignment requires:
- * $PCIDIR/config, $PCIDIR/resource, $PCIDIR/resourceNNN, $PCIDIR/rom
- */
- if (STREQ(ent->d_name, "config") ||
- STRPREFIX(ent->d_name, "resource") ||
- STREQ(ent->d_name, "rom")) {
- if (virAsprintf(&file, "%s/%s", pcidir, ent->d_name) < 0) {
- virReportOOMError(conn);
- goto cleanup;
- }
- if ((actor)(conn, dev, file, opaque) < 0)
- goto cleanup;
-
- VIR_FREE(file);
- }
- }
-
- ret = 0;
-
-cleanup:
- if (dir)
- closedir(dir);
- VIR_FREE(file);
- VIR_FREE(pcidir);
- return ret;
-}
+++ /dev/null
-/*
- * Copyright (C) 2009 Red Hat, Inc.
- *
- * 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
- *
- * Authors:
- * Mark McLoughlin <markmc@redhat.com>
- */
-
-#ifndef __VIR_PCI_H__
-#define __VIR_PCI_H__
-
-#include "internal.h"
-
-typedef struct _pciDevice pciDevice;
-
-typedef struct {
- unsigned count;
- pciDevice **devs;
-} pciDeviceList;
-
-pciDevice *pciGetDevice (virConnectPtr conn,
- unsigned domain,
- unsigned bus,
- unsigned slot,
- unsigned function);
-void pciFreeDevice (virConnectPtr conn,
- pciDevice *dev);
-int pciDettachDevice (virConnectPtr conn,
- pciDevice *dev);
-int pciReAttachDevice (virConnectPtr conn,
- pciDevice *dev);
-int pciResetDevice (virConnectPtr conn,
- pciDevice *dev,
- pciDeviceList *activeDevs);
-void pciDeviceSetManaged(pciDevice *dev,
- unsigned managed);
-unsigned pciDeviceGetManaged(pciDevice *dev);
-
-pciDeviceList *pciDeviceListNew (virConnectPtr conn);
-void pciDeviceListFree (virConnectPtr conn,
- pciDeviceList *list);
-int pciDeviceListAdd (virConnectPtr conn,
- pciDeviceList *list,
- pciDevice *dev);
-void pciDeviceListDel (virConnectPtr conn,
- pciDeviceList *list,
- pciDevice *dev);
-pciDevice * pciDeviceListFind (pciDeviceList *list,
- pciDevice *dev);
-
-/*
- * Callback that will be invoked once for each file
- * associated with / used for PCI host device access.
- *
- * Should return 0 if successfully processed, or
- * -1 to indicate error and abort iteration
- */
-typedef int (*pciDeviceFileActor)(virConnectPtr conn, pciDevice *dev,
- const char *path, void *opaque);
-
-int pciDeviceFileIterate(virConnectPtr conn,
- pciDevice *dev,
- pciDeviceFileActor actor,
- void *opaque);
-
-#endif /* __VIR_PCI_H__ */
+++ /dev/null
-/* Copyright (C) 2007, 2009 Red Hat, Inc.
- *
- * 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
- *
- * Authors:
- * Richard W.M. Jones <rjones@redhat.com>
- *
- * Utility functions to help parse and assemble query strings.
- */
-
-#include <config.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-
-#include <libxml/uri.h>
-
-#include "virterror_internal.h"
-#include "buf.h"
-#include "memory.h"
-#include "qparams.h"
-
-#define VIR_FROM_THIS VIR_FROM_NONE
-
-struct qparam_set *
-new_qparam_set (int init_alloc, ...)
-{
- va_list args;
- struct qparam_set *ps;
- const char *pname, *pvalue;
-
- if (init_alloc <= 0) init_alloc = 1;
-
- if (VIR_ALLOC(ps) < 0) {
- virReportOOMError(NULL);
- return NULL;
- }
- ps->n = 0;
- ps->alloc = init_alloc;
- if (VIR_ALLOC_N(ps->p, ps->alloc) < 0) {
- VIR_FREE (ps);
- virReportOOMError(NULL);
- return NULL;
- }
-
- va_start (args, init_alloc);
- while ((pname = va_arg (args, char *)) != NULL) {
- pvalue = va_arg (args, char *);
-
- if (append_qparam (ps, pname, pvalue) == -1) {
- free_qparam_set (ps);
- return NULL;
- }
- }
- va_end (args);
-
- return ps;
-}
-
-int
-append_qparams (struct qparam_set *ps, ...)
-{
- va_list args;
- const char *pname, *pvalue;
-
- va_start (args, ps);
- while ((pname = va_arg (args, char *)) != NULL) {
- pvalue = va_arg (args, char *);
-
- if (append_qparam (ps, pname, pvalue) == -1)
- return -1;
- }
- va_end (args);
-
- return 0;
-}
-
-/* Ensure there is space to store at least one more parameter
- * at the end of the set.
- */
-static int
-grow_qparam_set (struct qparam_set *ps)
-{
- if (ps->n >= ps->alloc) {
- if (VIR_REALLOC_N(ps->p, ps->alloc * 2) < 0) {
- virReportOOMError(NULL);
- return -1;
- }
- ps->alloc *= 2;
- }
-
- return 0;
-}
-
-int
-append_qparam (struct qparam_set *ps,
- const char *name, const char *value)
-{
- char *pname, *pvalue;
-
- pname = strdup (name);
- if (!pname) {
- virReportOOMError(NULL);
- return -1;
- }
-
- pvalue = strdup (value);
- if (!pvalue) {
- VIR_FREE (pname);
- virReportOOMError(NULL);
- return -1;
- }
-
- if (grow_qparam_set (ps) == -1) {
- VIR_FREE (pname);
- VIR_FREE (pvalue);
- return -1;
- }
-
- ps->p[ps->n].name = pname;
- ps->p[ps->n].value = pvalue;
- ps->p[ps->n].ignore = 0;
- ps->n++;
-
- return 0;
-}
-
-char *
-qparam_get_query (const struct qparam_set *ps)
-{
- virBuffer buf = VIR_BUFFER_INITIALIZER;
- int i, amp = 0;
-
- for (i = 0; i < ps->n; ++i) {
- if (!ps->p[i].ignore) {
- if (amp) virBufferAddChar (&buf, '&');
- virBufferStrcat (&buf, ps->p[i].name, "=", NULL);
- virBufferURIEncodeString (&buf, ps->p[i].value);
- amp = 1;
- }
- }
-
- if (virBufferError(&buf)) {
- virReportOOMError(NULL);
- return NULL;
- }
-
- return virBufferContentAndReset(&buf);
-}
-
-void
-free_qparam_set (struct qparam_set *ps)
-{
- int i;
-
- for (i = 0; i < ps->n; ++i) {
- VIR_FREE (ps->p[i].name);
- VIR_FREE (ps->p[i].value);
- }
- VIR_FREE (ps->p);
- VIR_FREE (ps);
-}
-
-struct qparam_set *
-qparam_query_parse (const char *query)
-{
- struct qparam_set *ps;
- const char *end, *eq;
-
- ps = new_qparam_set (0, NULL);
- if (!ps) {
- virReportOOMError(NULL);
- return NULL;
- }
-
- if (!query || query[0] == '\0') return ps;
-
- while (*query) {
- char *name = NULL, *value = NULL;
-
- /* Find the next separator, or end of the string. */
- end = strchr (query, '&');
- if (!end)
- end = strchr (query, ';');
- if (!end)
- end = query + strlen (query);
-
- /* Find the first '=' character between here and end. */
- eq = strchr (query, '=');
- if (eq && eq >= end) eq = NULL;
-
- /* Empty section (eg. "&&"). */
- if (end == query)
- goto next;
-
- /* If there is no '=' character, then we have just "name"
- * and consistent with CGI.pm we assume value is "".
- */
- else if (!eq) {
- name = xmlURIUnescapeString (query, end - query, NULL);
- if (!name) goto out_of_memory;
- }
- /* Or if we have "name=" here (works around annoying
- * problem when calling xmlURIUnescapeString with len = 0).
- */
- else if (eq+1 == end) {
- name = xmlURIUnescapeString (query, eq - query, NULL);
- if (!name) goto out_of_memory;
- }
- /* If the '=' character is at the beginning then we have
- * "=value" and consistent with CGI.pm we _ignore_ this.
- */
- else if (query == eq)
- goto next;
-
- /* Otherwise it's "name=value". */
- else {
- name = xmlURIUnescapeString (query, eq - query, NULL);
- if (!name)
- goto out_of_memory;
- value = xmlURIUnescapeString (eq+1, end - (eq+1), NULL);
- if (!value) {
- VIR_FREE(name);
- goto out_of_memory;
- }
- }
-
- /* Append to the parameter set. */
- if (append_qparam (ps, name, value ? value : "") == -1) {
- VIR_FREE(name);
- VIR_FREE(value);
- goto out_of_memory;
- }
- VIR_FREE(name);
- VIR_FREE(value);
-
- next:
- query = end;
- if (*query) query ++; /* skip '&' separator */
- }
-
- return ps;
-
- out_of_memory:
- virReportOOMError(NULL);
- free_qparam_set (ps);
- return NULL;
-}
+++ /dev/null
-/* Copyright (C) 2007 Red Hat, Inc.
- *
- * 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
- *
- * Authors:
- * Richard W.M. Jones <rjones@redhat.com>
- *
- * Utility functions to help parse and assemble query strings.
- */
-
-#ifndef _QPARAMS_H_
-#define _QPARAMS_H_
-
-/* Single web service query parameter 'name=value'. */
-struct qparam {
- char *name; /* Name (unescaped). */
- char *value; /* Value (unescaped). */
- int ignore; /* Ignore this field in qparam_get_query */
-};
-
-/* Set of parameters. */
-struct qparam_set {
- int n; /* number of parameters used */
- int alloc; /* allocated space */
- struct qparam *p; /* array of parameters */
-};
-
-/* New parameter set. */
-extern struct qparam_set *new_qparam_set (int init_alloc, ...);
-
-/* Appending parameters. */
-extern int append_qparams (struct qparam_set *ps, ...);
-extern int append_qparam (struct qparam_set *ps,
- const char *name, const char *value);
-
-/* Get a query string ("name=value&name=value&...") */
-extern char *qparam_get_query (const struct qparam_set *ps);
-
-/* Parse a query string into a parameter set. */
-extern struct qparam_set *qparam_query_parse (const char *query);
-
-extern void free_qparam_set (struct qparam_set *ps);
-
-#endif /* _QPARAMS_H_ */
+++ /dev/null
-/*
- * Linux block and network stats.
- *
- * Copyright (C) 2007-2009 Red Hat, Inc.
- *
- * See COPYING.LIB for the License of this software
- *
- * Richard W.M. Jones <rjones@redhat.com>
- */
-
-#include <config.h>
-
-/* This file only applies on Linux. */
-#ifdef __linux__
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <string.h>
-#include <unistd.h>
-#include <regex.h>
-
-#include "virterror_internal.h"
-#include "datatypes.h"
-#include "util.h"
-#include "stats_linux.h"
-#include "memory.h"
-
-#define VIR_FROM_THIS VIR_FROM_STATS_LINUX
-
-/**
- * statsErrorFunc:
- * @conn: the connection
- * @error: the error number
- * @func: the function failing
- * @info: extra information string
- * @value: extra information number
- *
- * Handle a stats error.
- */
-static void
-statsErrorFunc (virConnectPtr conn,
- virErrorNumber error, const char *func, const char *info,
- int value)
-{
- char fullinfo[1000];
- const char *errmsg;
-
- errmsg = virErrorMsg(error, info);
- if (func != NULL) {
- snprintf(fullinfo, sizeof (fullinfo) - 1, "%s: %s", func, info);
- fullinfo[sizeof (fullinfo) - 1] = 0;
- info = fullinfo;
- }
- virRaiseError(conn, NULL, NULL, VIR_FROM_STATS_LINUX, error,
- VIR_ERR_ERROR,
- errmsg, info, NULL, value, 0, errmsg, info,
- value);
-}
-
-
-/*-------------------- interface stats --------------------*/
-/* Just reads the named interface, so not Xen or QEMU-specific.
- * NB. Caller must check that libvirt user is trying to query
- * the interface of a domain they own. We do no such checking.
- */
-
-int
-linuxDomainInterfaceStats (virConnectPtr conn, const char *path,
- struct _virDomainInterfaceStats *stats)
-{
- int path_len;
- FILE *fp;
- char line[256], *colon;
-
- fp = fopen ("/proc/net/dev", "r");
- if (!fp) {
- statsErrorFunc (conn, VIR_ERR_INTERNAL_ERROR, __FUNCTION__,
- "/proc/net/dev", errno);
- return -1;
- }
-
- path_len = strlen (path);
-
- while (fgets (line, sizeof line, fp)) {
- long long dummy;
- long long rx_bytes;
- long long rx_packets;
- long long rx_errs;
- long long rx_drop;
- long long tx_bytes;
- long long tx_packets;
- long long tx_errs;
- long long tx_drop;
-
- /* The line looks like:
- * " eth0:..."
- * Split it at the colon.
- */
- colon = strchr (line, ':');
- if (!colon) continue;
- *colon = '\0';
- if (colon-path_len >= line &&
- STREQ (colon-path_len, path)) {
- /* IMPORTANT NOTE!
- * /proc/net/dev vif<domid>.nn sees the network from the point
- * of view of dom0 / hypervisor. So bytes TRANSMITTED by dom0
- * are bytes RECEIVED by the domain. That's why the TX/RX fields
- * appear to be swapped here.
- */
- if (sscanf (colon+1,
- "%lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld",
- &tx_bytes, &tx_packets, &tx_errs, &tx_drop,
- &dummy, &dummy, &dummy, &dummy,
- &rx_bytes, &rx_packets, &rx_errs, &rx_drop,
- &dummy, &dummy, &dummy, &dummy) != 16)
- continue;
-
- stats->rx_bytes = rx_bytes;
- stats->rx_packets = rx_packets;
- stats->rx_errs = rx_errs;
- stats->rx_drop = rx_drop;
- stats->tx_bytes = tx_bytes;
- stats->tx_packets = tx_packets;
- stats->tx_errs = tx_errs;
- stats->tx_drop = tx_drop;
- fclose (fp);
-
- return 0;
- }
- }
- fclose (fp);
-
- statsErrorFunc (conn, VIR_ERR_INTERNAL_ERROR, __FUNCTION__,
- "/proc/net/dev: Interface not found", 0);
- return -1;
-}
-
-#endif /* __linux__ */
+++ /dev/null
-/*
- * Linux block and network stats.
- *
- * Copyright (C) 2007 Red Hat, Inc.
- *
- * See COPYING.LIB for the License of this software
- *
- * Richard W.M. Jones <rjones@redhat.com>
- */
-
-#ifndef __STATS_LINUX_H__
-#define __STATS_LINUX_H__
-
-#ifdef __linux__
-
-#include "internal.h"
-
-extern int linuxDomainInterfaceStats (virConnectPtr conn, const char *path,
- struct _virDomainInterfaceStats *stats);
-
-#endif /* __linux__ */
-
-#endif /* __STATS_LINUX_H__ */
+++ /dev/null
-/*
- * threads-pthread.c: basic thread synchronization primitives
- *
- * Copyright (C) 2009 Red Hat, Inc.
- *
- * 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
- *
- */
-
-#include <config.h>
-
-
-/* Nothing special required for pthreads */
-int virThreadInitialize(void)
-{
- return 0;
-}
-
-void virThreadOnExit(void)
-{
-}
-
-
-int virMutexInit(virMutexPtr m)
-{
- if (pthread_mutex_init(&m->lock, NULL) != 0) {
- errno = EINVAL;
- return -1;
- }
- return 0;
-}
-
-void virMutexDestroy(virMutexPtr m)
-{
- pthread_mutex_destroy(&m->lock);
-}
-
-void virMutexLock(virMutexPtr m){
- pthread_mutex_lock(&m->lock);
-}
-
-void virMutexUnlock(virMutexPtr m)
-{
- pthread_mutex_unlock(&m->lock);
-}
-
-
-
-int virCondInit(virCondPtr c)
-{
- if (pthread_cond_init(&c->cond, NULL) != 0) {
- errno = EINVAL;
- return -1;
- }
- return 0;
-}
-
-int virCondDestroy(virCondPtr c)
-{
- if (pthread_cond_destroy(&c->cond) != 0) {
- errno = EINVAL;
- return -1;
- }
- return 0;
-}
-
-int virCondWait(virCondPtr c, virMutexPtr m)
-{
- if (pthread_cond_wait(&c->cond, &m->lock) != 0) {
- errno = EINVAL;
- return -1;
- }
- return 0;
-}
-
-void virCondSignal(virCondPtr c)
-{
- pthread_cond_signal(&c->cond);
-}
-
-void virCondBroadcast(virCondPtr c)
-{
- pthread_cond_broadcast(&c->cond);
-}
-
-
-int virThreadLocalInit(virThreadLocalPtr l,
- virThreadLocalCleanup c)
-{
- if (pthread_key_create(&l->key, c) != 0) {
- errno = EINVAL;
- return -1;
- }
- return 0;
-}
-
-void *virThreadLocalGet(virThreadLocalPtr l)
-{
- return pthread_getspecific(l->key);
-}
-
-void virThreadLocalSet(virThreadLocalPtr l, void *val)
-{
- pthread_setspecific(l->key, val);
-}
+++ /dev/null
-/*
- * threads.c: basic thread synchronization primitives
- *
- * Copyright (C) 2009 Red Hat, Inc.
- *
- * 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
- *
- */
-
-#include "internal.h"
-
-#include <pthread.h>
-
-struct virMutex {
- pthread_mutex_t lock;
-};
-
-struct virCond {
- pthread_cond_t cond;
-};
-
-struct virThreadLocal {
- pthread_key_t key;
-};
+++ /dev/null
-/*
- * threads-win32.c: basic thread synchronization primitives
- *
- * Copyright (C) 2009 Red Hat, Inc.
- *
- * 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
- *
- */
-
-#include <config.h>
-
-#include "memory.h"
-
-struct virThreadLocalData {
- DWORD key;
- virThreadLocalCleanup cleanup;
-};
-typedef struct virThreadLocalData virThreadLocalData;
-typedef virThreadLocalData *virThreadLocalDataPtr;
-
-virMutex virThreadLocalLock;
-unsigned int virThreadLocalCount = 0;
-virThreadLocalDataPtr virThreadLocalList = NULL;
-
-
-virThreadLocal virCondEvent;
-
-void virCondEventCleanup(void *data);
-
-int virThreadInitialize(void)
-{
- if (virMutexInit(&virThreadLocalLock) < 0)
- return -1;
- if (virThreadLocalInit(&virCondEvent, virCondEventCleanup) < 0)
- return -1;
-
- return 0;
-}
-
-void virThreadOnExit(void)
-{
- unsigned int i;
- virMutexLock(&virThreadLocalLock);
- for (i = 0 ; i < virThreadLocalCount ; i++) {
- if (virThreadLocalList[i].cleanup) {
- void *data = TlsGetValue(virThreadLocalList[i].key);
- if (data) {
- TlsSetValue(virThreadLocalList[i].key, NULL);
-
- (virThreadLocalList[i].cleanup)(data);
- }
- }
- }
- virMutexUnlock(&virThreadLocalLock);
-}
-
-
-int virMutexInit(virMutexPtr m)
-{
- if (!(m->lock = CreateMutex(NULL, FALSE, NULL))) {
- errno = ESRCH;
- return -1;
- }
- return 0;
-}
-
-void virMutexDestroy(virMutexPtr m)
-{
- CloseHandle(m->lock);
-}
-
-void virMutexLock(virMutexPtr m)
-{
- WaitForSingleObject(m->lock, INFINITE);
-}
-
-void virMutexUnlock(virMutexPtr m)
-{
- ReleaseMutex(m->lock);
-}
-
-
-
-int virCondInit(virCondPtr c)
-{
- c->waiters = NULL;
- if (virMutexInit(&c->lock) < 0)
- return -1;
- return 0;
-}
-
-int virCondDestroy(virCondPtr c)
-{
- if (c->waiters) {
- errno = EINVAL;
- return -1;
- }
- virMutexDestroy(&c->lock);
- return 0;
-}
-
-void virCondEventCleanup(void *data)
-{
- HANDLE event = data;
- CloseHandle(event);
-}
-
-int virCondWait(virCondPtr c, virMutexPtr m)
-{
- HANDLE event = virThreadLocalGet(&virCondEvent);
-
- if (!event) {
- event = CreateEvent(0, FALSE, FALSE, NULL);
- if (!event) {
- return -1;
- }
- virThreadLocalSet(&virCondEvent, event);
- }
-
- virMutexLock(&c->lock);
-
- if (VIR_REALLOC_N(c->waiters, c->nwaiters + 1) < 0) {
- virMutexUnlock(&c->lock);
- return -1;
- }
- c->waiters[c->nwaiters] = event;
- c->nwaiters++;
-
- virMutexUnlock(&c->lock);
-
- virMutexUnlock(m);
-
- if (WaitForSingleObject(event, INFINITE) == WAIT_FAILED) {
- virMutexLock(m);
- errno = EINVAL;
- return -1;
- }
-
- virMutexLock(m);
- return 0;
-}
-
-void virCondSignal(virCondPtr c)
-{
- virMutexLock(&c->lock);
-
- if (c->nwaiters) {
- HANDLE event = c->waiters[0];
- if (c->nwaiters > 1)
- memmove(c->waiters,
- c->waiters + 1,
- sizeof(c->waiters[0]) * (c->nwaiters-1));
- if (VIR_REALLOC_N(c->waiters, c->nwaiters - 1) < 0) {
- ;
- }
- c->nwaiters--;
- SetEvent(event);
- }
-
- virMutexUnlock(&c->lock);
-}
-
-void virCondBroadcast(virCondPtr c)
-{
- virMutexLock(&c->lock);
-
- if (c->nwaiters) {
- unsigned int i;
- for (i = 0 ; i < c->nwaiters ; i++) {
- HANDLE event = c->waiters[i];
- SetEvent(event);
- }
- VIR_FREE(c->waiters);
- c->nwaiters = 0;
- }
-
- virMutexUnlock(&c->lock);
-}
-
-
-
-int virThreadLocalInit(virThreadLocalPtr l,
- virThreadLocalCleanup c)
-{
- if ((l->key = TlsAlloc()) == TLS_OUT_OF_INDEXES) {
- errno = ESRCH;
- return -1;
- }
- TlsSetValue(l->key, NULL);
-
- if (c) {
- virMutexLock(&virThreadLocalLock);
- if (VIR_REALLOC_N(virThreadLocalList,
- virThreadLocalCount + 1) < 0)
- return -1;
- virThreadLocalList[virThreadLocalCount].key = l->key;
- virThreadLocalList[virThreadLocalCount].cleanup = c;
- virThreadLocalCount++;
- virMutexUnlock(&virThreadLocalLock);
- }
-
- return 0;
-}
-
-void *virThreadLocalGet(virThreadLocalPtr l)
-{
- return TlsGetValue(l->key);
-}
-
-void virThreadLocalSet(virThreadLocalPtr l, void *val)
-{
- TlsSetValue(l->key, val);
-}
+++ /dev/null
-/*
- * threads-win32.h basic thread synchronization primitives
- *
- * Copyright (C) 2009 Red Hat, Inc.
- *
- * 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
- *
- */
-
-#include "internal.h"
-
-#include <windows.h>
-
-struct virMutex {
- HANDLE lock;
-};
-
-struct virCond {
- virMutex lock;
- unsigned int nwaiters;
- HANDLE *waiters;
-};
-
-
-struct virThreadLocal {
- DWORD key;
-};
+++ /dev/null
-/*
- * threads.c: basic thread synchronization primitives
- *
- * Copyright (C) 2009 Red Hat, Inc.
- *
- * 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
- *
- */
-
-#include <config.h>
-
-#include "threads.h"
-
-#ifdef HAVE_PTHREAD_H
-#include "threads-pthread.c"
-#else
-#ifdef WIN32
-#include "threads-win32.c"
-#else
-#error "Either pthreads or Win32 threads are required"
-#endif
-#endif
+++ /dev/null
-/*
- * threads.h: basic thread synchronization primitives
- *
- * Copyright (C) 2009 Red Hat, Inc.
- *
- * 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
- *
- */
-
-#ifndef __THREADS_H_
-#define __THREADS_H_
-
-#include "internal.h"
-
-typedef struct virMutex virMutex;
-typedef virMutex *virMutexPtr;
-
-typedef struct virCond virCond;
-typedef virCond *virCondPtr;
-
-typedef struct virThreadLocal virThreadLocal;
-typedef virThreadLocal *virThreadLocalPtr;
-
-
-int virThreadInitialize(void) ATTRIBUTE_RETURN_CHECK;
-void virThreadOnExit(void);
-
-int virMutexInit(virMutexPtr m) ATTRIBUTE_RETURN_CHECK;
-void virMutexDestroy(virMutexPtr m);
-
-void virMutexLock(virMutexPtr m);
-void virMutexUnlock(virMutexPtr m);
-
-
-
-int virCondInit(virCondPtr c) ATTRIBUTE_RETURN_CHECK;
-int virCondDestroy(virCondPtr c) ATTRIBUTE_RETURN_CHECK;
-
-int virCondWait(virCondPtr c, virMutexPtr m) ATTRIBUTE_RETURN_CHECK;
-void virCondSignal(virCondPtr c);
-void virCondBroadcast(virCondPtr c);
-
-
-typedef void (*virThreadLocalCleanup)(void *);
-int virThreadLocalInit(virThreadLocalPtr l,
- virThreadLocalCleanup c) ATTRIBUTE_RETURN_CHECK;
-void *virThreadLocalGet(virThreadLocalPtr l);
-void virThreadLocalSet(virThreadLocalPtr l, void*);
-
-#ifdef HAVE_PTHREAD_H
-#include "threads-pthread.h"
-#else
-#ifdef WIN32
-#include "threads-win32.h"
-#else
-#error "Either pthreads or Win32 threads are required"
-#endif
-#endif
-
-#endif
+++ /dev/null
-/*
- * utils.c: common, generic utility functions
- *
- * Copyright (C) 2006, 2007, 2008, 2009 Red Hat, Inc.
- * Copyright (C) 2006 Daniel P. Berrange
- * Copyright (C) 2006, 2007 Binary Karma
- * Copyright (C) 2006 Shuveb Hussain
- *
- * 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>
- * File created Jul 18, 2007 - Shuveb Hussain <shuveb@binarykarma.com>
- */
-
-#include <config.h>
-
-#include <stdio.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <poll.h>
-#include <time.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#if HAVE_SYS_WAIT_H
-#include <sys/wait.h>
-#endif
-#if HAVE_MMAP
-#include <sys/mman.h>
-#endif
-#include <string.h>
-#include <signal.h>
-#if HAVE_TERMIOS_H
-#include <termios.h>
-#endif
-#include "c-ctype.h"
-
-#ifdef HAVE_PATHS_H
-#include <paths.h>
-#endif
-#include <netdb.h>
-#ifdef HAVE_GETPWUID_R
-#include <pwd.h>
-#include <grp.h>
-#endif
-#if HAVE_CAPNG
-#include <cap-ng.h>
-#endif
-#ifdef HAVE_MNTENT_H
-#include <mntent.h>
-#endif
-
-#include "virterror_internal.h"
-#include "logging.h"
-#include "event.h"
-#include "buf.h"
-#include "util.h"
-#include "memory.h"
-#include "threads.h"
-
-#ifndef NSIG
-# define NSIG 32
-#endif
-
-#ifndef MIN
-# define MIN(a, b) ((a) < (b) ? (a) : (b))
-#endif
-
-#define VIR_FROM_THIS VIR_FROM_NONE
-
-#define ReportError(conn, code, fmt...) \
- virReportErrorHelper(conn, VIR_FROM_NONE, code, __FILE__, \
- __FUNCTION__, __LINE__, fmt)
-
-/* Like read(), but restarts after EINTR */
-int saferead(int fd, void *buf, size_t count)
-{
- size_t nread = 0;
- while (count > 0) {
- ssize_t r = read(fd, buf, count);
- if (r < 0 && errno == EINTR)
- continue;
- if (r < 0)
- return r;
- if (r == 0)
- return nread;
- buf = (char *)buf + r;
- count -= r;
- nread += r;
- }
- return nread;
-}
-
-/* Like write(), but restarts after EINTR */
-ssize_t safewrite(int fd, const void *buf, size_t count)
-{
- size_t nwritten = 0;
- while (count > 0) {
- ssize_t r = write(fd, buf, count);
-
- if (r < 0 && errno == EINTR)
- continue;
- if (r < 0)
- return r;
- if (r == 0)
- return nwritten;
- buf = (const char *)buf + r;
- count -= r;
- nwritten += r;
- }
- return nwritten;
-}
-
-#ifdef HAVE_POSIX_FALLOCATE
-int safezero(int fd, int flags ATTRIBUTE_UNUSED, off_t offset, off_t len)
-{
- return posix_fallocate(fd, offset, len);
-}
-#else
-
-#ifdef HAVE_MMAP
-int safezero(int fd, int flags ATTRIBUTE_UNUSED, off_t offset, off_t len)
-{
- int r;
- char *buf;
-
- /* memset wants the mmap'ed file to be present on disk so create a
- * sparse file
- */
- r = ftruncate(fd, offset + len);
- if (r < 0)
- return -errno;
-
- buf = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset);
- if (buf == MAP_FAILED)
- return -errno;
-
- memset(buf, 0, len);
- munmap(buf, len);
-
- return 0;
-}
-
-#else /* HAVE_MMAP */
-
-int safezero(int fd, int flags ATTRIBUTE_UNUSED, off_t offset, off_t len)
-{
- int r;
- char *buf;
- unsigned long long remain, bytes;
-
- if (lseek(fd, offset, SEEK_SET) < 0)
- return errno;
-
- /* Split up the write in small chunks so as not to allocate lots of RAM */
- remain = len;
- bytes = 1024 * 1024;
-
- r = VIR_ALLOC_N(buf, bytes);
- if (r < 0)
- return -ENOMEM;
-
- while (remain) {
- if (bytes > remain)
- bytes = remain;
-
- r = safewrite(fd, buf, len);
- if (r < 0) {
- VIR_FREE(buf);
- return r;
- }
-
- /* safewrite() guarantees all data will be written */
- remain -= bytes;
- }
- VIR_FREE(buf);
- return 0;
-}
-#endif /* HAVE_MMAP */
-#endif /* HAVE_POSIX_FALLOCATE */
-
-#ifndef PROXY
-
-int virFileStripSuffix(char *str,
- const char *suffix)
-{
- int len = strlen(str);
- int suffixlen = strlen(suffix);
-
- if (len < suffixlen)
- return 0;
-
- if (!STREQ(str + len - suffixlen, suffix))
- return 0;
-
- str[len-suffixlen] = '\0';
-
- return 1;
-}
-
-char *
-virArgvToString(const char *const *argv)
-{
- int len, i;
- char *ret, *p;
-
- for (len = 1, i = 0; argv[i]; i++)
- len += strlen(argv[i]) + 1;
-
- if (VIR_ALLOC_N(ret, len) < 0)
- return NULL;
- p = ret;
-
- for (i = 0; argv[i]; i++) {
- if (i != 0)
- *(p++) = ' ';
-
- strcpy(p, argv[i]);
- p += strlen(argv[i]);
- }
-
- *p = '\0';
-
- return ret;
-}
-
-int virSetNonBlock(int fd) {
-#ifndef WIN32
- int flags;
- if ((flags = fcntl(fd, F_GETFL)) < 0)
- return -1;
- flags |= O_NONBLOCK;
- if ((fcntl(fd, F_SETFL, flags)) < 0)
- return -1;
-#else
- unsigned long flag = 1;
-
- /* This is actually Gnulib's replacement rpl_ioctl function.
- * We can't call ioctlsocket directly in any case.
- */
- if (ioctl (fd, FIONBIO, (void *) &flag) == -1)
- return -1;
-#endif
- return 0;
-}
-
-
-#ifndef WIN32
-
-int virSetCloseExec(int fd) {
- int flags;
- if ((flags = fcntl(fd, F_GETFD)) < 0)
- return -1;
- flags |= FD_CLOEXEC;
- if ((fcntl(fd, F_SETFD, flags)) < 0)
- return -1;
- return 0;
-}
-
-
-#if HAVE_CAPNG
-static int virClearCapabilities(void)
-{
- int ret;
-
- capng_clear(CAPNG_SELECT_BOTH);
-
- if ((ret = capng_apply(CAPNG_SELECT_BOTH)) < 0) {
- VIR_ERROR("cannot clear process capabilities %d", ret);
- return -1;
- }
-
- return 0;
-}
-#else
-static int virClearCapabilities(void)
-{
-// VIR_WARN0("libcap-ng support not compiled in, unable to clear capabilities");
- return 0;
-}
-#endif
-
-/*
- * @conn Connection to report errors against
- * @argv argv to exec
- * @envp optional enviroment to use for exec
- * @keepfd options fd_ret to keep open for child process
- * @retpid optional pointer to store child process pid
- * @infd optional file descriptor to use as child input, otherwise /dev/null
- * @outfd optional pointer to communicate output fd behavior
- * outfd == NULL : Use /dev/null
- * *outfd == -1 : Use a new fd
- * *outfd != -1 : Use *outfd
- * @errfd optional pointer to communcate error fd behavior. See outfd
- * @flags possible combination of the following:
- * VIR_EXEC_NONE : Default function behavior
- * VIR_EXEC_NONBLOCK : Set child process output fd's as non-blocking
- * VIR_EXEC_DAEMON : Daemonize the child process (don't use directly,
- * use virExecDaemonize wrapper)
- * @hook optional virExecHook function to call prior to exec
- * @data data to pass to the hook function
- * @pidfile path to use as pidfile for daemonized process (needs DAEMON flag)
- */
-static int
-__virExec(virConnectPtr conn,
- const char *const*argv,
- const char *const*envp,
- const fd_set *keepfd,
- pid_t *retpid,
- int infd, int *outfd, int *errfd,
- int flags,
- virExecHook hook,
- void *data,
- char *pidfile)
-{
- pid_t pid;
- int null, i, openmax;
- int pipeout[2] = {-1,-1};
- int pipeerr[2] = {-1,-1};
- int childout = -1;
- int childerr = -1;
- sigset_t oldmask, newmask;
- struct sigaction sig_action;
-
- /*
- * Need to block signals now, so that child process can safely
- * kill off caller's signal handlers without a race.
- */
- sigfillset(&newmask);
- if (pthread_sigmask(SIG_SETMASK, &newmask, &oldmask) != 0) {
- virReportSystemError(conn, errno,
- "%s", _("cannot block signals"));
- return -1;
- }
-
- if ((null = open("/dev/null", O_RDONLY)) < 0) {
- virReportSystemError(conn, errno,
- _("cannot open %s"),
- "/dev/null");
- goto cleanup;
- }
-
- if (outfd != NULL) {
- if (*outfd == -1) {
- if (pipe(pipeout) < 0) {
- virReportSystemError(conn, errno,
- "%s", _("cannot create pipe"));
- goto cleanup;
- }
-
- if ((flags & VIR_EXEC_NONBLOCK) &&
- virSetNonBlock(pipeout[0]) == -1) {
- virReportSystemError(conn, errno,
- "%s", _("Failed to set non-blocking file descriptor flag"));
- goto cleanup;
- }
-
- if (virSetCloseExec(pipeout[0]) == -1) {
- virReportSystemError(conn, errno,
- "%s", _("Failed to set close-on-exec file descriptor flag"));
- goto cleanup;
- }
-
- childout = pipeout[1];
- } else {
- childout = *outfd;
- }
- } else {
- childout = null;
- }
-
- if (errfd != NULL) {
- if (*errfd == -1) {
- if (pipe(pipeerr) < 0) {
- virReportSystemError(conn, errno,
- "%s", _("Failed to create pipe"));
- goto cleanup;
- }
-
- if ((flags & VIR_EXEC_NONBLOCK) &&
- virSetNonBlock(pipeerr[0]) == -1) {
- virReportSystemError(conn, errno,
- "%s", _("Failed to set non-blocking file descriptor flag"));
- goto cleanup;
- }
-
- if (virSetCloseExec(pipeerr[0]) == -1) {
- virReportSystemError(conn, errno,
- "%s", _("Failed to set close-on-exec file descriptor flag"));
- goto cleanup;
- }
-
- childerr = pipeerr[1];
- } else {
- childerr = *errfd;
- }
- } else {
- childerr = null;
- }
-
- if ((pid = fork()) < 0) {
- virReportSystemError(conn, errno,
- "%s", _("cannot fork child process"));
- goto cleanup;
- }
-
- if (pid) { /* parent */
- close(null);
- if (outfd && *outfd == -1) {
- close(pipeout[1]);
- *outfd = pipeout[0];
- }
- if (errfd && *errfd == -1) {
- close(pipeerr[1]);
- *errfd = pipeerr[0];
- }
-
- /* Restore our original signal mask now child is safely
- running */
- if (pthread_sigmask(SIG_SETMASK, &oldmask, NULL) != 0) {
- virReportSystemError(conn, errno,
- "%s", _("cannot unblock signals"));
- return -1;
- }
-
- *retpid = pid;
- return 0;
- }
-
- /* child */
-
- /* Don't want to report errors against this accidentally, so
- just discard it */
- conn = NULL;
- /* Remove any error callback too, so errors in child now
- get sent to stderr where they stand a fighting chance
- of being seen / logged */
- virSetErrorFunc(NULL, NULL);
-
- /* Clear out all signal handlers from parent so nothing
- unexpected can happen in our child once we unblock
- signals */
- sig_action.sa_handler = SIG_DFL;
- sig_action.sa_flags = 0;
- sigemptyset(&sig_action.sa_mask);
-
- for (i = 1 ; i < NSIG ; i++)
- /* Only possible errors are EFAULT or EINVAL
- The former wont happen, the latter we
- expect, so no need to check return value */
- sigaction(i, &sig_action, NULL);
-
- /* Unmask all signals in child, since we've no idea
- what the caller's done with their signal mask
- and don't want to propagate that to children */
- sigemptyset(&newmask);
- if (pthread_sigmask(SIG_SETMASK, &newmask, NULL) != 0) {
- virReportSystemError(conn, errno,
- "%s", _("cannot unblock signals"));
- _exit(1);
- }
-
- openmax = sysconf (_SC_OPEN_MAX);
- for (i = 3; i < openmax; i++)
- if (i != infd &&
- i != null &&
- i != childout &&
- i != childerr &&
- (!keepfd ||
- !FD_ISSET(i, keepfd)))
- close(i);
-
- if (dup2(infd >= 0 ? infd : null, STDIN_FILENO) < 0) {
- virReportSystemError(conn, errno,
- "%s", _("failed to setup stdin file handle"));
- _exit(1);
- }
- if (childout > 0 &&
- dup2(childout, STDOUT_FILENO) < 0) {
- virReportSystemError(conn, errno,
- "%s", _("failed to setup stdout file handle"));
- _exit(1);
- }
- if (childerr > 0 &&
- dup2(childerr, STDERR_FILENO) < 0) {
- virReportSystemError(conn, errno,
- "%s", _("failed to setup stderr file handle"));
- _exit(1);
- }
-
- if (infd > 0)
- close(infd);
- close(null);
- if (childout > 0)
- close(childout);
- if (childerr > 0 &&
- childerr != childout)
- close(childerr);
-
- /* Daemonize as late as possible, so the parent process can detect
- * the above errors with wait* */
- if (flags & VIR_EXEC_DAEMON) {
- if (setsid() < 0) {
- virReportSystemError(conn, errno,
- "%s", _("cannot become session leader"));
- _exit(1);
- }
-
- if (chdir("/") < 0) {
- virReportSystemError(conn, errno,
- "%s", _("cannot change to root directory: %s"));
- _exit(1);
- }
-
- pid = fork();
- if (pid < 0) {
- virReportSystemError(conn, errno,
- "%s", _("cannot fork child process"));
- _exit(1);
- }
-
- if (pid > 0) {
- if (pidfile && virFileWritePidPath(pidfile,pid)) {
- kill(pid, SIGTERM);
- usleep(500*1000);
- kill(pid, SIGTERM);
- virReportSystemError(conn, errno,
- _("could not write pidfile %s for %d"),
- pidfile, pid);
- _exit(1);
- }
- _exit(0);
- }
- }
-
- if (hook)
- if ((hook)(data) != 0)
- _exit(1);
-
- /* The steps above may need todo something privileged, so
- * we delay clearing capabilities until the last minute */
- if ((flags & VIR_EXEC_CLEAR_CAPS) &&
- virClearCapabilities() < 0)
- _exit(1);
-
- if (envp)
- execve(argv[0], (char **) argv, (char**)envp);
- else
- execvp(argv[0], (char **) argv);
-
- virReportSystemError(conn, errno,
- _("cannot execute binary %s"),
- argv[0]);
-
- _exit(1);
-
- cleanup:
- /* This is cleanup of parent process only - child
- should never jump here on error */
-
- /* NB we don't ReportError() on any failures here
- because the code which jumped hre already raised
- an error condition which we must not overwrite */
- if (pipeerr[0] > 0)
- close(pipeerr[0]);
- if (pipeerr[1] > 0)
- close(pipeerr[1]);
- if (pipeout[0] > 0)
- close(pipeout[0]);
- if (pipeout[1] > 0)
- close(pipeout[1]);
- if (null > 0)
- close(null);
- return -1;
-}
-
-int
-virExecWithHook(virConnectPtr conn,
- const char *const*argv,
- const char *const*envp,
- const fd_set *keepfd,
- pid_t *retpid,
- int infd, int *outfd, int *errfd,
- int flags,
- virExecHook hook,
- void *data,
- char *pidfile)
-{
- char *argv_str;
-
- if ((argv_str = virArgvToString(argv)) == NULL) {
- virReportOOMError(conn);
- return -1;
- }
- DEBUG0(argv_str);
- VIR_FREE(argv_str);
-
- return __virExec(conn, argv, envp, keepfd, retpid, infd, outfd, errfd,
- flags, hook, data, pidfile);
-}
-
-/*
- * See __virExec for explanation of the arguments.
- *
- * Wrapper function for __virExec, with a simpler set of parameters.
- * Used to insulate the numerous callers from changes to __virExec argument
- * list.
- */
-int
-virExec(virConnectPtr conn,
- const char *const*argv,
- const char *const*envp,
- const fd_set *keepfd,
- pid_t *retpid,
- int infd, int *outfd, int *errfd,
- int flags)
-{
- return virExecWithHook(conn, argv, envp, keepfd, retpid,
- infd, outfd, errfd,
- flags, NULL, NULL, NULL);
-}
-
-/*
- * See __virExec for explanation of the arguments.
- *
- * This function will wait for the intermediate process (between the caller
- * and the daemon) to exit. retpid will be the pid of the daemon, which can
- * be checked for example to see if the daemon crashed immediately.
- *
- * Returns 0 on success
- * -1 if initial fork failed (will have a reported error)
- * -2 if intermediate process failed
- * (won't have a reported error. pending on where the failure
- * occured and when in the process occured, the error output
- * could have gone to stderr or the passed errfd).
- */
-int virExecDaemonize(virConnectPtr conn,
- const char *const*argv,
- const char *const*envp,
- const fd_set *keepfd,
- pid_t *retpid,
- int infd, int *outfd, int *errfd,
- int flags,
- virExecHook hook,
- void *data,
- char *pidfile) {
- int ret;
- int childstat = 0;
-
- ret = virExecWithHook(conn, argv, envp, keepfd, retpid,
- infd, outfd, errfd,
- flags | VIR_EXEC_DAEMON,
- hook, data, pidfile);
-
- /* __virExec should have set an error */
- if (ret != 0)
- return -1;
-
- /* Wait for intermediate process to exit */
- while (waitpid(*retpid, &childstat, 0) == -1 &&
- errno == EINTR);
-
- if (childstat != 0) {
- ReportError(conn, VIR_ERR_INTERNAL_ERROR,
- _("Intermediate daemon process exited with status %d."),
- WEXITSTATUS(childstat));
- ret = -2;
- }
-
- return ret;
-}
-
-static int
-virPipeReadUntilEOF(virConnectPtr conn, int outfd, int errfd,
- char **outbuf, char **errbuf) {
-
- struct pollfd fds[2];
- int i;
- int finished[2];
-
- fds[0].fd = outfd;
- fds[0].events = POLLIN;
- finished[0] = 0;
- fds[1].fd = errfd;
- fds[1].events = POLLIN;
- finished[1] = 0;
-
- while(!(finished[0] && finished[1])) {
-
- if (poll(fds, ARRAY_CARDINALITY(fds), -1) < 0) {
- if ((errno == EAGAIN) || (errno == EINTR))
- continue;
- goto pollerr;
- }
-
- for (i = 0; i < ARRAY_CARDINALITY(fds); ++i) {
- char data[1024], **buf;
- int got, size;
-
- if (!(fds[i].revents))
- continue;
- else if (fds[i].revents & POLLHUP)
- finished[i] = 1;
-
- if (!(fds[i].revents & POLLIN)) {
- if (fds[i].revents & POLLHUP)
- continue;
-
- ReportError(conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("Unknown poll response."));
- goto error;
- }
-
- got = read(fds[i].fd, data, sizeof(data));
-
- if (got == 0) {
- finished[i] = 1;
- continue;
- }
- if (got < 0) {
- if (errno == EINTR)
- continue;
- if (errno == EAGAIN)
- break;
- goto pollerr;
- }
-
- buf = ((fds[i].fd == outfd) ? outbuf : errbuf);
- size = (*buf ? strlen(*buf) : 0);
- if (VIR_REALLOC_N(*buf, size+got+1) < 0) {
- virReportOOMError(conn);
- goto error;
- }
- memmove(*buf+size, data, got);
- (*buf)[size+got] = '\0';
- }
- continue;
-
- pollerr:
- virReportSystemError(conn, errno,
- "%s", _("poll error"));
- goto error;
- }
-
- return 0;
-
-error:
- VIR_FREE(*outbuf);
- VIR_FREE(*errbuf);
- return -1;
-}
-
-/**
- * @conn connection to report errors against
- * @argv NULL terminated argv to run
- * @status optional variable to return exit status in
- *
- * Run a command without using the shell.
- *
- * If status is NULL, then return 0 if the command run and
- * exited with 0 status; Otherwise return -1
- *
- * If status is not-NULL, then return 0 if the command ran.
- * The status variable is filled with the command exit status
- * and should be checked by caller for success. Return -1
- * only if the command could not be run.
- */
-int
-virRun(virConnectPtr conn,
- const char *const*argv,
- int *status) {
- pid_t childpid;
- int exitstatus, execret, waitret;
- int ret = -1;
- int errfd = -1, outfd = -1;
- char *outbuf = NULL;
- char *errbuf = NULL;
- char *argv_str = NULL;
-
- if ((argv_str = virArgvToString(argv)) == NULL) {
- virReportOOMError(conn);
- goto error;
- }
- DEBUG0(argv_str);
-
- if ((execret = __virExec(conn, argv, NULL, NULL,
- &childpid, -1, &outfd, &errfd,
- VIR_EXEC_NONE, NULL, NULL, NULL)) < 0) {
- ret = execret;
- goto error;
- }
-
- if (virPipeReadUntilEOF(conn, outfd, errfd, &outbuf, &errbuf) < 0) {
- while (waitpid(childpid, &exitstatus, 0) == -1 && errno == EINTR)
- ;
- goto error;
- }
-
- if (outbuf)
- DEBUG("Command stdout: %s", outbuf);
- if (errbuf)
- DEBUG("Command stderr: %s", errbuf);
-
- while ((waitret = waitpid(childpid, &exitstatus, 0) == -1) &&
- errno == EINTR);
- if (waitret == -1) {
- virReportSystemError(conn, errno,
- _("cannot wait for '%s'"),
- argv[0]);
- goto error;
- }
-
- if (status == NULL) {
- errno = EINVAL;
- if (WIFEXITED(exitstatus) && WEXITSTATUS(exitstatus) != 0) {
- ReportError(conn, VIR_ERR_INTERNAL_ERROR,
- _("'%s' exited with non-zero status %d and "
- "signal %d: %s"), argv_str,
- WIFEXITED(exitstatus) ? WEXITSTATUS(exitstatus) : 0,
- WIFSIGNALED(exitstatus) ? WTERMSIG(exitstatus) : 0,
- (errbuf ? errbuf : ""));
- goto error;
- }
- } else {
- *status = exitstatus;
- }
-
- ret = 0;
-
- error:
- VIR_FREE(outbuf);
- VIR_FREE(errbuf);
- VIR_FREE(argv_str);
- if (outfd != -1)
- close(outfd);
- if (errfd != -1)
- close(errfd);
- return ret;
-}
-
-#else /* __MINGW32__ */
-
-int
-virRun(virConnectPtr conn,
- const char *const *argv ATTRIBUTE_UNUSED,
- int *status)
-{
- if (status)
- *status = ENOTSUP;
- else
- ReportError (conn, VIR_ERR_INTERNAL_ERROR, __FUNCTION__);
- return -1;
-}
-
-int
-virExec(virConnectPtr conn,
- const char *const*argv ATTRIBUTE_UNUSED,
- const char *const*envp ATTRIBUTE_UNUSED,
- const fd_set *keepfd ATTRIBUTE_UNUSED,
- int *retpid ATTRIBUTE_UNUSED,
- int infd ATTRIBUTE_UNUSED,
- int *outfd ATTRIBUTE_UNUSED,
- int *errfd ATTRIBUTE_UNUSED,
- int flags ATTRIBUTE_UNUSED)
-{
- ReportError (conn, VIR_ERR_INTERNAL_ERROR, __FUNCTION__);
- return -1;
-}
-
-#endif /* __MINGW32__ */
-
-/* Like gnulib's fread_file, but read no more than the specified maximum
- number of bytes. If the length of the input is <= max_len, and
- upon error while reading that data, it works just like fread_file. */
-static char *
-fread_file_lim (FILE *stream, size_t max_len, size_t *length)
-{
- char *buf = NULL;
- size_t alloc = 0;
- size_t size = 0;
- int save_errno;
-
- for (;;) {
- size_t count;
- size_t requested;
-
- if (size + BUFSIZ + 1 > alloc) {
- alloc += alloc / 2;
- if (alloc < size + BUFSIZ + 1)
- alloc = size + BUFSIZ + 1;
-
- if (VIR_REALLOC_N(buf, alloc) < 0) {
- save_errno = errno;
- break;
- }
- }
-
- /* Ensure that (size + requested <= max_len); */
- requested = MIN (size < max_len ? max_len - size : 0,
- alloc - size - 1);
- count = fread (buf + size, 1, requested, stream);
- size += count;
-
- if (count != requested || requested == 0) {
- save_errno = errno;
- if (ferror (stream))
- break;
- buf[size] = '\0';
- *length = size;
- return buf;
- }
- }
-
- free (buf);
- errno = save_errno;
- return NULL;
-}
-
-/* A wrapper around fread_file_lim that maps a failure due to
- exceeding the maximum size limitation to EOVERFLOW. */
-static int virFileReadLimFP(FILE *fp, int maxlen, char **buf)
-{
- size_t len;
- char *s = fread_file_lim (fp, maxlen+1, &len);
- if (s == NULL)
- return -1;
- if (len > maxlen || (int)len != len) {
- VIR_FREE(s);
- /* There was at least one byte more than MAXLEN.
- Set errno accordingly. */
- errno = EOVERFLOW;
- return -1;
- }
- *buf = s;
- return len;
-}
-
-/* Like virFileReadLimFP, but use a file descriptor rather than a FILE*. */
-int virFileReadLimFD(int fd_arg, int maxlen, char **buf)
-{
- int fd = dup (fd_arg);
- if (fd >= 0) {
- FILE *fp = fdopen (fd, "r");
- if (fp) {
- int len = virFileReadLimFP (fp, maxlen, buf);
- int saved_errno = errno;
- fclose (fp);
- errno = saved_errno;
- return len;
- } else {
- int saved_errno = errno;
- close (fd);
- errno = saved_errno;
- }
- }
- return -1;
-}
-
-int virFileReadAll(const char *path, int maxlen, char **buf)
-{
- FILE *fh = fopen(path, "r");
- if (fh == NULL) {
- virReportSystemError(NULL, errno, _("Failed to open file '%s'"), path);
- return -1;
- }
-
- int len = virFileReadLimFP (fh, maxlen, buf);
- fclose(fh);
- if (len < 0) {
- virReportSystemError(NULL, errno, _("Failed to read file '%s'"), path);
- return -1;
- }
-
- return len;
-}
-
-/* Truncate @path and write @str to it.
- Return 0 for success, nonzero for failure.
- Be careful to preserve any errno value upon failure. */
-int virFileWriteStr(const char *path, const char *str)
-{
- int fd;
-
- if ((fd = open(path, O_WRONLY|O_TRUNC)) == -1)
- return -1;
-
- if (safewrite(fd, str, strlen(str)) < 0) {
- int saved_errno = errno;
- close (fd);
- errno = saved_errno;
- return -1;
- }
-
- /* Use errno from failed close only if there was no write error. */
- if (close (fd) != 0)
- return -1;
-
- return 0;
-}
-
-int virFileMatchesNameSuffix(const char *file,
- const char *name,
- const char *suffix)
-{
- int filelen = strlen(file);
- int namelen = strlen(name);
- int suffixlen = strlen(suffix);
-
- if (filelen == (namelen + suffixlen) &&
- STREQLEN(file, name, namelen) &&
- STREQLEN(file + namelen, suffix, suffixlen))
- return 1;
- else
- return 0;
-}
-
-int virFileHasSuffix(const char *str,
- const char *suffix)
-{
- int len = strlen(str);
- int suffixlen = strlen(suffix);
-
- if (len < suffixlen)
- return 0;
-
- return STREQ(str + len - suffixlen, suffix);
-}
-
-#define SAME_INODE(Stat_buf_1, Stat_buf_2) \
- ((Stat_buf_1).st_ino == (Stat_buf_2).st_ino \
- && (Stat_buf_1).st_dev == (Stat_buf_2).st_dev)
-
-/* Return nonzero if checkLink and checkDest
- refer to the same file. Otherwise, return 0. */
-int virFileLinkPointsTo(const char *checkLink,
- const char *checkDest)
-{
- struct stat src_sb;
- struct stat dest_sb;
-
- return (stat (checkLink, &src_sb) == 0
- && stat (checkDest, &dest_sb) == 0
- && SAME_INODE (src_sb, dest_sb));
-}
-
-
-
-/*
- * Attempt to resolve a symbolic link, returning the
- * real path
- *
- * Return 0 if path was not a symbolic, or the link was
- * resolved. Return -1 upon error
- */
-int virFileResolveLink(const char *linkpath,
- char **resultpath)
-{
-#ifdef HAVE_READLINK
- struct stat st;
- char *buf;
- int n;
-
- *resultpath = NULL;
-
- if (lstat(linkpath, &st) < 0)
- return errno;
-
- if (!S_ISLNK(st.st_mode)) {
- if (!(*resultpath = strdup(linkpath)))
- return -ENOMEM;
- return 0;
- }
-
- /* Posix says that 'st_size' field from
- * result of an lstat() call is filled with
- * number of bytes in the destination
- * filename.
- */
- if (VIR_ALLOC_N(buf, st.st_size + 1) < 0)
- return -ENOMEM;
-
- if ((n = readlink(linkpath, buf, st.st_size)) < 0) {
- VIR_FREE(buf);
- return -errno;
- }
-
- buf[n] = '\0';
-
- *resultpath = buf;
- return 0;
-#else
- if (!(*resultpath = strdup(linkpath)))
- return -ENOMEM;
- return 0;
-#endif
-}
-
-/*
- * Finds a requested file in the PATH env. e.g.:
- * "kvm-img" will return "/usr/bin/kvm-img"
- *
- * You must free the result
- */
-char *virFindFileInPath(const char *file)
-{
- char pathenv[PATH_MAX];
- char *penv = pathenv;
- char *pathseg;
- char fullpath[PATH_MAX];
-
- /* copy PATH env so we can tweak it */
- strncpy(pathenv, getenv("PATH"), PATH_MAX);
- pathenv[PATH_MAX - 1] = '\0';
-
-
- /* for each path segment, append the file to search for and test for
- * it. return it if found.
- */
- while ((pathseg = strsep(&penv, ":")) != NULL) {
- snprintf(fullpath, PATH_MAX, "%s/%s", pathseg, file);
- if (virFileExists(fullpath))
- return strdup(fullpath);
- }
-
- return NULL;
-}
-int virFileExists(const char *path)
-{
- struct stat st;
-
- if (stat(path, &st) >= 0)
- return(1);
- return(0);
-}
-
-int virFileMakePath(const char *path)
-{
- struct stat st;
- char parent[PATH_MAX];
- char *p;
- int err;
-
- if (stat(path, &st) >= 0)
- return 0;
-
- strncpy(parent, path, PATH_MAX);
- parent[PATH_MAX - 1] = '\0';
-
- if (!(p = strrchr(parent, '/')))
- return EINVAL;
-
- if (p != parent) {
- *p = '\0';
- if ((err = virFileMakePath(parent)))
- return err;
- }
-
- if (mkdir(path, 0777) < 0 && errno != EEXIST)
- return errno;
-
- return 0;
-}
-
-/* Build up a fully qualfiied path for a config file to be
- * associated with a persistent guest or network */
-int virFileBuildPath(const char *dir,
- const char *name,
- const char *ext,
- char *buf,
- unsigned int buflen)
-{
- if ((strlen(dir) + 1 + strlen(name) + (ext ? strlen(ext) : 0) + 1) >= (buflen-1))
- return -1;
-
- strcpy(buf, dir);
- strcat(buf, "/");
- strcat(buf, name);
- if (ext)
- strcat(buf, ext);
- return 0;
-}
-
-
-int virFileOpenTty(int *ttymaster,
- char **ttyName,
- int rawmode)
-{
- return virFileOpenTtyAt("/dev/ptmx",
- ttymaster,
- ttyName,
- rawmode);
-}
-
-#ifdef __linux__
-int virFileOpenTtyAt(const char *ptmx,
- int *ttymaster,
- char **ttyName,
- int rawmode)
-{
- int rc = -1;
-
- if ((*ttymaster = open(ptmx, O_RDWR|O_NOCTTY|O_NONBLOCK)) < 0)
- goto cleanup;
-
- if (unlockpt(*ttymaster) < 0)
- goto cleanup;
-
- if (grantpt(*ttymaster) < 0)
- goto cleanup;
-
- if (rawmode) {
- struct termios ttyAttr;
- if (tcgetattr(*ttymaster, &ttyAttr) < 0)
- goto cleanup;
-
- cfmakeraw(&ttyAttr);
-
- if (tcsetattr(*ttymaster, TCSADRAIN, &ttyAttr) < 0)
- goto cleanup;
- }
-
- if (ttyName) {
- char tempTtyName[PATH_MAX];
- if (ptsname_r(*ttymaster, tempTtyName, sizeof(tempTtyName)) < 0)
- goto cleanup;
-
- if ((*ttyName = strdup(tempTtyName)) == NULL) {
- errno = ENOMEM;
- goto cleanup;
- }
- }
-
- rc = 0;
-
-cleanup:
- if (rc != 0 &&
- *ttymaster != -1) {
- close(*ttymaster);
- }
-
- return rc;
-
-}
-#else
-int virFileOpenTtyAt(const char *ptmx ATTRIBUTE_UNUSED,
- int *ttymaster ATTRIBUTE_UNUSED,
- char **ttyName ATTRIBUTE_UNUSED,
- int rawmode ATTRIBUTE_UNUSED)
-{
- return -1;
-}
-#endif
-
-char* virFilePid(const char *dir, const char* name)
-{
- char *pidfile;
- virAsprintf(&pidfile, "%s/%s.pid", dir, name);
- return pidfile;
-}
-
-int virFileWritePid(const char *dir,
- const char *name,
- pid_t pid)
-{
- int rc;
- char *pidfile = NULL;
-
- if (name == NULL || dir == NULL) {
- rc = EINVAL;
- goto cleanup;
- }
-
- if ((rc = virFileMakePath(dir)))
- goto cleanup;
-
- if (!(pidfile = virFilePid(dir, name))) {
- rc = ENOMEM;
- goto cleanup;
- }
-
- rc = virFileWritePidPath(pidfile, pid);
-
-cleanup:
- VIR_FREE(pidfile);
- return rc;
-}
-
-int virFileWritePidPath(const char *pidfile,
- pid_t pid)
-{
- int rc;
- int fd;
- FILE *file = NULL;
-
- if ((fd = open(pidfile,
- O_WRONLY | O_CREAT | O_TRUNC,
- S_IRUSR | S_IWUSR)) < 0) {
- rc = errno;
- goto cleanup;
- }
-
- if (!(file = fdopen(fd, "w"))) {
- rc = errno;
- close(fd);
- goto cleanup;
- }
-
- if (fprintf(file, "%d", pid) < 0) {
- rc = errno;
- goto cleanup;
- }
-
- rc = 0;
-
-cleanup:
- if (file &&
- fclose(file) < 0) {
- rc = errno;
- }
-
- return rc;
-}
-
-int virFileReadPid(const char *dir,
- const char *name,
- pid_t *pid)
-{
- int rc;
- FILE *file;
- char *pidfile = NULL;
- *pid = 0;
-
- if (name == NULL || dir == NULL) {
- rc = EINVAL;
- goto cleanup;
- }
-
- if (!(pidfile = virFilePid(dir, name))) {
- rc = ENOMEM;
- goto cleanup;
- }
-
- if (!(file = fopen(pidfile, "r"))) {
- rc = errno;
- goto cleanup;
- }
-
- if (fscanf(file, "%d", pid) != 1) {
- rc = EINVAL;
- fclose(file);
- goto cleanup;
- }
-
- if (fclose(file) < 0) {
- rc = errno;
- goto cleanup;
- }
-
- rc = 0;
-
- cleanup:
- VIR_FREE(pidfile);
- return rc;
-}
-
-int virFileDeletePid(const char *dir,
- const char *name)
-{
- int rc = 0;
- char *pidfile = NULL;
-
- if (name == NULL || dir == NULL) {
- rc = EINVAL;
- goto cleanup;
- }
-
- if (!(pidfile = virFilePid(dir, name))) {
- rc = ENOMEM;
- goto cleanup;
- }
-
- if (unlink(pidfile) < 0 && errno != ENOENT)
- rc = errno;
-
-cleanup:
- VIR_FREE(pidfile);
- return rc;
-}
-
-#endif /* PROXY */
-
-
-/* Like strtol, but produce an "int" result, and check more carefully.
- Return 0 upon success; return -1 to indicate failure.
- When END_PTR is NULL, the byte after the final valid digit must be NUL.
- Otherwise, it's like strtol and lets the caller check any suffix for
- validity. This function is careful to return -1 when the string S
- represents a number that is not representable as an "int". */
-int
-virStrToLong_i(char const *s, char **end_ptr, int base, int *result)
-{
- long int val;
- char *p;
- int err;
-
- errno = 0;
- val = strtol(s, &p, base);
- err = (errno || (!end_ptr && *p) || p == s || (int) val != val);
- if (end_ptr)
- *end_ptr = p;
- if (err)
- return -1;
- *result = val;
- return 0;
-}
-
-/* Just like virStrToLong_i, above, but produce an "unsigned int" value. */
-int
-virStrToLong_ui(char const *s, char **end_ptr, int base, unsigned int *result)
-{
- unsigned long int val;
- char *p;
- int err;
-
- errno = 0;
- val = strtoul(s, &p, base);
- err = (errno || (!end_ptr && *p) || p == s || (unsigned int) val != val);
- if (end_ptr)
- *end_ptr = p;
- if (err)
- return -1;
- *result = val;
- return 0;
-}
-
-/* Just like virStrToLong_i, above, but produce an "long long" value. */
-int
-virStrToLong_ll(char const *s, char **end_ptr, int base, long long *result)
-{
- long long val;
- char *p;
- int err;
-
- errno = 0;
- val = strtoll(s, &p, base);
- err = (errno || (!end_ptr && *p) || p == s || (long long) val != val);
- if (end_ptr)
- *end_ptr = p;
- if (err)
- return -1;
- *result = val;
- return 0;
-}
-
-/* Just like virStrToLong_i, above, but produce an "unsigned long long" value. */
-int
-virStrToLong_ull(char const *s, char **end_ptr, int base, unsigned long long *result)
-{
- unsigned long long val;
- char *p;
- int err;
-
- errno = 0;
- val = strtoull(s, &p, base);
- err = (errno || (!end_ptr && *p) || p == s || (unsigned long long) val != val);
- if (end_ptr)
- *end_ptr = p;
- if (err)
- return -1;
- *result = val;
- return 0;
-}
-
-int
-virStrToDouble(char const *s,
- char **end_ptr,
- double *result)
-{
- double val;
- char *p;
- int err;
-
- errno = 0;
- val = strtod(s, &p);
- err = (errno || (!end_ptr && *p) || p == s);
- if (end_ptr)
- *end_ptr = p;
- if (err)
- return -1;
- *result = val;
- return 0;
-}
-
-/**
- * virSkipSpaces:
- * @str: pointer to the char pointer used
- *
- * Skip potential blanks, this includes space tabs, line feed,
- * carriage returns and also '\\' which can be erronously emitted
- * by xend
- */
-void
-virSkipSpaces(const char **str)
-{
- const char *cur = *str;
-
- while ((*cur == ' ') || (*cur == '\t') || (*cur == '\n') ||
- (*cur == '\r') || (*cur == '\\'))
- cur++;
- *str = cur;
-}
-
-/**
- * virParseNumber:
- * @str: pointer to the char pointer used
- *
- * Parse an unsigned number
- *
- * Returns the unsigned number or -1 in case of error. @str will be
- * updated to skip the number.
- */
-int
-virParseNumber(const char **str)
-{
- int ret = 0;
- const char *cur = *str;
-
- if ((*cur < '0') || (*cur > '9'))
- return (-1);
-
- while (c_isdigit(*cur)) {
- unsigned int c = *cur - '0';
-
- if ((ret > INT_MAX / 10) ||
- ((ret == INT_MAX / 10) && (c > INT_MAX % 10)))
- return (-1);
- ret = ret * 10 + c;
- cur++;
- }
- *str = cur;
- return (ret);
-}
-
-/**
- * virAsprintf
- *
- * like glibc's_asprintf but makes sure *strp == NULL on failure
- */
-int
-virAsprintf(char **strp, const char *fmt, ...)
-{
- va_list ap;
- int ret;
-
- va_start(ap, fmt);
-
- if ((ret = vasprintf(strp, fmt, ap)) == -1)
- *strp = NULL;
-
- va_end(ap);
- return ret;
-}
-
-/* Compare two MAC addresses, ignoring differences in case,
- * as well as leading zeros.
- */
-int
-virMacAddrCompare (const char *p, const char *q)
-{
- unsigned char c, d;
- do {
- while (*p == '0' && c_isxdigit (p[1]))
- ++p;
- while (*q == '0' && c_isxdigit (q[1]))
- ++q;
- c = c_tolower (*p);
- d = c_tolower (*q);
-
- if (c == 0 || d == 0)
- break;
-
- ++p;
- ++q;
- } while (c == d);
-
- if (UCHAR_MAX <= INT_MAX)
- return c - d;
-
- /* On machines where 'char' and 'int' are types of the same size, the
- difference of two 'unsigned char' values - including the sign bit -
- doesn't fit in an 'int'. */
- return (c > d ? 1 : c < d ? -1 : 0);
-}
-
-/**
- * virParseMacAddr:
- * @str: string representation of MAC address, e.g., "0:1E:FC:E:3a:CB"
- * @addr: 6-byte MAC address
- *
- * Parse a MAC address
- *
- * Return 0 upon success, or -1 in case of error.
- */
-int
-virParseMacAddr(const char* str, unsigned char *addr)
-{
- int i;
-
- errno = 0;
- for (i = 0; i < VIR_MAC_BUFLEN; i++) {
- char *end_ptr;
- unsigned long result;
-
- /* This is solely to avoid accepting the leading
- * space or "+" that strtoul would otherwise accept.
- */
- if (!c_isxdigit(*str))
- break;
-
- result = strtoul(str, &end_ptr, 16);
-
- if ((end_ptr - str) < 1 || 2 < (end_ptr - str) ||
- (errno != 0) ||
- (0xFF < result))
- break;
-
- addr[i] = (unsigned char) result;
-
- if ((i == 5) && (*end_ptr == '\0'))
- return 0;
- if (*end_ptr != ':')
- break;
-
- str = end_ptr + 1;
- }
-
- return -1;
-}
-
-void virFormatMacAddr(const unsigned char *addr,
- char *str)
-{
- snprintf(str, VIR_MAC_STRING_BUFLEN,
- "%02X:%02X:%02X:%02X:%02X:%02X",
- addr[0], addr[1], addr[2],
- addr[3], addr[4], addr[5]);
- str[VIR_MAC_STRING_BUFLEN-1] = '\0';
-}
-
-void virGenerateMacAddr(const unsigned char *prefix,
- unsigned char *addr)
-{
- addr[0] = prefix[0];
- addr[1] = prefix[1];
- addr[2] = prefix[2];
- addr[3] = virRandom(256);
- addr[4] = virRandom(256);
- addr[5] = virRandom(256);
-}
-
-
-int virEnumFromString(const char *const*types,
- unsigned int ntypes,
- const char *type)
-{
- unsigned int i;
- if (!type)
- return -1;
-
- for (i = 0 ; i < ntypes ; i++)
- if (STREQ(types[i], type))
- return i;
-
- return -1;
-}
-
-const char *virEnumToString(const char *const*types,
- unsigned int ntypes,
- int type)
-{
- if (type < 0 || type >= ntypes)
- return NULL;
-
- return types[type];
-}
-
-/* Translates a device name of the form (regex) "[fhv]d[a-z]+" into
- * the corresponding index (e.g. sda => 0, hdz => 25, vdaa => 26)
- * @param name The name of the device
- * @return name's index, or -1 on failure
- */
-int virDiskNameToIndex(const char *name) {
- const char *ptr = NULL;
- int idx = 0;
- static char const* const drive_prefix[] = {"fd", "hd", "vd", "sd", "xvd"};
- unsigned int i;
-
- for (i = 0; i < ARRAY_CARDINALITY(drive_prefix); i++) {
- if (STRPREFIX(name, drive_prefix[i])) {
- ptr = name + strlen(drive_prefix[i]);
- break;
- }
- }
-
- if (!ptr)
- return -1;
-
- for (i = 0; *ptr; i++) {
- idx = (idx + i) * 26;
-
- if (!c_islower(*ptr))
- return -1;
-
- idx += *ptr - 'a';
- ptr++;
- }
-
- return idx;
-}
-
-#ifndef AI_CANONIDN
-#define AI_CANONIDN 0
-#endif
-
-char *virGetHostname(void)
-{
- int r;
- char hostname[HOST_NAME_MAX+1], *result;
- struct addrinfo hints, *info;
-
- r = gethostname (hostname, sizeof(hostname));
- if (r == -1)
- return NULL;
- NUL_TERMINATE(hostname);
-
- memset(&hints, 0, sizeof(hints));
- hints.ai_flags = AI_CANONNAME|AI_CANONIDN;
- hints.ai_family = AF_UNSPEC;
- r = getaddrinfo(hostname, NULL, &hints, &info);
- if (r != 0)
- return NULL;
- if (info->ai_canonname == NULL) {
- freeaddrinfo(info);
- return NULL;
- }
-
- /* Caller frees this string. */
- result = strdup (info->ai_canonname);
- freeaddrinfo(info);
- return result;
-}
-
-/* send signal to a single process */
-int virKillProcess(pid_t pid, int sig)
-{
- if (pid <= 1) {
- errno = ESRCH;
- return -1;
- }
-
-#ifdef WIN32
- /* Mingw / Windows don't have many signals (AFAIK) */
- switch (sig) {
- case SIGINT:
- /* This does a Ctrl+C equiv */
- if (!GenerateConsoleCtrlEvent(CTRL_C_EVENT, pid)) {
- errno = ESRCH;
- return -1;
- }
- break;
-
- case SIGTERM:
- /* Since TerminateProcess is closer to SIG_KILL, we do
- * a Ctrl+Break equiv which is more pleasant like the
- * good old unix SIGTERM/HUP
- */
- if (!GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, pid)) {
- errno = ESRCH;
- return -1;
- }
- break;
-
- default:
- {
- HANDLE proc;
- proc = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
- if (!proc) {
- errno = ESRCH; /* Not entirely accurate, but close enough */
- return -1;
- }
-
- /*
- * TerminateProcess is more or less equiv to SIG_KILL, in that
- * a process can't trap / block it
- */
- if (!TerminateProcess(proc, sig)) {
- errno = ESRCH;
- return -1;
- }
- CloseHandle(proc);
- }
- }
- return 0;
-#else
- return kill(pid, sig);
-#endif
-}
-
-
-static char randomState[128];
-static struct random_data randomData;
-static virMutex randomLock;
-
-int virRandomInitialize(unsigned int seed)
-{
- if (virMutexInit(&randomLock) < 0)
- return -1;
-
- if (initstate_r(seed,
- randomState,
- sizeof(randomState),
- &randomData) < 0)
- return -1;
-
- return 0;
-}
-
-int virRandom(int max)
-{
- int32_t ret;
-
- virMutexLock(&randomLock);
- random_r(&randomData, &ret);
- virMutexUnlock(&randomLock);
-
- return (int) ((double)max * ((double)ret / (double)RAND_MAX));
-}
-
-
-#ifdef HAVE_GETPWUID_R
-enum {
- VIR_USER_ENT_DIRECTORY,
- VIR_USER_ENT_NAME,
-};
-
-static char *virGetUserEnt(virConnectPtr conn,
- uid_t uid,
- int field)
-{
- char *strbuf;
- char *ret;
- struct passwd pwbuf;
- struct passwd *pw = NULL;
- size_t strbuflen = sysconf(_SC_GETPW_R_SIZE_MAX);
-
- if (VIR_ALLOC_N(strbuf, strbuflen) < 0) {
- virReportOOMError(conn);
- return NULL;
- }
-
- /*
- * From the manpage (terrifying but true):
- *
- * ERRORS
- * 0 or ENOENT or ESRCH or EBADF or EPERM or ...
- * The given name or uid was not found.
- */
- if (getpwuid_r(uid, &pwbuf, strbuf, strbuflen, &pw) != 0 || pw == NULL) {
- virReportSystemError(conn, errno,
- _("Failed to find user record for uid '%d'"),
- uid);
- VIR_FREE(strbuf);
- return NULL;
- }
-
- if (field == VIR_USER_ENT_DIRECTORY)
- ret = strdup(pw->pw_dir);
- else
- ret = strdup(pw->pw_name);
-
- VIR_FREE(strbuf);
- if (!ret)
- virReportOOMError(conn);
-
- return ret;
-}
-
-char *virGetUserDirectory(virConnectPtr conn,
- uid_t uid)
-{
- return virGetUserEnt(conn, uid, VIR_USER_ENT_DIRECTORY);
-}
-
-char *virGetUserName(virConnectPtr conn,
- uid_t uid)
-{
- return virGetUserEnt(conn, uid, VIR_USER_ENT_NAME);
-}
-
-
-int virGetUserID(virConnectPtr conn,
- const char *name,
- uid_t *uid)
-{
- char *strbuf;
- struct passwd pwbuf;
- struct passwd *pw = NULL;
- size_t strbuflen = sysconf(_SC_GETPW_R_SIZE_MAX);
-
- if (VIR_ALLOC_N(strbuf, strbuflen) < 0) {
- virReportOOMError(conn);
- return -1;
- }
-
- /*
- * From the manpage (terrifying but true):
- *
- * ERRORS
- * 0 or ENOENT or ESRCH or EBADF or EPERM or ...
- * The given name or uid was not found.
- */
- if (getpwnam_r(name, &pwbuf, strbuf, strbuflen, &pw) != 0 || pw == NULL) {
- virReportSystemError(conn, errno,
- _("Failed to find user record for name '%s'"),
- name);
- VIR_FREE(strbuf);
- return -1;
- }
-
- *uid = pw->pw_uid;
-
- VIR_FREE(strbuf);
-
- return 0;
-}
-
-
-int virGetGroupID(virConnectPtr conn,
- const char *name,
- gid_t *gid)
-{
- char *strbuf;
- struct group grbuf;
- struct group *gr = NULL;
- size_t strbuflen = sysconf(_SC_GETGR_R_SIZE_MAX);
-
- if (VIR_ALLOC_N(strbuf, strbuflen) < 0) {
- virReportOOMError(conn);
- return -1;
- }
-
- /*
- * From the manpage (terrifying but true):
- *
- * ERRORS
- * 0 or ENOENT or ESRCH or EBADF or EPERM or ...
- * The given name or uid was not found.
- */
- if (getgrnam_r(name, &grbuf, strbuf, strbuflen, &gr) != 0 || gr == NULL) {
- virReportSystemError(conn, errno,
- _("Failed to find group record for name '%s'"),
- name);
- VIR_FREE(strbuf);
- return -1;
- }
-
- *gid = gr->gr_gid;
-
- VIR_FREE(strbuf);
-
- return 0;
-}
-#endif
-
-
-#ifdef HAVE_MNTENT_H
-/* search /proc/mounts for mount point of *type; return pointer to
- * malloc'ed string of the path if found, otherwise return NULL
- * with errno set to an appropriate value.
- */
-char *virFileFindMountPoint(const char *type)
-{
- FILE *f;
- struct mntent mb;
- char mntbuf[1024];
- char *ret = NULL;
-
- f = setmntent("/proc/mounts", "r");
- if (!f)
- return NULL;
-
- while (getmntent_r(f, &mb, mntbuf, sizeof(mntbuf))) {
- if (STREQ(mb.mnt_type, type)) {
- ret = strdup(mb.mnt_dir);
- goto cleanup;
- }
- }
-
- if (!ret)
- errno = ENOENT;
-
-cleanup:
- endmntent(f);
-
- return ret;
-}
-#endif
-
-#ifndef PROXY
-#if defined(UDEVADM) || defined(UDEVSETTLE)
-void virFileWaitForDevices(virConnectPtr conn)
-{
-#ifdef UDEVADM
- const char *const settleprog[] = { UDEVADM, "settle", NULL };
-#else
- const char *const settleprog[] = { UDEVSETTLE, NULL };
-#endif
- int exitstatus;
-
- if (access(settleprog[0], X_OK) != 0)
- return;
-
- /*
- * NOTE: we ignore errors here; this is just to make sure that any device
- * nodes that are being created finish before we try to scan them.
- * If this fails for any reason, we still have the backup of polling for
- * 5 seconds for device nodes.
- */
- virRun(conn, settleprog, &exitstatus);
-}
-#else
-void virFileWaitForDevices(virConnectPtr conn ATTRIBUTE_UNUSED) {}
-#endif
-#endif
+++ /dev/null
-
-/*
- * utils.h: common, generic utility functions
- *
- * Copyright (C) 2006, 2007 Binary Karma
- * Copyright (C) 2006 Shuveb Hussain
- *
- * 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
- *
- * File created Jul 18, 2007 - Shuveb Hussain <shuveb@binarykarma.com>
- */
-
-#ifndef __VIR_UTIL_H__
-#define __VIR_UTIL_H__
-
-#include "verify.h"
-#include <sys/select.h>
-#include <sys/types.h>
-
-int saferead(int fd, void *buf, size_t count);
-ssize_t safewrite(int fd, const void *buf, size_t count);
-int safezero(int fd, int flags, off_t offset, off_t len);
-
-enum {
- VIR_EXEC_NONE = 0,
- VIR_EXEC_NONBLOCK = (1 << 0),
- VIR_EXEC_DAEMON = (1 << 1),
- VIR_EXEC_CLEAR_CAPS = (1 << 2),
-};
-
-int virSetNonBlock(int fd);
-int virSetCloseExec(int fd);
-
-/* This will execute in the context of the first child
- * after fork() but before execve() */
-typedef int (*virExecHook)(void *data);
-
-int virExecDaemonize(virConnectPtr conn,
- const char *const*argv,
- const char *const*envp,
- const fd_set *keepfd,
- pid_t *retpid,
- int infd, int *outfd, int *errfd,
- int flags,
- virExecHook hook,
- void *data,
- char *pidfile);
-int virExecWithHook(virConnectPtr conn,
- const char *const*argv,
- const char *const*envp,
- const fd_set *keepfd,
- int *retpid,
- int infd,
- int *outfd,
- int *errfd,
- int flags,
- virExecHook hook,
- void *data,
- char *pidfile);
-int virExec(virConnectPtr conn,
- const char *const*argv,
- const char *const*envp,
- const fd_set *keepfd,
- pid_t *retpid,
- int infd,
- int *outfd,
- int *errfd,
- int flags);
-int virRun(virConnectPtr conn, const char *const*argv, int *status);
-
-int virFileReadLimFD(int fd, int maxlen, char **buf);
-
-int virFileReadAll(const char *path, int maxlen, char **buf);
-
-int virFileWriteStr(const char *path, const char *str);
-
-int virFileMatchesNameSuffix(const char *file,
- const char *name,
- const char *suffix);
-
-int virFileHasSuffix(const char *str,
- const char *suffix);
-
-int virFileStripSuffix(char *str,
- const char *suffix);
-
-int virFileLinkPointsTo(const char *checkLink,
- const char *checkDest);
-
-int virFileResolveLink(const char *linkpath,
- char **resultpath);
-
-char *virFindFileInPath(const char *file);
-
-int virFileExists(const char *path);
-
-int virFileMakePath(const char *path);
-
-int virFileBuildPath(const char *dir,
- const char *name,
- const char *ext,
- char *buf,
- unsigned int buflen);
-
-int virFileOpenTty(int *ttymaster,
- char **ttyName,
- int rawmode);
-int virFileOpenTtyAt(const char *ptmx,
- int *ttymaster,
- char **ttyName,
- int rawmode);
-
-char* virFilePid(const char *dir,
- const char *name);
-int virFileWritePidPath(const char *path,
- pid_t pid);
-int virFileWritePid(const char *dir,
- const char *name,
- pid_t pid);
-int virFileReadPid(const char *dir,
- const char *name,
- pid_t *pid);
-int virFileDeletePid(const char *dir,
- const char *name);
-
-char *virArgvToString(const char *const *argv);
-
-int virStrToLong_i(char const *s,
- char **end_ptr,
- int base,
- int *result);
-
-int virStrToLong_ui(char const *s,
- char **end_ptr,
- int base,
- unsigned int *result);
-int virStrToLong_ll(char const *s,
- char **end_ptr,
- int base,
- long long *result);
-int virStrToLong_ull(char const *s,
- char **end_ptr,
- int base,
- unsigned long long *result);
-int virStrToDouble(char const *s,
- char **end_ptr,
- double *result);
-
-int virMacAddrCompare (const char *mac1, const char *mac2);
-
-void virSkipSpaces(const char **str);
-int virParseNumber(const char **str);
-int virAsprintf(char **strp, const char *fmt, ...)
- ATTRIBUTE_FMT_PRINTF(2, 3);
-
-#define VIR_MAC_BUFLEN 6
-#define VIR_MAC_PREFIX_BUFLEN 3
-#define VIR_MAC_STRING_BUFLEN VIR_MAC_BUFLEN * 3
-
-int virParseMacAddr(const char* str,
- unsigned char *addr);
-void virFormatMacAddr(const unsigned char *addr,
- char *str);
-void virGenerateMacAddr(const unsigned char *prefix,
- unsigned char *addr);
-
-int virDiskNameToIndex(const char* str);
-
-
-int virEnumFromString(const char *const*types,
- unsigned int ntypes,
- const char *type);
-
-const char *virEnumToString(const char *const*types,
- unsigned int ntypes,
- int type);
-
-#define VIR_ENUM_IMPL(name, lastVal, ...) \
- static const char *const name ## TypeList[] = { __VA_ARGS__ }; \
- extern int (* name ## Verify (void)) [verify_true (ARRAY_CARDINALITY(name ## TypeList) == lastVal)]; \
- const char *name ## TypeToString(int type) { \
- return virEnumToString(name ## TypeList, \
- ARRAY_CARDINALITY(name ## TypeList), \
- type); \
- } \
- int name ## TypeFromString(const char *type) { \
- return virEnumFromString(name ## TypeList, \
- ARRAY_CARDINALITY(name ## TypeList), \
- type); \
- }
-
-#define VIR_ENUM_DECL(name) \
- const char *name ## TypeToString(int type); \
- int name ## TypeFromString(const char*type);
-
-#ifndef HAVE_GETUID
-static inline int getuid (void) { return 0; }
-#endif
-
-#ifndef HAVE_GETGID
-static inline int getgid (void) { return 0; }
-#endif
-
-char *virGetHostname(void);
-
-int virKillProcess(pid_t pid, int sig);
-
-#ifdef HAVE_GETPWUID_R
-char *virGetUserDirectory(virConnectPtr conn,
- uid_t uid);
-char *virGetUserName(virConnectPtr conn,
- uid_t uid);
-int virGetUserID(virConnectPtr conn,
- const char *name,
- uid_t *uid);
-int virGetGroupID(virConnectPtr conn,
- const char *name,
- gid_t *gid);
-#endif
-
-int virRandomInitialize(unsigned int seed);
-int virRandom(int max);
-
-#ifdef HAVE_MNTENT_H
-char *virFileFindMountPoint(const char *type);
-#endif
-
-void virFileWaitForDevices(virConnectPtr conn);
-
-#endif /* __VIR_UTIL_H__ */
--- /dev/null
+/*
+ * Copyright (C) 2007, 2009 Red Hat, Inc.
+ *
+ * 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
+ *
+ * Authors:
+ * Mark McLoughlin <markmc@redhat.com>
+ */
+
+#include <config.h>
+
+#if defined(WITH_BRIDGE)
+
+#include "bridge.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <arpa/inet.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <paths.h>
+#include <sys/wait.h>
+
+#include <linux/param.h> /* HZ */
+#include <linux/sockios.h> /* SIOCBRADDBR etc. */
+#include <linux/if_bridge.h> /* SYSFS_BRIDGE_ATTR */
+#include <linux/if_tun.h> /* IFF_TUN, IFF_NO_PI */
+#include <net/if_arp.h> /* ARPHRD_ETHER */
+
+#include "internal.h"
+#include "memory.h"
+#include "util.h"
+#include "logging.h"
+
+#define JIFFIES_TO_MS(j) (((j)*1000)/HZ)
+#define MS_TO_JIFFIES(ms) (((ms)*HZ)/1000)
+
+struct _brControl {
+ int fd;
+};
+
+/**
+ * brInit:
+ * @ctlp: pointer to bridge control return value
+ *
+ * Initialize a new bridge layer. In case of success
+ * @ctlp will contain a pointer to the new bridge structure.
+ *
+ * Returns 0 in case of success, an error code otherwise.
+ */
+int
+brInit(brControl **ctlp)
+{
+ int fd;
+ int flags;
+
+ if (!ctlp || *ctlp)
+ return EINVAL;
+
+ fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (fd < 0)
+ return errno;
+
+ if ((flags = fcntl(fd, F_GETFD)) < 0 ||
+ fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) {
+ int err = errno;
+ close(fd);
+ return err;
+ }
+
+ if (VIR_ALLOC(*ctlp) < 0) {
+ close(fd);
+ return ENOMEM;
+ }
+
+ (*ctlp)->fd = fd;
+
+ return 0;
+}
+
+/**
+ * brShutdown:
+ * @ctl: pointer to a bridge control
+ *
+ * Shutdown the bridge layer and deallocate the associated structures
+ */
+void
+brShutdown(brControl *ctl)
+{
+ if (!ctl)
+ return;
+
+ close(ctl->fd);
+ ctl->fd = 0;
+
+ VIR_FREE(ctl);
+}
+
+/**
+ * brAddBridge:
+ * @ctl: bridge control pointer
+ * @name: the bridge name
+ *
+ * This function register a new bridge
+ *
+ * Returns 0 in case of success or an errno code in case of failure.
+ */
+#ifdef SIOCBRADDBR
+int
+brAddBridge(brControl *ctl,
+ const char *name)
+{
+ if (!ctl || !ctl->fd || !name)
+ return EINVAL;
+
+ if (ioctl(ctl->fd, SIOCBRADDBR, name) == 0)
+ return 0;
+
+ return errno;
+}
+#else
+int brAddBridge (brControl *ctl ATTRIBUTE_UNUSED,
+ const char *name ATTRIBUTE_UNUSED)
+{
+ return EINVAL;
+}
+#endif
+
+#ifdef SIOCBRDELBR
+int
+brHasBridge(brControl *ctl,
+ const char *name)
+{
+ struct ifreq ifr;
+ int len;
+
+ if (!ctl || !name) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if ((len = strlen(name)) >= BR_IFNAME_MAXLEN) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+
+ strncpy(ifr.ifr_name, name, len);
+ ifr.ifr_name[len] = '\0';
+
+ if (ioctl(ctl->fd, SIOCGIFFLAGS, &ifr))
+ return -1;
+
+ return 0;
+}
+#else
+int
+brHasBridge(brControl *ctl ATTRIBUTE_UNUSED,
+ const char *name ATTRIBUTE_UNUSED)
+{
+ return EINVAL;
+}
+#endif
+
+/**
+ * brDeleteBridge:
+ * @ctl: bridge control pointer
+ * @name: the bridge name
+ *
+ * Remove a bridge from the layer.
+ *
+ * Returns 0 in case of success or an errno code in case of failure.
+ */
+#ifdef SIOCBRDELBR
+int
+brDeleteBridge(brControl *ctl,
+ const char *name)
+{
+ if (!ctl || !ctl->fd || !name)
+ return EINVAL;
+
+ return ioctl(ctl->fd, SIOCBRDELBR, name) == 0 ? 0 : errno;
+}
+#else
+int
+brDeleteBridge(brControl *ctl ATTRIBUTE_UNUSED,
+ const char *name ATTRIBUTE_UNUSED)
+{
+ return EINVAL;
+}
+#endif
+
+#if defined(SIOCBRADDIF) && defined(SIOCBRDELIF)
+static int
+brAddDelInterface(brControl *ctl,
+ int cmd,
+ const char *bridge,
+ const char *iface)
+{
+ struct ifreq ifr;
+ int len;
+
+ if (!ctl || !ctl->fd || !bridge || !iface)
+ return EINVAL;
+
+ if ((len = strlen(bridge)) >= BR_IFNAME_MAXLEN)
+ return EINVAL;
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+
+ strncpy(ifr.ifr_name, bridge, len);
+ ifr.ifr_name[len] = '\0';
+
+ if (!(ifr.ifr_ifindex = if_nametoindex(iface)))
+ return ENODEV;
+
+ return ioctl(ctl->fd, cmd, &ifr) == 0 ? 0 : errno;
+}
+#endif
+
+/**
+ * brAddInterface:
+ * @ctl: bridge control pointer
+ * @bridge: the bridge name
+ * @iface: the network interface name
+ *
+ * Adds an interface to a bridge
+ *
+ * Returns 0 in case of success or an errno code in case of failure.
+ */
+#ifdef SIOCBRADDIF
+int
+brAddInterface(brControl *ctl,
+ const char *bridge,
+ const char *iface)
+{
+ return brAddDelInterface(ctl, SIOCBRADDIF, bridge, iface);
+}
+#else
+int
+brAddInterface(brControl *ctl ATTRIBUTE_UNUSED,
+ const char *bridge ATTRIBUTE_UNUSED,
+ const char *iface ATTRIBUTE_UNUSED)
+{
+ return EINVAL;
+}
+#endif
+
+/**
+ * brDeleteInterface:
+ * @ctl: bridge control pointer
+ * @bridge: the bridge name
+ * @iface: the network interface name
+ *
+ * Removes an interface from a bridge
+ *
+ * Returns 0 in case of success or an errno code in case of failure.
+ */
+#ifdef SIOCBRDELIF
+int
+brDeleteInterface(brControl *ctl,
+ const char *bridge,
+ const char *iface)
+{
+ return brAddDelInterface(ctl, SIOCBRDELIF, bridge, iface);
+}
+#else
+int
+brDeleteInterface(brControl *ctl ATTRIBUTE_UNUSED,
+ const char *bridge ATTRIBUTE_UNUSED,
+ const char *iface ATTRIBUTE_UNUSED)
+{
+ return EINVAL;
+}
+#endif
+
+/**
+ * ifGetMtu
+ * @ctl: bridge control pointer
+ * @ifname: interface name get MTU for
+ *
+ * This function gets the @mtu value set for a given interface @ifname.
+ *
+ * Returns the MTU value in case of success.
+ * On error, returns -1 and sets errno accordingly
+ */
+static int ifGetMtu(brControl *ctl, const char *ifname)
+{
+ struct ifreq ifr;
+ int len;
+
+ if (!ctl || !ifname) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if ((len = strlen(ifname)) >= BR_IFNAME_MAXLEN) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+
+ strncpy(ifr.ifr_name, ifname, len);
+ ifr.ifr_name[len] = '\0';
+
+ if (ioctl(ctl->fd, SIOCGIFMTU, &ifr))
+ return -1;
+
+ return ifr.ifr_mtu;
+
+}
+
+/**
+ * ifSetMtu:
+ * @ctl: bridge control pointer
+ * @ifname: interface name to set MTU for
+ * @mtu: MTU value
+ *
+ * This function sets the @mtu for a given interface @ifname. Typically
+ * used on a tap device to set up for Jumbo Frames.
+ *
+ * Returns 0 in case of success or an errno code in case of failure.
+ */
+static int ifSetMtu(brControl *ctl, const char *ifname, int mtu)
+{
+ struct ifreq ifr;
+ int len;
+
+ if (!ctl || !ifname)
+ return EINVAL;
+
+ if ((len = strlen(ifname)) >= BR_IFNAME_MAXLEN)
+ return EINVAL;
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+
+ strncpy(ifr.ifr_name, ifname, len);
+ ifr.ifr_name[len] = '\0';
+ ifr.ifr_mtu = mtu;
+
+ return ioctl(ctl->fd, SIOCSIFMTU, &ifr) == 0 ? 0 : errno;
+}
+
+/**
+ * brSetInterfaceMtu
+ * @ctl: bridge control pointer
+ * @bridge: name of the bridge interface
+ * @ifname: name of the interface whose MTU we want to set
+ *
+ * Sets the interface mtu to the same MTU of the bridge
+ *
+ * Returns 0 in case of success or an errno code in case of failure.
+ */
+static int brSetInterfaceMtu(brControl *ctl,
+ const char *bridge,
+ const char *ifname)
+{
+ int mtu = ifGetMtu(ctl, bridge);
+
+ if (mtu < 0)
+ return errno;
+
+ return ifSetMtu(ctl, ifname, mtu);
+}
+
+/**
+ * brProbeVnetHdr:
+ * @tapfd: a tun/tap file descriptor
+ *
+ * Check whether it is safe to enable the IFF_VNET_HDR flag on the
+ * tap interface.
+ *
+ * Setting IFF_VNET_HDR enables QEMU's virtio_net driver to allow
+ * guests to pass larger (GSO) packets, with partial checksums, to
+ * the host. This greatly increases the achievable throughput.
+ *
+ * It is only useful to enable this when we're setting up a virtio
+ * interface. And it is only *safe* to enable it when we know for
+ * sure that a) qemu has support for IFF_VNET_HDR and b) the running
+ * kernel implements the TUNGETIFF ioctl(), which qemu needs to query
+ * the supplied tapfd.
+ *
+ * Returns 0 in case of success or an errno code in case of failure.
+ */
+#ifdef IFF_VNET_HDR
+static int
+brProbeVnetHdr(int tapfd)
+{
+#if defined(IFF_VNET_HDR) && defined(TUNGETFEATURES) && defined(TUNGETIFF)
+ unsigned int features;
+ struct ifreq dummy;
+
+ if (ioctl(tapfd, TUNGETFEATURES, &features) != 0) {
+ VIR_INFO0(_("Not enabling IFF_VNET_HDR; "
+ "TUNGETFEATURES ioctl() not implemented"));
+ return 0;
+ }
+
+ if (!(features & IFF_VNET_HDR)) {
+ VIR_INFO0(_("Not enabling IFF_VNET_HDR; "
+ "TUNGETFEATURES ioctl() reports no IFF_VNET_HDR"));
+ return 0;
+ }
+
+ /* The kernel will always return -1 at this point.
+ * If TUNGETIFF is not implemented then errno == EBADFD.
+ */
+ if (ioctl(tapfd, TUNGETIFF, &dummy) != -1 || errno != EBADFD) {
+ VIR_INFO0(_("Not enabling IFF_VNET_HDR; "
+ "TUNGETIFF ioctl() not implemented"));
+ return 0;
+ }
+
+ VIR_INFO0(_("Enabling IFF_VNET_HDR"));
+
+ return 1;
+#else
+ (void) tapfd;
+ VIR_INFO0(_("Not enabling IFF_VNET_HDR; disabled at build time"));
+ return 0;
+#endif
+}
+#endif
+
+/**
+ * brAddTap:
+ * @ctl: bridge control pointer
+ * @bridge: the bridge name
+ * @ifname: the interface name (or name template)
+ * @vnet_hdr: whether to try enabling IFF_VNET_HDR
+ * @tapfd: file descriptor return value for the new tap device
+ *
+ * This function creates a new tap device on a bridge. @ifname can be either
+ * a fixed name or a name template with '%d' for dynamic name allocation.
+ * in either case the final name for the bridge will be stored in @ifname.
+ * If the @tapfd parameter is supplied, the open tap device file
+ * descriptor will be returned, otherwise the TAP device will be made
+ * persistent and closed. The caller must use brDeleteTap to remove
+ * a persistent TAP devices when it is no longer needed.
+ *
+ * Returns 0 in case of success or an errno code in case of failure.
+ */
+int
+brAddTap(brControl *ctl,
+ const char *bridge,
+ char **ifname,
+ int vnet_hdr,
+ int *tapfd)
+{
+ int fd, len;
+ struct ifreq ifr;
+
+ if (!ctl || !ctl->fd || !bridge || !ifname)
+ return EINVAL;
+
+ if ((fd = open("/dev/net/tun", O_RDWR)) < 0)
+ return errno;
+
+ memset(&ifr, 0, sizeof(ifr));
+
+ ifr.ifr_flags = IFF_TAP|IFF_NO_PI;
+
+#ifdef IFF_VNET_HDR
+ if (vnet_hdr && brProbeVnetHdr(fd))
+ ifr.ifr_flags |= IFF_VNET_HDR;
+#else
+ (void) vnet_hdr;
+#endif
+
+ strncpy(ifr.ifr_name, *ifname, IFNAMSIZ-1);
+
+ if (ioctl(fd, TUNSETIFF, &ifr) < 0)
+ goto error;
+
+ len = strlen(ifr.ifr_name);
+ if (len >= BR_IFNAME_MAXLEN - 1) {
+ errno = EINVAL;
+ goto error;
+ }
+
+ /* We need to set the interface MTU before adding it
+ * to the bridge, because the bridge will have its
+ * MTU adjusted automatically when we add the new interface.
+ */
+ if ((errno = brSetInterfaceMtu(ctl, bridge, ifr.ifr_name)))
+ goto error;
+ if ((errno = brAddInterface(ctl, bridge, ifr.ifr_name)))
+ goto error;
+ if ((errno = brSetInterfaceUp(ctl, ifr.ifr_name, 1)))
+ goto error;
+ if (!tapfd &&
+ (errno = ioctl(fd, TUNSETPERSIST, 1)))
+ goto error;
+ VIR_FREE(*ifname);
+ if (!(*ifname = strdup(ifr.ifr_name)))
+ goto error;
+ if (tapfd)
+ *tapfd = fd;
+ return 0;
+
+ error:
+ close(fd);
+
+ return errno;
+}
+
+int brDeleteTap(brControl *ctl,
+ const char *ifname)
+{
+ struct ifreq try;
+ int len;
+ int fd;
+
+ if (!ctl || !ctl->fd || !ifname)
+ return EINVAL;
+
+ if ((fd = open("/dev/net/tun", O_RDWR)) < 0)
+ return errno;
+
+ memset(&try, 0, sizeof(struct ifreq));
+ try.ifr_flags = IFF_TAP|IFF_NO_PI;
+
+ len = strlen(ifname);
+ if (len >= BR_IFNAME_MAXLEN - 1) {
+ errno = EINVAL;
+ goto error;
+ }
+
+ strncpy(try.ifr_name, ifname, len);
+ try.ifr_name[len] = '\0';
+
+ if (ioctl(fd, TUNSETIFF, &try) == 0) {
+ if ((errno = ioctl(fd, TUNSETPERSIST, 0)))
+ goto error;
+ }
+
+ error:
+ close(fd);
+
+ return errno;
+}
+
+
+/**
+ * brSetInterfaceUp:
+ * @ctl: bridge control pointer
+ * @ifname: the interface name
+ * @up: 1 for up, 0 for down
+ *
+ * Function to control if an interface is activated (up, 1) or not (down, 0)
+ *
+ * Returns 0 in case of success or an errno code in case of failure.
+ */
+int
+brSetInterfaceUp(brControl *ctl,
+ const char *ifname,
+ int up)
+{
+ struct ifreq ifr;
+ int len;
+ int flags;
+
+ if (!ctl || !ifname)
+ return EINVAL;
+
+ if ((len = strlen(ifname)) >= BR_IFNAME_MAXLEN)
+ return EINVAL;
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+
+ strncpy(ifr.ifr_name, ifname, len);
+ ifr.ifr_name[len] = '\0';
+
+ if (ioctl(ctl->fd, SIOCGIFFLAGS, &ifr) < 0)
+ return errno;
+
+ flags = up ? (ifr.ifr_flags | IFF_UP) : (ifr.ifr_flags & ~IFF_UP);
+
+ if (ifr.ifr_flags != flags) {
+ ifr.ifr_flags = flags;
+
+ if (ioctl(ctl->fd, SIOCSIFFLAGS, &ifr) < 0)
+ return errno;
+ }
+
+ return 0;
+}
+
+/**
+ * brGetInterfaceUp:
+ * @ctl: bridge control pointer
+ * @ifname: the interface name
+ * @up: where to store the status
+ *
+ * Function to query if an interface is activated (1) or not (0)
+ *
+ * Returns 0 in case of success or an errno code in case of failure.
+ */
+int
+brGetInterfaceUp(brControl *ctl,
+ const char *ifname,
+ int *up)
+{
+ struct ifreq ifr;
+ int len;
+
+ if (!ctl || !ifname || !up)
+ return EINVAL;
+
+ if ((len = strlen(ifname)) >= BR_IFNAME_MAXLEN)
+ return EINVAL;
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+
+ strncpy(ifr.ifr_name, ifname, len);
+ ifr.ifr_name[len] = '\0';
+
+ if (ioctl(ctl->fd, SIOCGIFFLAGS, &ifr) < 0)
+ return errno;
+
+ *up = (ifr.ifr_flags & IFF_UP) ? 1 : 0;
+
+ return 0;
+}
+
+static int
+brSetInetAddr(brControl *ctl,
+ const char *ifname,
+ int cmd,
+ const char *addr)
+{
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in sa_in;
+ } s;
+ struct ifreq ifr;
+ struct in_addr inaddr;
+ int len, ret;
+
+ if (!ctl || !ctl->fd || !ifname || !addr)
+ return EINVAL;
+
+ if ((len = strlen(ifname)) >= BR_IFNAME_MAXLEN)
+ return EINVAL;
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+
+ strncpy(ifr.ifr_name, ifname, len);
+ ifr.ifr_name[len] = '\0';
+
+ if ((ret = inet_pton(AF_INET, addr, &inaddr)) < 0)
+ return errno;
+ else if (ret == 0)
+ return EINVAL;
+
+ s.sa_in.sin_family = AF_INET;
+ s.sa_in.sin_addr = inaddr;
+
+ ifr.ifr_addr = s.sa;
+
+ if (ioctl(ctl->fd, cmd, &ifr) < 0)
+ return errno;
+
+ return 0;
+}
+
+static int
+brGetInetAddr(brControl *ctl,
+ const char *ifname,
+ int cmd,
+ char *addr,
+ int maxlen)
+{
+ struct ifreq ifr;
+ struct in_addr *inaddr;
+ int len;
+
+ if (!ctl || !ctl->fd || !ifname || !addr)
+ return EINVAL;
+
+ if ((len = strlen(ifname)) >= BR_IFNAME_MAXLEN)
+ return EINVAL;
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+
+ strncpy(ifr.ifr_name, ifname, len);
+ ifr.ifr_name[len] = '\0';
+
+ if (ioctl(ctl->fd, cmd, &ifr) < 0)
+ return errno;
+
+ if (maxlen < BR_INET_ADDR_MAXLEN || ifr.ifr_addr.sa_family != AF_INET)
+ return EFAULT;
+
+ inaddr = &((struct sockaddr_in *)&ifr.ifr_data)->sin_addr;
+
+ if (!inet_ntop(AF_INET, inaddr, addr, maxlen))
+ return errno;
+
+ return 0;
+}
+
+/**
+ * brSetInetAddress:
+ * @ctl: bridge control pointer
+ * @ifname: the interface name
+ * @addr: the string representation of the IP address
+ *
+ * Function to bind the interface to an IP address, it should handle
+ * IPV4 and IPv6. The string for addr would be of the form
+ * "ddd.ddd.ddd.ddd" assuming the common IPv4 format.
+ *
+ * Returns 0 in case of success or an errno code in case of failure.
+ */
+
+int
+brSetInetAddress(brControl *ctl,
+ const char *ifname,
+ const char *addr)
+{
+ return brSetInetAddr(ctl, ifname, SIOCSIFADDR, addr);
+}
+
+/**
+ * brGetInetAddress:
+ * @ctl: bridge control pointer
+ * @ifname: the interface name
+ * @addr: the array for the string representation of the IP address
+ * @maxlen: size of @addr in bytes
+ *
+ * Function to get the IP address of an interface, it should handle
+ * IPV4 and IPv6. The returned string for addr would be of the form
+ * "ddd.ddd.ddd.ddd" assuming the common IPv4 format.
+ *
+ * Returns 0 in case of success or an errno code in case of failure.
+ */
+
+int
+brGetInetAddress(brControl *ctl,
+ const char *ifname,
+ char *addr,
+ int maxlen)
+{
+ return brGetInetAddr(ctl, ifname, SIOCGIFADDR, addr, maxlen);
+}
+
+/**
+ * brSetInetNetmask:
+ * @ctl: bridge control pointer
+ * @ifname: the interface name
+ * @addr: the string representation of the netmask
+ *
+ * Function to set the netmask of an interface, it should handle
+ * IPV4 and IPv6 forms. The string for addr would be of the form
+ * "ddd.ddd.ddd.ddd" assuming the common IPv4 format.
+ *
+ * Returns 0 in case of success or an errno code in case of failure.
+ */
+
+int
+brSetInetNetmask(brControl *ctl,
+ const char *ifname,
+ const char *addr)
+{
+ return brSetInetAddr(ctl, ifname, SIOCSIFNETMASK, addr);
+}
+
+/**
+ * brGetInetNetmask:
+ * @ctl: bridge control pointer
+ * @ifname: the interface name
+ * @addr: the array for the string representation of the netmask
+ * @maxlen: size of @addr in bytes
+ *
+ * Function to get the netmask of an interface, it should handle
+ * IPV4 and IPv6. The returned string for addr would be of the form
+ * "ddd.ddd.ddd.ddd" assuming the common IPv4 format.
+ *
+ * Returns 0 in case of success or an errno code in case of failure.
+ */
+
+int
+brGetInetNetmask(brControl *ctl,
+ const char *ifname,
+ char *addr,
+ int maxlen)
+{
+ return brGetInetAddr(ctl, ifname, SIOCGIFNETMASK, addr, maxlen);
+}
+
+
+/**
+ * brSetForwardDelay:
+ * @ctl: bridge control pointer
+ * @bridge: the bridge name
+ * @delay: delay in seconds
+ *
+ * Set the bridge forward delay
+ *
+ * Returns 0 in case of success or -1 on failure
+ */
+
+int
+brSetForwardDelay(brControl *ctl ATTRIBUTE_UNUSED,
+ const char *bridge,
+ int delay)
+{
+ char delayStr[30];
+ const char *const progargv[] = {
+ BRCTL, "setfd", bridge, delayStr, NULL
+ };
+
+ snprintf(delayStr, sizeof(delayStr), "%d", delay);
+
+ if (virRun(NULL, progargv, NULL) < 0)
+ return -1;
+
+ return 0;
+}
+
+/**
+ * brSetEnableSTP:
+ * @ctl: bridge control pointer
+ * @bridge: the bridge name
+ * @enable: 1 to enable, 0 to disable
+ *
+ * Control whether the bridge participates in the spanning tree protocol,
+ * in general don't disable it without good reasons.
+ *
+ * Returns 0 in case of success or -1 on failure
+ */
+int
+brSetEnableSTP(brControl *ctl ATTRIBUTE_UNUSED,
+ const char *bridge,
+ int enable)
+{
+ const char *setting = enable ? "on" : "off";
+ const char *const progargv[] = {
+ BRCTL, "stp", bridge, setting, NULL
+ };
+
+ if (virRun(NULL, progargv, NULL) < 0)
+ return -1;
+
+ return 0;
+}
+
+#endif /* WITH_BRIDGE */
--- /dev/null
+/*
+ * Copyright (C) 2007 Red Hat, Inc.
+ *
+ * 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
+ *
+ * Authors:
+ * Mark McLoughlin <markmc@redhat.com>
+ */
+
+#ifndef __QEMUD_BRIDGE_H__
+#define __QEMUD_BRIDGE_H__
+
+#include <config.h>
+
+#if defined(WITH_BRIDGE)
+
+#include <net/if.h>
+#include <netinet/in.h>
+
+/**
+ * BR_IFNAME_MAXLEN:
+ * maximum size in byte of the name for an interface
+ */
+#define BR_IFNAME_MAXLEN IF_NAMESIZE
+
+/**
+ * BR_INET_ADDR_MAXLEN:
+ * maximum size in bytes for an inet addess name
+ */
+#define BR_INET_ADDR_MAXLEN INET_ADDRSTRLEN
+
+typedef struct _brControl brControl;
+
+int brInit (brControl **ctl);
+void brShutdown (brControl *ctl);
+
+int brAddBridge (brControl *ctl,
+ const char *name);
+int brDeleteBridge (brControl *ctl,
+ const char *name);
+int brHasBridge (brControl *ctl,
+ const char *name);
+
+int brAddInterface (brControl *ctl,
+ const char *bridge,
+ const char *iface);
+int brDeleteInterface (brControl *ctl,
+ const char *bridge,
+ const char *iface);
+
+enum {
+ BR_TAP_VNET_HDR = (1 << 0),
+ BR_TAP_PERSIST = (1 << 1),
+};
+
+int brAddTap (brControl *ctl,
+ const char *bridge,
+ char **ifname,
+ int features,
+ int *tapfd);
+
+int brDeleteTap (brControl *ctl,
+ const char *ifname);
+
+int brSetInterfaceUp (brControl *ctl,
+ const char *ifname,
+ int up);
+int brGetInterfaceUp (brControl *ctl,
+ const char *ifname,
+ int *up);
+
+int brSetInetAddress (brControl *ctl,
+ const char *ifname,
+ const char *addr);
+int brGetInetAddress (brControl *ctl,
+ const char *ifname,
+ char *addr,
+ int maxlen);
+int brSetInetNetmask (brControl *ctl,
+ const char *ifname,
+ const char *netmask);
+int brGetInetNetmask (brControl *ctl,
+ const char *ifname,
+ char *netmask,
+ int maxlen);
+
+int brSetForwardDelay (brControl *ctl,
+ const char *bridge,
+ int delay);
+int brGetForwardDelay (brControl *ctl,
+ const char *bridge,
+ int *delay);
+int brSetEnableSTP (brControl *ctl,
+ const char *bridge,
+ int enable);
+int brGetEnableSTP (brControl *ctl,
+ const char *bridge,
+ int *enable);
+
+#endif /* WITH_BRIDGE */
+
+#endif /* __QEMUD_BRIDGE_H__ */
--- /dev/null
+/*
+ * buf.c: buffers for libvirt
+ *
+ * Copyright (C) 2005-2008 Red Hat, Inc.
+ *
+ * See COPYING.LIB for the License of this software
+ *
+ * Daniel Veillard <veillard@redhat.com>
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include "c-ctype.h"
+
+#define __VIR_BUFFER_C__
+
+#include "buf.h"
+#include "memory.h"
+
+
+/* If adding more fields, ensure to edit buf.h to match
+ the number of fields */
+struct _virBuffer {
+ unsigned int size;
+ unsigned int use;
+ unsigned int error;
+ char *content;
+};
+
+/**
+ * virBufferFail
+ * @buf: the buffer
+ *
+ * Mark the buffer has having failed a memory allocation,
+ * freeing the content and setting the error flag.
+ */
+static void
+virBufferNoMemory(const virBufferPtr buf)
+{
+ VIR_FREE(buf->content);
+ buf->size = 0;
+ buf->use = 0;
+ buf->error = 1;
+}
+
+/**
+ * virBufferGrow:
+ * @buf: the buffer
+ * @len: the minimum free size to allocate on top of existing used space
+ *
+ * Grow the available space of a buffer to at least @len bytes.
+ *
+ * Returns zero on success or -1 on error
+ */
+static int
+virBufferGrow(virBufferPtr buf, unsigned int len)
+{
+ int size;
+
+ if (buf->error)
+ return -1;
+
+ if ((len + buf->use) < buf->size)
+ return 0;
+
+ size = buf->use + len + 1000;
+
+ if (VIR_REALLOC_N(buf->content, size) < 0) {
+ virBufferNoMemory(buf);
+ return -1;
+ }
+ buf->size = size;
+ return 0;
+}
+
+/**
+ * virBufferAdd:
+ * @buf: the buffer to add to
+ * @str: the string
+ * @len: the number of bytes to add
+ *
+ * Add a string range to an XML buffer. if len == -1, the length of
+ * str is recomputed to the full string.
+ *
+ */
+void
+virBufferAdd(const virBufferPtr buf, const char *str, int len)
+{
+ unsigned int needSize;
+
+ if ((str == NULL) || (buf == NULL) || (len == 0))
+ return;
+
+ if (buf->error)
+ return;
+
+ if (len < 0)
+ len = strlen(str);
+
+ needSize = buf->use + len + 2;
+ if (needSize > buf->size &&
+ virBufferGrow(buf, needSize - buf->use) < 0)
+ return;
+
+ memcpy (&buf->content[buf->use], str, len);
+ buf->use += len;
+ buf->content[buf->use] = '\0';
+}
+
+/**
+ * virBufferAddChar:
+ * @buf: the buffer to add to
+ * @c: the character to add
+ *
+ * Add a single character 'c' to a buffer.
+ *
+ */
+void
+virBufferAddChar (virBufferPtr buf, char c)
+{
+ unsigned int needSize;
+
+ if (buf == NULL)
+ return;
+
+ if (buf->error)
+ return;
+
+ needSize = buf->use + 2;
+ if (needSize > buf->size &&
+ virBufferGrow (buf, needSize - buf->use) < 0)
+ return;
+
+ buf->content[buf->use++] = c;
+ buf->content[buf->use] = '\0';
+}
+
+/**
+ * virBufferContentAndReset:
+ * @buf: Buffer
+ *
+ * Get the content from the buffer and free (only) the buffer structure.
+ * The caller owns the returned string & should free it when no longer
+ * required. The buffer object is reset to its initial state.
+ *
+ * Returns the buffer content or NULL in case of error.
+ */
+char *
+virBufferContentAndReset(const virBufferPtr buf)
+{
+ char *str;
+ if (buf == NULL)
+ return NULL;
+
+ if (buf->error) {
+ memset(buf, 0, sizeof(*buf));
+ return NULL;
+ }
+
+ str = buf->content;
+ memset(buf, 0, sizeof(*buf));
+ return str;
+}
+
+/**
+ * virBufferError:
+ * @buf: the buffer
+ *
+ * Check to see if the buffer is in an error state due
+ * to failed memory allocation
+ *
+ * Return true if in error, 0 if normal
+ */
+int
+virBufferError(const virBufferPtr buf)
+{
+ if (buf == NULL)
+ return 1;
+
+ return buf->error;
+}
+
+/**
+ * virBufferUse:
+ * @buf: the usage of the string in the buffer
+ *
+ * Return the string usage in bytes
+ */
+unsigned int
+virBufferUse(const virBufferPtr buf)
+{
+ if (buf == NULL)
+ return 0;
+
+ return buf->use;
+}
+
+/**
+ * virBufferVSprintf:
+ * @buf: the buffer to dump
+ * @format: the format
+ * @...: the variable list of arguments
+ *
+ * Do a formatted print to an XML buffer.
+ */
+void
+virBufferVSprintf(const virBufferPtr buf, const char *format, ...)
+{
+ int size, count, grow_size;
+ va_list locarg, argptr;
+
+ if ((format == NULL) || (buf == NULL))
+ return;
+
+ if (buf->error)
+ return;
+
+ if (buf->size == 0 &&
+ virBufferGrow(buf, 100) < 0)
+ return;
+
+ size = buf->size - buf->use - 1;
+ va_start(argptr, format);
+ va_copy(locarg, argptr);
+ while (((count = vsnprintf(&buf->content[buf->use], size, format,
+ locarg)) < 0) || (count >= size - 1)) {
+ buf->content[buf->use] = 0;
+ va_end(locarg);
+
+ grow_size = (count > 1000) ? count : 1000;
+ if (virBufferGrow(buf, grow_size) < 0)
+ return;
+
+ size = buf->size - buf->use - 1;
+ va_copy(locarg, argptr);
+ }
+ va_end(locarg);
+ buf->use += count;
+ buf->content[buf->use] = '\0';
+}
+
+/**
+ * virBufferEscapeString:
+ * @buf: the buffer to dump
+ * @format: a printf like format string but with only one %s parameter
+ * @str: the string argument which need to be escaped
+ *
+ * Do a formatted print with a single string to an XML buffer. The string
+ * is escaped to avoid generating a not well-formed XML instance.
+ */
+void
+virBufferEscapeString(const virBufferPtr buf, const char *format, const char *str)
+{
+ int size, count, len, grow_size;
+ char *escaped, *out;
+ const char *cur;
+
+ if ((format == NULL) || (buf == NULL) || (str == NULL))
+ return;
+
+ if (buf->error)
+ return;
+
+ len = strlen(str);
+ if (VIR_ALLOC_N(escaped, 6 * len + 1) < 0) {
+ virBufferNoMemory(buf);
+ return;
+ }
+
+ cur = str;
+ out = escaped;
+ while (*cur != 0) {
+ if (*cur == '<') {
+ *out++ = '&';
+ *out++ = 'l';
+ *out++ = 't';
+ *out++ = ';';
+ } else if (*cur == '>') {
+ *out++ = '&';
+ *out++ = 'g';
+ *out++ = 't';
+ *out++ = ';';
+ } else if (*cur == '&') {
+ *out++ = '&';
+ *out++ = 'a';
+ *out++ = 'm';
+ *out++ = 'p';
+ *out++ = ';';
+ } else if (*cur == '"') {
+ *out++ = '&';
+ *out++ = 'q';
+ *out++ = 'u';
+ *out++ = 'o';
+ *out++ = 't';
+ *out++ = ';';
+ } else if (*cur == '\'') {
+ *out++ = '&';
+ *out++ = 'a';
+ *out++ = 'p';
+ *out++ = 'o';
+ *out++ = 's';
+ *out++ = ';';
+ } else if (((unsigned char)*cur >= 0x20) || (*cur == '\n') || (*cur == '\t') ||
+ (*cur == '\r')) {
+ /*
+ * default case, just copy !
+ * Note that character over 0x80 are likely to give problem
+ * with UTF-8 XML, but since our string don't have an encoding
+ * it's hard to handle properly we have to assume it's UTF-8 too
+ */
+ *out++ = *cur;
+ }
+ cur++;
+ }
+ *out = 0;
+
+ size = buf->size - buf->use - 1;
+ while (((count = snprintf(&buf->content[buf->use], size, format,
+ (char *)escaped)) < 0) || (count >= size - 1)) {
+ buf->content[buf->use] = 0;
+ grow_size = (count > 1000) ? count : 1000;
+ if (virBufferGrow(buf, grow_size) < 0) {
+ VIR_FREE(escaped);
+ return;
+ }
+ size = buf->size - buf->use - 1;
+ }
+ buf->use += count;
+ buf->content[buf->use] = '\0';
+ VIR_FREE(escaped);
+}
+
+/**
+ * virBufferURIEncodeString:
+ * @buf: the buffer to append to
+ * @str: the string argument which will be URI-encoded
+ *
+ * Append the string to the buffer. The string will be URI-encoded
+ * during the append (ie any non alpha-numeric characters are replaced
+ * with '%xx' hex sequences).
+ */
+void
+virBufferURIEncodeString (virBufferPtr buf, const char *str)
+{
+ int grow_size = 0;
+ const char *p;
+ unsigned char uc;
+ const char *hex = "0123456789abcdef";
+
+ if ((buf == NULL) || (str == NULL))
+ return;
+
+ if (buf->error)
+ return;
+
+ for (p = str; *p; ++p) {
+ if (c_isalnum(*p))
+ grow_size++;
+ else
+ grow_size += 3; /* %ab */
+ }
+
+ if (virBufferGrow (buf, grow_size) < 0)
+ return;
+
+ for (p = str; *p; ++p) {
+ if (c_isalnum(*p))
+ buf->content[buf->use++] = *p;
+ else {
+ uc = (unsigned char) *p;
+ buf->content[buf->use++] = '%';
+ buf->content[buf->use++] = hex[uc >> 4];
+ buf->content[buf->use++] = hex[uc & 0xf];
+ }
+ }
+
+ buf->content[buf->use] = '\0';
+}
+
+/**
+ * virBufferStrcat:
+ * @buf: the buffer to dump
+ * @...: the variable list of strings, the last argument must be NULL
+ *
+ * Concatenate strings to an XML buffer.
+ */
+void
+virBufferStrcat(virBufferPtr buf, ...)
+{
+ va_list ap;
+ char *str;
+
+ if (buf->error)
+ return;
+
+ va_start(ap, buf);
+
+ while ((str = va_arg(ap, char *)) != NULL) {
+ unsigned int len = strlen(str);
+ unsigned int needSize = buf->use + len + 2;
+
+ if (needSize > buf->size) {
+ if (virBufferGrow(buf, needSize - buf->use) < 0)
+ return;
+ }
+ memcpy(&buf->content[buf->use], str, len);
+ buf->use += len;
+ buf->content[buf->use] = 0;
+ }
+ va_end(ap);
+}
--- /dev/null
+/*
+ * buf.h: buffers for libvirt
+ *
+ * Copyright (C) 2005-2008 Red Hat, Inc.
+ *
+ * See COPYING.LIB for the License of this software
+ *
+ * Daniel Veillard <veillard@redhat.com>
+ */
+
+#ifndef __VIR_BUFFER_H__
+#define __VIR_BUFFER_H__
+
+#include "internal.h"
+
+/**
+ * virBuffer:
+ *
+ * A buffer structure.
+ */
+typedef struct _virBuffer virBuffer;
+typedef virBuffer *virBufferPtr;
+
+#ifndef __VIR_BUFFER_C__
+#define VIR_BUFFER_INITIALIZER { 0, 0, 0, NULL }
+
+/* This struct must be kept in syn with the real struct
+ in the buf.c impl file */
+struct _virBuffer {
+ unsigned int a;
+ unsigned int b;
+ unsigned int c;
+ char *d;
+};
+#endif
+
+char *virBufferContentAndReset(const virBufferPtr buf);
+int virBufferError(const virBufferPtr buf);
+unsigned int virBufferUse(const virBufferPtr buf);
+void virBufferAdd(const virBufferPtr buf, const char *str, int len);
+void virBufferAddChar(const virBufferPtr buf, char c);
+void virBufferVSprintf(const virBufferPtr buf, const char *format, ...)
+ ATTRIBUTE_FMT_PRINTF(2, 3);
+void virBufferStrcat(const virBufferPtr buf, ...);
+void virBufferEscapeString(const virBufferPtr buf, const char *format, const char *str);
+void virBufferURIEncodeString (const virBufferPtr buf, const char *str);
+
+#define virBufferAddLit(buf_, literal_string_) \
+ virBufferAdd (buf_, "" literal_string_ "", sizeof literal_string_ - 1)
+
+#endif /* __VIR_BUFFER_H__ */
--- /dev/null
+/*
+ * cgroup.c: Tools for managing cgroups
+ *
+ * Copyright IBM Corp. 2008
+ *
+ * See COPYING.LIB for the License of this software
+ *
+ * Authors:
+ * Dan Smith <danms@us.ibm.com>
+ */
+#include <config.h>
+
+#include <stdio.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <mntent.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <libgen.h>
+
+#include "internal.h"
+#include "util.h"
+#include "memory.h"
+#include "cgroup.h"
+#include "logging.h"
+
+#define CGROUP_MAX_VAL 512
+
+VIR_ENUM_IMPL(virCgroupController, VIR_CGROUP_CONTROLLER_LAST,
+ "cpu", "cpuacct", "cpuset", "memory", "devices");
+
+struct virCgroupController {
+ int type;
+ char *mountPoint;
+ char *placement;
+};
+
+struct virCgroup {
+ char *path;
+
+ struct virCgroupController controllers[VIR_CGROUP_CONTROLLER_LAST];
+};
+
+/**
+ * virCgroupFree:
+ *
+ * @group: The group structure to free
+ */
+void virCgroupFree(virCgroupPtr *group)
+{
+ int i;
+
+ if (*group == NULL)
+ return;
+
+ for (i = 0 ; i < VIR_CGROUP_CONTROLLER_LAST ; i++) {
+ VIR_FREE((*group)->controllers[i].mountPoint);
+ VIR_FREE((*group)->controllers[i].placement);
+ }
+
+ VIR_FREE((*group)->path);
+ VIR_FREE(*group);
+}
+
+
+/*
+ * Process /proc/mounts figuring out what controllers are
+ * mounted and where
+ */
+static int virCgroupDetectMounts(virCgroupPtr group)
+{
+ int i;
+ FILE *mounts = NULL;
+ struct mntent entry;
+ char buf[CGROUP_MAX_VAL];
+
+ mounts = fopen("/proc/mounts", "r");
+ if (mounts == NULL) {
+ VIR_ERROR0("Unable to open /proc/mounts");
+ return -ENOENT;
+ }
+
+ while (getmntent_r(mounts, &entry, buf, sizeof(buf)) != NULL) {
+ if (STRNEQ(entry.mnt_type, "cgroup"))
+ continue;
+
+ for (i = 0 ; i < VIR_CGROUP_CONTROLLER_LAST ; i++) {
+ const char *typestr = virCgroupControllerTypeToString(i);
+ int typelen = strlen(typestr);
+ char *tmp = entry.mnt_opts;
+ while (tmp) {
+ char *next = strchr(tmp, ',');
+ int len;
+ if (next) {
+ len = next-tmp;
+ next++;
+ } else {
+ len = strlen(tmp);
+ }
+ if (typelen == len && STREQLEN(typestr, tmp, len) &&
+ !(group->controllers[i].mountPoint = strdup(entry.mnt_dir)))
+ goto no_memory;
+ tmp = next;
+ }
+ }
+ }
+
+ fclose(mounts);
+
+ return 0;
+
+no_memory:
+ if (mounts)
+ fclose(mounts);
+ return -ENOMEM;
+}
+
+
+/*
+ * Process /proc/self/cgroup figuring out what cgroup
+ * sub-path the current process is assigned to. ie not
+ * neccessarily in the root
+ */
+static int virCgroupDetectPlacement(virCgroupPtr group)
+{
+ int i;
+ FILE *mapping = NULL;
+ char line[1024];
+
+ mapping = fopen("/proc/self/cgroup", "r");
+ if (mapping == NULL) {
+ VIR_ERROR0("Unable to open /proc/self/cgroup");
+ return -ENOENT;
+ }
+
+ while (fgets(line, sizeof(line), mapping) != NULL) {
+ char *controllers = strchr(line, ':');
+ char *path = controllers ? strchr(controllers+1, ':') : NULL;
+ char *nl = path ? strchr(path, '\n') : NULL;
+
+ if (!controllers || !path)
+ continue;
+
+ if (nl)
+ *nl = '\0';
+
+ *path = '\0';
+ controllers++;
+ path++;
+
+ for (i = 0 ; i < VIR_CGROUP_CONTROLLER_LAST ; i++) {
+ const char *typestr = virCgroupControllerTypeToString(i);
+ int typelen = strlen(typestr);
+ char *tmp = controllers;
+ while (tmp) {
+ char *next = strchr(tmp, ',');
+ int len;
+ if (next) {
+ len = next-tmp;
+ next++;
+ } else {
+ len = strlen(tmp);
+ }
+ if (typelen == len && STREQLEN(typestr, tmp, len) &&
+ !(group->controllers[i].placement = strdup(STREQ(path, "/") ? "" : path)))
+ goto no_memory;
+
+ tmp = next;
+ }
+ }
+ }
+
+ fclose(mapping);
+
+ return 0;
+
+no_memory:
+ return -ENOMEM;
+
+}
+
+static int virCgroupDetect(virCgroupPtr group)
+{
+ int any = 0;
+ int rc;
+ int i;
+
+ rc = virCgroupDetectMounts(group);
+ if (rc < 0) {
+ VIR_ERROR("Failed to detect mounts for %s", group->path);
+ return rc;
+ }
+
+ /* Check that at least 1 controller is available */
+ for (i = 0 ; i < VIR_CGROUP_CONTROLLER_LAST ; i++) {
+ if (group->controllers[i].mountPoint != NULL)
+ any = 1;
+ }
+ if (!any)
+ return -ENXIO;
+
+
+ rc = virCgroupDetectPlacement(group);
+
+ if (rc == 0) {
+ /* Check that for every mounted controller, we found our placement */
+ for (i = 0 ; i < VIR_CGROUP_CONTROLLER_LAST ; i++) {
+ if (!group->controllers[i].mountPoint)
+ continue;
+
+ if (!group->controllers[i].placement) {
+ VIR_ERROR("Could not find placement for controller %s at %s",
+ virCgroupControllerTypeToString(i),
+ group->controllers[i].placement);
+ rc = -ENOENT;
+ break;
+ }
+
+ VIR_DEBUG("Detected mount/mapping %i:%s at %s in %s", i,
+ virCgroupControllerTypeToString(i),
+ group->controllers[i].mountPoint,
+ group->controllers[i].placement);
+ }
+ } else {
+ VIR_ERROR("Failed to detect mapping for %s", group->path);
+ }
+
+ return rc;
+}
+
+
+static int virCgroupPathOfController(virCgroupPtr group,
+ int controller,
+ const char *key,
+ char **path)
+{
+ if (group->controllers[controller].mountPoint == NULL)
+ return -ENOENT;
+
+ if (group->controllers[controller].placement == NULL)
+ return -ENOENT;
+
+ if (virAsprintf(path, "%s%s%s/%s",
+ group->controllers[controller].mountPoint,
+ group->controllers[controller].placement,
+ STREQ(group->path, "/") ? "" : group->path,
+ key ? key : "") == -1)
+ return -ENOMEM;
+
+ return 0;
+}
+
+
+static int virCgroupSetValueStr(virCgroupPtr group,
+ int controller,
+ const char *key,
+ const char *value)
+{
+ int rc = 0;
+ char *keypath = NULL;
+
+ rc = virCgroupPathOfController(group, controller, key, &keypath);
+ if (rc != 0)
+ return rc;
+
+ VIR_DEBUG("Set value %s", keypath);
+ rc = virFileWriteStr(keypath, value);
+ if (rc < 0) {
+ DEBUG("Failed to write value '%s': %m", value);
+ rc = -errno;
+ } else {
+ rc = 0;
+ }
+
+ VIR_FREE(keypath);
+
+ return rc;
+}
+
+static int virCgroupGetValueStr(virCgroupPtr group,
+ int controller,
+ const char *key,
+ char **value)
+{
+ int rc;
+ char *keypath = NULL;
+
+ *value = NULL;
+
+ rc = virCgroupPathOfController(group, controller, key, &keypath);
+ if (rc != 0) {
+ DEBUG("No path of %s, %s", group->path, key);
+ return rc;
+ }
+
+ VIR_DEBUG("Get value %s", keypath);
+
+ rc = virFileReadAll(keypath, 1024, value);
+ if (rc < 0) {
+ DEBUG("Failed to read %s: %m\n", keypath);
+ rc = -errno;
+ } else {
+ rc = 0;
+ }
+
+ VIR_FREE(keypath);
+
+ return rc;
+}
+
+static int virCgroupSetValueU64(virCgroupPtr group,
+ int controller,
+ const char *key,
+ uint64_t value)
+{
+ char *strval = NULL;
+ int rc;
+
+ if (virAsprintf(&strval, "%" PRIu64, value) == -1)
+ return -ENOMEM;
+
+ rc = virCgroupSetValueStr(group, controller, key, strval);
+
+ VIR_FREE(strval);
+
+ return rc;
+}
+
+
+#if 0
+/* This is included for completeness, but not yet used */
+
+static int virCgroupSetValueI64(virCgroupPtr group,
+ int controller,
+ const char *key,
+ int64_t value)
+{
+ char *strval = NULL;
+ int rc;
+
+ if (virAsprintf(&strval, "%" PRIi64, value) == -1)
+ return -ENOMEM;
+
+ rc = virCgroupSetValueStr(group, controller, key, strval);
+
+ VIR_FREE(strval);
+
+ return rc;
+}
+
+static int virCgroupGetValueI64(virCgroupPtr group,
+ int controller,
+ const char *key,
+ int64_t *value)
+{
+ char *strval = NULL;
+ int rc = 0;
+
+ rc = virCgroupGetValueStr(group, controller, key, &strval);
+ if (rc != 0)
+ goto out;
+
+ if (sscanf(strval, "%" SCNi64, value) != 1)
+ rc = -EINVAL;
+out:
+ VIR_FREE(strval);
+
+ return rc;
+}
+#endif
+
+static int virCgroupGetValueU64(virCgroupPtr group,
+ int controller,
+ const char *key,
+ uint64_t *value)
+{
+ char *strval = NULL;
+ int rc = 0;
+
+ rc = virCgroupGetValueStr(group, controller, key, &strval);
+ if (rc != 0)
+ goto out;
+
+ if (sscanf(strval, "%" SCNu64, value) != 1)
+ rc = -EINVAL;
+out:
+ VIR_FREE(strval);
+
+ return rc;
+}
+
+
+static int virCgroupCpuSetInherit(virCgroupPtr parent, virCgroupPtr group)
+{
+ int i;
+ int rc = 0;
+ const char *inherit_values[] = {
+ "cpuset.cpus",
+ "cpuset.mems",
+ };
+
+ VIR_DEBUG("Setting up inheritance %s -> %s", parent->path, group->path);
+ for (i = 0; i < ARRAY_CARDINALITY(inherit_values) ; i++) {
+ char *value;
+
+ rc = virCgroupGetValueStr(parent,
+ VIR_CGROUP_CONTROLLER_CPUSET,
+ inherit_values[i],
+ &value);
+ if (rc != 0) {
+ VIR_ERROR("Failed to get %s %d", inherit_values[i], rc);
+ break;
+ }
+
+ VIR_DEBUG("Inherit %s = %s", inherit_values[i], value);
+
+ rc = virCgroupSetValueStr(group,
+ VIR_CGROUP_CONTROLLER_CPUSET,
+ inherit_values[i],
+ value);
+
+ if (rc != 0) {
+ VIR_ERROR("Failed to set %s %d", inherit_values[i], rc);
+ break;
+ }
+ }
+
+ return rc;
+}
+
+static int virCgroupMakeGroup(virCgroupPtr parent, virCgroupPtr group)
+{
+ int i;
+ int rc = 0;
+
+ VIR_DEBUG("Make group %s", group->path);
+ for (i = 0 ; i < VIR_CGROUP_CONTROLLER_LAST ; i++) {
+ char *path = NULL;
+
+ /* Skip over controllers that aren't mounted */
+ if (!group->controllers[i].mountPoint)
+ continue;
+
+ rc = virCgroupPathOfController(group, i, "", &path);
+ if (rc < 0)
+ return rc;
+
+ VIR_DEBUG("Make controller %s", path);
+ if (access(path, F_OK) != 0) {
+ if (mkdir(path, 0755) < 0) {
+ rc = -errno;
+ VIR_FREE(path);
+ break;
+ }
+ if (group->controllers[VIR_CGROUP_CONTROLLER_CPUSET].mountPoint != NULL &&
+ (i == VIR_CGROUP_CONTROLLER_CPUSET ||
+ STREQ(group->controllers[i].mountPoint, group->controllers[VIR_CGROUP_CONTROLLER_CPUSET].mountPoint))) {
+ rc = virCgroupCpuSetInherit(parent, group);
+ if (rc != 0)
+ break;
+ }
+ }
+
+ VIR_FREE(path);
+ }
+
+ return rc;
+}
+
+
+static int virCgroupNew(const char *path,
+ virCgroupPtr *group)
+{
+ int rc = 0;
+ char *typpath = NULL;
+
+ VIR_DEBUG("New group %s", path);
+ *group = NULL;
+
+ if (VIR_ALLOC((*group)) != 0) {
+ rc = -ENOMEM;
+ goto err;
+ }
+
+ if (!((*group)->path = strdup(path))) {
+ rc = -ENOMEM;
+ goto err;
+ }
+
+ rc = virCgroupDetect(*group);
+ if (rc < 0)
+ goto err;
+
+ return rc;
+err:
+ virCgroupFree(group);
+ *group = NULL;
+
+ VIR_FREE(typpath);
+
+ return rc;
+}
+
+static int virCgroupAppRoot(int privileged,
+ virCgroupPtr *group)
+{
+ virCgroupPtr rootgrp = NULL;
+ int rc;
+
+ rc = virCgroupNew("/", &rootgrp);
+ if (rc != 0)
+ return rc;
+
+ if (privileged) {
+ rc = virCgroupNew("/libvirt", group);
+ } else {
+ char *rootname;
+ char *username;
+ username = virGetUserName(NULL, getuid());
+ if (!username) {
+ rc = -ENOMEM;
+ goto cleanup;
+ }
+ rc = virAsprintf(&rootname, "/libvirt-%s", username);
+ VIR_FREE(username);
+ if (rc < 0) {
+ rc = -ENOMEM;
+ goto cleanup;
+ }
+
+ rc = virCgroupNew(rootname, group);
+ VIR_FREE(rootname);
+ }
+ if (rc != 0)
+ goto cleanup;
+
+ rc = virCgroupMakeGroup(rootgrp, *group);
+
+cleanup:
+ virCgroupFree(&rootgrp);
+ return rc;
+}
+
+
+/**
+ * virCgroupRemove:
+ *
+ * @group: The group to be removed
+ *
+ * Returns: 0 on success
+ */
+int virCgroupRemove(virCgroupPtr group)
+{
+ int rc = 0;
+ int i;
+ char *grppath = NULL;
+
+ for (i = 0 ; i < VIR_CGROUP_CONTROLLER_LAST ; i++) {
+ /* Skip over controllers not mounted */
+ if (!group->controllers[i].mountPoint)
+ continue;
+
+ if (virCgroupPathOfController(group,
+ i,
+ NULL,
+ &grppath) != 0)
+ continue;
+
+ DEBUG("Removing cgroup %s", grppath);
+ if (rmdir(grppath) != 0 && errno != ENOENT) {
+ rc = -errno;
+ }
+ VIR_FREE(grppath);
+ }
+
+ return rc;
+}
+
+/**
+ * virCgroupAddTask:
+ *
+ * @group: The cgroup to add a task to
+ * @pid: The pid of the task to add
+ *
+ * Returns: 0 on success
+ */
+int virCgroupAddTask(virCgroupPtr group, pid_t pid)
+{
+ int rc = 0;
+ int i;
+
+ for (i = 0 ; i < VIR_CGROUP_CONTROLLER_LAST ; i++) {
+ /* Skip over controllers not mounted */
+ if (!group->controllers[i].mountPoint)
+ continue;
+
+ rc = virCgroupSetValueU64(group, i, "tasks", (unsigned long long)pid);
+ if (rc != 0)
+ break;
+ }
+
+ return rc;
+}
+
+
+/**
+ * virCgroupForDriver:
+ *
+ * @name: name of this driver (e.g., xen, qemu, lxc)
+ * @group: Pointer to returned virCgroupPtr
+ *
+ * Returns 0 on success
+ */
+int virCgroupForDriver(const char *name,
+ virCgroupPtr *group,
+ int privileged,
+ int create)
+{
+ int rc;
+ char *path = NULL;
+ virCgroupPtr rootgrp = NULL;
+
+ rc = virCgroupAppRoot(privileged, &rootgrp);
+ if (rc != 0)
+ goto out;
+
+ if (virAsprintf(&path, "%s/%s", rootgrp->path, name) < 0) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ rc = virCgroupNew(path, group);
+ VIR_FREE(path);
+
+ if (rc == 0 &&
+ create) {
+ rc = virCgroupMakeGroup(rootgrp, *group);
+ if (rc != 0)
+ virCgroupFree(group);
+ }
+
+out:
+ virCgroupFree(&rootgrp);
+
+ return rc;
+}
+
+
+/**
+ * virCgroupForDomain:
+ *
+ * @driver: group for driver owning the domain
+ * @name: name of the domain
+ * @group: Pointer to returned virCgroupPtr
+ *
+ * Returns 0 on success
+ */
+int virCgroupForDomain(virCgroupPtr driver,
+ const char *name,
+ virCgroupPtr *group,
+ int create)
+{
+ int rc;
+ char *path;
+
+ if (virAsprintf(&path, "%s/%s", driver->path, name) < 0)
+ return -ENOMEM;
+
+ rc = virCgroupNew(path, group);
+ VIR_FREE(path);
+
+ if (rc == 0 &&
+ create) {
+ rc = virCgroupMakeGroup(driver, *group);
+ if (rc != 0)
+ virCgroupFree(group);
+ }
+
+ return rc;
+}
+
+/**
+ * virCgroupSetMemory:
+ *
+ * @group: The cgroup to change memory for
+ * @kb: The memory amount in kilobytes
+ *
+ * Returns: 0 on success
+ */
+int virCgroupSetMemory(virCgroupPtr group, unsigned long kb)
+{
+ return virCgroupSetValueU64(group,
+ VIR_CGROUP_CONTROLLER_MEMORY,
+ "memory.limit_in_bytes",
+ kb << 10);
+}
+
+/**
+ * virCgroupDenyAllDevices:
+ *
+ * @group: The cgroup to deny devices for
+ *
+ * Returns: 0 on success
+ */
+int virCgroupDenyAllDevices(virCgroupPtr group)
+{
+ return virCgroupSetValueStr(group,
+ VIR_CGROUP_CONTROLLER_DEVICES,
+ "devices.deny",
+ "a");
+}
+
+/**
+ * virCgroupAllowDevice:
+ *
+ * @group: The cgroup to allow a device for
+ * @type: The device type (i.e., 'c' or 'b')
+ * @major: The major number of the device
+ * @minor: The minor number of the device
+ *
+ * Returns: 0 on success
+ */
+int virCgroupAllowDevice(virCgroupPtr group, char type, int major, int minor)
+{
+ int rc;
+ char *devstr = NULL;
+
+ if (virAsprintf(&devstr, "%c %i:%i rwm", type, major, minor) == -1) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ rc = virCgroupSetValueStr(group,
+ VIR_CGROUP_CONTROLLER_DEVICES,
+ "devices.allow",
+ devstr);
+out:
+ VIR_FREE(devstr);
+
+ return rc;
+}
+
+/**
+ * virCgroupAllowDeviceMajor:
+ *
+ * @group: The cgroup to allow an entire device major type for
+ * @type: The device type (i.e., 'c' or 'b')
+ * @major: The major number of the device type
+ *
+ * Returns: 0 on success
+ */
+int virCgroupAllowDeviceMajor(virCgroupPtr group, char type, int major)
+{
+ int rc;
+ char *devstr = NULL;
+
+ if (virAsprintf(&devstr, "%c %i:* rwm", type, major) == -1) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ rc = virCgroupSetValueStr(group,
+ VIR_CGROUP_CONTROLLER_DEVICES,
+ "devices.allow",
+ devstr);
+ out:
+ VIR_FREE(devstr);
+
+ return rc;
+}
+
+/**
+ * virCgroupAllowDevicePath:
+ *
+ * @group: The cgroup to allow the device for
+ * @path: the device to allow
+ *
+ * Queries the type of device and its major/minor number, and
+ * adds that to the cgroup ACL
+ *
+ * Returns: 0 on success
+ */
+int virCgroupAllowDevicePath(virCgroupPtr group, const char *path)
+{
+ struct stat sb;
+
+ if (stat(path, &sb) < 0)
+ return -errno;
+
+ if (!S_ISCHR(sb.st_mode) && !S_ISBLK(sb.st_mode))
+ return -EINVAL;
+
+ return virCgroupAllowDevice(group,
+ S_ISCHR(sb.st_mode) ? 'c' : 'b',
+ major(sb.st_rdev),
+ minor(sb.st_rdev));
+}
+
+/**
+ * virCgroupDenyDevice:
+ *
+ * @group: The cgroup to deny a device for
+ * @type: The device type (i.e., 'c' or 'b')
+ * @major: The major number of the device
+ * @minor: The minor number of the device
+ *
+ * Returns: 0 on success
+ */
+int virCgroupDenyDevice(virCgroupPtr group, char type, int major, int minor)
+{
+ int rc;
+ char *devstr = NULL;
+
+ if (virAsprintf(&devstr, "%c %i:%i rwm", type, major, minor) == -1) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ rc = virCgroupSetValueStr(group,
+ VIR_CGROUP_CONTROLLER_DEVICES,
+ "devices.deny",
+ devstr);
+out:
+ VIR_FREE(devstr);
+
+ return rc;
+}
+
+/**
+ * virCgroupDenyDeviceMajor:
+ *
+ * @group: The cgroup to deny an entire device major type for
+ * @type: The device type (i.e., 'c' or 'b')
+ * @major: The major number of the device type
+ *
+ * Returns: 0 on success
+ */
+int virCgroupDenyDeviceMajor(virCgroupPtr group, char type, int major)
+{
+ int rc;
+ char *devstr = NULL;
+
+ if (virAsprintf(&devstr, "%c %i:* rwm", type, major) == -1) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ rc = virCgroupSetValueStr(group,
+ VIR_CGROUP_CONTROLLER_DEVICES,
+ "devices.deny",
+ devstr);
+ out:
+ VIR_FREE(devstr);
+
+ return rc;
+}
+
+int virCgroupDenyDevicePath(virCgroupPtr group, const char *path)
+{
+ struct stat sb;
+
+ if (stat(path, &sb) < 0)
+ return -errno;
+
+ if (!S_ISCHR(sb.st_mode) && !S_ISBLK(sb.st_mode))
+ return -EINVAL;
+
+ return virCgroupDenyDevice(group,
+ S_ISCHR(sb.st_mode) ? 'c' : 'b',
+ major(sb.st_rdev),
+ minor(sb.st_rdev));
+}
+
+int virCgroupSetCpuShares(virCgroupPtr group, unsigned long long shares)
+{
+ return virCgroupSetValueU64(group,
+ VIR_CGROUP_CONTROLLER_CPU,
+ "cpu.shares", (uint64_t)shares);
+}
+
+int virCgroupGetCpuShares(virCgroupPtr group, unsigned long long *shares)
+{
+ return virCgroupGetValueU64(group,
+ VIR_CGROUP_CONTROLLER_CPU,
+ "cpu.shares", (uint64_t *)shares);
+}
+
+int virCgroupGetCpuacctUsage(virCgroupPtr group, unsigned long long *usage)
+{
+ return virCgroupGetValueU64(group,
+ VIR_CGROUP_CONTROLLER_CPUACCT,
+ "cpuacct.usage", (uint64_t *)usage);
+}
--- /dev/null
+/*
+ * cgroup.h: Interface to tools for managing cgroups
+ *
+ * Copyright IBM Corp. 2008
+ *
+ * See COPYING.LIB for the License of this software
+ *
+ * Authors:
+ * Dan Smith <danms@us.ibm.com>
+ */
+
+#ifndef CGROUP_H
+#define CGROUP_H
+
+struct virCgroup;
+typedef struct virCgroup *virCgroupPtr;
+
+enum {
+ VIR_CGROUP_CONTROLLER_CPU,
+ VIR_CGROUP_CONTROLLER_CPUACCT,
+ VIR_CGROUP_CONTROLLER_CPUSET,
+ VIR_CGROUP_CONTROLLER_MEMORY,
+ VIR_CGROUP_CONTROLLER_DEVICES,
+
+ VIR_CGROUP_CONTROLLER_LAST
+};
+
+VIR_ENUM_DECL(virCgroupController);
+
+int virCgroupForDriver(const char *name,
+ virCgroupPtr *group,
+ int privileged,
+ int create);
+
+int virCgroupForDomain(virCgroupPtr driver,
+ const char *name,
+ virCgroupPtr *group,
+ int create);
+
+int virCgroupAddTask(virCgroupPtr group, pid_t pid);
+
+int virCgroupSetMemory(virCgroupPtr group, unsigned long kb);
+
+int virCgroupDenyAllDevices(virCgroupPtr group);
+
+int virCgroupAllowDevice(virCgroupPtr group,
+ char type,
+ int major,
+ int minor);
+int virCgroupAllowDeviceMajor(virCgroupPtr group,
+ char type,
+ int major);
+int virCgroupAllowDevicePath(virCgroupPtr group,
+ const char *path);
+
+int virCgroupDenyDevice(virCgroupPtr group,
+ char type,
+ int major,
+ int minor);
+int virCgroupDenyDeviceMajor(virCgroupPtr group,
+ char type,
+ int major);
+int virCgroupDenyDevicePath(virCgroupPtr group,
+ const char *path);
+
+int virCgroupSetCpuShares(virCgroupPtr group, unsigned long long shares);
+int virCgroupGetCpuShares(virCgroupPtr group, unsigned long long *shares);
+
+int virCgroupGetCpuacctUsage(virCgroupPtr group, unsigned long long *usage);
+
+int virCgroupRemove(virCgroupPtr group);
+
+void virCgroupFree(virCgroupPtr *group);
+
+#endif /* CGROUP_H */
--- /dev/null
+/**
+ * conf.c: parser for a subset of the Python encoded Xen configuration files
+ *
+ * Copyright (C) 2006, 2007, 2008, 2009 Red Hat, Inc.
+ *
+ * See COPYING.LIB for the License of this software
+ *
+ * Daniel Veillard <veillard@redhat.com>
+ */
+
+#include <config.h>
+
+#include <string.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "virterror_internal.h"
+#include "buf.h"
+#include "conf.h"
+#include "util.h"
+#include "c-ctype.h"
+#include "memory.h"
+
+#define VIR_FROM_THIS VIR_FROM_CONF
+
+/************************************************************************
+ * *
+ * Structures and macros used by the mini parser *
+ * *
+ ************************************************************************/
+
+typedef struct _virConfParserCtxt virConfParserCtxt;
+typedef virConfParserCtxt *virConfParserCtxtPtr;
+
+struct _virConfParserCtxt {
+ const char* filename;
+ const char* base;
+ const char* cur;
+ const char *end;
+ int line;
+
+ virConfPtr conf;
+};
+
+#define CUR (*ctxt->cur)
+#define NEXT if (ctxt->cur < ctxt->end) ctxt->cur++;
+#define IS_EOL(c) (((c) == '\n') || ((c) == '\r'))
+
+#define SKIP_BLANKS_AND_EOL \
+ do { while ((ctxt->cur < ctxt->end) && (c_isblank(CUR) || IS_EOL(CUR))) { \
+ if (CUR == '\n') ctxt->line++; \
+ ctxt->cur++;}} while (0)
+#define SKIP_BLANKS \
+ do { while ((ctxt->cur < ctxt->end) && (c_isblank(CUR))) \
+ ctxt->cur++; } while (0)
+
+/************************************************************************
+ * *
+ * Structures used by configuration data *
+ * *
+ ************************************************************************/
+
+typedef struct _virConfEntry virConfEntry;
+typedef virConfEntry *virConfEntryPtr;
+
+struct _virConfEntry {
+ virConfEntryPtr next;
+ char* name;
+ char* comment;
+ virConfValuePtr value;
+};
+
+struct _virConf {
+ const char* filename;
+ unsigned int flags;
+ virConfEntryPtr entries;
+};
+
+/**
+ * virConfError:
+ * @ctxt: the parser context if available or NULL
+ * @error: the error number
+ * @info: extra information string
+ *
+ * Handle an error at the xend daemon interface
+ */
+static void
+virConfError(virConfParserCtxtPtr ctxt,
+ virErrorNumber error, const char *info)
+{
+ const char *format;
+
+ if (error == VIR_ERR_OK)
+ return;
+
+ /* Construct the string 'filename:line: info' if we have that. */
+ if (ctxt && ctxt->filename) {
+ virRaiseError(NULL, NULL, NULL, VIR_FROM_CONF, error, VIR_ERR_ERROR,
+ info, ctxt->filename, NULL,
+ ctxt->line, 0,
+ "%s:%d: %s", ctxt->filename, ctxt->line, info);
+ } else {
+ format = virErrorMsg(error, info);
+ virRaiseError(NULL, NULL, NULL, VIR_FROM_CONF, error, VIR_ERR_ERROR,
+ info, NULL, NULL,
+ ctxt ? ctxt->line : 0, 0,
+ format, info);
+ }
+}
+
+
+/************************************************************************
+ * *
+ * Structures allocations and deallocations *
+ * *
+ ************************************************************************/
+
+/**
+ * virConfFreeList:
+ * @list: the list to free
+ *
+ * Free a list
+ */
+static void
+virConfFreeList(virConfValuePtr list)
+{
+ virConfValuePtr next;
+
+ while (list != NULL) {
+ next = list->next;
+ list->next = NULL;
+ virConfFreeValue(list);
+ list = next;
+ }
+}
+
+/**
+ * virConfFreeValue:
+ * @val: the value to free
+ *
+ * Free a value
+ */
+void
+virConfFreeValue(virConfValuePtr val)
+{
+ if (val == NULL)
+ return;
+ if (val->type == VIR_CONF_STRING &&
+ val->str != NULL)
+ VIR_FREE(val->str);
+ if (val->type == VIR_CONF_LIST &&
+ val->list != NULL)
+ virConfFreeList(val->list);
+ VIR_FREE(val);
+}
+
+virConfPtr
+virConfNew(void)
+{
+ virConfPtr ret;
+
+ if (VIR_ALLOC(ret) < 0) {
+ virReportOOMError(NULL);
+ return(NULL);
+ }
+ ret->filename = NULL;
+ ret->flags = 0;
+
+ return(ret);
+}
+
+/**
+ * virConfCreate:
+ * @filename: the name to report errors
+ * @flags: combination of virConfFlag(s)
+ *
+ * Create a configuration internal structure
+ *
+ * Returns a pointer or NULL in case of error.
+ */
+static virConfPtr
+virConfCreate(const char *filename, unsigned int flags)
+{
+ virConfPtr ret = virConfNew();
+ if (ret) {
+ ret->filename = filename;
+ ret->flags = flags;
+ }
+ return(ret);
+}
+
+/**
+ * virConfAddEntry:
+ * @conf: the conf structure
+ * @name: name of the entry or NULL for comment
+ * @value: the value if any
+ * @comm: extra comment for that entry if any
+ *
+ * add one entry to the conf, the parameters are included in the conf
+ * if successful and freed on virConfFree()
+ *
+ * Returns a pointer to the entry or NULL in case of failure
+ */
+static virConfEntryPtr
+virConfAddEntry(virConfPtr conf, char *name, virConfValuePtr value, char *comm)
+{
+ virConfEntryPtr ret, prev;
+
+ if (conf == NULL)
+ return(NULL);
+ if ((comm == NULL) && (name == NULL))
+ return(NULL);
+
+ if (VIR_ALLOC(ret) < 0) {
+ virReportOOMError(NULL);
+ return(NULL);
+ }
+
+ ret->name = name;
+ ret->value = value;
+ ret->comment = comm;
+
+ if (conf->entries == NULL) {
+ conf->entries = ret;
+ } else {
+ prev = conf->entries;
+ while (prev->next != NULL)
+ prev = prev->next;
+ prev->next = ret;
+ }
+ return(ret);
+}
+
+/************************************************************************
+ * *
+ * Serialization *
+ * *
+ ************************************************************************/
+
+/**
+ * virConfSaveValue:
+ * @buf: output buffer
+ * @val: a value
+ *
+ * Serialize the value to the buffer
+ *
+ * Returns 0 in case of success, -1 in case of error.
+ */
+static int
+virConfSaveValue(virBufferPtr buf, virConfValuePtr val)
+{
+ if (val == NULL)
+ return(-1);
+ switch (val->type) {
+ case VIR_CONF_NONE:
+ return(-1);
+ case VIR_CONF_LONG:
+ virBufferVSprintf(buf, "%ld", val->l);
+ break;
+ case VIR_CONF_STRING:
+ if (strchr(val->str, '\n') != NULL) {
+ virBufferVSprintf(buf, "\"\"\"%s\"\"\"", val->str);
+ } else if (strchr(val->str, '"') == NULL) {
+ virBufferVSprintf(buf, "\"%s\"", val->str);
+ } else if (strchr(val->str, '\'') == NULL) {
+ virBufferVSprintf(buf, "'%s'", val->str);
+ } else {
+ virBufferVSprintf(buf, "\"\"\"%s\"\"\"", val->str);
+ }
+ break;
+ case VIR_CONF_LIST: {
+ virConfValuePtr cur;
+
+ cur = val->list;
+ virBufferAddLit(buf, "[ ");
+ if (cur != NULL) {
+ virConfSaveValue(buf, cur);
+ cur = cur->next;
+ while (cur != NULL) {
+ virBufferAddLit(buf, ", ");
+ virConfSaveValue(buf, cur);
+ cur = cur->next;
+ }
+ }
+ virBufferAddLit(buf, " ]");
+ break;
+ }
+ default:
+ return(-1);
+ }
+ return(0);
+}
+
+/**
+ * virConfSaveEntry:
+ * @buf: output buffer
+ * @cur: a conf entry
+ *
+ * Serialize the entry to the buffer
+ *
+ * Returns 0 in case of success, -1 in case of error.
+ */
+static int
+virConfSaveEntry(virBufferPtr buf, virConfEntryPtr cur)
+{
+ if (cur->name != NULL) {
+ virBufferAdd(buf, cur->name, -1);
+ virBufferAddLit(buf, " = ");
+ virConfSaveValue(buf, cur->value);
+ if (cur->comment != NULL) {
+ virBufferAddLit(buf, " #");
+ virBufferAdd(buf, cur->comment, -1);
+ }
+ } else if (cur->comment != NULL) {
+ virBufferAddLit(buf, "#");
+ virBufferAdd(buf, cur->comment, -1);
+ }
+ virBufferAddLit(buf, "\n");
+ return(0);
+}
+
+/************************************************************************
+ * *
+ * The parser core *
+ * *
+ ************************************************************************/
+
+/**
+ * virConfParseLong:
+ * @ctxt: the parsing context
+ * @val: the result
+ *
+ * Parse one long int value
+ *
+ * Returns 0 in case of success and -1 in case of error
+ */
+static int
+virConfParseLong(virConfParserCtxtPtr ctxt, long *val)
+{
+ long l = 0;
+ int neg = 0;
+
+ if (CUR == '-') {
+ neg = 1;
+ NEXT;
+ } else if (CUR == '+') {
+ NEXT;
+ }
+ if ((ctxt->cur >= ctxt->end) || (!c_isdigit(CUR))) {
+ virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated number"));
+ return(-1);
+ }
+ while ((ctxt->cur < ctxt->end) && (c_isdigit(CUR))) {
+ l = l * 10 + (CUR - '0');
+ NEXT;
+ }
+ if (neg)
+ l = -l;
+ *val = l;
+ return(0);
+}
+
+/**
+ * virConfParseString:
+ * @ctxt: the parsing context
+ *
+ * Parse one string
+ *
+ * Returns a pointer to the string or NULL in case of error
+ */
+static char *
+virConfParseString(virConfParserCtxtPtr ctxt)
+{
+ const char *base;
+ char *ret = NULL;
+
+ if (CUR == '\'') {
+ NEXT;
+ base = ctxt->cur;
+ while ((ctxt->cur < ctxt->end) && (CUR != '\'') && (!IS_EOL(CUR)))
+ NEXT;
+ if (CUR != '\'') {
+ virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated string"));
+ return(NULL);
+ }
+ ret = strndup(base, ctxt->cur - base);
+ NEXT;
+ } else if ((ctxt->cur + 6 < ctxt->end) && (ctxt->cur[0] == '"') &&
+ (ctxt->cur[1] == '"') && (ctxt->cur[2] == '"')) {
+ ctxt->cur += 3;
+ base = ctxt->cur;
+ while ((ctxt->cur + 2 < ctxt->end) && (ctxt->cur[0] == '"') &&
+ (ctxt->cur[1] == '"') && (ctxt->cur[2] == '"')) {
+ if (CUR == '\n') ctxt->line++;
+ NEXT;
+ }
+ if ((ctxt->cur[0] != '"') || (ctxt->cur[1] != '"') ||
+ (ctxt->cur[2] != '"')) {
+ virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated string"));
+ return(NULL);
+ }
+ ret = strndup(base, ctxt->cur - base);
+ ctxt->cur += 3;
+ } else if (CUR == '"') {
+ NEXT;
+ base = ctxt->cur;
+ while ((ctxt->cur < ctxt->end) && (CUR != '"') && (!IS_EOL(CUR)))
+ NEXT;
+ if (CUR != '"') {
+ virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated string"));
+ return(NULL);
+ }
+ ret = strndup(base, ctxt->cur - base);
+ NEXT;
+ }
+ return(ret);
+}
+
+/**
+ * virConfParseValue:
+ * @ctxt: the parsing context
+ *
+ * Parse one value
+ *
+ * Returns a pointer to the value or NULL in case of error
+ */
+static virConfValuePtr
+virConfParseValue(virConfParserCtxtPtr ctxt)
+{
+ virConfValuePtr ret, lst = NULL, tmp, prev;
+ virConfType type = VIR_CONF_NONE;
+ char *str = NULL;
+ long l = 0;
+
+ SKIP_BLANKS;
+ if (ctxt->cur >= ctxt->end) {
+ virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting a value"));
+ return(NULL);
+ }
+ if ((CUR == '"') || (CUR == '\'')) {
+ type = VIR_CONF_STRING;
+ str = virConfParseString(ctxt);
+ if (str == NULL)
+ return(NULL);
+ } else if (CUR == '[') {
+ if (ctxt->conf->flags & VIR_CONF_FLAG_VMX_FORMAT) {
+ virConfError(ctxt, VIR_ERR_CONF_SYNTAX,
+ _("lists not allowed in VMX format"));
+ return(NULL);
+ }
+ type = VIR_CONF_LIST;
+ NEXT;
+ SKIP_BLANKS_AND_EOL;
+ if ((ctxt->cur < ctxt->end) && (CUR != ']')) {
+ if ((lst = virConfParseValue(ctxt)) == NULL)
+ return(NULL);
+ SKIP_BLANKS_AND_EOL;
+ }
+ while ((ctxt->cur < ctxt->end) && (CUR != ']')) {
+ if (CUR != ',') {
+ virConfError(ctxt, VIR_ERR_CONF_SYNTAX,
+ _("expecting a separator in list"));
+ virConfFreeList(lst);
+ return(NULL);
+ }
+ NEXT;
+ SKIP_BLANKS_AND_EOL;
+ if (CUR == ']') {
+ break;
+ }
+ tmp = virConfParseValue(ctxt);
+ if (tmp == NULL) {
+ virConfFreeList(lst);
+ return(NULL);
+ }
+ prev = lst;
+ while (prev->next != NULL) prev = prev->next;
+ prev->next = tmp;
+ SKIP_BLANKS_AND_EOL;
+ }
+ if (CUR == ']') {
+ NEXT;
+ } else {
+ virConfError(ctxt, VIR_ERR_CONF_SYNTAX,
+ _("list is not closed with ]"));
+ virConfFreeList(lst);
+ return(NULL);
+ }
+ } else if (c_isdigit(CUR) || (CUR == '-') || (CUR == '+')) {
+ if (ctxt->conf->flags & VIR_CONF_FLAG_VMX_FORMAT) {
+ virConfError(ctxt, VIR_ERR_CONF_SYNTAX,
+ _("numbers not allowed in VMX format"));
+ return(NULL);
+ }
+ if (virConfParseLong(ctxt, &l) < 0) {
+ return(NULL);
+ }
+ type = VIR_CONF_LONG;
+ } else {
+ virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting a value"));
+ return(NULL);
+ }
+ if (VIR_ALLOC(ret) < 0) {
+ virReportOOMError(NULL);
+ virConfFreeList(lst);
+ VIR_FREE(str);
+ return(NULL);
+ }
+ ret->type = type;
+ ret->l = l;
+ ret->str = str;
+ ret->list = lst;
+ return(ret);
+}
+
+/**
+ * virConfParseName:
+ * @ctxt: the parsing context
+ *
+ * Parse one name
+ *
+ * Returns a copy of the new string, NULL in case of error
+ */
+static char *
+virConfParseName(virConfParserCtxtPtr ctxt)
+{
+ const char *base;
+ char *ret;
+
+ SKIP_BLANKS;
+ base = ctxt->cur;
+ /* TODO: probably need encoding support and UTF-8 parsing ! */
+ if (!c_isalpha(CUR) &&
+ !((ctxt->conf->flags & VIR_CONF_FLAG_VMX_FORMAT) && (CUR == '.'))) {
+ virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting a name"));
+ return(NULL);
+ }
+ while ((ctxt->cur < ctxt->end) &&
+ (c_isalnum(CUR) || (CUR == '_') ||
+ ((ctxt->conf->flags & VIR_CONF_FLAG_VMX_FORMAT) &&
+ ((CUR == ':') || (CUR == '.')))))
+ NEXT;
+ ret = strndup(base, ctxt->cur - base);
+ if (ret == NULL) {
+ virReportOOMError(NULL);
+ return(NULL);
+ }
+ return(ret);
+}
+
+/**
+ * virConfParseComment:
+ * @ctxt: the parsing context
+ *
+ * Parse one standalone comment in the configuration file
+ *
+ * Returns 0 in case of success and -1 in case of error
+ */
+static int
+virConfParseComment(virConfParserCtxtPtr ctxt)
+{
+ const char *base;
+ char *comm;
+
+ if (CUR != '#')
+ return(-1);
+ NEXT;
+ base = ctxt->cur;
+ while ((ctxt->cur < ctxt->end) && (!IS_EOL(CUR))) NEXT;
+ comm = strndup(base, ctxt->cur - base);
+ if (comm == NULL) {
+ virReportOOMError(NULL);
+ return(-1);
+ }
+ virConfAddEntry(ctxt->conf, NULL, NULL, comm);
+ return(0);
+}
+
+/**
+ * virConfParseSeparator:
+ * @ctxt: the parsing context
+ *
+ * Parse one separator between statement if not at the end.
+ *
+ * Returns 0 in case of success and -1 in case of error
+ */
+static int
+virConfParseSeparator(virConfParserCtxtPtr ctxt)
+{
+ SKIP_BLANKS;
+ if (ctxt->cur >= ctxt->end)
+ return(0);
+ if (IS_EOL(CUR)) {
+ SKIP_BLANKS_AND_EOL;
+ } else if (CUR == ';') {
+ NEXT;
+ SKIP_BLANKS_AND_EOL;
+ } else {
+ virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting a separator"));
+ return(-1);
+ }
+ return(0);
+}
+
+/**
+ * virConfParseStatement:
+ * @ctxt: the parsing context
+ *
+ * Parse one statement in the conf file
+ *
+ * Returns 0 in case of success and -1 in case of error
+ */
+static int
+virConfParseStatement(virConfParserCtxtPtr ctxt)
+{
+ const char *base;
+ char *name;
+ virConfValuePtr value;
+ char *comm = NULL;
+
+ SKIP_BLANKS_AND_EOL;
+ if (CUR == '#') {
+ return(virConfParseComment(ctxt));
+ }
+ name = virConfParseName(ctxt);
+ if (name == NULL)
+ return(-1);
+ SKIP_BLANKS;
+ if (CUR != '=') {
+ virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting an assignment"));
+ return(-1);
+ }
+ NEXT;
+ SKIP_BLANKS;
+ value = virConfParseValue(ctxt);
+ if (value == NULL) {
+ VIR_FREE(name);
+ return(-1);
+ }
+ SKIP_BLANKS;
+ if (CUR == '#') {
+ NEXT;
+ base = ctxt->cur;
+ while ((ctxt->cur < ctxt->end) && (!IS_EOL(CUR))) NEXT;
+ comm = strndup(base, ctxt->cur - base);
+ if (comm == NULL) {
+ virReportOOMError(NULL);
+ VIR_FREE(name);
+ virConfFreeValue(value);
+ return(-1);
+ }
+ }
+ if (virConfAddEntry(ctxt->conf, name, value, comm) == NULL) {
+ VIR_FREE(name);
+ virConfFreeValue(value);
+ VIR_FREE(comm);
+ return(-1);
+ }
+ return(0);
+}
+
+/**
+ * virConfParse:
+ * @filename: the name to report errors
+ * @content: the configuration content in memory
+ * @len: the length in bytes
+ * @flags: combination of virConfFlag(s)
+ *
+ * Parse the subset of the Python language needed to handle simple
+ * Xen configuration files.
+ *
+ * Returns an handle to lookup settings or NULL if it failed to
+ * read or parse the file, use virConfFree() to free the data.
+ */
+static virConfPtr
+virConfParse(const char *filename, const char *content, int len,
+ unsigned int flags) {
+ virConfParserCtxt ctxt;
+
+ ctxt.filename = filename;
+ ctxt.base = ctxt.cur = content;
+ ctxt.end = content + len - 1;
+ ctxt.line = 1;
+
+ ctxt.conf = virConfCreate(filename, flags);
+ if (ctxt.conf == NULL)
+ return(NULL);
+
+ while (ctxt.cur < ctxt.end) {
+ if (virConfParseStatement(&ctxt) < 0)
+ goto error;
+ if (virConfParseSeparator(&ctxt) < 0)
+ goto error;
+ }
+
+ return(ctxt.conf);
+
+error:
+ virConfFree(ctxt.conf);
+ return(NULL);
+}
+
+/************************************************************************
+ * *
+ * The module entry points *
+ * *
+ ************************************************************************/
+
+/* 10 MB limit on config file size as a sanity check */
+#define MAX_CONFIG_FILE_SIZE (1024*1024*10)
+
+/**
+ * virConfReadFile:
+ * @filename: the path to the configuration file.
+ * @flags: combination of virConfFlag(s)
+ *
+ * Reads a configuration file.
+ *
+ * Returns an handle to lookup settings or NULL if it failed to
+ * read or parse the file, use virConfFree() to free the data.
+ */
+virConfPtr
+virConfReadFile(const char *filename, unsigned int flags)
+{
+ char *content;
+ int len;
+ virConfPtr conf;
+
+ if (filename == NULL) {
+ virConfError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ return(NULL);
+ }
+
+ if ((len = virFileReadAll(filename, MAX_CONFIG_FILE_SIZE, &content)) < 0) {
+ return NULL;
+ }
+
+ conf = virConfParse(filename, content, len, flags);
+
+ VIR_FREE(content);
+
+ return conf;
+}
+
+/**
+ * virConfReadMem:
+ * @memory: pointer to the content of the configuration file
+ * @len: length in byte
+ * @flags: combination of virConfFlag(s)
+ *
+ * Reads a configuration file loaded in memory. The string can be
+ * zero terminated in which case @len can be 0
+ *
+ * Returns an handle to lookup settings or NULL if it failed to
+ * parse the content, use virConfFree() to free the data.
+ */
+virConfPtr
+virConfReadMem(const char *memory, int len, unsigned int flags)
+{
+ if ((memory == NULL) || (len < 0)) {
+ virConfError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ return(NULL);
+ }
+ if (len == 0)
+ len = strlen(memory);
+
+ return(virConfParse("memory conf", memory, len, flags));
+}
+
+/**
+ * virConfFree:
+ * @conf: a configuration file handle
+ *
+ * Frees all data associated to the handle
+ *
+ * Returns 0 in case of success, -1 in case of error.
+ */
+int
+virConfFree(virConfPtr conf)
+{
+ virConfEntryPtr tmp;
+ if (conf == NULL) {
+ virConfError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ return(-1);
+ }
+
+ tmp = conf->entries;
+ while (tmp) {
+ virConfEntryPtr next;
+ VIR_FREE(tmp->name);
+ virConfFreeValue(tmp->value);
+ VIR_FREE(tmp->comment);
+ next = tmp->next;
+ VIR_FREE(tmp);
+ tmp = next;
+ }
+ VIR_FREE(conf);
+ return(0);
+}
+
+/**
+ * virConfGetValue:
+ * @conf: a configuration file handle
+ * @entry: the name of the entry
+ *
+ * Lookup the value associated to this entry in the configuration file
+ *
+ * Returns a pointer to the value or NULL if the lookup failed, the data
+ * associated will be freed when virConfFree() is called
+ */
+virConfValuePtr
+virConfGetValue(virConfPtr conf, const char *setting)
+{
+ virConfEntryPtr cur;
+
+ cur = conf->entries;
+ while (cur != NULL) {
+ if ((cur->name != NULL) && (STREQ(cur->name, setting)))
+ return(cur->value);
+ cur = cur->next;
+ }
+ return(NULL);
+}
+
+/**
+ * virConfSetValue:
+ * @conf: a configuration file handle
+ * @entry: the name of the entry
+ * @value: the new configuration value
+ *
+ * Set (or replace) the value associated to this entry in the configuration
+ * file. The passed in 'value' will be owned by the conf object upon return
+ * of this method, even in case of error. It should not be referenced again
+ * by the caller.
+ *
+ * Returns 0 on success, or -1 on failure.
+ */
+int
+virConfSetValue (virConfPtr conf,
+ const char *setting,
+ virConfValuePtr value)
+{
+ virConfEntryPtr cur, prev = NULL;
+
+ cur = conf->entries;
+ while (cur != NULL) {
+ if ((cur->name != NULL) && (STREQ(cur->name, setting))) {
+ break;
+ }
+ prev = cur;
+ cur = cur->next;
+ }
+
+ if (!cur) {
+ if (VIR_ALLOC(cur) < 0) {
+ virConfFreeValue(value);
+ return (-1);
+ }
+ cur->comment = NULL;
+ if (!(cur->name = strdup(setting))) {
+ virConfFreeValue(value);
+ VIR_FREE(cur);
+ return (-1);
+ }
+ cur->value = value;
+ if (prev) {
+ cur->next = prev->next;
+ prev->next = cur;
+ } else {
+ cur->next = conf->entries;
+ conf->entries = cur;
+ }
+ } else {
+ if (cur->value) {
+ virConfFreeValue(cur->value);
+ }
+ cur->value = value;
+ }
+ return (0);
+}
+
+
+/**
+ * virConfWriteFile:
+ * @filename: the path to the configuration file.
+ * @conf: the conf
+ *
+ * Writes a configuration file back to a file.
+ *
+ * Returns the number of bytes written or -1 in case of error.
+ */
+int
+virConfWriteFile(const char *filename, virConfPtr conf)
+{
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ virConfEntryPtr cur;
+ int ret;
+ int fd;
+ char *content;
+ unsigned int use;
+
+ if (conf == NULL)
+ return(-1);
+
+ cur = conf->entries;
+ while (cur != NULL) {
+ virConfSaveEntry(&buf, cur);
+ cur = cur->next;
+ }
+
+ if (virBufferError(&buf)) {
+ virReportOOMError(NULL);
+ return -1;
+ }
+
+ fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR );
+ if (fd < 0) {
+ char *tmp = virBufferContentAndReset(&buf);
+ virConfError(NULL, VIR_ERR_WRITE_FAILED, _("failed to open file"));
+ VIR_FREE(tmp);
+ return -1;
+ }
+
+ use = virBufferUse(&buf);
+ content = virBufferContentAndReset(&buf);
+ ret = safewrite(fd, content, use);
+ VIR_FREE(content);
+ close(fd);
+ if (ret != (int)use) {
+ virConfError(NULL, VIR_ERR_WRITE_FAILED, _("failed to save content"));
+ return -1;
+ }
+
+ return ret;
+}
+
+/**
+ * virConfWriteMem:
+ * @memory: pointer to the memory to store the config file
+ * @len: pointer to the length in bytes of the store, on output the size
+ * @conf: the conf
+ *
+ * Writes a configuration file back to a memory area. @len is an IN/OUT
+ * parameter, it indicates the size available in bytes, and on output the
+ * size required for the configuration file (even if the call fails due to
+ * insufficient space).
+ *
+ * Returns the number of bytes written or -1 in case of error.
+ */
+int
+virConfWriteMem(char *memory, int *len, virConfPtr conf)
+{
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ virConfEntryPtr cur;
+ char *content;
+ unsigned int use;
+
+ if ((memory == NULL) || (len == NULL) || (*len <= 0) || (conf == NULL))
+ return(-1);
+
+ cur = conf->entries;
+ while (cur != NULL) {
+ virConfSaveEntry(&buf, cur);
+ cur = cur->next;
+ }
+
+ if (virBufferError(&buf)) {
+ virReportOOMError(NULL);
+ return -1;
+ }
+
+ use = virBufferUse(&buf);
+ content = virBufferContentAndReset(&buf);
+
+ if ((int)use >= *len) {
+ *len = (int)use;
+ VIR_FREE(content);
+ return -1;
+ }
+ memcpy(memory, content, use);
+ VIR_FREE(content);
+ *len = use;
+ return use;
+}
--- /dev/null
+/**
+ * conf.h: parser for a subset of the Python encoded Xen configuration files
+ *
+ * Copyright (C) 2006, 2007 Red Hat, Inc.
+ *
+ * See COPYING.LIB for the License of this software
+ *
+ * Daniel Veillard <veillard@redhat.com>
+ */
+
+#ifndef __VIR_CONF_H__
+#define __VIR_CONF_H__
+
+/**
+ * virConfType:
+ * one of the possible type for a value from the configuration file
+ *
+ * TODO: we probably need a float too.
+ */
+typedef enum {
+ VIR_CONF_NONE = 0, /* undefined */
+ VIR_CONF_LONG = 1, /* a long int */
+ VIR_CONF_STRING = 2, /* a string */
+ VIR_CONF_LIST = 3 /* a list */
+} virConfType;
+
+typedef enum {
+ VIR_CONF_FLAG_VMX_FORMAT = 1, /* allow : and . in names for compatibility with
+ VMware VMX configuration file, but restrict
+ allowed value types to string only */
+} virConfFlags;
+
+static inline const char *
+virConfTypeName (virConfType t)
+{
+ switch (t) {
+ case VIR_CONF_LONG:
+ return "long";
+ case VIR_CONF_STRING:
+ return "string";
+ case VIR_CONF_LIST:
+ return "list";
+ default:
+ return "*unexpected*";
+ }
+}
+
+/**
+ * virConfValue:
+ * a value from the configuration file
+ */
+typedef struct _virConfValue virConfValue;
+typedef virConfValue *virConfValuePtr;
+
+struct _virConfValue {
+ virConfType type; /* the virConfType */
+ virConfValuePtr next; /* next element if in a list */
+ long l; /* long integer */
+ char *str; /* pointer to 0 terminated string */
+ virConfValuePtr list; /* list of a list */
+};
+
+/**
+ * virConfPtr:
+ * a pointer to a parsed configuration file
+ */
+typedef struct _virConf virConf;
+typedef virConf *virConfPtr;
+
+virConfPtr virConfNew (void);
+virConfPtr virConfReadFile (const char *filename, unsigned int flags);
+virConfPtr virConfReadMem (const char *memory,
+ int len, unsigned int flags);
+int virConfFree (virConfPtr conf);
+void virConfFreeValue (virConfValuePtr val);
+
+virConfValuePtr virConfGetValue (virConfPtr conf,
+ const char *setting);
+int virConfSetValue (virConfPtr conf,
+ const char *setting,
+ virConfValuePtr value);
+int virConfWriteFile (const char *filename,
+ virConfPtr conf);
+int virConfWriteMem (char *memory,
+ int *len,
+ virConfPtr conf);
+
+#endif /* __VIR_CONF_H__ */
--- /dev/null
+/*
+ * event.c: event loop for monitoring file handles
+ *
+ * Copyright (C) 2007 Daniel P. Berrange
+ * Copyright (C) 2007 Red Hat, Inc.
+ *
+ * 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 "event.h"
+
+#include <stdlib.h>
+
+static virEventAddHandleFunc addHandleImpl = NULL;
+static virEventUpdateHandleFunc updateHandleImpl = NULL;
+static virEventRemoveHandleFunc removeHandleImpl = NULL;
+static virEventAddTimeoutFunc addTimeoutImpl = NULL;
+static virEventUpdateTimeoutFunc updateTimeoutImpl = NULL;
+static virEventRemoveTimeoutFunc removeTimeoutImpl = NULL;
+
+int virEventAddHandle(int fd,
+ int events,
+ virEventHandleCallback cb,
+ void *opaque,
+ virFreeCallback ff) {
+ if (!addHandleImpl)
+ return -1;
+
+ return addHandleImpl(fd, events, cb, opaque, ff);
+}
+
+void virEventUpdateHandle(int watch, int events) {
+ updateHandleImpl(watch, events);
+}
+
+int virEventRemoveHandle(int watch) {
+ if (!removeHandleImpl)
+ return -1;
+
+ return removeHandleImpl(watch);
+}
+
+int virEventAddTimeout(int timeout,
+ virEventTimeoutCallback cb,
+ void *opaque,
+ virFreeCallback ff) {
+ if (!addTimeoutImpl)
+ return -1;
+
+ return addTimeoutImpl(timeout, cb, opaque, ff);
+}
+
+void virEventUpdateTimeout(int timer, int timeout) {
+ updateTimeoutImpl(timer, timeout);
+}
+
+int virEventRemoveTimeout(int timer) {
+ if (!removeTimeoutImpl)
+ return -1;
+
+ return removeTimeoutImpl(timer);
+}
+
+/**
+ * virEventRegisterImpl:
+ * Register an EventImpl
+ * @addHandle: the callback to add fd handles
+ * @updateHandle: the callback to update fd handles
+ * @removeHandle: the callback to remove fd handles
+ * @addTimeout: the callback to add a timeout
+ * @updateTimeout: the callback to update a timeout
+ * @removeTimeout: the callback to remove a timeout
+ */
+void virEventRegisterImpl(virEventAddHandleFunc addHandle,
+ virEventUpdateHandleFunc updateHandle,
+ virEventRemoveHandleFunc removeHandle,
+ virEventAddTimeoutFunc addTimeout,
+ virEventUpdateTimeoutFunc updateTimeout,
+ virEventRemoveTimeoutFunc removeTimeout) {
+ addHandleImpl = addHandle;
+ updateHandleImpl = updateHandle;
+ removeHandleImpl = removeHandle;
+ addTimeoutImpl = addTimeout;
+ updateTimeoutImpl = updateTimeout;
+ removeTimeoutImpl = removeTimeout;
+}
--- /dev/null
+/*
+ * event.h: event loop for monitoring file handles
+ *
+ * Copyright (C) 2007 Daniel P. Berrange
+ * Copyright (C) 2007 Red Hat, Inc.
+ *
+ * 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>
+ */
+
+#ifndef __VIR_EVENT_H__
+#define __VIR_EVENT_H__
+#include "internal.h"
+/**
+ * virEventAddHandle: register a callback for monitoring file handle events
+ *
+ * @fd: file handle to monitor for events
+ * @events: bitset of events to watch from virEventHandleType constants
+ * @cb: callback to invoke when an event occurs
+ * @opaque: user data to pass to callback
+ *
+ * returns -1 if the file handle cannot be registered, 0 upon success
+ */
+int virEventAddHandle(int fd, int events,
+ virEventHandleCallback cb,
+ void *opaque,
+ virFreeCallback ff);
+
+/**
+ * virEventUpdateHandle: change event set for a monitored file handle
+ *
+ * @watch: watch whose file handle to update
+ * @events: bitset of events to watch from virEventHandleType constants
+ *
+ * Will not fail if fd exists
+ */
+void virEventUpdateHandle(int watch, int events);
+
+/**
+ * virEventRemoveHandle: unregister a callback from a file handle
+ *
+ * @watch: watch whose file handle to remove
+ *
+ * returns -1 if the file handle was not registered, 0 upon success
+ */
+int virEventRemoveHandle(int watch);
+
+/**
+ * virEventAddTimeout: register a callback for a timer event
+ *
+ * @frequency: time between events in milliseconds
+ * @cb: callback to invoke when an event occurs
+ * @opaque: user data to pass to callback
+ *
+ * Setting frequency to -1 will disable the timer. Setting the frequency
+ * to zero will cause it to fire on every event loop iteration.
+ *
+ * returns -1 if the file handle cannot be registered, a positive
+ * integer timer id upon success
+ */
+int virEventAddTimeout(int frequency,
+ virEventTimeoutCallback cb,
+ void *opaque,
+ virFreeCallback ff);
+
+/**
+ * virEventUpdateTimeoutImpl: change frequency for a timer
+ *
+ * @timer: timer id to change
+ * @frequency: time between events in milliseconds
+ *
+ * Setting frequency to -1 will disable the timer. Setting the frequency
+ * to zero will cause it to fire on every event loop iteration.
+ *
+ * Will not fail if timer exists
+ */
+void virEventUpdateTimeout(int timer, int frequency);
+
+/**
+ * virEventRemoveTimeout: unregister a callback for a timer
+ *
+ * @timer: the timer id to remove
+ *
+ * returns -1 if the timer was not registered, 0 upon success
+ */
+int virEventRemoveTimeout(int timer);
+
+#endif /* __VIR_EVENT_H__ */
--- /dev/null
+/*
+ * hash.c: chained hash tables for domain and domain/connection deallocations
+ *
+ * Reference: Your favorite introductory book on algorithms
+ *
+ * Copyright (C) 2000 Bjorn Reese and Daniel Veillard.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
+ * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
+ *
+ * Author: breese@users.sourceforge.net
+ * Daniel Veillard <veillard@redhat.com>
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "virterror_internal.h"
+#include "hash.h"
+#include "memory.h"
+
+#define MAX_HASH_LEN 8
+
+/* #define DEBUG_GROW */
+
+/*
+ * A single entry in the hash table
+ */
+typedef struct _virHashEntry virHashEntry;
+typedef virHashEntry *virHashEntryPtr;
+struct _virHashEntry {
+ struct _virHashEntry *next;
+ char *name;
+ void *payload;
+ int valid;
+};
+
+/*
+ * The entire hash table
+ */
+struct _virHashTable {
+ struct _virHashEntry *table;
+ int size;
+ int nbElems;
+};
+
+/*
+ * virHashComputeKey:
+ * Calculate the hash key
+ */
+static unsigned long
+virHashComputeKey(virHashTablePtr table, const char *name)
+{
+ unsigned long value = 0L;
+ char ch;
+
+ if (name != NULL) {
+ value += 30 * (*name);
+ while ((ch = *name++) != 0) {
+ value =
+ value ^ ((value << 5) + (value >> 3) + (unsigned long) ch);
+ }
+ }
+ return (value % table->size);
+}
+
+/**
+ * virHashCreate:
+ * @size: the size of the hash table
+ *
+ * Create a new virHashTablePtr.
+ *
+ * Returns the newly created object, or NULL if an error occured.
+ */
+virHashTablePtr
+virHashCreate(int size)
+{
+ virHashTablePtr table = NULL;
+
+ if (size <= 0)
+ size = 256;
+
+ if (VIR_ALLOC(table) < 0)
+ return NULL;
+
+ table->size = size;
+ table->nbElems = 0;
+ if (VIR_ALLOC_N(table->table, size) < 0) {
+ VIR_FREE(table);
+ return NULL;
+ }
+
+ return table;
+}
+
+/**
+ * virHashGrow:
+ * @table: the hash table
+ * @size: the new size of the hash table
+ *
+ * resize the hash table
+ *
+ * Returns 0 in case of success, -1 in case of failure
+ */
+static int
+virHashGrow(virHashTablePtr table, int size)
+{
+ unsigned long key;
+ int oldsize, i;
+ virHashEntryPtr iter, next;
+ struct _virHashEntry *oldtable;
+
+#ifdef DEBUG_GROW
+ unsigned long nbElem = 0;
+#endif
+
+ if (table == NULL)
+ return (-1);
+ if (size < 8)
+ return (-1);
+ if (size > 8 * 2048)
+ return (-1);
+
+ oldsize = table->size;
+ oldtable = table->table;
+ if (oldtable == NULL)
+ return (-1);
+
+ if (VIR_ALLOC_N(table->table, size) < 0) {
+ table->table = oldtable;
+ return (-1);
+ }
+ table->size = size;
+
+ /* If the two loops are merged, there would be situations where
+ * a new entry needs to allocated and data copied into it from
+ * the main table. So instead, we run through the array twice, first
+ * copying all the elements in the main array (where we can't get
+ * conflicts) and then the rest, so we only free (and don't allocate)
+ */
+ for (i = 0; i < oldsize; i++) {
+ if (oldtable[i].valid == 0)
+ continue;
+ key = virHashComputeKey(table, oldtable[i].name);
+ memcpy(&(table->table[key]), &(oldtable[i]), sizeof(virHashEntry));
+ table->table[key].next = NULL;
+ }
+
+ for (i = 0; i < oldsize; i++) {
+ iter = oldtable[i].next;
+ while (iter) {
+ next = iter->next;
+
+ /*
+ * put back the entry in the new table
+ */
+
+ key = virHashComputeKey(table, iter->name);
+ if (table->table[key].valid == 0) {
+ memcpy(&(table->table[key]), iter, sizeof(virHashEntry));
+ table->table[key].next = NULL;
+ VIR_FREE(iter);
+ } else {
+ iter->next = table->table[key].next;
+ table->table[key].next = iter;
+ }
+
+#ifdef DEBUG_GROW
+ nbElem++;
+#endif
+
+ iter = next;
+ }
+ }
+
+ VIR_FREE(oldtable);
+
+#ifdef DEBUG_GROW
+ xmlGenericError(xmlGenericErrorContext,
+ "virHashGrow : from %d to %d, %d elems\n", oldsize,
+ size, nbElem);
+#endif
+
+ return (0);
+}
+
+/**
+ * virHashFree:
+ * @table: the hash table
+ * @f: the deallocator function for items in the hash
+ *
+ * Free the hash @table and its contents. The userdata is
+ * deallocated with @f if provided.
+ */
+void
+virHashFree(virHashTablePtr table, virHashDeallocator f)
+{
+ int i;
+ virHashEntryPtr iter;
+ virHashEntryPtr next;
+ int inside_table = 0;
+ int nbElems;
+
+ if (table == NULL)
+ return;
+ if (table->table) {
+ nbElems = table->nbElems;
+ for (i = 0; (i < table->size) && (nbElems > 0); i++) {
+ iter = &(table->table[i]);
+ if (iter->valid == 0)
+ continue;
+ inside_table = 1;
+ while (iter) {
+ next = iter->next;
+ if ((f != NULL) && (iter->payload != NULL))
+ f(iter->payload, iter->name);
+ VIR_FREE(iter->name);
+ iter->payload = NULL;
+ if (!inside_table)
+ VIR_FREE(iter);
+ nbElems--;
+ inside_table = 0;
+ iter = next;
+ }
+ }
+ VIR_FREE(table->table);
+ }
+ VIR_FREE(table);
+}
+
+/**
+ * virHashAddEntry3:
+ * @table: the hash table
+ * @name: the name of the userdata
+ * @userdata: a pointer to the userdata
+ *
+ * Add the @userdata to the hash @table. This can later be retrieved
+ * by using @name. Duplicate entries generate errors.
+ *
+ * Returns 0 the addition succeeded and -1 in case of error.
+ */
+int
+virHashAddEntry(virHashTablePtr table, const char *name, void *userdata)
+{
+ unsigned long key, len = 0;
+ virHashEntryPtr entry;
+ virHashEntryPtr insert;
+
+ if ((table == NULL) || (name == NULL))
+ return (-1);
+
+ /*
+ * Check for duplicate and insertion location.
+ */
+ key = virHashComputeKey(table, name);
+ if (table->table[key].valid == 0) {
+ insert = NULL;
+ } else {
+ for (insert = &(table->table[key]); insert->next != NULL;
+ insert = insert->next) {
+ if (STREQ(insert->name, name))
+ return (-1);
+ len++;
+ }
+ if (STREQ(insert->name, name))
+ return (-1);
+ }
+
+ if (insert == NULL) {
+ entry = &(table->table[key]);
+ } else {
+ if (VIR_ALLOC(entry) < 0)
+ return (-1);
+ }
+
+ entry->name = strdup(name);
+ entry->payload = userdata;
+ entry->next = NULL;
+ entry->valid = 1;
+
+
+ if (insert != NULL)
+ insert->next = entry;
+
+ table->nbElems++;
+
+ if (len > MAX_HASH_LEN)
+ virHashGrow(table, MAX_HASH_LEN * table->size);
+
+ return (0);
+}
+
+/**
+ * virHashUpdateEntry:
+ * @table: the hash table
+ * @name: the name of the userdata
+ * @userdata: a pointer to the userdata
+ * @f: the deallocator function for replaced item (if any)
+ *
+ * Add the @userdata to the hash @table. This can later be retrieved
+ * by using @name. Existing entry for this tuple
+ * will be removed and freed with @f if found.
+ *
+ * Returns 0 the addition succeeded and -1 in case of error.
+ */
+int
+virHashUpdateEntry(virHashTablePtr table, const char *name,
+ void *userdata, virHashDeallocator f)
+{
+ unsigned long key;
+ virHashEntryPtr entry;
+ virHashEntryPtr insert;
+
+ if ((table == NULL) || name == NULL)
+ return (-1);
+
+ /*
+ * Check for duplicate and insertion location.
+ */
+ key = virHashComputeKey(table, name);
+ if (table->table[key].valid == 0) {
+ insert = NULL;
+ } else {
+ for (insert = &(table->table[key]); insert->next != NULL;
+ insert = insert->next) {
+ if (STREQ(insert->name, name)) {
+ if (f)
+ f(insert->payload, insert->name);
+ insert->payload = userdata;
+ return (0);
+ }
+ }
+ if (STREQ(insert->name, name)) {
+ if (f)
+ f(insert->payload, insert->name);
+ insert->payload = userdata;
+ return (0);
+ }
+ }
+
+ if (insert == NULL) {
+ entry = &(table->table[key]);
+ } else {
+ if (VIR_ALLOC(entry) < 0)
+ return (-1);
+ }
+
+ entry->name = strdup(name);
+ entry->payload = userdata;
+ entry->next = NULL;
+ entry->valid = 1;
+ table->nbElems++;
+
+
+ if (insert != NULL) {
+ insert->next = entry;
+ }
+ return (0);
+}
+
+/**
+ * virHashLookup:
+ * @table: the hash table
+ * @name: the name of the userdata
+ *
+ * Find the userdata specified by the (@name, @name2, @name3) tuple.
+ *
+ * Returns the a pointer to the userdata
+ */
+void *
+virHashLookup(virHashTablePtr table, const char *name)
+{
+ unsigned long key;
+ virHashEntryPtr entry;
+
+ if (table == NULL)
+ return (NULL);
+ if (name == NULL)
+ return (NULL);
+ key = virHashComputeKey(table, name);
+ if (table->table[key].valid == 0)
+ return (NULL);
+ for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
+ if (STREQ(entry->name, name))
+ return (entry->payload);
+ }
+ return (NULL);
+}
+
+/**
+ * virHashSize:
+ * @table: the hash table
+ *
+ * Query the number of elements installed in the hash @table.
+ *
+ * Returns the number of elements in the hash table or
+ * -1 in case of error
+ */
+int
+virHashSize(virHashTablePtr table)
+{
+ if (table == NULL)
+ return (-1);
+ return (table->nbElems);
+}
+
+/**
+ * virHashRemoveEntry:
+ * @table: the hash table
+ * @name: the name of the userdata
+ * @f: the deallocator function for removed item (if any)
+ *
+ * Find the userdata specified by the @name and remove
+ * it from the hash @table. Existing userdata for this tuple will be removed
+ * and freed with @f.
+ *
+ * Returns 0 if the removal succeeded and -1 in case of error or not found.
+ */
+int
+virHashRemoveEntry(virHashTablePtr table, const char *name,
+ virHashDeallocator f)
+{
+ unsigned long key;
+ virHashEntryPtr entry;
+ virHashEntryPtr prev = NULL;
+
+ if (table == NULL || name == NULL)
+ return (-1);
+
+ key = virHashComputeKey(table, name);
+ if (table->table[key].valid == 0) {
+ return (-1);
+ } else {
+ for (entry = &(table->table[key]); entry != NULL;
+ entry = entry->next) {
+ if (STREQ(entry->name, name)) {
+ if ((f != NULL) && (entry->payload != NULL))
+ f(entry->payload, entry->name);
+ entry->payload = NULL;
+ VIR_FREE(entry->name);
+ if (prev) {
+ prev->next = entry->next;
+ VIR_FREE(entry);
+ } else {
+ if (entry->next == NULL) {
+ entry->valid = 0;
+ } else {
+ entry = entry->next;
+ memcpy(&(table->table[key]), entry,
+ sizeof(virHashEntry));
+ VIR_FREE(entry);
+ }
+ }
+ table->nbElems--;
+ return (0);
+ }
+ prev = entry;
+ }
+ return (-1);
+ }
+}
+
+
+/**
+ * virHashForEach
+ * @table: the hash table to process
+ * @iter: callback to process each element
+ * @data: opaque data to pass to the iterator
+ *
+ * Iterates over every element in the hash table, invoking the
+ * 'iter' callback. The callback must not call any other virHash*
+ * functions, and in particular must not attempt to remove the
+ * element.
+ *
+ * Returns number of items iterated over upon completion, -1 on failure
+ */
+int virHashForEach(virHashTablePtr table, virHashIterator iter, const void *data) {
+ int i, count = 0;
+
+ if (table == NULL || iter == NULL)
+ return (-1);
+
+ for (i = 0 ; i < table->size ; i++) {
+ virHashEntryPtr entry = table->table + i;
+ while (entry) {
+ if (entry->valid) {
+ iter(entry->payload, entry->name, data);
+ count++;
+ }
+ entry = entry->next;
+ }
+ }
+ return (count);
+}
+
+/**
+ * virHashRemoveSet
+ * @table: the hash table to process
+ * @iter: callback to identify elements for removal
+ * @f: callback to free memory from element payload
+ * @data: opaque data to pass to the iterator
+ *
+ * Iterates over all elements in the hash table, invoking the 'iter'
+ * callback. If the callback returns a non-zero value, the element
+ * will be removed from the hash table & its payload passed to the
+ * callback 'f' for de-allocation.
+ *
+ * Returns number of items removed on success, -1 on failure
+ */
+int virHashRemoveSet(virHashTablePtr table, virHashSearcher iter, virHashDeallocator f, const void *data) {
+ int i, count = 0;
+
+ if (table == NULL || iter == NULL)
+ return (-1);
+
+ for (i = 0 ; i < table->size ; i++) {
+ virHashEntryPtr prev = NULL;
+ virHashEntryPtr entry = &(table->table[i]);
+
+ while (entry && entry->valid) {
+ if (iter(entry->payload, entry->name, data)) {
+ count++;
+ f(entry->payload, entry->name);
+ VIR_FREE(entry->name);
+ table->nbElems--;
+ if (prev) {
+ prev->next = entry->next;
+ VIR_FREE(entry);
+ entry = prev;
+ } else {
+ if (entry->next == NULL) {
+ entry->valid = 0;
+ entry->name = NULL;
+ } else {
+ entry = entry->next;
+ memcpy(&(table->table[i]), entry,
+ sizeof(virHashEntry));
+ VIR_FREE(entry);
+ entry = &(table->table[i]);
+ continue;
+ }
+ }
+ }
+ prev = entry;
+ if (entry) {
+ entry = entry->next;
+ }
+ }
+ }
+ return (count);
+}
+
+/**
+ * virHashSearch:
+ * @table: the hash table to search
+ * @iter: an iterator to identify the desired element
+ * @data: extra opaque information passed to the iter
+ *
+ * Iterates over the hash table calling the 'iter' callback
+ * for each element. The first element for which the iter
+ * returns non-zero will be returned by this function.
+ * The elements are processed in a undefined order
+ */
+void *virHashSearch(virHashTablePtr table, virHashSearcher iter, const void *data) {
+ int i;
+
+ if (table == NULL || iter == NULL)
+ return (NULL);
+
+ for (i = 0 ; i < table->size ; i++) {
+ virHashEntryPtr entry = table->table + i;
+ while (entry) {
+ if (entry->valid) {
+ if (iter(entry->payload, entry->name, data))
+ return entry->payload;
+ }
+ entry = entry->next;
+ }
+ }
+ return (NULL);
+}
--- /dev/null
+/*
+ * Summary: Chained hash tables and domain/connections handling
+ * Description: This module implements the hash table and allocation and
+ * deallocation of domains and connections
+ *
+ * Copy: Copyright (C) 2005 Red Hat, Inc.
+ *
+ * Author: Bjorn Reese <bjorn.reese@systematic.dk>
+ * Daniel Veillard <veillard@redhat.com>
+ */
+
+#ifndef __VIR_HASH_H__
+#define __VIR_HASH_H__
+
+/*
+ * The hash table.
+ */
+typedef struct _virHashTable virHashTable;
+typedef virHashTable *virHashTablePtr;
+
+/*
+ * function types:
+ */
+
+/**
+ * virHashDeallocator:
+ * @payload: the data in the hash
+ * @name: the name associated
+ *
+ * Callback to free data from a hash.
+ */
+typedef void (*virHashDeallocator) (void *payload, const char *name);
+/**
+ * virHashIterator:
+ * @payload: the data in the hash
+ * @name: the name associated
+ * @data: user supplied data blob
+ *
+ * Callback to process a hash entry during iteration
+ */
+typedef void (*virHashIterator) (const void *payload, const char *name, const void *data);
+/**
+ * virHashSearcher
+ * @payload: the data in the hash
+ * @name: the name associated
+ * @data: user supplied data blob
+ *
+ * Callback to identify hash entry desired
+ * Returns 1 if the hash entry is desired, 0 to move
+ * to next entry
+ */
+typedef int (*virHashSearcher) (const void *payload, const char *name, const void *data);
+
+/*
+ * Constructor and destructor.
+ */
+virHashTablePtr virHashCreate(int size);
+void virHashFree(virHashTablePtr table, virHashDeallocator f);
+int virHashSize(virHashTablePtr table);
+
+/*
+ * Add a new entry to the hash table.
+ */
+int virHashAddEntry(virHashTablePtr table,
+ const char *name, void *userdata);
+int virHashUpdateEntry(virHashTablePtr table,
+ const char *name,
+ void *userdata, virHashDeallocator f);
+
+/*
+ * Remove an entry from the hash table.
+ */
+int virHashRemoveEntry(virHashTablePtr table,
+ const char *name, virHashDeallocator f);
+
+/*
+ * Retrieve the userdata.
+ */
+void *virHashLookup(virHashTablePtr table, const char *name);
+
+
+/*
+ * Iterators
+ */
+int virHashForEach(virHashTablePtr table, virHashIterator iter, const void *data);
+int virHashRemoveSet(virHashTablePtr table, virHashSearcher iter, virHashDeallocator f, const void *data);
+void *virHashSearch(virHashTablePtr table, virHashSearcher iter, const void *data);
+
+#endif /* ! __VIR_HASH_H__ */
--- /dev/null
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * 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
+ *
+ * Authors:
+ * Daniel P. Berrange <berrange@redhat.com>
+ */
+
+#include <config.h>
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "hostusb.h"
+#include "logging.h"
+#include "memory.h"
+#include "util.h"
+#include "virterror_internal.h"
+
+#define USB_DEVFS "/dev/bus/usb/"
+#define USB_ID_LEN 10 /* "XXXX XXXX" */
+#define USB_ADDR_LEN 8 /* "XXX:XXX" */
+
+struct _usbDevice {
+ unsigned bus;
+ unsigned dev;
+
+ char name[USB_ADDR_LEN]; /* domain:bus:slot.function */
+ char id[USB_ID_LEN]; /* product vendor */
+ char path[PATH_MAX];
+};
+
+/* For virReportOOMError() and virReportSystemError() */
+#define VIR_FROM_THIS VIR_FROM_NONE
+
+#define usbReportError(conn, code, fmt...) \
+ virReportErrorHelper(conn, VIR_FROM_NONE, code, __FILE__, \
+ __FUNCTION__, __LINE__, fmt)
+
+
+usbDevice *
+usbGetDevice(virConnectPtr conn,
+ unsigned bus,
+ unsigned devno)
+{
+ usbDevice *dev;
+
+ if (VIR_ALLOC(dev) < 0) {
+ virReportOOMError(conn);
+ return NULL;
+ }
+
+ dev->bus = bus;
+ dev->dev = devno;
+
+ snprintf(dev->name, sizeof(dev->name), "%.3o:%.3o",
+ dev->bus, dev->dev);
+ snprintf(dev->path, sizeof(dev->path),
+ USB_DEVFS "%03o/%03o", dev->bus, dev->dev);
+
+ /* XXX fixme. this should be product/vendor */
+ snprintf(dev->id, sizeof(dev->id), "%d %d", dev->bus, dev->dev);
+
+ VIR_DEBUG("%s %s: initialized", dev->id, dev->name);
+
+ return dev;
+}
+
+void
+usbFreeDevice(virConnectPtr conn ATTRIBUTE_UNUSED, usbDevice *dev)
+{
+ VIR_DEBUG("%s %s: freeing", dev->id, dev->name);
+ VIR_FREE(dev);
+}
+
+
+int usbDeviceFileIterate(virConnectPtr conn,
+ usbDevice *dev,
+ usbDeviceFileActor actor,
+ void *opaque)
+{
+ return (actor)(conn, dev, dev->path, opaque);
+}
--- /dev/null
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * 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
+ *
+ * Authors:
+ * Daniel P. Berrange <berrange@redhat.com>
+ */
+
+#ifndef __VIR_USB_H__
+#define __VIR_USB_H__
+
+#include "internal.h"
+
+typedef struct _usbDevice usbDevice;
+
+usbDevice *usbGetDevice (virConnectPtr conn,
+ unsigned bus,
+ unsigned devno);
+void usbFreeDevice (virConnectPtr conn,
+ usbDevice *dev);
+
+/*
+ * Callback that will be invoked once for each file
+ * associated with / used for USB host device access.
+ *
+ * Should return 0 if successfully processed, or
+ * -1 to indicate error and abort iteration
+ */
+typedef int (*usbDeviceFileActor)(virConnectPtr conn, usbDevice *dev,
+ const char *path, void *opaque);
+
+int usbDeviceFileIterate(virConnectPtr conn,
+ usbDevice *dev,
+ usbDeviceFileActor actor,
+ void *opaque);
+
+
+#endif /* __VIR_USB_H__ */
--- /dev/null
+/*
+ * Copyright (C) 2007-2009 Red Hat, Inc.
+ *
+ * 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
+ *
+ * Authors:
+ * Mark McLoughlin <markmc@redhat.com>
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+
+#include "internal.h"
+#include "iptables.h"
+#include "util.h"
+#include "memory.h"
+#include "virterror_internal.h"
+#include "logging.h"
+
+enum {
+ ADD = 0,
+ REMOVE
+};
+
+typedef struct
+{
+ char *rule;
+ const char **argv;
+ int command_idx;
+} iptRule;
+
+typedef struct
+{
+ char *table;
+ char *chain;
+
+ int nrules;
+ iptRule *rules;
+
+#ifdef ENABLE_IPTABLES_LOKKIT
+
+ char dir[PATH_MAX];
+ char path[PATH_MAX];
+
+#endif /* ENABLE_IPTABLES_LOKKIT */
+
+} iptRules;
+
+struct _iptablesContext
+{
+ iptRules *input_filter;
+ iptRules *forward_filter;
+ iptRules *nat_postrouting;
+};
+
+#ifdef ENABLE_IPTABLES_LOKKIT
+static void
+notifyRulesUpdated(const char *table,
+ const char *path)
+{
+ char arg[PATH_MAX];
+ const char *argv[4];
+
+ snprintf(arg, sizeof(arg), "--custom-rules=ipv4:%s:%s", table, path);
+
+ argv[0] = (char *) LOKKIT_PATH;
+ argv[1] = (char *) "--nostart";
+ argv[2] = arg;
+ argv[3] = NULL;
+
+ char ebuf[1024];
+ if (virRun(NULL, argv, NULL) < 0)
+ VIR_WARN(_("Failed to run '%s %s': %s"),
+ LOKKIT_PATH, arg, virStrerror(errno, ebuf, sizeof ebuf));
+}
+
+static int
+stripLine(char *str, int len, const char *line)
+{
+ char *s, *p;
+ int changed;
+
+ changed = 0;
+ s = str;
+
+ while ((p = strchr(s, '\n'))) {
+ if (p == s || STRNEQLEN(s, line, p - s)) {
+ s = ++p;
+ continue;
+ }
+
+ ++p;
+ memmove(s, p, len - (p - str) + 1);
+ len -= p - s;
+ changed = 1;
+ }
+
+ if (STREQ(s, line)) {
+ *s = '\0';
+ changed = 1;
+ }
+
+ return changed;
+}
+
+static void
+notifyRulesRemoved(const char *table,
+ const char *path)
+{
+/* 10 MB limit on config file size as a sanity check */
+#define MAX_FILE_LEN (1024*1024*10)
+
+ char arg[PATH_MAX];
+ char *content;
+ int len;
+ FILE *f = NULL;
+
+ len = virFileReadAll(SYSCONF_DIR "/sysconfig/system-config-firewall",
+ MAX_FILE_LEN, &content);
+ if (len < 0) {
+ VIR_WARN("%s", _("Failed to read " SYSCONF_DIR
+ "/sysconfig/system-config-firewall"));
+ return;
+ }
+
+ snprintf(arg, sizeof(arg), "--custom-rules=ipv4:%s:%s", table, path);
+
+ if (!stripLine(content, len, arg)) {
+ VIR_FREE(content);
+ return;
+ }
+
+ if (!(f = fopen(SYSCONF_DIR "/sysconfig/system-config-firewall", "w")))
+ goto write_error;
+
+ if (fputs(content, f) == EOF)
+ goto write_error;
+
+ if (fclose(f) == EOF) {
+ f = NULL;
+ goto write_error;
+ }
+
+ VIR_FREE(content);
+
+ return;
+
+ write_error:;
+ char ebuf[1024];
+ VIR_WARN(_("Failed to write to " SYSCONF_DIR
+ "/sysconfig/system-config-firewall : %s"),
+ virStrerror(errno, ebuf, sizeof ebuf));
+ if (f)
+ fclose(f);
+ VIR_FREE(content);
+
+#undef MAX_FILE_LEN
+}
+
+static int
+writeRules(const char *path,
+ const iptRule *rules,
+ int nrules)
+{
+ char tmp[PATH_MAX];
+ FILE *f;
+ int istmp;
+ int i;
+
+ if (nrules == 0 && unlink(path) == 0)
+ return 0;
+
+ if (snprintf(tmp, PATH_MAX, "%s.new", path) >= PATH_MAX)
+ return EINVAL;
+
+ istmp = 1;
+
+ if (!(f = fopen(tmp, "w"))) {
+ istmp = 0;
+ if (!(f = fopen(path, "w")))
+ return errno;
+ }
+
+ for (i = 0; i < nrules; i++) {
+ if (fputs(rules[i].rule, f) == EOF ||
+ fputc('\n', f) == EOF) {
+ fclose(f);
+ if (istmp)
+ unlink(tmp);
+ return errno;
+ }
+ }
+
+ fclose(f);
+
+ if (istmp && rename(tmp, path) < 0) {
+ unlink(tmp);
+ return errno;
+ }
+
+ if (istmp)
+ unlink(tmp);
+
+ return 0;
+}
+#endif /* ENABLE_IPTABLES_LOKKIT */
+
+static void
+iptRulesSave(iptRules *rules)
+{
+#ifdef ENABLE_IPTABLES_LOKKIT
+ int err;
+
+ char ebuf[1024];
+ if ((err = virFileMakePath(rules->dir))) {
+ VIR_WARN(_("Failed to create directory %s : %s"),
+ rules->dir, virStrerror(err, ebuf, sizeof ebuf));
+ return;
+ }
+
+ if ((err = writeRules(rules->path, rules->rules, rules->nrules))) {
+ VIR_WARN(_("Failed to saves iptables rules to %s : %s"),
+ rules->path, virStrerror(err, ebuf, sizeof ebuf));
+ return;
+ }
+
+ if (rules->nrules > 0)
+ notifyRulesUpdated(rules->table, rules->path);
+ else
+ notifyRulesRemoved(rules->table, rules->path);
+#else
+ (void) rules;
+#endif /* ENABLE_IPTABLES_LOKKIT */
+}
+
+static void
+iptRuleFree(iptRule *rule)
+{
+ VIR_FREE(rule->rule);
+
+ if (rule->argv) {
+ int i = 0;
+ while (rule->argv[i])
+ VIR_FREE(rule->argv[i++]);
+ VIR_FREE(rule->argv);
+ }
+}
+
+static int
+iptRulesAppend(iptRules *rules,
+ char *rule,
+ const char **argv,
+ int command_idx)
+{
+ if (VIR_REALLOC_N(rules->rules, rules->nrules+1) < 0) {
+ int i = 0;
+ while (argv[i])
+ VIR_FREE(argv[i++]);
+ VIR_FREE(argv);
+ return ENOMEM;
+ }
+
+ rules->rules[rules->nrules].rule = rule;
+ rules->rules[rules->nrules].argv = argv;
+ rules->rules[rules->nrules].command_idx = command_idx;
+
+ rules->nrules++;
+
+ return 0;
+}
+
+static int
+iptRulesRemove(iptRules *rules,
+ char *rule)
+{
+ int i;
+
+ for (i = 0; i < rules->nrules; i++)
+ if (STREQ(rules->rules[i].rule, rule))
+ break;
+
+ if (i >= rules->nrules)
+ return EINVAL;
+
+ iptRuleFree(&rules->rules[i]);
+
+ memmove(&rules->rules[i],
+ &rules->rules[i+1],
+ (rules->nrules - i - 1) * sizeof (iptRule));
+
+ rules->nrules--;
+
+ return 0;
+}
+
+static void
+iptRulesFree(iptRules *rules)
+{
+ int i;
+
+ VIR_FREE(rules->table);
+ VIR_FREE(rules->chain);
+
+ if (rules->rules) {
+ for (i = 0; i < rules->nrules; i++)
+ iptRuleFree(&rules->rules[i]);
+
+ VIR_FREE(rules->rules);
+
+ rules->nrules = 0;
+ }
+
+#ifdef ENABLE_IPTABLES_LOKKIT
+ rules->dir[0] = '\0';
+ rules->path[0] = '\0';
+#endif /* ENABLE_IPTABLES_LOKKIT */
+
+ VIR_FREE(rules);
+}
+
+static iptRules *
+iptRulesNew(const char *table,
+ const char *chain)
+{
+ iptRules *rules;
+
+ if (VIR_ALLOC(rules) < 0)
+ return NULL;
+
+ if (!(rules->table = strdup(table)))
+ goto error;
+
+ if (!(rules->chain = strdup(chain)))
+ goto error;
+
+ rules->rules = NULL;
+ rules->nrules = 0;
+
+#ifdef ENABLE_IPTABLES_LOKKIT
+ if (virFileBuildPath(LOCAL_STATE_DIR "/lib/libvirt/iptables", table, NULL,
+ rules->dir, sizeof(rules->dir)) < 0)
+ goto error;
+
+ if (virFileBuildPath(rules->dir, chain, ".chain", rules->path, sizeof(rules->path)) < 0)
+ goto error;
+#endif /* ENABLE_IPTABLES_LOKKIT */
+
+ return rules;
+
+ error:
+ iptRulesFree(rules);
+ return NULL;
+}
+
+static int
+iptablesAddRemoveRule(iptRules *rules, int action, const char *arg, ...)
+{
+ va_list args;
+ int retval = ENOMEM;
+ const char **argv;
+ char *rule = NULL;
+ const char *s;
+ int n, command_idx;
+
+ n = 1 + /* /sbin/iptables */
+ 2 + /* --table foo */
+ 2 + /* --insert bar */
+ 1; /* arg */
+
+ va_start(args, arg);
+ while (va_arg(args, const char *))
+ n++;
+
+ va_end(args);
+
+ if (VIR_ALLOC_N(argv, n + 1) < 0)
+ goto error;
+
+ n = 0;
+
+ if (!(argv[n++] = strdup(IPTABLES_PATH)))
+ goto error;
+
+ if (!(argv[n++] = strdup("--table")))
+ goto error;
+
+ if (!(argv[n++] = strdup(rules->table)))
+ goto error;
+
+ command_idx = n;
+
+ if (!(argv[n++] = strdup("--insert")))
+ goto error;
+
+ if (!(argv[n++] = strdup(rules->chain)))
+ goto error;
+
+ if (!(argv[n++] = strdup(arg)))
+ goto error;
+
+ va_start(args, arg);
+
+ while ((s = va_arg(args, const char *)))
+ if (!(argv[n++] = strdup(s)))
+ goto error;
+
+ va_end(args);
+
+ if (!(rule = virArgvToString(&argv[command_idx])))
+ goto error;
+
+ if (action == REMOVE) {
+ VIR_FREE(argv[command_idx]);
+ if (!(argv[command_idx] = strdup("--delete")))
+ goto error;
+ }
+
+ if (virRun(NULL, argv, NULL) < 0) {
+ retval = errno;
+ goto error;
+ }
+
+ if (action == ADD) {
+ retval = iptRulesAppend(rules, rule, argv, command_idx);
+ rule = NULL;
+ argv = NULL;
+ } else {
+ retval = iptRulesRemove(rules, rule);
+ }
+
+ error:
+ VIR_FREE(rule);
+
+ if (argv) {
+ n = 0;
+ while (argv[n])
+ VIR_FREE(argv[n++]);
+ VIR_FREE(argv);
+ }
+
+ return retval;
+}
+
+/**
+ * iptablesContextNew:
+ *
+ * Create a new IPtable context
+ *
+ * Returns a pointer to the new structure or NULL in case of error
+ */
+iptablesContext *
+iptablesContextNew(void)
+{
+ iptablesContext *ctx;
+
+ if (VIR_ALLOC(ctx) < 0)
+ return NULL;
+
+ if (!(ctx->input_filter = iptRulesNew("filter", "INPUT")))
+ goto error;
+
+ if (!(ctx->forward_filter = iptRulesNew("filter", "FORWARD")))
+ goto error;
+
+ if (!(ctx->nat_postrouting = iptRulesNew("nat", "POSTROUTING")))
+ goto error;
+
+ return ctx;
+
+ error:
+ iptablesContextFree(ctx);
+ return NULL;
+}
+
+/**
+ * iptablesContextFree:
+ * @ctx: pointer to the IP table context
+ *
+ * Free the resources associated with an IP table context
+ */
+void
+iptablesContextFree(iptablesContext *ctx)
+{
+ if (ctx->input_filter)
+ iptRulesFree(ctx->input_filter);
+ if (ctx->forward_filter)
+ iptRulesFree(ctx->forward_filter);
+ if (ctx->nat_postrouting)
+ iptRulesFree(ctx->nat_postrouting);
+ VIR_FREE(ctx);
+}
+
+/**
+ * iptablesSaveRules:
+ * @ctx: pointer to the IP table context
+ *
+ * Saves all the IP table rules associated with a context
+ * to disk so that if iptables is restarted, the rules
+ * will automatically be reload.
+ */
+void
+iptablesSaveRules(iptablesContext *ctx)
+{
+ iptRulesSave(ctx->input_filter);
+ iptRulesSave(ctx->forward_filter);
+ iptRulesSave(ctx->nat_postrouting);
+}
+
+static void
+iptRulesReload(iptRules *rules)
+{
+ int i;
+ char ebuf[1024];
+
+ for (i = 0; i < rules->nrules; i++) {
+ iptRule *rule = &rules->rules[i];
+ const char *orig;
+
+ orig = rule->argv[rule->command_idx];
+ rule->argv[rule->command_idx] = (char *) "--delete";
+
+ if (virRun(NULL, rule->argv, NULL) < 0)
+ VIR_WARN(_("Failed to remove iptables rule '%s'"
+ " from chain '%s' in table '%s': %s"),
+ rule->rule, rules->chain, rules->table,
+ virStrerror(errno, ebuf, sizeof ebuf));
+
+ rule->argv[rule->command_idx] = orig;
+ }
+
+ for (i = 0; i < rules->nrules; i++)
+ if (virRun(NULL, rules->rules[i].argv, NULL) < 0)
+ VIR_WARN(_("Failed to add iptables rule '%s'"
+ " to chain '%s' in table '%s': %s"),
+ rules->rules[i].rule, rules->chain, rules->table,
+ virStrerror(errno, ebuf, sizeof ebuf));
+}
+
+/**
+ * iptablesReloadRules:
+ * @ctx: pointer to the IP table context
+ *
+ * Reloads all the IP table rules associated to a context
+ */
+void
+iptablesReloadRules(iptablesContext *ctx)
+{
+ iptRulesReload(ctx->input_filter);
+ iptRulesReload(ctx->forward_filter);
+ iptRulesReload(ctx->nat_postrouting);
+}
+
+static int
+iptablesInput(iptablesContext *ctx,
+ const char *iface,
+ int port,
+ int action,
+ int tcp)
+{
+ char portstr[32];
+
+ snprintf(portstr, sizeof(portstr), "%d", port);
+ portstr[sizeof(portstr) - 1] = '\0';
+
+ return iptablesAddRemoveRule(ctx->input_filter,
+ action,
+ "--in-interface", iface,
+ "--protocol", tcp ? "tcp" : "udp",
+ "--destination-port", portstr,
+ "--jump", "ACCEPT",
+ NULL);
+}
+
+/**
+ * iptablesAddTcpInput:
+ * @ctx: pointer to the IP table context
+ * @iface: the interface name
+ * @port: the TCP port to add
+ *
+ * Add an input to the IP table allowing access to the given @port on
+ * the given @iface interface for TCP packets
+ *
+ * Returns 0 in case of success or an error code in case of error
+ */
+
+int
+iptablesAddTcpInput(iptablesContext *ctx,
+ const char *iface,
+ int port)
+{
+ return iptablesInput(ctx, iface, port, ADD, 1);
+}
+
+/**
+ * iptablesRemoveTcpInput:
+ * @ctx: pointer to the IP table context
+ * @iface: the interface name
+ * @port: the TCP port to remove
+ *
+ * Removes an input from the IP table, hence forbidding access to the given
+ * @port on the given @iface interface for TCP packets
+ *
+ * Returns 0 in case of success or an error code in case of error
+ */
+int
+iptablesRemoveTcpInput(iptablesContext *ctx,
+ const char *iface,
+ int port)
+{
+ return iptablesInput(ctx, iface, port, REMOVE, 1);
+}
+
+/**
+ * iptablesAddUdpInput:
+ * @ctx: pointer to the IP table context
+ * @iface: the interface name
+ * @port: the UDP port to add
+ *
+ * Add an input to the IP table allowing access to the given @port on
+ * the given @iface interface for UDP packets
+ *
+ * Returns 0 in case of success or an error code in case of error
+ */
+
+int
+iptablesAddUdpInput(iptablesContext *ctx,
+ const char *iface,
+ int port)
+{
+ return iptablesInput(ctx, iface, port, ADD, 0);
+}
+
+/**
+ * iptablesRemoveUdpInput:
+ * @ctx: pointer to the IP table context
+ * @iface: the interface name
+ * @port: the UDP port to remove
+ *
+ * Removes an input from the IP table, hence forbidding access to the given
+ * @port on the given @iface interface for UDP packets
+ *
+ * Returns 0 in case of success or an error code in case of error
+ */
+int
+iptablesRemoveUdpInput(iptablesContext *ctx,
+ const char *iface,
+ int port)
+{
+ return iptablesInput(ctx, iface, port, REMOVE, 0);
+}
+
+
+/* Allow all traffic coming from the bridge, with a valid network address
+ * to proceed to WAN
+ */
+static int
+iptablesForwardAllowOut(iptablesContext *ctx,
+ const char *network,
+ const char *iface,
+ const char *physdev,
+ int action)
+{
+ if (physdev && physdev[0]) {
+ return iptablesAddRemoveRule(ctx->forward_filter,
+ action,
+ "--source", network,
+ "--in-interface", iface,
+ "--out-interface", physdev,
+ "--jump", "ACCEPT",
+ NULL);
+ } else {
+ return iptablesAddRemoveRule(ctx->forward_filter,
+ action,
+ "--source", network,
+ "--in-interface", iface,
+ "--jump", "ACCEPT",
+ NULL);
+ }
+}
+
+/**
+ * iptablesAddForwardAllowOut:
+ * @ctx: pointer to the IP table context
+ * @network: the source network name
+ * @iface: the source interface name
+ * @physdev: the physical output device
+ *
+ * Add a rule to the IP table context to allow the traffic for the
+ * network @network via interface @iface to be forwarded to
+ * @physdev device. This allow the outbound traffic on a bridge.
+ *
+ * Returns 0 in case of success or an error code otherwise
+ */
+int
+iptablesAddForwardAllowOut(iptablesContext *ctx,
+ const char *network,
+ const char *iface,
+ const char *physdev)
+{
+ return iptablesForwardAllowOut(ctx, network, iface, physdev, ADD);
+}
+
+/**
+ * iptablesRemoveForwardAllowOut:
+ * @ctx: pointer to the IP table context
+ * @network: the source network name
+ * @iface: the source interface name
+ * @physdev: the physical output device
+ *
+ * Remove a rule from the IP table context hence forbidding forwarding
+ * of the traffic for the network @network via interface @iface
+ * to the @physdev device output. This stops the outbound traffic on a bridge.
+ *
+ * Returns 0 in case of success or an error code otherwise
+ */
+int
+iptablesRemoveForwardAllowOut(iptablesContext *ctx,
+ const char *network,
+ const char *iface,
+ const char *physdev)
+{
+ return iptablesForwardAllowOut(ctx, network, iface, physdev, REMOVE);
+}
+
+
+/* Allow all traffic destined to the bridge, with a valid network address
+ * and associated with an existing connection
+ */
+static int
+iptablesForwardAllowRelatedIn(iptablesContext *ctx,
+ const char *network,
+ const char *iface,
+ const char *physdev,
+ int action)
+{
+ if (physdev && physdev[0]) {
+ return iptablesAddRemoveRule(ctx->forward_filter,
+ action,
+ "--destination", network,
+ "--in-interface", physdev,
+ "--out-interface", iface,
+ "--match", "state",
+ "--state", "ESTABLISHED,RELATED",
+ "--jump", "ACCEPT",
+ NULL);
+ } else {
+ return iptablesAddRemoveRule(ctx->forward_filter,
+ action,
+ "--destination", network,
+ "--out-interface", iface,
+ "--match", "state",
+ "--state", "ESTABLISHED,RELATED",
+ "--jump", "ACCEPT",
+ NULL);
+ }
+}
+
+/**
+ * iptablesAddForwardAllowRelatedIn:
+ * @ctx: pointer to the IP table context
+ * @network: the source network name
+ * @iface: the output interface name
+ * @physdev: the physical input device or NULL
+ *
+ * Add rules to the IP table context to allow the traffic for the
+ * network @network on @physdev device to be forwarded to
+ * interface @iface, if it is part of an existing connection.
+ *
+ * Returns 0 in case of success or an error code otherwise
+ */
+int
+iptablesAddForwardAllowRelatedIn(iptablesContext *ctx,
+ const char *network,
+ const char *iface,
+ const char *physdev)
+{
+ return iptablesForwardAllowRelatedIn(ctx, network, iface, physdev, ADD);
+}
+
+/**
+ * iptablesRemoveForwardAllowRelatedIn:
+ * @ctx: pointer to the IP table context
+ * @network: the source network name
+ * @iface: the output interface name
+ * @physdev: the physical input device or NULL
+ *
+ * Remove rules from the IP table context hence forbidding the traffic for
+ * network @network on @physdev device to be forwarded to
+ * interface @iface, if it is part of an existing connection.
+ *
+ * Returns 0 in case of success or an error code otherwise
+ */
+int
+iptablesRemoveForwardAllowRelatedIn(iptablesContext *ctx,
+ const char *network,
+ const char *iface,
+ const char *physdev)
+{
+ return iptablesForwardAllowRelatedIn(ctx, network, iface, physdev, REMOVE);
+}
+
+/* Allow all traffic destined to the bridge, with a valid network address
+ */
+static int
+iptablesForwardAllowIn(iptablesContext *ctx,
+ const char *network,
+ const char *iface,
+ const char *physdev,
+ int action)
+{
+ if (physdev && physdev[0]) {
+ return iptablesAddRemoveRule(ctx->forward_filter,
+ action,
+ "--destination", network,
+ "--in-interface", physdev,
+ "--out-interface", iface,
+ "--jump", "ACCEPT",
+ NULL);
+ } else {
+ return iptablesAddRemoveRule(ctx->forward_filter,
+ action,
+ "--destination", network,
+ "--out-interface", iface,
+ "--jump", "ACCEPT",
+ NULL);
+ }
+}
+
+/**
+ * iptablesAddForwardAllowIn:
+ * @ctx: pointer to the IP table context
+ * @network: the source network name
+ * @iface: the output interface name
+ * @physdev: the physical input device or NULL
+ *
+ * Add rules to the IP table context to allow the traffic for the
+ * network @network on @physdev device to be forwarded to
+ * interface @iface. This allow the inbound traffic on a bridge.
+ *
+ * Returns 0 in case of success or an error code otherwise
+ */
+int
+iptablesAddForwardAllowIn(iptablesContext *ctx,
+ const char *network,
+ const char *iface,
+ const char *physdev)
+{
+ return iptablesForwardAllowIn(ctx, network, iface, physdev, ADD);
+}
+
+/**
+ * iptablesRemoveForwardAllowIn:
+ * @ctx: pointer to the IP table context
+ * @network: the source network name
+ * @iface: the output interface name
+ * @physdev: the physical input device or NULL
+ *
+ * Remove rules from the IP table context hence forbidding the traffic for
+ * network @network on @physdev device to be forwarded to
+ * interface @iface. This stops the inbound traffic on a bridge.
+ *
+ * Returns 0 in case of success or an error code otherwise
+ */
+int
+iptablesRemoveForwardAllowIn(iptablesContext *ctx,
+ const char *network,
+ const char *iface,
+ const char *physdev)
+{
+ return iptablesForwardAllowIn(ctx, network, iface, physdev, REMOVE);
+}
+
+
+/* Allow all traffic between guests on the same bridge,
+ * with a valid network address
+ */
+static int
+iptablesForwardAllowCross(iptablesContext *ctx,
+ const char *iface,
+ int action)
+{
+ return iptablesAddRemoveRule(ctx->forward_filter,
+ action,
+ "--in-interface", iface,
+ "--out-interface", iface,
+ "--jump", "ACCEPT",
+ NULL);
+}
+
+/**
+ * iptablesAddForwardAllowCross:
+ * @ctx: pointer to the IP table context
+ * @iface: the input/output interface name
+ *
+ * Add rules to the IP table context to allow traffic to cross that
+ * interface. It allows all traffic between guests on the same bridge
+ * represented by that interface.
+ *
+ * Returns 0 in case of success or an error code otherwise
+ */
+int
+iptablesAddForwardAllowCross(iptablesContext *ctx,
+ const char *iface) {
+ return iptablesForwardAllowCross(ctx, iface, ADD);
+}
+
+/**
+ * iptablesRemoveForwardAllowCross:
+ * @ctx: pointer to the IP table context
+ * @iface: the input/output interface name
+ *
+ * Remove rules to the IP table context to block traffic to cross that
+ * interface. It forbids traffic between guests on the same bridge
+ * represented by that interface.
+ *
+ * Returns 0 in case of success or an error code otherwise
+ */
+int
+iptablesRemoveForwardAllowCross(iptablesContext *ctx,
+ const char *iface) {
+ return iptablesForwardAllowCross(ctx, iface, REMOVE);
+}
+
+
+/* Drop all traffic trying to forward from the bridge.
+ * ie the bridge is the in interface
+ */
+static int
+iptablesForwardRejectOut(iptablesContext *ctx,
+ const char *iface,
+ int action)
+{
+ return iptablesAddRemoveRule(ctx->forward_filter,
+ action,
+ "--in-interface", iface,
+ "--jump", "REJECT",
+ NULL);
+}
+
+/**
+ * iptablesAddForwardRejectOut:
+ * @ctx: pointer to the IP table context
+ * @iface: the output interface name
+ *
+ * Add rules to the IP table context to forbid all traffic to that
+ * interface. It forbids forwarding from the bridge to that interface.
+ *
+ * Returns 0 in case of success or an error code otherwise
+ */
+int
+iptablesAddForwardRejectOut(iptablesContext *ctx,
+ const char *iface)
+{
+ return iptablesForwardRejectOut(ctx, iface, ADD);
+}
+
+/**
+ * iptablesRemoveForwardRejectOut:
+ * @ctx: pointer to the IP table context
+ * @iface: the output interface name
+ *
+ * Remove rules from the IP table context forbidding all traffic to that
+ * interface. It reallow forwarding from the bridge to that interface.
+ *
+ * Returns 0 in case of success or an error code otherwise
+ */
+int
+iptablesRemoveForwardRejectOut(iptablesContext *ctx,
+ const char *iface)
+{
+ return iptablesForwardRejectOut(ctx, iface, REMOVE);
+}
+
+
+
+
+/* Drop all traffic trying to forward to the bridge.
+ * ie the bridge is the out interface
+ */
+static int
+iptablesForwardRejectIn(iptablesContext *ctx,
+ const char *iface,
+ int action)
+{
+ return iptablesAddRemoveRule(ctx->forward_filter,
+ action,
+ "--out-interface", iface,
+ "--jump", "REJECT",
+ NULL);
+}
+
+/**
+ * iptablesAddForwardRejectIn:
+ * @ctx: pointer to the IP table context
+ * @iface: the input interface name
+ *
+ * Add rules to the IP table context to forbid all traffic from that
+ * interface. It forbids forwarding from that interface to the bridge.
+ *
+ * Returns 0 in case of success or an error code otherwise
+ */
+int
+iptablesAddForwardRejectIn(iptablesContext *ctx,
+ const char *iface)
+{
+ return iptablesForwardRejectIn(ctx, iface, ADD);
+}
+
+/**
+ * iptablesRemoveForwardRejectIn:
+ * @ctx: pointer to the IP table context
+ * @iface: the input interface name
+ *
+ * Remove rules from the IP table context forbidding all traffic from that
+ * interface. It allows forwarding from that interface to the bridge.
+ *
+ * Returns 0 in case of success or an error code otherwise
+ */
+int
+iptablesRemoveForwardRejectIn(iptablesContext *ctx,
+ const char *iface)
+{
+ return iptablesForwardRejectIn(ctx, iface, REMOVE);
+}
+
+
+/* Masquerade all traffic coming from the network associated
+ * with the bridge
+ */
+static int
+iptablesForwardMasquerade(iptablesContext *ctx,
+ const char *network,
+ const char *physdev,
+ int action)
+{
+ if (physdev && physdev[0]) {
+ return iptablesAddRemoveRule(ctx->nat_postrouting,
+ action,
+ "--source", network,
+ "--destination", "!", network,
+ "--out-interface", physdev,
+ "--jump", "MASQUERADE",
+ NULL);
+ } else {
+ return iptablesAddRemoveRule(ctx->nat_postrouting,
+ action,
+ "--source", network,
+ "--destination", "!", network,
+ "--jump", "MASQUERADE",
+ NULL);
+ }
+}
+
+/**
+ * iptablesAddForwardMasquerade:
+ * @ctx: pointer to the IP table context
+ * @network: the source network name
+ * @physdev: the physical input device or NULL
+ *
+ * Add rules to the IP table context to allow masquerading
+ * network @network on @physdev. This allow the bridge to
+ * masquerade for that network (on @physdev).
+ *
+ * Returns 0 in case of success or an error code otherwise
+ */
+int
+iptablesAddForwardMasquerade(iptablesContext *ctx,
+ const char *network,
+ const char *physdev)
+{
+ return iptablesForwardMasquerade(ctx, network, physdev, ADD);
+}
+
+/**
+ * iptablesRemoveForwardMasquerade:
+ * @ctx: pointer to the IP table context
+ * @network: the source network name
+ * @physdev: the physical input device or NULL
+ *
+ * Remove rules from the IP table context to stop masquerading
+ * network @network on @physdev. This stops the bridge from
+ * masquerading for that network (on @physdev).
+ *
+ * Returns 0 in case of success or an error code otherwise
+ */
+int
+iptablesRemoveForwardMasquerade(iptablesContext *ctx,
+ const char *network,
+ const char *physdev)
+{
+ return iptablesForwardMasquerade(ctx, network, physdev, REMOVE);
+}
--- /dev/null
+/*
+ * Copyright (C) 2007, 2008 Red Hat, Inc.
+ *
+ * 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
+ *
+ * Authors:
+ * Mark McLoughlin <markmc@redhat.com>
+ */
+
+#ifndef __QEMUD_IPTABLES_H__
+#define __QEMUD_IPTABLES_H__
+
+typedef struct _iptablesContext iptablesContext;
+
+iptablesContext *iptablesContextNew (void);
+void iptablesContextFree (iptablesContext *ctx);
+
+void iptablesSaveRules (iptablesContext *ctx);
+void iptablesReloadRules (iptablesContext *ctx);
+
+int iptablesAddTcpInput (iptablesContext *ctx,
+ const char *iface,
+ int port);
+int iptablesRemoveTcpInput (iptablesContext *ctx,
+ const char *iface,
+ int port);
+
+int iptablesAddUdpInput (iptablesContext *ctx,
+ const char *iface,
+ int port);
+int iptablesRemoveUdpInput (iptablesContext *ctx,
+ const char *iface,
+ int port);
+
+int iptablesAddForwardAllowOut (iptablesContext *ctx,
+ const char *network,
+ const char *iface,
+ const char *physdev);
+int iptablesRemoveForwardAllowOut (iptablesContext *ctx,
+ const char *network,
+ const char *iface,
+ const char *physdev);
+
+int iptablesAddForwardAllowRelatedIn(iptablesContext *ctx,
+ const char *network,
+ const char *iface,
+ const char *physdev);
+int iptablesRemoveForwardAllowRelatedIn(iptablesContext *ctx,
+ const char *network,
+ const char *iface,
+ const char *physdev);
+
+int iptablesAddForwardAllowIn (iptablesContext *ctx,
+ const char *network,
+ const char *iface,
+ const char *physdev);
+int iptablesRemoveForwardAllowIn (iptablesContext *ctx,
+ const char *network,
+ const char *iface,
+ const char *physdev);
+
+int iptablesAddForwardAllowCross (iptablesContext *ctx,
+ const char *iface);
+int iptablesRemoveForwardAllowCross (iptablesContext *ctx,
+ const char *iface);
+
+int iptablesAddForwardRejectOut (iptablesContext *ctx,
+ const char *iface);
+int iptablesRemoveForwardRejectOut (iptablesContext *ctx,
+ const char *iface);
+
+int iptablesAddForwardRejectIn (iptablesContext *ctx,
+ const char *iface);
+int iptablesRemoveForwardRejectIn (iptablesContext *ctx,
+ const char *iface);
+
+int iptablesAddForwardMasquerade (iptablesContext *ctx,
+ const char *network,
+ const char *physdev);
+int iptablesRemoveForwardMasquerade (iptablesContext *ctx,
+ const char *network,
+ const char *physdev);
+
+#endif /* __QEMUD_IPTABLES_H__ */
--- /dev/null
+/*
+ * logging.c: internal logging and debugging
+ *
+ * Copyright (C) 2008 Red Hat, Inc.
+ *
+ * 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
+ *
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#if HAVE_SYSLOG_H
+#include <syslog.h>
+#endif
+
+#include "logging.h"
+#include "memory.h"
+#include "util.h"
+#include "threads.h"
+
+/*
+ * Macro used to format the message as a string in virLogMessage
+ * and borrowed from libxml2 (also used in virRaiseError)
+ */
+#define VIR_GET_VAR_STR(msg, str) { \
+ int size, prev_size = -1; \
+ int chars; \
+ char *larger; \
+ va_list ap; \
+ \
+ str = (char *) malloc(150); \
+ if (str != NULL) { \
+ \
+ size = 150; \
+ \
+ while (1) { \
+ va_start(ap, msg); \
+ chars = vsnprintf(str, size, msg, ap); \
+ va_end(ap); \
+ if ((chars > -1) && (chars < size)) { \
+ if (prev_size == chars) { \
+ break; \
+ } else { \
+ prev_size = chars; \
+ } \
+ } \
+ if (chars > -1) \
+ size += chars + 1; \
+ else \
+ size += 100; \
+ if ((larger = (char *) realloc(str, size)) == NULL) { \
+ break; \
+ } \
+ str = larger; \
+ }} \
+}
+
+/*
+ * A logging buffer to keep some history over logs
+ */
+#define LOG_BUFFER_SIZE 64000
+
+static char virLogBuffer[LOG_BUFFER_SIZE + 1];
+static int virLogLen = 0;
+static int virLogStart = 0;
+static int virLogEnd = 0;
+
+/*
+ * Filters are used to refine the rules on what to keep or drop
+ * based on a matching pattern (currently a substring)
+ */
+struct _virLogFilter {
+ const char *match;
+ int priority;
+};
+typedef struct _virLogFilter virLogFilter;
+typedef virLogFilter *virLogFilterPtr;
+
+static virLogFilterPtr virLogFilters = NULL;
+static int virLogNbFilters = 0;
+
+/*
+ * Outputs are used to emit the messages retained
+ * after filtering, multiple output can be used simultaneously
+ */
+struct _virLogOutput {
+ void *data;
+ virLogOutputFunc f;
+ virLogCloseFunc c;
+ int priority;
+};
+typedef struct _virLogOutput virLogOutput;
+typedef virLogOutput *virLogOutputPtr;
+
+static virLogOutputPtr virLogOutputs = NULL;
+static int virLogNbOutputs = 0;
+
+/*
+ * Default priorities
+ */
+static virLogPriority virLogDefaultPriority = VIR_LOG_DEFAULT;
+
+static int virLogResetFilters(void);
+static int virLogResetOutputs(void);
+
+/*
+ * Logs accesses must be serialized though a mutex
+ */
+virMutex virLogMutex;
+
+static void virLogLock(void)
+{
+ virMutexLock(&virLogMutex);
+}
+static void virLogUnlock(void)
+{
+ virMutexUnlock(&virLogMutex);
+}
+
+
+static const char *virLogPriorityString(virLogPriority lvl) {
+ switch (lvl) {
+ case VIR_LOG_DEBUG:
+ return("debug");
+ case VIR_LOG_INFO:
+ return("info");
+ case VIR_LOG_WARN:
+ return("warning");
+ case VIR_LOG_ERROR:
+ return("error");
+ }
+ return("unknown");
+}
+
+static int virLogInitialized = 0;
+
+/**
+ * virLogStartup:
+ *
+ * Initialize the logging module
+ *
+ * Returns 0 if successful, and -1 in case or error
+ */
+int virLogStartup(void) {
+ if (virLogInitialized)
+ return(-1);
+
+ if (virMutexInit(&virLogMutex) < 0)
+ return -1;
+
+ virLogInitialized = 1;
+ virLogLock();
+ virLogLen = 0;
+ virLogStart = 0;
+ virLogEnd = 0;
+ virLogDefaultPriority = VIR_LOG_DEFAULT;
+ virLogUnlock();
+ return(0);
+}
+
+/**
+ * virLogReset:
+ *
+ * Reset the logging module to its default initial state
+ *
+ * Returns 0 if successful, and -1 in case or error
+ */
+int virLogReset(void) {
+ if (!virLogInitialized)
+ return(virLogStartup());
+
+ virLogLock();
+ virLogResetFilters();
+ virLogResetOutputs();
+ virLogLen = 0;
+ virLogStart = 0;
+ virLogEnd = 0;
+ virLogDefaultPriority = VIR_LOG_DEFAULT;
+ virLogUnlock();
+ return(0);
+}
+/**
+ * virLogShutdown:
+ *
+ * Shutdown the logging module
+ */
+void virLogShutdown(void) {
+ if (!virLogInitialized)
+ return;
+ virLogLock();
+ virLogResetFilters();
+ virLogResetOutputs();
+ virLogLen = 0;
+ virLogStart = 0;
+ virLogEnd = 0;
+ virLogUnlock();
+ virMutexDestroy(&virLogMutex);
+ virLogInitialized = 0;
+}
+
+/*
+ * Store a string in the ring buffer
+ */
+static void virLogStr(const char *str, int len) {
+ int tmp;
+
+ if (str == NULL)
+ return;
+ if (len <= 0)
+ len = strlen(str);
+ if (len > LOG_BUFFER_SIZE)
+ return;
+ virLogLock();
+
+ /*
+ * copy the data and reset the end, we cycle over the end of the buffer
+ */
+ if (virLogEnd + len >= LOG_BUFFER_SIZE) {
+ tmp = LOG_BUFFER_SIZE - virLogEnd;
+ memcpy(&virLogBuffer[virLogEnd], str, tmp);
+ virLogBuffer[LOG_BUFFER_SIZE] = 0;
+ memcpy(&virLogBuffer[0], &str[tmp], len - tmp);
+ virLogEnd = len - tmp;
+ } else {
+ memcpy(&virLogBuffer[virLogEnd], str, len);
+ virLogEnd += len;
+ }
+ /*
+ * Update the log length, and if full move the start index
+ */
+ virLogLen += len;
+ if (virLogLen > LOG_BUFFER_SIZE) {
+ tmp = virLogLen - LOG_BUFFER_SIZE;
+ virLogLen = LOG_BUFFER_SIZE;
+ virLogStart += tmp;
+ }
+ virLogUnlock();
+}
+
+#if 0
+/*
+ * Output the ring buffer
+ */
+static int virLogDump(void *data, virLogOutputFunc f) {
+ int ret = 0, tmp;
+
+ if ((virLogLen == 0) || (f == NULL))
+ return(0);
+ virLogLock();
+ if (virLogStart + virLogLen < LOG_BUFFER_SIZE) {
+push_end:
+ virLogBuffer[virLogStart + virLogLen] = 0;
+ tmp = f(data, &virLogBuffer[virLogStart], virLogLen);
+ if (tmp < 0) {
+ ret = -1;
+ goto error;
+ }
+ ret += tmp;
+ virLogStart += tmp;
+ virLogLen -= tmp;
+ } else {
+ tmp = LOG_BUFFER_SIZE - virLogStart;
+ ret = f(data, &virLogBuffer[virLogStart], tmp);
+ if (ret < 0) {
+ ret = -1;
+ goto error;
+ }
+ if (ret < tmp) {
+ virLogStart += ret;
+ virLogLen -= ret;
+ } else {
+ virLogStart = 0;
+ virLogLen -= tmp;
+ /* dump the second part */
+ if (virLogLen > 0)
+ goto push_end;
+ }
+ }
+error:
+ virLogUnlock();
+ return(ret);
+}
+#endif
+
+/**
+ * virLogSetDefaultPriority:
+ * @priority: the default priority level
+ *
+ * Set the default priority level, i.e. any logged data of a priority
+ * equal or superior to this level will be logged, unless a specific rule
+ * was defined for the log category of the message.
+ *
+ * Returns 0 if successful, -1 in case of error.
+ */
+int virLogSetDefaultPriority(int priority) {
+ if ((priority < VIR_LOG_DEBUG) || (priority > VIR_LOG_ERROR)) {
+ VIR_WARN0(_("Ignoring invalid log level setting."));
+ return(-1);
+ }
+ if (!virLogInitialized)
+ virLogStartup();
+ virLogDefaultPriority = priority;
+ return(0);
+}
+
+/**
+ * virLogResetFilters:
+ *
+ * Removes the set of logging filters defined.
+ *
+ * Returns the number of filters removed
+ */
+static int virLogResetFilters(void) {
+ int i;
+
+ for (i = 0; i < virLogNbFilters;i++)
+ VIR_FREE(virLogFilters[i].match);
+ VIR_FREE(virLogFilters);
+ virLogNbFilters = 0;
+ return(i);
+}
+
+/**
+ * virLogDefineFilter:
+ * @match: the pattern to match
+ * @priority: the priority to give to messages matching the pattern
+ * @flags: extra flag, currently unused
+ *
+ * Defines a pattern used for log filtering, it allow to select or
+ * reject messages independently of the default priority.
+ * The filter defines a rules that will apply only to messages matching
+ * the pattern (currently if @match is a substring of the message category)
+ *
+ * Returns -1 in case of failure or the filter number if successful
+ */
+int virLogDefineFilter(const char *match, int priority,
+ int flags ATTRIBUTE_UNUSED) {
+ int i;
+ char *mdup = NULL;
+
+ if ((match == NULL) || (priority < VIR_LOG_DEBUG) ||
+ (priority > VIR_LOG_ERROR))
+ return(-1);
+
+ virLogLock();
+ for (i = 0;i < virLogNbFilters;i++) {
+ if (STREQ(virLogFilters[i].match, match)) {
+ virLogFilters[i].priority = priority;
+ goto cleanup;
+ }
+ }
+
+ mdup = strdup(match);
+ if (dup == NULL) {
+ i = -1;
+ goto cleanup;
+ }
+ i = virLogNbFilters;
+ if (VIR_REALLOC_N(virLogFilters, virLogNbFilters + 1)) {
+ i = -1;
+ VIR_FREE(mdup);
+ goto cleanup;
+ }
+ virLogFilters[i].match = mdup;
+ virLogFilters[i].priority = priority;
+ virLogNbFilters++;
+cleanup:
+ virLogUnlock();
+ return(i);
+}
+
+/**
+ * virLogFiltersCheck:
+ * @input: the input string
+ *
+ * Check the input of the message against the existing filters. Currently
+ * the match is just a substring check of the category used as the input
+ * string, a more subtle approach could be used instead
+ *
+ * Returns 0 if not matched or the new priority if found.
+ */
+static int virLogFiltersCheck(const char *input) {
+ int ret = 0;
+ int i;
+
+ virLogLock();
+ for (i = 0;i < virLogNbFilters;i++) {
+ if (strstr(input, virLogFilters[i].match)) {
+ ret = virLogFilters[i].priority;
+ break;
+ }
+ }
+ virLogUnlock();
+ return(ret);
+}
+
+/**
+ * virLogResetOutputs:
+ *
+ * Removes the set of logging output defined.
+ *
+ * Returns the number of output removed
+ */
+static int virLogResetOutputs(void) {
+ int i;
+
+ for (i = 0;i < virLogNbOutputs;i++) {
+ if (virLogOutputs[i].c != NULL)
+ virLogOutputs[i].c(virLogOutputs[i].data);
+ }
+ VIR_FREE(virLogOutputs);
+ i = virLogNbOutputs;
+ virLogNbOutputs = 0;
+ return(i);
+}
+
+/**
+ * virLogDefineOutput:
+ * @f: the function to call to output a message
+ * @f: the function to call to close the output (or NULL)
+ * @data: extra data passed as first arg to the function
+ * @priority: minimal priority for this filter, use 0 for none
+ * @flags: extra flag, currently unused
+ *
+ * Defines an output function for log messages. Each message once
+ * gone though filtering is emitted through each registered output.
+ *
+ * Returns -1 in case of failure or the output number if successful
+ */
+int virLogDefineOutput(virLogOutputFunc f, virLogCloseFunc c, void *data,
+ int priority, int flags ATTRIBUTE_UNUSED) {
+ int ret = -1;
+
+ if (f == NULL)
+ return(-1);
+
+ virLogLock();
+ if (VIR_REALLOC_N(virLogOutputs, virLogNbOutputs + 1)) {
+ goto cleanup;
+ }
+ ret = virLogNbOutputs++;
+ virLogOutputs[ret].f = f;
+ virLogOutputs[ret].c = c;
+ virLogOutputs[ret].data = data;
+ virLogOutputs[ret].priority = priority;
+cleanup:
+ virLogUnlock();
+ return(ret);
+}
+
+/**
+ * virLogMessage:
+ * @category: where is that message coming from
+ * @priority: the priority level
+ * @funcname: the function emitting the (debug) message
+ * @linenr: line where the message was emitted
+ * @flags: extra flags, 1 if coming from the error handler
+ * @fmt: the string format
+ * @...: the arguments
+ *
+ * Call the libvirt logger with some informations. Based on the configuration
+ * the message may be stored, sent to output or just discarded
+ */
+void virLogMessage(const char *category, int priority, const char *funcname,
+ long long linenr, int flags, const char *fmt, ...) {
+ char *str = NULL;
+ char *msg;
+ struct timeval cur_time;
+ struct tm time_info;
+ int len, fprio, i, ret;
+
+ if (!virLogInitialized)
+ virLogStartup();
+
+ if (fmt == NULL)
+ return;
+
+ /*
+ * check against list of specific logging patterns
+ */
+ fprio = virLogFiltersCheck(category);
+ if (fprio == 0) {
+ if (priority < virLogDefaultPriority)
+ return;
+ } else if (priority < fprio)
+ return;
+
+ /*
+ * serialize the error message, add level and timestamp
+ */
+ VIR_GET_VAR_STR(fmt, str);
+ if (str == NULL)
+ return;
+ gettimeofday(&cur_time, NULL);
+ localtime_r(&cur_time.tv_sec, &time_info);
+
+ if ((funcname != NULL)) {
+ ret = virAsprintf(&msg, "%02d:%02d:%02d.%03d: %s : %s:%lld : %s\n",
+ time_info.tm_hour, time_info.tm_min,
+ time_info.tm_sec, (int) cur_time.tv_usec / 1000,
+ virLogPriorityString(priority), funcname, linenr, str);
+ } else {
+ ret = virAsprintf(&msg, "%02d:%02d:%02d.%03d: %s : %s\n",
+ time_info.tm_hour, time_info.tm_min,
+ time_info.tm_sec, (int) cur_time.tv_usec / 1000,
+ virLogPriorityString(priority), str);
+ }
+ VIR_FREE(str);
+ if (ret < 0) {
+ /* apparently we're running out of memory */
+ return;
+ }
+
+ /*
+ * Log based on defaults, first store in the history buffer
+ * then push the message on the outputs defined, if none
+ * use stderr.
+ * NOTE: the locking is a single point of contention for multiple
+ * threads, but avoid intermixing. Maybe set up locks per output
+ * to improve paralellism.
+ */
+ len = strlen(msg);
+ virLogStr(msg, len);
+ virLogLock();
+ for (i = 0; i < virLogNbOutputs;i++) {
+ if (priority >= virLogOutputs[i].priority)
+ virLogOutputs[i].f(category, priority, funcname, linenr,
+ msg, len, virLogOutputs[i].data);
+ }
+ if ((virLogNbOutputs == 0) && (flags != 1))
+ safewrite(2, msg, len);
+ virLogUnlock();
+
+ VIR_FREE(msg);
+}
+
+static int virLogOutputToFd(const char *category ATTRIBUTE_UNUSED,
+ int priority ATTRIBUTE_UNUSED,
+ const char *funcname ATTRIBUTE_UNUSED,
+ long long linenr ATTRIBUTE_UNUSED,
+ const char *str, int len, void *data) {
+ int fd = (long) data;
+ int ret;
+
+ if (fd < 0)
+ return(-1);
+ ret = safewrite(fd, str, len);
+ return(ret);
+}
+
+static void virLogCloseFd(void *data) {
+ int fd = (long) data;
+
+ if (fd >= 0)
+ close(fd);
+}
+
+static int virLogAddOutputToStderr(int priority) {
+ if (virLogDefineOutput(virLogOutputToFd, NULL, (void *)2L, priority, 0) < 0)
+ return(-1);
+ return(0);
+}
+
+static int virLogAddOutputToFile(int priority, const char *file) {
+ int fd;
+
+ fd = open(file, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR);
+ if (fd < 0)
+ return(-1);
+ if (virLogDefineOutput(virLogOutputToFd, virLogCloseFd, (void *)(long)fd,
+ priority, 0) < 0) {
+ close(fd);
+ return(-1);
+ }
+ return(0);
+}
+
+#if HAVE_SYSLOG_H
+static int virLogOutputToSyslog(const char *category ATTRIBUTE_UNUSED,
+ int priority,
+ const char *funcname ATTRIBUTE_UNUSED,
+ long long linenr ATTRIBUTE_UNUSED,
+ const char *str, int len ATTRIBUTE_UNUSED,
+ void *data ATTRIBUTE_UNUSED) {
+ int prio;
+
+ switch (priority) {
+ case VIR_LOG_DEBUG:
+ prio = LOG_DEBUG;
+ break;
+ case VIR_LOG_INFO:
+ prio = LOG_INFO;
+ break;
+ case VIR_LOG_WARN:
+ prio = LOG_WARNING;
+ break;
+ case VIR_LOG_ERROR:
+ prio = LOG_ERR;
+ break;
+ default:
+ prio = LOG_ERR;
+ }
+ syslog(prio, "%s", str);
+ return(len);
+}
+
+static char *current_ident = NULL;
+
+static void virLogCloseSyslog(void *data ATTRIBUTE_UNUSED) {
+ closelog();
+ VIR_FREE(current_ident);
+}
+
+static int virLogAddOutputToSyslog(int priority, const char *ident) {
+ /*
+ * ident needs to be kept around on Solaris
+ */
+ VIR_FREE(current_ident);
+ current_ident = strdup(ident);
+ if (current_ident == NULL)
+ return(-1);
+
+ openlog(current_ident, 0, 0);
+ if (virLogDefineOutput(virLogOutputToSyslog, virLogCloseSyslog, NULL,
+ priority, 0) < 0) {
+ closelog();
+ VIR_FREE(current_ident);
+ return(-1);
+ }
+ return(0);
+}
+#endif /* HAVE_SYSLOG_H */
+
+#define IS_SPACE(cur) \
+ ((*cur == ' ') || (*cur == '\t') || (*cur == '\n') || \
+ (*cur == '\r') || (*cur == '\\'))
+
+/**
+ * virLogParseOutputs:
+ * @outputs: string defining a (set of) output(s)
+ *
+ * The format for an output can be:
+ * x:stderr
+ * output goes to stderr
+ * x:syslog:name
+ * use syslog for the output and use the given name as the ident
+ * x:file:file_path
+ * output to a file, with the given filepath
+ * In all case the x prefix is the minimal level, acting as a filter
+ * 0: everything
+ * 1: DEBUG
+ * 2: INFO
+ * 3: WARNING
+ * 4: ERROR
+ *
+ * Multiple output can be defined in a single @output, they just need to be
+ * separated by spaces.
+ *
+ * Returns the number of output parsed and installed or -1 in case of error
+ */
+int virLogParseOutputs(const char *outputs) {
+ const char *cur = outputs, *str;
+ char *name;
+ int prio;
+ int ret = -1;
+ int count = 0;
+
+ if (cur == NULL)
+ return(-1);
+
+ virSkipSpaces(&cur);
+ while (*cur != 0) {
+ prio= virParseNumber(&cur);
+ if ((prio < VIR_LOG_DEBUG) || (prio > VIR_LOG_ERROR))
+ goto cleanup;
+ if (*cur != ':')
+ goto cleanup;
+ cur++;
+ if (STREQLEN(cur, "stderr", 6)) {
+ cur += 6;
+ if (virLogAddOutputToStderr(prio) == 0)
+ count++;
+ } else if (STREQLEN(cur, "syslog", 6)) {
+ cur += 6;
+ if (*cur != ':')
+ goto cleanup;
+ cur++;
+ str = cur;
+ while ((*cur != 0) && (!IS_SPACE(cur)))
+ cur++;
+ if (str == cur)
+ goto cleanup;
+#if HAVE_SYSLOG_H
+ name = strndup(str, cur - str);
+ if (name == NULL)
+ goto cleanup;
+ if (virLogAddOutputToSyslog(prio, name) == 0)
+ count++;
+ VIR_FREE(name);
+#endif /* HAVE_SYSLOG_H */
+ } else if (STREQLEN(cur, "file", 4)) {
+ cur += 4;
+ if (*cur != ':')
+ goto cleanup;
+ cur++;
+ str = cur;
+ while ((*cur != 0) && (!IS_SPACE(cur)))
+ cur++;
+ if (str == cur)
+ goto cleanup;
+ name = strndup(str, cur - str);
+ if (name == NULL)
+ goto cleanup;
+ if (virLogAddOutputToFile(prio, name) == 0)
+ count++;
+ VIR_FREE(name);
+ } else {
+ goto cleanup;
+ }
+ virSkipSpaces(&cur);
+ }
+ ret = count;
+cleanup:
+ if (ret == -1)
+ VIR_WARN0(_("Ignoring invalid log output setting."));
+ return(ret);
+}
+
+/**
+ * virLogParseFilters:
+ * @filters: string defining a (set of) filter(s)
+ *
+ * The format for a filter is:
+ * x:name
+ * where name is a match string
+ * the x prefix is the minimal level where the messages should be logged
+ * 1: DEBUG
+ * 2: INFO
+ * 3: WARNING
+ * 4: ERROR
+ *
+ * Multiple filter can be defined in a single @filters, they just need to be
+ * separated by spaces.
+ *
+ * Returns the number of filter parsed and installed or -1 in case of error
+ */
+int virLogParseFilters(const char *filters) {
+ const char *cur = filters, *str;
+ char *name;
+ int prio;
+ int ret = -1;
+ int count = 0;
+
+ if (cur == NULL)
+ return(-1);
+
+ virSkipSpaces(&cur);
+ while (*cur != 0) {
+ prio= virParseNumber(&cur);
+ if ((prio < VIR_LOG_DEBUG) || (prio > VIR_LOG_ERROR))
+ goto cleanup;
+ if (*cur != ':')
+ goto cleanup;
+ cur++;
+ str = cur;
+ while ((*cur != 0) && (!IS_SPACE(cur)))
+ cur++;
+ if (str == cur)
+ goto cleanup;
+ name = strndup(str, cur - str);
+ if (name == NULL)
+ goto cleanup;
+ if (virLogDefineFilter(name, prio, 0) >= 0)
+ count++;
+ VIR_FREE(name);
+ virSkipSpaces(&cur);
+ }
+ ret = count;
+cleanup:
+ if (ret == -1)
+ VIR_WARN0(_("Ignoring invalid log filter setting."));
+ return(ret);
+}
+
+/**
+ * virLogGetDefaultPriority:
+ *
+ * Returns the current logging priority level.
+ */
+int virLogGetDefaultPriority(void) {
+ return (virLogDefaultPriority);
+}
+
+/**
+ * virLogGetNbFilters:
+ *
+ * Returns the current number of defined log filters.
+ */
+int virLogGetNbFilters(void) {
+ return (virLogNbFilters);
+}
+
+/**
+ * virLogGetNbOutputs:
+ *
+ * Returns the current number of defined log outputs.
+ */
+int virLogGetNbOutputs(void) {
+ return (virLogNbOutputs);
+}
+
+/**
+ * virLogParseDefaultPriority:
+ * @priority: string defining the desired logging level
+ *
+ * Parses and sets the default log priority level. It can take a string or
+ * number corresponding to the following levels:
+ * 1: DEBUG
+ * 2: INFO
+ * 3: WARNING
+ * 4: ERROR
+ *
+ * Returns the parsed log level or -1 on error.
+ */
+int virLogParseDefaultPriority(const char *priority) {
+ int ret = -1;
+
+ if (STREQ(priority, "1") || STREQ(priority, "debug"))
+ ret = virLogSetDefaultPriority(VIR_LOG_DEBUG);
+ else if (STREQ(priority, "2") || STREQ(priority, "info"))
+ ret = virLogSetDefaultPriority(VIR_LOG_INFO);
+ else if (STREQ(priority, "3") || STREQ(priority, "warning"))
+ ret = virLogSetDefaultPriority(VIR_LOG_WARN);
+ else if (STREQ(priority, "4") || STREQ(priority, "error"))
+ ret = virLogSetDefaultPriority(VIR_LOG_ERROR);
+ else
+ VIR_WARN0(_("Ignoring invalid log level setting"));
+
+ return ret;
+}
+
+/**
+ * virLogSetFromEnv:
+ *
+ * Sets virLogDefaultPriority, virLogFilters and virLogOutputs based on
+ * environment variables.
+ */
+void virLogSetFromEnv(void) {
+ char *debugEnv;
+
+ debugEnv = getenv("LIBVIRT_DEBUG");
+ if (debugEnv && *debugEnv)
+ virLogParseDefaultPriority(debugEnv);
+ debugEnv = getenv("LIBVIRT_LOG_FILTERS");
+ if (debugEnv && *debugEnv)
+ virLogParseFilters(strdup(debugEnv));
+ debugEnv = getenv("LIBVIRT_LOG_OUTPUTS");
+ if (debugEnv && *debugEnv)
+ virLogParseOutputs(strdup(debugEnv));
+}
--- /dev/null
+/*
+ * logging.h: internal logging and debugging
+ *
+ * Copyright (C) 2006-2008 Red Hat, Inc.
+ *
+ * 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
+ *
+ */
+
+#ifndef __VIRTLOG_H_
+#define __VIRTLOG_H_
+
+#include "internal.h"
+
+/*
+ * If configured with --enable-debug=yes then library calls
+ * are printed to stderr for debugging or to an appropriate channel
+ * defined at runtime of from the libvirt daemon configuration file
+ */
+#ifdef ENABLE_DEBUG
+#define VIR_DEBUG_INT(category, f, l, fmt,...) \
+ virLogMessage(category, VIR_LOG_DEBUG, f, l, 0, fmt, __VA_ARGS__)
+#else
+#define VIR_DEBUG_INT(category, f, l, fmt,...) \
+ do { } while (0)
+#endif /* !ENABLE_DEBUG */
+
+#define VIR_INFO_INT(category, f, l, fmt,...) \
+ virLogMessage(category, VIR_LOG_INFO, f, l, 0, fmt, __VA_ARGS__)
+#define VIR_WARN_INT(category, f, l, fmt,...) \
+ virLogMessage(category, VIR_LOG_WARN, f, l, 0, fmt, __VA_ARGS__)
+#define VIR_ERROR_INT(category, f, l, fmt,...) \
+ virLogMessage(category, VIR_LOG_ERROR, f, l, 0, fmt, __VA_ARGS__)
+
+#define VIR_DEBUG(fmt,...) \
+ VIR_DEBUG_INT("file." __FILE__, __func__, __LINE__, fmt, __VA_ARGS__)
+#define VIR_DEBUG0(msg) \
+ VIR_DEBUG_INT("file." __FILE__, __func__, __LINE__, "%s", msg)
+#define VIR_INFO(fmt,...) \
+ VIR_INFO_INT("file." __FILE__, __func__, __LINE__, fmt, __VA_ARGS__)
+#define VIR_INFO0(msg) \
+ VIR_INFO_INT("file." __FILE__, __func__, __LINE__, "%s", msg)
+#define VIR_WARN(fmt,...) \
+ VIR_WARN_INT("file." __FILE__, __func__, __LINE__, fmt, __VA_ARGS__)
+#define VIR_WARN0(msg) \
+ VIR_WARN_INT("file." __FILE__, __func__, __LINE__, "%s", msg)
+#define VIR_ERROR(fmt,...) \
+ VIR_ERROR_INT("file." __FILE__, __func__, __LINE__, fmt, __VA_ARGS__)
+#define VIR_ERROR0(msg) \
+ VIR_ERROR_INT("file." __FILE__, __func__, __LINE__, "%s", msg)
+
+/* Legacy compat */
+#define DEBUG(fmt,...) \
+ VIR_DEBUG_INT("file." __FILE__, __func__, __LINE__, fmt, __VA_ARGS__)
+#define DEBUG0(msg) \
+ VIR_DEBUG_INT("file." __FILE__, __func__, __LINE__, "%s", msg)
+
+/*
+ * To be made public
+ */
+typedef enum {
+ VIR_LOG_DEBUG = 1,
+ VIR_LOG_INFO,
+ VIR_LOG_WARN,
+ VIR_LOG_ERROR,
+} virLogPriority;
+
+#define VIR_LOG_DEFAULT VIR_LOG_WARN
+
+/**
+ * virLogOutputFunc:
+ * @category: the category for the message
+ * @priority: the priority for the message
+ * @funcname: the function emitting the message
+ * @linenr: line where the message was emitted
+ * @msg: the message to log, preformatted and zero terminated
+ * @len: the lenght of the message in bytes without the terminating zero
+ * @data: extra output logging data
+ *
+ * Callback function used to output messages
+ *
+ * Returns the number of bytes written or -1 in case of error
+ */
+typedef int (*virLogOutputFunc) (const char *category, int priority,
+ const char *funcname, long long lineno,
+ const char *str, int len, void *data);
+
+/**
+ * virLogCloseFunc:
+ * @data: extra output logging data
+ *
+ * Callback function used to close a log output
+ */
+typedef void (*virLogCloseFunc) (void *data);
+
+extern int virLogGetNbFilters(void);
+extern int virLogGetNbOutputs(void);
+extern int virLogGetDefaultPriority(void);
+extern int virLogSetDefaultPriority(int priority);
+extern void virLogSetFromEnv(void);
+extern int virLogDefineFilter(const char *match, int priority, int flags);
+extern int virLogDefineOutput(virLogOutputFunc f, virLogCloseFunc c,
+ void *data, int priority, int flags);
+
+/*
+ * Internal logging API
+ */
+
+extern int virLogStartup(void);
+extern int virLogReset(void);
+extern void virLogShutdown(void);
+extern int virLogParseDefaultPriority(const char *priority);
+extern int virLogParseFilters(const char *filters);
+extern int virLogParseOutputs(const char *output);
+extern void virLogMessage(const char *category, int priority,
+ const char *funcname, long long linenr, int flags,
+ const char *fmt, ...) ATTRIBUTE_FMT_PRINTF(6, 7);
+
+#endif
--- /dev/null
+/*
+ * memory.c: safer memory allocation
+ *
+ * Copyright (C) 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
+ *
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <stddef.h>
+
+#include "memory.h"
+
+
+#if TEST_OOM
+static int testMallocNext = 0;
+static int testMallocFailFirst = 0;
+static int testMallocFailLast = 0;
+static void (*testMallocHook)(int, void*) = NULL;
+static void *testMallocHookData = NULL;
+
+void virAllocTestInit(void)
+{
+ testMallocNext = 1;
+ testMallocFailFirst = 0;
+ testMallocFailLast = 0;
+}
+
+int virAllocTestCount(void)
+{
+ return testMallocNext - 1;
+}
+
+void virAllocTestHook(void (*func)(int, void*), void *data)
+{
+ testMallocHook = func;
+ testMallocHookData = data;
+}
+
+void virAllocTestOOM(int n, int m)
+{
+ testMallocNext = 1;
+ testMallocFailFirst = n;
+ testMallocFailLast = n + m - 1;
+}
+
+static int virAllocTestFail(void)
+{
+ int fail = 0;
+ if (testMallocNext == 0)
+ return 0;
+
+ fail =
+ testMallocNext >= testMallocFailFirst &&
+ testMallocNext <= testMallocFailLast;
+
+ if (fail && testMallocHook)
+ (testMallocHook)(testMallocNext, testMallocHookData);
+
+ testMallocNext++;
+ return fail;
+}
+#endif
+
+
+/**
+ * virAlloc:
+ * @ptrptr: pointer to pointer for address of allocated memory
+ * @size: number of bytes to allocate
+ *
+ * Allocate 'size' bytes of memory. Return the address of the
+ * allocated memory in 'ptrptr'. The newly allocated memory is
+ * filled with zeros.
+ *
+ * Returns -1 on failure to allocate, zero on success
+ */
+int virAlloc(void *ptrptr, size_t size)
+{
+#if TEST_OOM
+ if (virAllocTestFail()) {
+ *(void **)ptrptr = NULL;
+ return -1;
+ }
+#endif
+
+ *(void **)ptrptr = calloc(1, size);
+ if (*(void **)ptrptr == NULL)
+ return -1;
+ return 0;
+}
+
+/**
+ * virAllocN:
+ * @ptrptr: pointer to pointer for address of allocated memory
+ * @size: number of bytes to allocate
+ * @count: number of elements to allocate
+ *
+ * Allocate an array of memory 'count' elements long,
+ * each with 'size' bytes. Return the address of the
+ * allocated memory in 'ptrptr'. The newly allocated
+ * memory is filled with zeros.
+ *
+ * Returns -1 on failure to allocate, zero on success
+ */
+int virAllocN(void *ptrptr, size_t size, size_t count)
+{
+#if TEST_OOM
+ if (virAllocTestFail()) {
+ *(void **)ptrptr = NULL;
+ return -1;
+ }
+#endif
+
+ *(void**)ptrptr = calloc(count, size);
+ if (*(void**)ptrptr == NULL)
+ return -1;
+ return 0;
+}
+
+/**
+ * virReallocN:
+ * @ptrptr: pointer to pointer for address of allocated memory
+ * @size: number of bytes to allocate
+ * @count: number of elements in array
+ *
+ * Resize the block of memory in 'ptrptr' to be an array of
+ * 'count' elements, each 'size' bytes in length. Update 'ptrptr'
+ * with the address of the newly allocated memory. On failure,
+ * 'ptrptr' is not changed and still points to the original memory
+ * block. The newly allocated memory is filled with zeros.
+ *
+ * Returns -1 on failure to allocate, zero on success
+ */
+int virReallocN(void *ptrptr, size_t size, size_t count)
+{
+ void *tmp;
+#if TEST_OOM
+ if (virAllocTestFail())
+ return -1;
+#endif
+
+ if (xalloc_oversized(count, size)) {
+ errno = ENOMEM;
+ return -1;
+ }
+ tmp = realloc(*(void**)ptrptr, size * count);
+ if (!tmp && (size * count))
+ return -1;
+ *(void**)ptrptr = tmp;
+ return 0;
+}
+
+/**
+ * virFree:
+ * @ptrptr: pointer to pointer for address of memory to be freed
+ *
+ * Release the chunk of memory in the pointer pointed to by
+ * the 'ptrptr' variable. After release, 'ptrptr' will be
+ * updated to point to NULL.
+ */
+void virFree(void *ptrptr)
+{
+ free(*(void**)ptrptr);
+ *(void**)ptrptr = NULL;
+}
--- /dev/null
+/*
+ * memory.c: safer memory allocation
+ *
+ * Copyright (C) 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
+ *
+ */
+
+
+#ifndef __VIR_MEMORY_H_
+#define __VIR_MEMORY_H_
+
+#include "internal.h"
+
+/* Return 1 if an array of N objects, each of size S, cannot exist due
+ to size arithmetic overflow. S must be positive and N must be
+ nonnegative. This is a macro, not an inline function, so that it
+ works correctly even when SIZE_MAX < N.
+
+ By gnulib convention, SIZE_MAX represents overflow in size
+ calculations, so the conservative dividend to use here is
+ SIZE_MAX - 1, since SIZE_MAX might represent an overflowed value.
+ However, malloc (SIZE_MAX) fails on all known hosts where
+ sizeof (ptrdiff_t) <= sizeof (size_t), so do not bother to test for
+ exactly-SIZE_MAX allocations on such hosts; this avoids a test and
+ branch when S is known to be 1. */
+#ifndef xalloc_oversized
+# define xalloc_oversized(n, s) \
+ ((size_t) (sizeof (ptrdiff_t) <= sizeof (size_t) ? -1 : -2) / (s) < (n))
+#endif
+
+
+
+/* Don't call these directly - use the macros below */
+int virAlloc(void *ptrptr, size_t size) ATTRIBUTE_RETURN_CHECK;
+int virAllocN(void *ptrptr, size_t size, size_t count) ATTRIBUTE_RETURN_CHECK;
+int virReallocN(void *ptrptr, size_t size, size_t count) ATTRIBUTE_RETURN_CHECK;
+void virFree(void *ptrptr);
+
+/**
+ * VIR_ALLOC:
+ * @ptr: pointer to hold address of allocated memory
+ *
+ * Allocate sizeof(*ptr) bytes of memory and store
+ * the address of allocated memory in 'ptr'. Fill the
+ * newly allocated memory with zeros.
+ *
+ * Returns -1 on failure, 0 on success
+ */
+#define VIR_ALLOC(ptr) virAlloc(&(ptr), sizeof(*(ptr)))
+
+/**
+ * VIR_ALLOC_N:
+ * @ptr: pointer to hold address of allocated memory
+ * @count: number of elements to allocate
+ *
+ * Allocate an array of 'count' elements, each sizeof(*ptr)
+ * bytes long and store the address of allocated memory in
+ * 'ptr'. Fill the newly allocated memory with zeros.
+ *
+ * Returns -1 on failure, 0 on success
+ */
+#define VIR_ALLOC_N(ptr, count) virAllocN(&(ptr), sizeof(*(ptr)), (count))
+
+/**
+ * VIR_REALLOC_N:
+ * @ptr: pointer to hold address of allocated memory
+ * @count: number of elements to allocate
+ *
+ * Re-allocate an array of 'count' elements, each sizeof(*ptr)
+ * bytes long and store the address of allocated memory in
+ * 'ptr'. Fill the newly allocated memory with zeros
+ *
+ * Returns -1 on failure, 0 on success
+ */
+#define VIR_REALLOC_N(ptr, count) virReallocN(&(ptr), sizeof(*(ptr)), (count))
+
+/**
+ * VIR_FREE:
+ * @ptr: pointer holding address to be freed
+ *
+ * Free the memory stored in 'ptr' and update to point
+ * to NULL.
+ */
+#define VIR_FREE(ptr) virFree(&(ptr))
+
+
+#if TEST_OOM
+void virAllocTestInit(void);
+int virAllocTestCount(void);
+void virAllocTestOOM(int n, int m);
+void virAllocTestHook(void (*func)(int, void*), void *data);
+#endif
+
+
+
+#endif /* __VIR_MEMORY_H_ */
--- /dev/null
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * 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
+ *
+ * Authors:
+ * Mark McLoughlin <markmc@redhat.com>
+ */
+
+#include <config.h>
+
+#include "pci.h"
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "logging.h"
+#include "memory.h"
+#include "util.h"
+#include "virterror_internal.h"
+
+/* avoid compilation breakage on some systems */
+#ifndef MODPROBE
+#define MODPROBE "modprobe"
+#endif
+
+#define PCI_SYSFS "/sys/bus/pci/"
+#define PCI_ID_LEN 10 /* "XXXX XXXX" */
+#define PCI_ADDR_LEN 13 /* "XXXX:XX:XX.X" */
+
+struct _pciDevice {
+ unsigned domain;
+ unsigned bus;
+ unsigned slot;
+ unsigned function;
+
+ char name[PCI_ADDR_LEN]; /* domain:bus:slot.function */
+ char id[PCI_ID_LEN]; /* product vendor */
+ char path[PATH_MAX];
+ int fd;
+
+ unsigned initted;
+ unsigned pcie_cap_pos;
+ unsigned pci_pm_cap_pos;
+ unsigned has_flr : 1;
+ unsigned has_pm_reset : 1;
+ unsigned managed : 1;
+};
+
+/* For virReportOOMError() and virReportSystemError() */
+#define VIR_FROM_THIS VIR_FROM_NONE
+
+#define pciReportError(conn, code, fmt...) \
+ virReportErrorHelper(conn, VIR_FROM_NONE, code, __FILE__, \
+ __FUNCTION__, __LINE__, fmt)
+
+/* Specifications referenced in comments:
+ * PCI30 - PCI Local Bus Specification 3.0
+ * PCIe20 - PCI Express Base Specification 2.0
+ * BR12 - PCI-to-PCI Bridge Architecture Specification 1.2
+ * PM12 - PCI Bus Power Management Interface Specification 1.2
+ * ECN_AF - Advanced Capabilities for Conventional PCI ECN
+ */
+
+/* Type 0 config space header length; PCI30 Section 6.1 Configuration Space Organization */
+#define PCI_CONF_LEN 0x100
+#define PCI_CONF_HEADER_LEN 0x40
+
+/* PCI30 6.2.1 */
+#define PCI_HEADER_TYPE 0x0e /* Header type */
+#define PCI_HEADER_TYPE_BRIDGE 0x1
+#define PCI_HEADER_TYPE_MASK 0x7f
+#define PCI_HEADER_TYPE_MULTI 0x80
+
+/* PCI30 6.2.1 Device Identification */
+#define PCI_CLASS_DEVICE 0x0a /* Device class */
+
+/* Class Code for bridge; PCI30 D.7 Base Class 06h */
+#define PCI_CLASS_BRIDGE_PCI 0x0604
+
+/* PCI30 6.2.3 Device Status */
+#define PCI_STATUS 0x06 /* 16 bits */
+#define PCI_STATUS_CAP_LIST 0x10 /* Support Capability List */
+
+/* PCI30 6.7 Capabilities List */
+#define PCI_CAPABILITY_LIST 0x34 /* Offset of first capability list entry */
+
+/* PM12 3.2.1 Capability Identifier */
+#define PCI_CAP_ID_PM 0x01 /* Power Management */
+/* PCI30 H Capability IDs */
+#define PCI_CAP_ID_EXP 0x10 /* PCI Express */
+/* ECN_AF 6.x.1.1 Capability ID for AF */
+#define PCI_CAP_ID_AF 0x13 /* Advanced Features */
+
+/* PCIe20 7.8.3 Device Capabilities Register (Offset 04h) */
+#define PCI_EXP_DEVCAP 0x4 /* Device capabilities */
+#define PCI_EXP_DEVCAP_FLR (1<<28) /* Function Level Reset */
+
+/* Header type 1 BR12 3.2 PCI-to-PCI Bridge Configuration Space Header Format */
+#define PCI_PRIMARY_BUS 0x18 /* BR12 3.2.5.2 Primary bus number */
+#define PCI_SECONDARY_BUS 0x19 /* BR12 3.2.5.3 Secondary bus number */
+#define PCI_SUBORDINATE_BUS 0x1a /* BR12 3.2.5.4 Highest bus number behind the bridge */
+#define PCI_BRIDGE_CONTROL 0x3e
+/* BR12 3.2.5.18 Bridge Control Register */
+#define PCI_BRIDGE_CTL_RESET 0x40 /* Secondary bus reset */
+
+/* PM12 3.2.4 Power Management Control/Status (Offset = 4) */
+#define PCI_PM_CTRL 4 /* PM control and status register */
+#define PCI_PM_CTRL_STATE_MASK 0x3 /* Current power state (D0 to D3) */
+#define PCI_PM_CTRL_STATE_D0 0x0 /* D0 state */
+#define PCI_PM_CTRL_STATE_D3hot 0x3 /* D3 state */
+#define PCI_PM_CTRL_NO_SOFT_RESET 0x8 /* No reset for D3hot->D0 */
+
+/* ECN_AF 6.x.1 Advanced Features Capability Structure */
+#define PCI_AF_CAP 0x3 /* Advanced features capabilities */
+#define PCI_AF_CAP_FLR 0x2 /* Function Level Reset */
+
+static int
+pciOpenConfig(pciDevice *dev)
+{
+ int fd;
+
+ if (dev->fd > 0)
+ return 0;
+
+ fd = open(dev->path, O_RDWR);
+ if (fd < 0) {
+ char ebuf[1024];
+ VIR_WARN(_("Failed to open config space file '%s': %s"),
+ dev->path, virStrerror(errno, ebuf, sizeof(ebuf)));
+ return -1;
+ }
+ VIR_DEBUG("%s %s: opened %s", dev->id, dev->name, dev->path);
+ dev->fd = fd;
+ return 0;
+}
+
+static int
+pciRead(pciDevice *dev, unsigned pos, uint8_t *buf, unsigned buflen)
+{
+ memset(buf, 0, buflen);
+
+ if (pciOpenConfig(dev) < 0)
+ return -1;
+
+ if (lseek(dev->fd, pos, SEEK_SET) != pos ||
+ saferead(dev->fd, buf, buflen) != buflen) {
+ char ebuf[1024];
+ VIR_WARN(_("Failed to read from '%s' : %s"), dev->path,
+ virStrerror(errno, ebuf, sizeof(ebuf)));
+ return -1;
+ }
+ return 0;
+}
+
+static uint8_t
+pciRead8(pciDevice *dev, unsigned pos)
+{
+ uint8_t buf;
+ pciRead(dev, pos, &buf, sizeof(buf));
+ return buf;
+}
+
+static uint16_t
+pciRead16(pciDevice *dev, unsigned pos)
+{
+ uint8_t buf[2];
+ pciRead(dev, pos, &buf[0], sizeof(buf));
+ return (buf[0] << 0) | (buf[1] << 8);
+}
+
+static uint32_t
+pciRead32(pciDevice *dev, unsigned pos)
+{
+ uint8_t buf[4];
+ pciRead(dev, pos, &buf[0], sizeof(buf));
+ return (buf[0] << 0) | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
+}
+
+static int
+pciWrite(pciDevice *dev, unsigned pos, uint8_t *buf, unsigned buflen)
+{
+ if (pciOpenConfig(dev) < 0)
+ return -1;
+
+ if (lseek(dev->fd, pos, SEEK_SET) != pos ||
+ safewrite(dev->fd, buf, buflen) != buflen) {
+ char ebuf[1024];
+ VIR_WARN(_("Failed to write to '%s' : %s"), dev->path,
+ virStrerror(errno, ebuf, sizeof(ebuf)));
+ return -1;
+ }
+ return 0;
+}
+
+static void
+pciWrite16(pciDevice *dev, unsigned pos, uint16_t val)
+{
+ uint8_t buf[2] = { (val >> 0), (val >> 8) };
+ pciWrite(dev, pos, &buf[0], sizeof(buf));
+}
+
+static void
+pciWrite32(pciDevice *dev, unsigned pos, uint32_t val)
+{
+ uint8_t buf[4] = { (val >> 0), (val >> 8), (val >> 16), (val >> 14) };
+ pciWrite(dev, pos, &buf[0], sizeof(buf));
+}
+
+typedef int (*pciIterPredicate)(pciDevice *, pciDevice *, void *);
+
+/* Iterate over available PCI devices calling @predicate
+ * to compare each one to @dev.
+ * Return -1 on error since we don't want to assume it is
+ * safe to reset if there is an error.
+ */
+static int
+pciIterDevices(virConnectPtr conn,
+ pciIterPredicate predicate,
+ pciDevice *dev,
+ pciDevice **matched,
+ void *data)
+{
+ DIR *dir;
+ struct dirent *entry;
+ int ret = 0;
+
+ *matched = NULL;
+
+ VIR_DEBUG("%s %s: iterating over " PCI_SYSFS "devices", dev->id, dev->name);
+
+ dir = opendir(PCI_SYSFS "devices");
+ if (!dir) {
+ VIR_WARN0("Failed to open " PCI_SYSFS "devices");
+ return -1;
+ }
+
+ while ((entry = readdir(dir))) {
+ unsigned domain, bus, slot, function;
+ pciDevice *check;
+
+ /* Ignore '.' and '..' */
+ if (entry->d_name[0] == '.')
+ continue;
+
+ if (sscanf(entry->d_name, "%x:%x:%x.%x",
+ &domain, &bus, &slot, &function) < 4) {
+ VIR_WARN("Unusual entry in " PCI_SYSFS "devices: %s", entry->d_name);
+ continue;
+ }
+
+ check = pciGetDevice(conn, domain, bus, slot, function);
+ if (!check) {
+ ret = -1;
+ break;
+ }
+
+ if (predicate(dev, check, data)) {
+ VIR_DEBUG("%s %s: iter matched on %s", dev->id, dev->name, check->name);
+ *matched = check;
+ break;
+ }
+ pciFreeDevice(conn, check);
+ }
+ closedir(dir);
+ return ret;
+}
+
+static uint8_t
+pciFindCapabilityOffset(pciDevice *dev, unsigned capability)
+{
+ uint16_t status;
+ uint8_t pos;
+
+ status = pciRead16(dev, PCI_STATUS);
+ if (!(status & PCI_STATUS_CAP_LIST))
+ return 0;
+
+ pos = pciRead8(dev, PCI_CAPABILITY_LIST);
+
+ /* Zero indicates last capability, capabilities can't
+ * be in the config space header and 0xff is returned
+ * by the kernel if we don't have access to this region
+ *
+ * Note: we're not handling loops or extended
+ * capabilities here.
+ */
+ while (pos >= PCI_CONF_HEADER_LEN && pos != 0xff) {
+ uint8_t capid = pciRead8(dev, pos);
+ if (capid == capability) {
+ VIR_DEBUG("%s %s: found cap 0x%.2x at 0x%.2x",
+ dev->id, dev->name, capability, pos);
+ return pos;
+ }
+
+ pos = pciRead8(dev, pos + 1);
+ }
+
+ VIR_DEBUG("%s %s: failed to find cap 0x%.2x", dev->id, dev->name, capability);
+
+ return 0;
+}
+
+static unsigned
+pciDetectFunctionLevelReset(pciDevice *dev)
+{
+ uint32_t caps;
+ uint8_t pos;
+
+ /* The PCIe Function Level Reset capability allows
+ * individual device functions to be reset without
+ * affecting any other functions on the device or
+ * any other devices on the bus. This is only common
+ * on SR-IOV NICs at the moment.
+ */
+ if (dev->pcie_cap_pos) {
+ caps = pciRead32(dev, dev->pcie_cap_pos + PCI_EXP_DEVCAP);
+ if (caps & PCI_EXP_DEVCAP_FLR) {
+ VIR_DEBUG("%s %s: detected PCIe FLR capability", dev->id, dev->name);
+ return 1;
+ }
+ }
+
+ /* The PCI AF Function Level Reset capability is
+ * the same thing, except for conventional PCI
+ * devices. This is not common yet.
+ */
+ pos = pciFindCapabilityOffset(dev, PCI_CAP_ID_AF);
+ if (pos) {
+ caps = pciRead16(dev, pos + PCI_AF_CAP);
+ if (caps & PCI_AF_CAP_FLR) {
+ VIR_DEBUG("%s %s: detected PCI FLR capability", dev->id, dev->name);
+ return 1;
+ }
+ }
+
+ VIR_DEBUG("%s %s: no FLR capability found", dev->id, dev->name);
+
+ return 0;
+}
+
+/* Require the device has the PCI Power Management capability
+ * and that a D3hot->D0 transition will results in a full
+ * internal reset, not just a soft reset.
+ */
+static unsigned
+pciDetectPowerManagementReset(pciDevice *dev)
+{
+ if (dev->pci_pm_cap_pos) {
+ uint32_t ctl;
+
+ /* require the NO_SOFT_RESET bit is clear */
+ ctl = pciRead32(dev, dev->pci_pm_cap_pos + PCI_PM_CTRL);
+ if (!(ctl & PCI_PM_CTRL_NO_SOFT_RESET)) {
+ VIR_DEBUG("%s %s: detected PM reset capability", dev->id, dev->name);
+ return 1;
+ }
+ }
+
+ VIR_DEBUG("%s %s: no PM reset capability found", dev->id, dev->name);
+
+ return 0;
+}
+
+/* Any active devices other than the one supplied on the same domain/bus ? */
+static int
+pciSharesBusWithActive(pciDevice *dev, pciDevice *check, void *data)
+{
+ pciDeviceList *activeDevs = data;
+
+ if (dev->domain != check->domain ||
+ dev->bus != check->bus ||
+ (check->slot == check->slot &&
+ check->function == check->function))
+ return 0;
+
+ if (activeDevs && !pciDeviceListFind(activeDevs, check))
+ return 0;
+
+ return 1;
+}
+
+static pciDevice *
+pciBusContainsActiveDevices(virConnectPtr conn,
+ pciDevice *dev,
+ pciDeviceList *activeDevs)
+{
+ pciDevice *active = NULL;
+ if (pciIterDevices(conn, pciSharesBusWithActive,
+ dev, &active, activeDevs) < 0)
+ return NULL;
+ return active;
+}
+
+/* Is @check the parent of @dev ? */
+static int
+pciIsParent(pciDevice *dev, pciDevice *check, void *data ATTRIBUTE_UNUSED)
+{
+ uint16_t device_class;
+ uint8_t header_type, secondary, subordinate;
+
+ if (dev->domain != check->domain)
+ return 0;
+
+ /* Is it a bridge? */
+ device_class = pciRead16(check, PCI_CLASS_DEVICE);
+ if (device_class != PCI_CLASS_BRIDGE_PCI)
+ return 0;
+
+ /* Is it a plane? */
+ header_type = pciRead8(check, PCI_HEADER_TYPE);
+ if ((header_type & PCI_HEADER_TYPE_MASK) != PCI_HEADER_TYPE_BRIDGE)
+ return 0;
+
+ secondary = pciRead8(check, PCI_SECONDARY_BUS);
+ subordinate = pciRead8(check, PCI_SUBORDINATE_BUS);
+
+ VIR_DEBUG("%s %s: found parent device %s\n", dev->id, dev->name, check->name);
+
+ /* No, it's superman! */
+ return (dev->bus >= secondary && dev->bus <= subordinate);
+}
+
+static pciDevice *
+pciGetParentDevice(virConnectPtr conn, pciDevice *dev)
+{
+ pciDevice *parent = NULL;
+ pciIterDevices(conn, pciIsParent, dev, &parent, NULL);
+ return parent;
+}
+
+/* Secondary Bus Reset is our sledgehammer - it resets all
+ * devices behind a bus.
+ */
+static int
+pciTrySecondaryBusReset(virConnectPtr conn,
+ pciDevice *dev,
+ pciDeviceList *activeDevs)
+{
+ pciDevice *parent, *conflict;
+ uint8_t config_space[PCI_CONF_LEN];
+ uint16_t ctl;
+ int ret = -1;
+
+ /* For now, we just refuse to do a secondary bus reset
+ * if there are other devices/functions behind the bus.
+ * In future, we could allow it so long as those devices
+ * are not in use by the host or other guests.
+ */
+ if ((conflict = pciBusContainsActiveDevices(conn, dev, activeDevs))) {
+ pciReportError(conn, VIR_ERR_NO_SUPPORT,
+ _("Active %s devices on bus with %s, not doing bus reset"),
+ conflict->name, dev->name);
+ return -1;
+ }
+
+ /* Find the parent bus */
+ parent = pciGetParentDevice(conn, dev);
+ if (!parent) {
+ pciReportError(conn, VIR_ERR_NO_SUPPORT,
+ _("Failed to find parent device for %s"),
+ dev->name);
+ return -1;
+ }
+
+ VIR_DEBUG("%s %s: doing a secondary bus reset", dev->id, dev->name);
+
+ /* Save and restore the device's config space; we only do this
+ * for the supplied device since we refuse to do a reset if there
+ * are multiple devices/functions
+ */
+ if (pciRead(dev, 0, config_space, PCI_CONF_LEN) < 0) {
+ pciReportError(conn, VIR_ERR_NO_SUPPORT,
+ _("Failed to save PCI config space for %s"),
+ dev->name);
+ goto out;
+ }
+
+ /* Read the control register, set the reset flag, wait 200ms,
+ * unset the reset flag and wait 200ms.
+ */
+ ctl = pciRead16(dev, PCI_BRIDGE_CONTROL);
+
+ pciWrite16(parent, PCI_BRIDGE_CONTROL, ctl | PCI_BRIDGE_CTL_RESET);
+
+ usleep(200 * 1000); /* sleep 200ms */
+
+ pciWrite16(parent, PCI_BRIDGE_CONTROL, ctl);
+
+ usleep(200 * 1000); /* sleep 200ms */
+
+ if (pciWrite(dev, 0, config_space, PCI_CONF_LEN) < 0) {
+ pciReportError(conn, VIR_ERR_NO_SUPPORT,
+ _("Failed to restore PCI config space for %s"),
+ dev->name);
+ goto out;
+ }
+ ret = 0;
+out:
+ pciFreeDevice(conn, parent);
+ return ret;
+}
+
+/* Power management reset attempts to reset a device using a
+ * D-state transition from D3hot to D0. Note, in detect_pm_reset()
+ * above we require the device supports a full internal reset.
+ */
+static int
+pciTryPowerManagementReset(virConnectPtr conn ATTRIBUTE_UNUSED, pciDevice *dev)
+{
+ uint8_t config_space[PCI_CONF_LEN];
+ uint32_t ctl;
+
+ if (!dev->pci_pm_cap_pos)
+ return -1;
+
+ /* Save and restore the device's config space. */
+ if (pciRead(dev, 0, &config_space[0], PCI_CONF_LEN) < 0) {
+ pciReportError(conn, VIR_ERR_NO_SUPPORT,
+ _("Failed to save PCI config space for %s"),
+ dev->name);
+ return -1;
+ }
+
+ VIR_DEBUG("%s %s: doing a power management reset", dev->id, dev->name);
+
+ ctl = pciRead32(dev, dev->pci_pm_cap_pos + PCI_PM_CTRL);
+ ctl &= ~PCI_PM_CTRL_STATE_MASK;
+
+ pciWrite32(dev, dev->pci_pm_cap_pos + PCI_PM_CTRL, ctl|PCI_PM_CTRL_STATE_D3hot);
+
+ usleep(10 * 1000); /* sleep 10ms */
+
+ pciWrite32(dev, dev->pci_pm_cap_pos + PCI_PM_CTRL, ctl|PCI_PM_CTRL_STATE_D0);
+
+ usleep(10 * 1000); /* sleep 10ms */
+
+ if (pciWrite(dev, 0, &config_space[0], PCI_CONF_LEN) < 0) {
+ pciReportError(conn, VIR_ERR_NO_SUPPORT,
+ _("Failed to restore PCI config space for %s"),
+ dev->name);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+pciInitDevice(virConnectPtr conn, pciDevice *dev)
+{
+ if (pciOpenConfig(dev) < 0) {
+ virReportSystemError(conn, errno,
+ _("Failed to open config space file '%s'"),
+ dev->path);
+ return -1;
+ }
+
+ dev->pcie_cap_pos = pciFindCapabilityOffset(dev, PCI_CAP_ID_EXP);
+ dev->pci_pm_cap_pos = pciFindCapabilityOffset(dev, PCI_CAP_ID_PM);
+ dev->has_flr = pciDetectFunctionLevelReset(dev);
+ dev->has_pm_reset = pciDetectPowerManagementReset(dev);
+ dev->initted = 1;
+ return 0;
+}
+
+int
+pciResetDevice(virConnectPtr conn,
+ pciDevice *dev,
+ pciDeviceList *activeDevs)
+{
+ int ret = -1;
+
+ if (activeDevs && pciDeviceListFind(activeDevs, dev)) {
+ pciReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("Not resetting active device %s"), dev->name);
+ return -1;
+ }
+
+ if (!dev->initted && pciInitDevice(conn, dev) < 0)
+ return -1;
+
+ /* KVM will perform FLR when starting and stopping
+ * a guest, so there is no need for us to do it here.
+ */
+ if (dev->has_flr)
+ return 0;
+
+ /* If the device supports PCI power management reset,
+ * that's the next best thing because it only resets
+ * the function, not the whole device.
+ */
+ if (dev->has_pm_reset)
+ ret = pciTryPowerManagementReset(conn, dev);
+
+ /* Bus reset is not an option with the root bus */
+ if (ret < 0 && dev->bus != 0)
+ ret = pciTrySecondaryBusReset(conn, dev, activeDevs);
+
+ if (ret < 0) {
+ virErrorPtr err = virGetLastError();
+ pciReportError(conn, VIR_ERR_NO_SUPPORT,
+ _("Unable to reset PCI device %s: %s"),
+ dev->name,
+ err ? err->message : _("no FLR, PM reset or bus reset available"));
+ }
+
+ return ret;
+}
+
+
+static void
+pciDriverDir(char *buf, size_t buflen, const char *driver)
+{
+ snprintf(buf, buflen, PCI_SYSFS "drivers/%s", driver);
+}
+
+static void
+pciDriverFile(char *buf, size_t buflen, const char *driver, const char *file)
+{
+ snprintf(buf, buflen, PCI_SYSFS "drivers/%s/%s", driver, file);
+}
+
+static void
+pciDeviceFile(char *buf, size_t buflen, const char *device, const char *file)
+{
+ snprintf(buf, buflen, PCI_SYSFS "devices/%s/%s", device, file);
+}
+
+
+static const char *
+pciFindStubDriver(virConnectPtr conn)
+{
+ char drvpath[PATH_MAX];
+ int probed = 0;
+
+recheck:
+ pciDriverDir(drvpath, sizeof(drvpath), "pci-stub");
+ if (virFileExists(drvpath))
+ return "pci-stub";
+ pciDriverDir(drvpath, sizeof(drvpath), "pciback");
+ if (virFileExists(drvpath))
+ return "pciback";
+
+ if (!probed) {
+ const char *const stubprobe[] = { MODPROBE, "pci-stub", NULL };
+ const char *const backprobe[] = { MODPROBE, "pciback", NULL };
+
+ probed = 1;
+ /*
+ * Probing for pci-stub will succeed regardless of whether
+ * on native or Xen kernels.
+ * On Xen though, we want to prefer pciback, so probe
+ * for that first, because that will only work on Xen
+ */
+ if (virRun(conn, backprobe, NULL) < 0 &&
+ virRun(conn, stubprobe, NULL) < 0) {
+ char ebuf[1024];
+ VIR_WARN(_("failed to load pci-stub or pciback drivers: %s"),
+ virStrerror(errno, ebuf, sizeof ebuf));
+ return 0;
+ }
+
+ goto recheck;
+ }
+
+ return NULL;
+}
+
+
+static int
+pciBindDeviceToStub(virConnectPtr conn, pciDevice *dev, const char *driver)
+{
+ char drvdir[PATH_MAX];
+ char path[PATH_MAX];
+
+ /* Add the PCI device ID to the stub's dynamic ID table;
+ * this is needed to allow us to bind the device to the stub.
+ * Note: if the device is not currently bound to any driver,
+ * stub will immediately be bound to the device. Also, note
+ * that if a new device with this ID is hotplugged, or if a probe
+ * is triggered for such a device, it will also be immediately
+ * bound by the stub.
+ */
+ pciDriverFile(path, sizeof(path), driver, "new_id");
+ if (virFileWriteStr(path, dev->id) < 0) {
+ virReportSystemError(conn, errno,
+ _("Failed to add PCI device ID '%s' to %s"),
+ dev->id, driver);
+ return -1;
+ }
+
+ /* If the device is already bound to a driver, unbind it.
+ * Note, this will have rather unpleasant side effects if this
+ * PCI device happens to be IDE controller for the disk hosting
+ * your root filesystem.
+ */
+ pciDeviceFile(path, sizeof(path), dev->name, "driver/unbind");
+ if (virFileExists(path) && virFileWriteStr(path, dev->name) < 0) {
+ virReportSystemError(conn, errno,
+ _("Failed to unbind PCI device '%s'"), dev->name);
+ return -1;
+ }
+
+ /* If the device isn't already bound to pci-stub, try binding it now.
+ */
+ pciDriverDir(drvdir, sizeof(drvdir), driver);
+ pciDeviceFile(path, sizeof(path), dev->name, "driver");
+ if (!virFileLinkPointsTo(path, drvdir)) {
+ /* Xen's pciback.ko wants you to use new_slot first */
+ pciDriverFile(path, sizeof(path), driver, "new_slot");
+ if (virFileExists(path) && virFileWriteStr(path, dev->name) < 0) {
+ virReportSystemError(conn, errno,
+ _("Failed to add slot for PCI device '%s' to %s"),
+ dev->name, driver);
+ return -1;
+ }
+
+ pciDriverFile(path, sizeof(path), driver, "bind");
+ if (virFileWriteStr(path, dev->name) < 0) {
+ virReportSystemError(conn, errno,
+ _("Failed to bind PCI device '%s' to %s"),
+ dev->name, driver);
+ return -1;
+ }
+ }
+
+ /* If 'remove_id' exists, remove the device id from pci-stub's dynamic
+ * ID table so that 'drivers_probe' works below.
+ */
+ pciDriverFile(path, sizeof(path), driver, "remove_id");
+ if (virFileExists(path) && virFileWriteStr(path, dev->id) < 0) {
+ virReportSystemError(conn, errno,
+ _("Failed to remove PCI ID '%s' from %s"),
+ dev->id, driver);
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+pciDettachDevice(virConnectPtr conn, pciDevice *dev)
+{
+ const char *driver = pciFindStubDriver(conn);
+ if (!driver) {
+ pciReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
+ _("cannot find any PCI stub module"));
+ return -1;
+ }
+
+ return pciBindDeviceToStub(conn, dev, driver);
+}
+
+static int
+pciUnBindDeviceFromStub(virConnectPtr conn, pciDevice *dev, const char *driver)
+{
+ char drvdir[PATH_MAX];
+ char path[PATH_MAX];
+
+ /* If the device is bound to stub, unbind it.
+ */
+ pciDriverDir(drvdir, sizeof(drvdir), driver);
+ pciDeviceFile(path, sizeof(path), dev->name, "driver");
+ if (virFileExists(drvdir) && virFileLinkPointsTo(path, drvdir)) {
+ pciDriverFile(path, sizeof(path), driver, "unbind");
+ if (virFileWriteStr(path, dev->name) < 0) {
+ virReportSystemError(conn, errno,
+ _("Failed to bind PCI device '%s' to %s"),
+ dev->name, driver);
+ return -1;
+ }
+ }
+
+ /* Xen's pciback.ko wants you to use remove_slot on the specific device */
+ pciDriverFile(path, sizeof(path), driver, "remove_slot");
+ if (virFileExists(path) && virFileWriteStr(path, dev->name) < 0) {
+ virReportSystemError(conn, errno,
+ _("Failed to remove slot for PCI device '%s' to %s"),
+ dev->name, driver);
+ return -1;
+ }
+
+
+ /* Trigger a re-probe of the device is not in the stub's dynamic
+ * ID table. If the stub is available, but 'remove_id' isn't
+ * available, then re-probing would just cause the device to be
+ * re-bound to the stub.
+ */
+ pciDriverFile(path, sizeof(path), driver, "remove_id");
+ if (!virFileExists(drvdir) || virFileExists(path)) {
+ if (virFileWriteStr(PCI_SYSFS "drivers_probe", dev->name) < 0) {
+ virReportSystemError(conn, errno,
+ _("Failed to trigger a re-probe for PCI device '%s'"),
+ dev->name);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int
+pciReAttachDevice(virConnectPtr conn, pciDevice *dev)
+{
+ const char *driver = pciFindStubDriver(conn);
+ if (!driver) {
+ pciReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
+ _("cannot find any PCI stub module"));
+ return -1;
+ }
+
+ return pciUnBindDeviceFromStub(conn, dev, driver);
+}
+
+static char *
+pciReadDeviceID(pciDevice *dev, const char *id_name)
+{
+ char path[PATH_MAX];
+ char *id_str;
+
+ snprintf(path, sizeof(path), PCI_SYSFS "devices/%s/%s",
+ dev->name, id_name);
+
+ /* ID string is '0xNNNN\n' ... i.e. 7 bytes */
+ if (virFileReadAll(path, 7, &id_str) < 0)
+ return NULL;
+
+ /* Check for 0x suffix */
+ if (id_str[0] != '0' || id_str[1] != 'x') {
+ VIR_FREE(id_str);
+ return NULL;
+ }
+
+ /* Chop off the newline; we know the string is 7 bytes */
+ id_str[6] = '\0';
+
+ return id_str;
+}
+
+pciDevice *
+pciGetDevice(virConnectPtr conn,
+ unsigned domain,
+ unsigned bus,
+ unsigned slot,
+ unsigned function)
+{
+ pciDevice *dev;
+ char *vendor, *product;
+
+ if (VIR_ALLOC(dev) < 0) {
+ virReportOOMError(conn);
+ return NULL;
+ }
+
+ dev->fd = -1;
+ dev->domain = domain;
+ dev->bus = bus;
+ dev->slot = slot;
+ dev->function = function;
+
+ snprintf(dev->name, sizeof(dev->name), "%.4x:%.2x:%.2x.%.1x",
+ dev->domain, dev->bus, dev->slot, dev->function);
+ snprintf(dev->path, sizeof(dev->path),
+ PCI_SYSFS "devices/%s/config", dev->name);
+
+ vendor = pciReadDeviceID(dev, "vendor");
+ product = pciReadDeviceID(dev, "device");
+
+ if (!vendor || !product) {
+ pciReportError(conn, VIR_ERR_NO_SUPPORT,
+ _("Failed to read product/vendor ID for %s"),
+ dev->name);
+ VIR_FREE(product);
+ VIR_FREE(vendor);
+ pciFreeDevice(conn, dev);
+ return NULL;
+ }
+
+ /* strings contain '0x' prefix */
+ snprintf(dev->id, sizeof(dev->id), "%s %s", &vendor[2], &product[2]);
+
+ VIR_FREE(product);
+ VIR_FREE(vendor);
+
+ VIR_DEBUG("%s %s: initialized", dev->id, dev->name);
+
+ return dev;
+}
+
+void
+pciFreeDevice(virConnectPtr conn ATTRIBUTE_UNUSED, pciDevice *dev)
+{
+ if (!dev)
+ return;
+ VIR_DEBUG("%s %s: freeing", dev->id, dev->name);
+ if (dev->fd >= 0)
+ close(dev->fd);
+ VIR_FREE(dev);
+}
+
+void pciDeviceSetManaged(pciDevice *dev, unsigned managed)
+{
+ dev->managed = !!managed;
+}
+
+unsigned pciDeviceGetManaged(pciDevice *dev)
+{
+ return dev->managed;
+}
+
+pciDeviceList *
+pciDeviceListNew(virConnectPtr conn)
+{
+ pciDeviceList *list;
+
+ if (VIR_ALLOC(list) < 0) {
+ virReportOOMError(conn);
+ return NULL;
+ }
+
+ return list;
+}
+
+void
+pciDeviceListFree(virConnectPtr conn,
+ pciDeviceList *list)
+{
+ int i;
+
+ if (!list)
+ return;
+
+ for (i = 0; i < list->count; i++) {
+ pciFreeDevice(conn, list->devs[i]);
+ list->devs[i] = NULL;
+ }
+
+ list->count = 0;
+ VIR_FREE(list->devs);
+ VIR_FREE(list);
+}
+
+int
+pciDeviceListAdd(virConnectPtr conn,
+ pciDeviceList *list,
+ pciDevice *dev)
+{
+ if (pciDeviceListFind(list, dev)) {
+ pciReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("Device %s is already in use"), dev->name);
+ return -1;
+ }
+
+ if (VIR_REALLOC_N(list->devs, list->count+1) < 0) {
+ virReportOOMError(conn);
+ return -1;
+ }
+
+ list->devs[list->count++] = dev;
+
+ return 0;
+}
+
+void
+pciDeviceListDel(virConnectPtr conn ATTRIBUTE_UNUSED,
+ pciDeviceList *list,
+ pciDevice *dev)
+{
+ int i;
+
+ for (i = 0; i < list->count; i++) {
+ if (list->devs[i]->domain != dev->domain ||
+ list->devs[i]->bus != dev->bus ||
+ list->devs[i]->slot != dev->slot ||
+ list->devs[i]->function != dev->function)
+ continue;
+
+ pciFreeDevice(conn, list->devs[i]);
+
+ if (i != --list->count)
+ memmove(&list->devs[i],
+ &list->devs[i+1],
+ sizeof(*list->devs) * (list->count-i));
+
+ if (VIR_REALLOC_N(list->devs, list->count) < 0) {
+ ; /* not fatal */
+ }
+
+ break;
+ }
+}
+
+pciDevice *
+pciDeviceListFind(pciDeviceList *list, pciDevice *dev)
+{
+ int i;
+
+ for (i = 0; i < list->count; i++)
+ if (list->devs[i]->domain == dev->domain &&
+ list->devs[i]->bus == dev->bus &&
+ list->devs[i]->slot == dev->slot &&
+ list->devs[i]->function == dev->function)
+ return list->devs[i];
+ return NULL;
+}
+
+
+int pciDeviceFileIterate(virConnectPtr conn,
+ pciDevice *dev,
+ pciDeviceFileActor actor,
+ void *opaque)
+{
+ char *pcidir = NULL;
+ char *file = NULL;
+ DIR *dir = NULL;
+ int ret = -1;
+ struct dirent *ent;
+
+ if (virAsprintf(&pcidir, "/sys/bus/pci/devices/%04x:%02x:%02x.%x",
+ dev->domain, dev->bus, dev->slot, dev->function) < 0) {
+ virReportOOMError(conn);
+ goto cleanup;
+ }
+
+ if (!(dir = opendir(pcidir))) {
+ virReportSystemError(conn, errno,
+ _("cannot open %s"), pcidir);
+ goto cleanup;
+ }
+
+ while ((ent = readdir(dir)) != NULL) {
+ /* Device assignment requires:
+ * $PCIDIR/config, $PCIDIR/resource, $PCIDIR/resourceNNN, $PCIDIR/rom
+ */
+ if (STREQ(ent->d_name, "config") ||
+ STRPREFIX(ent->d_name, "resource") ||
+ STREQ(ent->d_name, "rom")) {
+ if (virAsprintf(&file, "%s/%s", pcidir, ent->d_name) < 0) {
+ virReportOOMError(conn);
+ goto cleanup;
+ }
+ if ((actor)(conn, dev, file, opaque) < 0)
+ goto cleanup;
+
+ VIR_FREE(file);
+ }
+ }
+
+ ret = 0;
+
+cleanup:
+ if (dir)
+ closedir(dir);
+ VIR_FREE(file);
+ VIR_FREE(pcidir);
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * 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
+ *
+ * Authors:
+ * Mark McLoughlin <markmc@redhat.com>
+ */
+
+#ifndef __VIR_PCI_H__
+#define __VIR_PCI_H__
+
+#include "internal.h"
+
+typedef struct _pciDevice pciDevice;
+
+typedef struct {
+ unsigned count;
+ pciDevice **devs;
+} pciDeviceList;
+
+pciDevice *pciGetDevice (virConnectPtr conn,
+ unsigned domain,
+ unsigned bus,
+ unsigned slot,
+ unsigned function);
+void pciFreeDevice (virConnectPtr conn,
+ pciDevice *dev);
+int pciDettachDevice (virConnectPtr conn,
+ pciDevice *dev);
+int pciReAttachDevice (virConnectPtr conn,
+ pciDevice *dev);
+int pciResetDevice (virConnectPtr conn,
+ pciDevice *dev,
+ pciDeviceList *activeDevs);
+void pciDeviceSetManaged(pciDevice *dev,
+ unsigned managed);
+unsigned pciDeviceGetManaged(pciDevice *dev);
+
+pciDeviceList *pciDeviceListNew (virConnectPtr conn);
+void pciDeviceListFree (virConnectPtr conn,
+ pciDeviceList *list);
+int pciDeviceListAdd (virConnectPtr conn,
+ pciDeviceList *list,
+ pciDevice *dev);
+void pciDeviceListDel (virConnectPtr conn,
+ pciDeviceList *list,
+ pciDevice *dev);
+pciDevice * pciDeviceListFind (pciDeviceList *list,
+ pciDevice *dev);
+
+/*
+ * Callback that will be invoked once for each file
+ * associated with / used for PCI host device access.
+ *
+ * Should return 0 if successfully processed, or
+ * -1 to indicate error and abort iteration
+ */
+typedef int (*pciDeviceFileActor)(virConnectPtr conn, pciDevice *dev,
+ const char *path, void *opaque);
+
+int pciDeviceFileIterate(virConnectPtr conn,
+ pciDevice *dev,
+ pciDeviceFileActor actor,
+ void *opaque);
+
+#endif /* __VIR_PCI_H__ */
--- /dev/null
+/* Copyright (C) 2007, 2009 Red Hat, Inc.
+ *
+ * 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
+ *
+ * Authors:
+ * Richard W.M. Jones <rjones@redhat.com>
+ *
+ * Utility functions to help parse and assemble query strings.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include <libxml/uri.h>
+
+#include "virterror_internal.h"
+#include "buf.h"
+#include "memory.h"
+#include "qparams.h"
+
+#define VIR_FROM_THIS VIR_FROM_NONE
+
+struct qparam_set *
+new_qparam_set (int init_alloc, ...)
+{
+ va_list args;
+ struct qparam_set *ps;
+ const char *pname, *pvalue;
+
+ if (init_alloc <= 0) init_alloc = 1;
+
+ if (VIR_ALLOC(ps) < 0) {
+ virReportOOMError(NULL);
+ return NULL;
+ }
+ ps->n = 0;
+ ps->alloc = init_alloc;
+ if (VIR_ALLOC_N(ps->p, ps->alloc) < 0) {
+ VIR_FREE (ps);
+ virReportOOMError(NULL);
+ return NULL;
+ }
+
+ va_start (args, init_alloc);
+ while ((pname = va_arg (args, char *)) != NULL) {
+ pvalue = va_arg (args, char *);
+
+ if (append_qparam (ps, pname, pvalue) == -1) {
+ free_qparam_set (ps);
+ return NULL;
+ }
+ }
+ va_end (args);
+
+ return ps;
+}
+
+int
+append_qparams (struct qparam_set *ps, ...)
+{
+ va_list args;
+ const char *pname, *pvalue;
+
+ va_start (args, ps);
+ while ((pname = va_arg (args, char *)) != NULL) {
+ pvalue = va_arg (args, char *);
+
+ if (append_qparam (ps, pname, pvalue) == -1)
+ return -1;
+ }
+ va_end (args);
+
+ return 0;
+}
+
+/* Ensure there is space to store at least one more parameter
+ * at the end of the set.
+ */
+static int
+grow_qparam_set (struct qparam_set *ps)
+{
+ if (ps->n >= ps->alloc) {
+ if (VIR_REALLOC_N(ps->p, ps->alloc * 2) < 0) {
+ virReportOOMError(NULL);
+ return -1;
+ }
+ ps->alloc *= 2;
+ }
+
+ return 0;
+}
+
+int
+append_qparam (struct qparam_set *ps,
+ const char *name, const char *value)
+{
+ char *pname, *pvalue;
+
+ pname = strdup (name);
+ if (!pname) {
+ virReportOOMError(NULL);
+ return -1;
+ }
+
+ pvalue = strdup (value);
+ if (!pvalue) {
+ VIR_FREE (pname);
+ virReportOOMError(NULL);
+ return -1;
+ }
+
+ if (grow_qparam_set (ps) == -1) {
+ VIR_FREE (pname);
+ VIR_FREE (pvalue);
+ return -1;
+ }
+
+ ps->p[ps->n].name = pname;
+ ps->p[ps->n].value = pvalue;
+ ps->p[ps->n].ignore = 0;
+ ps->n++;
+
+ return 0;
+}
+
+char *
+qparam_get_query (const struct qparam_set *ps)
+{
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ int i, amp = 0;
+
+ for (i = 0; i < ps->n; ++i) {
+ if (!ps->p[i].ignore) {
+ if (amp) virBufferAddChar (&buf, '&');
+ virBufferStrcat (&buf, ps->p[i].name, "=", NULL);
+ virBufferURIEncodeString (&buf, ps->p[i].value);
+ amp = 1;
+ }
+ }
+
+ if (virBufferError(&buf)) {
+ virReportOOMError(NULL);
+ return NULL;
+ }
+
+ return virBufferContentAndReset(&buf);
+}
+
+void
+free_qparam_set (struct qparam_set *ps)
+{
+ int i;
+
+ for (i = 0; i < ps->n; ++i) {
+ VIR_FREE (ps->p[i].name);
+ VIR_FREE (ps->p[i].value);
+ }
+ VIR_FREE (ps->p);
+ VIR_FREE (ps);
+}
+
+struct qparam_set *
+qparam_query_parse (const char *query)
+{
+ struct qparam_set *ps;
+ const char *end, *eq;
+
+ ps = new_qparam_set (0, NULL);
+ if (!ps) {
+ virReportOOMError(NULL);
+ return NULL;
+ }
+
+ if (!query || query[0] == '\0') return ps;
+
+ while (*query) {
+ char *name = NULL, *value = NULL;
+
+ /* Find the next separator, or end of the string. */
+ end = strchr (query, '&');
+ if (!end)
+ end = strchr (query, ';');
+ if (!end)
+ end = query + strlen (query);
+
+ /* Find the first '=' character between here and end. */
+ eq = strchr (query, '=');
+ if (eq && eq >= end) eq = NULL;
+
+ /* Empty section (eg. "&&"). */
+ if (end == query)
+ goto next;
+
+ /* If there is no '=' character, then we have just "name"
+ * and consistent with CGI.pm we assume value is "".
+ */
+ else if (!eq) {
+ name = xmlURIUnescapeString (query, end - query, NULL);
+ if (!name) goto out_of_memory;
+ }
+ /* Or if we have "name=" here (works around annoying
+ * problem when calling xmlURIUnescapeString with len = 0).
+ */
+ else if (eq+1 == end) {
+ name = xmlURIUnescapeString (query, eq - query, NULL);
+ if (!name) goto out_of_memory;
+ }
+ /* If the '=' character is at the beginning then we have
+ * "=value" and consistent with CGI.pm we _ignore_ this.
+ */
+ else if (query == eq)
+ goto next;
+
+ /* Otherwise it's "name=value". */
+ else {
+ name = xmlURIUnescapeString (query, eq - query, NULL);
+ if (!name)
+ goto out_of_memory;
+ value = xmlURIUnescapeString (eq+1, end - (eq+1), NULL);
+ if (!value) {
+ VIR_FREE(name);
+ goto out_of_memory;
+ }
+ }
+
+ /* Append to the parameter set. */
+ if (append_qparam (ps, name, value ? value : "") == -1) {
+ VIR_FREE(name);
+ VIR_FREE(value);
+ goto out_of_memory;
+ }
+ VIR_FREE(name);
+ VIR_FREE(value);
+
+ next:
+ query = end;
+ if (*query) query ++; /* skip '&' separator */
+ }
+
+ return ps;
+
+ out_of_memory:
+ virReportOOMError(NULL);
+ free_qparam_set (ps);
+ return NULL;
+}
--- /dev/null
+/* Copyright (C) 2007 Red Hat, Inc.
+ *
+ * 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
+ *
+ * Authors:
+ * Richard W.M. Jones <rjones@redhat.com>
+ *
+ * Utility functions to help parse and assemble query strings.
+ */
+
+#ifndef _QPARAMS_H_
+#define _QPARAMS_H_
+
+/* Single web service query parameter 'name=value'. */
+struct qparam {
+ char *name; /* Name (unescaped). */
+ char *value; /* Value (unescaped). */
+ int ignore; /* Ignore this field in qparam_get_query */
+};
+
+/* Set of parameters. */
+struct qparam_set {
+ int n; /* number of parameters used */
+ int alloc; /* allocated space */
+ struct qparam *p; /* array of parameters */
+};
+
+/* New parameter set. */
+extern struct qparam_set *new_qparam_set (int init_alloc, ...);
+
+/* Appending parameters. */
+extern int append_qparams (struct qparam_set *ps, ...);
+extern int append_qparam (struct qparam_set *ps,
+ const char *name, const char *value);
+
+/* Get a query string ("name=value&name=value&...") */
+extern char *qparam_get_query (const struct qparam_set *ps);
+
+/* Parse a query string into a parameter set. */
+extern struct qparam_set *qparam_query_parse (const char *query);
+
+extern void free_qparam_set (struct qparam_set *ps);
+
+#endif /* _QPARAMS_H_ */
--- /dev/null
+/*
+ * Linux block and network stats.
+ *
+ * Copyright (C) 2007-2009 Red Hat, Inc.
+ *
+ * See COPYING.LIB for the License of this software
+ *
+ * Richard W.M. Jones <rjones@redhat.com>
+ */
+
+#include <config.h>
+
+/* This file only applies on Linux. */
+#ifdef __linux__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <regex.h>
+
+#include "virterror_internal.h"
+#include "datatypes.h"
+#include "util.h"
+#include "stats_linux.h"
+#include "memory.h"
+
+#define VIR_FROM_THIS VIR_FROM_STATS_LINUX
+
+/**
+ * statsErrorFunc:
+ * @conn: the connection
+ * @error: the error number
+ * @func: the function failing
+ * @info: extra information string
+ * @value: extra information number
+ *
+ * Handle a stats error.
+ */
+static void
+statsErrorFunc (virConnectPtr conn,
+ virErrorNumber error, const char *func, const char *info,
+ int value)
+{
+ char fullinfo[1000];
+ const char *errmsg;
+
+ errmsg = virErrorMsg(error, info);
+ if (func != NULL) {
+ snprintf(fullinfo, sizeof (fullinfo) - 1, "%s: %s", func, info);
+ fullinfo[sizeof (fullinfo) - 1] = 0;
+ info = fullinfo;
+ }
+ virRaiseError(conn, NULL, NULL, VIR_FROM_STATS_LINUX, error,
+ VIR_ERR_ERROR,
+ errmsg, info, NULL, value, 0, errmsg, info,
+ value);
+}
+
+
+/*-------------------- interface stats --------------------*/
+/* Just reads the named interface, so not Xen or QEMU-specific.
+ * NB. Caller must check that libvirt user is trying to query
+ * the interface of a domain they own. We do no such checking.
+ */
+
+int
+linuxDomainInterfaceStats (virConnectPtr conn, const char *path,
+ struct _virDomainInterfaceStats *stats)
+{
+ int path_len;
+ FILE *fp;
+ char line[256], *colon;
+
+ fp = fopen ("/proc/net/dev", "r");
+ if (!fp) {
+ statsErrorFunc (conn, VIR_ERR_INTERNAL_ERROR, __FUNCTION__,
+ "/proc/net/dev", errno);
+ return -1;
+ }
+
+ path_len = strlen (path);
+
+ while (fgets (line, sizeof line, fp)) {
+ long long dummy;
+ long long rx_bytes;
+ long long rx_packets;
+ long long rx_errs;
+ long long rx_drop;
+ long long tx_bytes;
+ long long tx_packets;
+ long long tx_errs;
+ long long tx_drop;
+
+ /* The line looks like:
+ * " eth0:..."
+ * Split it at the colon.
+ */
+ colon = strchr (line, ':');
+ if (!colon) continue;
+ *colon = '\0';
+ if (colon-path_len >= line &&
+ STREQ (colon-path_len, path)) {
+ /* IMPORTANT NOTE!
+ * /proc/net/dev vif<domid>.nn sees the network from the point
+ * of view of dom0 / hypervisor. So bytes TRANSMITTED by dom0
+ * are bytes RECEIVED by the domain. That's why the TX/RX fields
+ * appear to be swapped here.
+ */
+ if (sscanf (colon+1,
+ "%lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld",
+ &tx_bytes, &tx_packets, &tx_errs, &tx_drop,
+ &dummy, &dummy, &dummy, &dummy,
+ &rx_bytes, &rx_packets, &rx_errs, &rx_drop,
+ &dummy, &dummy, &dummy, &dummy) != 16)
+ continue;
+
+ stats->rx_bytes = rx_bytes;
+ stats->rx_packets = rx_packets;
+ stats->rx_errs = rx_errs;
+ stats->rx_drop = rx_drop;
+ stats->tx_bytes = tx_bytes;
+ stats->tx_packets = tx_packets;
+ stats->tx_errs = tx_errs;
+ stats->tx_drop = tx_drop;
+ fclose (fp);
+
+ return 0;
+ }
+ }
+ fclose (fp);
+
+ statsErrorFunc (conn, VIR_ERR_INTERNAL_ERROR, __FUNCTION__,
+ "/proc/net/dev: Interface not found", 0);
+ return -1;
+}
+
+#endif /* __linux__ */
--- /dev/null
+/*
+ * Linux block and network stats.
+ *
+ * Copyright (C) 2007 Red Hat, Inc.
+ *
+ * See COPYING.LIB for the License of this software
+ *
+ * Richard W.M. Jones <rjones@redhat.com>
+ */
+
+#ifndef __STATS_LINUX_H__
+#define __STATS_LINUX_H__
+
+#ifdef __linux__
+
+#include "internal.h"
+
+extern int linuxDomainInterfaceStats (virConnectPtr conn, const char *path,
+ struct _virDomainInterfaceStats *stats);
+
+#endif /* __linux__ */
+
+#endif /* __STATS_LINUX_H__ */
--- /dev/null
+/*
+ * threads-pthread.c: basic thread synchronization primitives
+ *
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * 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
+ *
+ */
+
+#include <config.h>
+
+
+/* Nothing special required for pthreads */
+int virThreadInitialize(void)
+{
+ return 0;
+}
+
+void virThreadOnExit(void)
+{
+}
+
+
+int virMutexInit(virMutexPtr m)
+{
+ if (pthread_mutex_init(&m->lock, NULL) != 0) {
+ errno = EINVAL;
+ return -1;
+ }
+ return 0;
+}
+
+void virMutexDestroy(virMutexPtr m)
+{
+ pthread_mutex_destroy(&m->lock);
+}
+
+void virMutexLock(virMutexPtr m){
+ pthread_mutex_lock(&m->lock);
+}
+
+void virMutexUnlock(virMutexPtr m)
+{
+ pthread_mutex_unlock(&m->lock);
+}
+
+
+
+int virCondInit(virCondPtr c)
+{
+ if (pthread_cond_init(&c->cond, NULL) != 0) {
+ errno = EINVAL;
+ return -1;
+ }
+ return 0;
+}
+
+int virCondDestroy(virCondPtr c)
+{
+ if (pthread_cond_destroy(&c->cond) != 0) {
+ errno = EINVAL;
+ return -1;
+ }
+ return 0;
+}
+
+int virCondWait(virCondPtr c, virMutexPtr m)
+{
+ if (pthread_cond_wait(&c->cond, &m->lock) != 0) {
+ errno = EINVAL;
+ return -1;
+ }
+ return 0;
+}
+
+void virCondSignal(virCondPtr c)
+{
+ pthread_cond_signal(&c->cond);
+}
+
+void virCondBroadcast(virCondPtr c)
+{
+ pthread_cond_broadcast(&c->cond);
+}
+
+
+int virThreadLocalInit(virThreadLocalPtr l,
+ virThreadLocalCleanup c)
+{
+ if (pthread_key_create(&l->key, c) != 0) {
+ errno = EINVAL;
+ return -1;
+ }
+ return 0;
+}
+
+void *virThreadLocalGet(virThreadLocalPtr l)
+{
+ return pthread_getspecific(l->key);
+}
+
+void virThreadLocalSet(virThreadLocalPtr l, void *val)
+{
+ pthread_setspecific(l->key, val);
+}
--- /dev/null
+/*
+ * threads.c: basic thread synchronization primitives
+ *
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * 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
+ *
+ */
+
+#include "internal.h"
+
+#include <pthread.h>
+
+struct virMutex {
+ pthread_mutex_t lock;
+};
+
+struct virCond {
+ pthread_cond_t cond;
+};
+
+struct virThreadLocal {
+ pthread_key_t key;
+};
--- /dev/null
+/*
+ * threads-win32.c: basic thread synchronization primitives
+ *
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * 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
+ *
+ */
+
+#include <config.h>
+
+#include "memory.h"
+
+struct virThreadLocalData {
+ DWORD key;
+ virThreadLocalCleanup cleanup;
+};
+typedef struct virThreadLocalData virThreadLocalData;
+typedef virThreadLocalData *virThreadLocalDataPtr;
+
+virMutex virThreadLocalLock;
+unsigned int virThreadLocalCount = 0;
+virThreadLocalDataPtr virThreadLocalList = NULL;
+
+
+virThreadLocal virCondEvent;
+
+void virCondEventCleanup(void *data);
+
+int virThreadInitialize(void)
+{
+ if (virMutexInit(&virThreadLocalLock) < 0)
+ return -1;
+ if (virThreadLocalInit(&virCondEvent, virCondEventCleanup) < 0)
+ return -1;
+
+ return 0;
+}
+
+void virThreadOnExit(void)
+{
+ unsigned int i;
+ virMutexLock(&virThreadLocalLock);
+ for (i = 0 ; i < virThreadLocalCount ; i++) {
+ if (virThreadLocalList[i].cleanup) {
+ void *data = TlsGetValue(virThreadLocalList[i].key);
+ if (data) {
+ TlsSetValue(virThreadLocalList[i].key, NULL);
+
+ (virThreadLocalList[i].cleanup)(data);
+ }
+ }
+ }
+ virMutexUnlock(&virThreadLocalLock);
+}
+
+
+int virMutexInit(virMutexPtr m)
+{
+ if (!(m->lock = CreateMutex(NULL, FALSE, NULL))) {
+ errno = ESRCH;
+ return -1;
+ }
+ return 0;
+}
+
+void virMutexDestroy(virMutexPtr m)
+{
+ CloseHandle(m->lock);
+}
+
+void virMutexLock(virMutexPtr m)
+{
+ WaitForSingleObject(m->lock, INFINITE);
+}
+
+void virMutexUnlock(virMutexPtr m)
+{
+ ReleaseMutex(m->lock);
+}
+
+
+
+int virCondInit(virCondPtr c)
+{
+ c->waiters = NULL;
+ if (virMutexInit(&c->lock) < 0)
+ return -1;
+ return 0;
+}
+
+int virCondDestroy(virCondPtr c)
+{
+ if (c->waiters) {
+ errno = EINVAL;
+ return -1;
+ }
+ virMutexDestroy(&c->lock);
+ return 0;
+}
+
+void virCondEventCleanup(void *data)
+{
+ HANDLE event = data;
+ CloseHandle(event);
+}
+
+int virCondWait(virCondPtr c, virMutexPtr m)
+{
+ HANDLE event = virThreadLocalGet(&virCondEvent);
+
+ if (!event) {
+ event = CreateEvent(0, FALSE, FALSE, NULL);
+ if (!event) {
+ return -1;
+ }
+ virThreadLocalSet(&virCondEvent, event);
+ }
+
+ virMutexLock(&c->lock);
+
+ if (VIR_REALLOC_N(c->waiters, c->nwaiters + 1) < 0) {
+ virMutexUnlock(&c->lock);
+ return -1;
+ }
+ c->waiters[c->nwaiters] = event;
+ c->nwaiters++;
+
+ virMutexUnlock(&c->lock);
+
+ virMutexUnlock(m);
+
+ if (WaitForSingleObject(event, INFINITE) == WAIT_FAILED) {
+ virMutexLock(m);
+ errno = EINVAL;
+ return -1;
+ }
+
+ virMutexLock(m);
+ return 0;
+}
+
+void virCondSignal(virCondPtr c)
+{
+ virMutexLock(&c->lock);
+
+ if (c->nwaiters) {
+ HANDLE event = c->waiters[0];
+ if (c->nwaiters > 1)
+ memmove(c->waiters,
+ c->waiters + 1,
+ sizeof(c->waiters[0]) * (c->nwaiters-1));
+ if (VIR_REALLOC_N(c->waiters, c->nwaiters - 1) < 0) {
+ ;
+ }
+ c->nwaiters--;
+ SetEvent(event);
+ }
+
+ virMutexUnlock(&c->lock);
+}
+
+void virCondBroadcast(virCondPtr c)
+{
+ virMutexLock(&c->lock);
+
+ if (c->nwaiters) {
+ unsigned int i;
+ for (i = 0 ; i < c->nwaiters ; i++) {
+ HANDLE event = c->waiters[i];
+ SetEvent(event);
+ }
+ VIR_FREE(c->waiters);
+ c->nwaiters = 0;
+ }
+
+ virMutexUnlock(&c->lock);
+}
+
+
+
+int virThreadLocalInit(virThreadLocalPtr l,
+ virThreadLocalCleanup c)
+{
+ if ((l->key = TlsAlloc()) == TLS_OUT_OF_INDEXES) {
+ errno = ESRCH;
+ return -1;
+ }
+ TlsSetValue(l->key, NULL);
+
+ if (c) {
+ virMutexLock(&virThreadLocalLock);
+ if (VIR_REALLOC_N(virThreadLocalList,
+ virThreadLocalCount + 1) < 0)
+ return -1;
+ virThreadLocalList[virThreadLocalCount].key = l->key;
+ virThreadLocalList[virThreadLocalCount].cleanup = c;
+ virThreadLocalCount++;
+ virMutexUnlock(&virThreadLocalLock);
+ }
+
+ return 0;
+}
+
+void *virThreadLocalGet(virThreadLocalPtr l)
+{
+ return TlsGetValue(l->key);
+}
+
+void virThreadLocalSet(virThreadLocalPtr l, void *val)
+{
+ TlsSetValue(l->key, val);
+}
--- /dev/null
+/*
+ * threads-win32.h basic thread synchronization primitives
+ *
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * 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
+ *
+ */
+
+#include "internal.h"
+
+#include <windows.h>
+
+struct virMutex {
+ HANDLE lock;
+};
+
+struct virCond {
+ virMutex lock;
+ unsigned int nwaiters;
+ HANDLE *waiters;
+};
+
+
+struct virThreadLocal {
+ DWORD key;
+};
--- /dev/null
+/*
+ * threads.c: basic thread synchronization primitives
+ *
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * 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
+ *
+ */
+
+#include <config.h>
+
+#include "threads.h"
+
+#ifdef HAVE_PTHREAD_H
+#include "threads-pthread.c"
+#else
+#ifdef WIN32
+#include "threads-win32.c"
+#else
+#error "Either pthreads or Win32 threads are required"
+#endif
+#endif
--- /dev/null
+/*
+ * threads.h: basic thread synchronization primitives
+ *
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * 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
+ *
+ */
+
+#ifndef __THREADS_H_
+#define __THREADS_H_
+
+#include "internal.h"
+
+typedef struct virMutex virMutex;
+typedef virMutex *virMutexPtr;
+
+typedef struct virCond virCond;
+typedef virCond *virCondPtr;
+
+typedef struct virThreadLocal virThreadLocal;
+typedef virThreadLocal *virThreadLocalPtr;
+
+
+int virThreadInitialize(void) ATTRIBUTE_RETURN_CHECK;
+void virThreadOnExit(void);
+
+int virMutexInit(virMutexPtr m) ATTRIBUTE_RETURN_CHECK;
+void virMutexDestroy(virMutexPtr m);
+
+void virMutexLock(virMutexPtr m);
+void virMutexUnlock(virMutexPtr m);
+
+
+
+int virCondInit(virCondPtr c) ATTRIBUTE_RETURN_CHECK;
+int virCondDestroy(virCondPtr c) ATTRIBUTE_RETURN_CHECK;
+
+int virCondWait(virCondPtr c, virMutexPtr m) ATTRIBUTE_RETURN_CHECK;
+void virCondSignal(virCondPtr c);
+void virCondBroadcast(virCondPtr c);
+
+
+typedef void (*virThreadLocalCleanup)(void *);
+int virThreadLocalInit(virThreadLocalPtr l,
+ virThreadLocalCleanup c) ATTRIBUTE_RETURN_CHECK;
+void *virThreadLocalGet(virThreadLocalPtr l);
+void virThreadLocalSet(virThreadLocalPtr l, void*);
+
+#ifdef HAVE_PTHREAD_H
+#include "threads-pthread.h"
+#else
+#ifdef WIN32
+#include "threads-win32.h"
+#else
+#error "Either pthreads or Win32 threads are required"
+#endif
+#endif
+
+#endif
--- /dev/null
+/*
+ * utils.c: common, generic utility functions
+ *
+ * Copyright (C) 2006, 2007, 2008, 2009 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ * Copyright (C) 2006, 2007 Binary Karma
+ * Copyright (C) 2006 Shuveb Hussain
+ *
+ * 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>
+ * File created Jul 18, 2007 - Shuveb Hussain <shuveb@binarykarma.com>
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <poll.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#if HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+#if HAVE_MMAP
+#include <sys/mman.h>
+#endif
+#include <string.h>
+#include <signal.h>
+#if HAVE_TERMIOS_H
+#include <termios.h>
+#endif
+#include "c-ctype.h"
+
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+#include <netdb.h>
+#ifdef HAVE_GETPWUID_R
+#include <pwd.h>
+#include <grp.h>
+#endif
+#if HAVE_CAPNG
+#include <cap-ng.h>
+#endif
+#ifdef HAVE_MNTENT_H
+#include <mntent.h>
+#endif
+
+#include "virterror_internal.h"
+#include "logging.h"
+#include "event.h"
+#include "buf.h"
+#include "util.h"
+#include "memory.h"
+#include "threads.h"
+
+#ifndef NSIG
+# define NSIG 32
+#endif
+
+#ifndef MIN
+# define MIN(a, b) ((a) < (b) ? (a) : (b))
+#endif
+
+#define VIR_FROM_THIS VIR_FROM_NONE
+
+#define ReportError(conn, code, fmt...) \
+ virReportErrorHelper(conn, VIR_FROM_NONE, code, __FILE__, \
+ __FUNCTION__, __LINE__, fmt)
+
+/* Like read(), but restarts after EINTR */
+int saferead(int fd, void *buf, size_t count)
+{
+ size_t nread = 0;
+ while (count > 0) {
+ ssize_t r = read(fd, buf, count);
+ if (r < 0 && errno == EINTR)
+ continue;
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return nread;
+ buf = (char *)buf + r;
+ count -= r;
+ nread += r;
+ }
+ return nread;
+}
+
+/* Like write(), but restarts after EINTR */
+ssize_t safewrite(int fd, const void *buf, size_t count)
+{
+ size_t nwritten = 0;
+ while (count > 0) {
+ ssize_t r = write(fd, buf, count);
+
+ if (r < 0 && errno == EINTR)
+ continue;
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return nwritten;
+ buf = (const char *)buf + r;
+ count -= r;
+ nwritten += r;
+ }
+ return nwritten;
+}
+
+#ifdef HAVE_POSIX_FALLOCATE
+int safezero(int fd, int flags ATTRIBUTE_UNUSED, off_t offset, off_t len)
+{
+ return posix_fallocate(fd, offset, len);
+}
+#else
+
+#ifdef HAVE_MMAP
+int safezero(int fd, int flags ATTRIBUTE_UNUSED, off_t offset, off_t len)
+{
+ int r;
+ char *buf;
+
+ /* memset wants the mmap'ed file to be present on disk so create a
+ * sparse file
+ */
+ r = ftruncate(fd, offset + len);
+ if (r < 0)
+ return -errno;
+
+ buf = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset);
+ if (buf == MAP_FAILED)
+ return -errno;
+
+ memset(buf, 0, len);
+ munmap(buf, len);
+
+ return 0;
+}
+
+#else /* HAVE_MMAP */
+
+int safezero(int fd, int flags ATTRIBUTE_UNUSED, off_t offset, off_t len)
+{
+ int r;
+ char *buf;
+ unsigned long long remain, bytes;
+
+ if (lseek(fd, offset, SEEK_SET) < 0)
+ return errno;
+
+ /* Split up the write in small chunks so as not to allocate lots of RAM */
+ remain = len;
+ bytes = 1024 * 1024;
+
+ r = VIR_ALLOC_N(buf, bytes);
+ if (r < 0)
+ return -ENOMEM;
+
+ while (remain) {
+ if (bytes > remain)
+ bytes = remain;
+
+ r = safewrite(fd, buf, len);
+ if (r < 0) {
+ VIR_FREE(buf);
+ return r;
+ }
+
+ /* safewrite() guarantees all data will be written */
+ remain -= bytes;
+ }
+ VIR_FREE(buf);
+ return 0;
+}
+#endif /* HAVE_MMAP */
+#endif /* HAVE_POSIX_FALLOCATE */
+
+#ifndef PROXY
+
+int virFileStripSuffix(char *str,
+ const char *suffix)
+{
+ int len = strlen(str);
+ int suffixlen = strlen(suffix);
+
+ if (len < suffixlen)
+ return 0;
+
+ if (!STREQ(str + len - suffixlen, suffix))
+ return 0;
+
+ str[len-suffixlen] = '\0';
+
+ return 1;
+}
+
+char *
+virArgvToString(const char *const *argv)
+{
+ int len, i;
+ char *ret, *p;
+
+ for (len = 1, i = 0; argv[i]; i++)
+ len += strlen(argv[i]) + 1;
+
+ if (VIR_ALLOC_N(ret, len) < 0)
+ return NULL;
+ p = ret;
+
+ for (i = 0; argv[i]; i++) {
+ if (i != 0)
+ *(p++) = ' ';
+
+ strcpy(p, argv[i]);
+ p += strlen(argv[i]);
+ }
+
+ *p = '\0';
+
+ return ret;
+}
+
+int virSetNonBlock(int fd) {
+#ifndef WIN32
+ int flags;
+ if ((flags = fcntl(fd, F_GETFL)) < 0)
+ return -1;
+ flags |= O_NONBLOCK;
+ if ((fcntl(fd, F_SETFL, flags)) < 0)
+ return -1;
+#else
+ unsigned long flag = 1;
+
+ /* This is actually Gnulib's replacement rpl_ioctl function.
+ * We can't call ioctlsocket directly in any case.
+ */
+ if (ioctl (fd, FIONBIO, (void *) &flag) == -1)
+ return -1;
+#endif
+ return 0;
+}
+
+
+#ifndef WIN32
+
+int virSetCloseExec(int fd) {
+ int flags;
+ if ((flags = fcntl(fd, F_GETFD)) < 0)
+ return -1;
+ flags |= FD_CLOEXEC;
+ if ((fcntl(fd, F_SETFD, flags)) < 0)
+ return -1;
+ return 0;
+}
+
+
+#if HAVE_CAPNG
+static int virClearCapabilities(void)
+{
+ int ret;
+
+ capng_clear(CAPNG_SELECT_BOTH);
+
+ if ((ret = capng_apply(CAPNG_SELECT_BOTH)) < 0) {
+ VIR_ERROR("cannot clear process capabilities %d", ret);
+ return -1;
+ }
+
+ return 0;
+}
+#else
+static int virClearCapabilities(void)
+{
+// VIR_WARN0("libcap-ng support not compiled in, unable to clear capabilities");
+ return 0;
+}
+#endif
+
+/*
+ * @conn Connection to report errors against
+ * @argv argv to exec
+ * @envp optional enviroment to use for exec
+ * @keepfd options fd_ret to keep open for child process
+ * @retpid optional pointer to store child process pid
+ * @infd optional file descriptor to use as child input, otherwise /dev/null
+ * @outfd optional pointer to communicate output fd behavior
+ * outfd == NULL : Use /dev/null
+ * *outfd == -1 : Use a new fd
+ * *outfd != -1 : Use *outfd
+ * @errfd optional pointer to communcate error fd behavior. See outfd
+ * @flags possible combination of the following:
+ * VIR_EXEC_NONE : Default function behavior
+ * VIR_EXEC_NONBLOCK : Set child process output fd's as non-blocking
+ * VIR_EXEC_DAEMON : Daemonize the child process (don't use directly,
+ * use virExecDaemonize wrapper)
+ * @hook optional virExecHook function to call prior to exec
+ * @data data to pass to the hook function
+ * @pidfile path to use as pidfile for daemonized process (needs DAEMON flag)
+ */
+static int
+__virExec(virConnectPtr conn,
+ const char *const*argv,
+ const char *const*envp,
+ const fd_set *keepfd,
+ pid_t *retpid,
+ int infd, int *outfd, int *errfd,
+ int flags,
+ virExecHook hook,
+ void *data,
+ char *pidfile)
+{
+ pid_t pid;
+ int null, i, openmax;
+ int pipeout[2] = {-1,-1};
+ int pipeerr[2] = {-1,-1};
+ int childout = -1;
+ int childerr = -1;
+ sigset_t oldmask, newmask;
+ struct sigaction sig_action;
+
+ /*
+ * Need to block signals now, so that child process can safely
+ * kill off caller's signal handlers without a race.
+ */
+ sigfillset(&newmask);
+ if (pthread_sigmask(SIG_SETMASK, &newmask, &oldmask) != 0) {
+ virReportSystemError(conn, errno,
+ "%s", _("cannot block signals"));
+ return -1;
+ }
+
+ if ((null = open("/dev/null", O_RDONLY)) < 0) {
+ virReportSystemError(conn, errno,
+ _("cannot open %s"),
+ "/dev/null");
+ goto cleanup;
+ }
+
+ if (outfd != NULL) {
+ if (*outfd == -1) {
+ if (pipe(pipeout) < 0) {
+ virReportSystemError(conn, errno,
+ "%s", _("cannot create pipe"));
+ goto cleanup;
+ }
+
+ if ((flags & VIR_EXEC_NONBLOCK) &&
+ virSetNonBlock(pipeout[0]) == -1) {
+ virReportSystemError(conn, errno,
+ "%s", _("Failed to set non-blocking file descriptor flag"));
+ goto cleanup;
+ }
+
+ if (virSetCloseExec(pipeout[0]) == -1) {
+ virReportSystemError(conn, errno,
+ "%s", _("Failed to set close-on-exec file descriptor flag"));
+ goto cleanup;
+ }
+
+ childout = pipeout[1];
+ } else {
+ childout = *outfd;
+ }
+ } else {
+ childout = null;
+ }
+
+ if (errfd != NULL) {
+ if (*errfd == -1) {
+ if (pipe(pipeerr) < 0) {
+ virReportSystemError(conn, errno,
+ "%s", _("Failed to create pipe"));
+ goto cleanup;
+ }
+
+ if ((flags & VIR_EXEC_NONBLOCK) &&
+ virSetNonBlock(pipeerr[0]) == -1) {
+ virReportSystemError(conn, errno,
+ "%s", _("Failed to set non-blocking file descriptor flag"));
+ goto cleanup;
+ }
+
+ if (virSetCloseExec(pipeerr[0]) == -1) {
+ virReportSystemError(conn, errno,
+ "%s", _("Failed to set close-on-exec file descriptor flag"));
+ goto cleanup;
+ }
+
+ childerr = pipeerr[1];
+ } else {
+ childerr = *errfd;
+ }
+ } else {
+ childerr = null;
+ }
+
+ if ((pid = fork()) < 0) {
+ virReportSystemError(conn, errno,
+ "%s", _("cannot fork child process"));
+ goto cleanup;
+ }
+
+ if (pid) { /* parent */
+ close(null);
+ if (outfd && *outfd == -1) {
+ close(pipeout[1]);
+ *outfd = pipeout[0];
+ }
+ if (errfd && *errfd == -1) {
+ close(pipeerr[1]);
+ *errfd = pipeerr[0];
+ }
+
+ /* Restore our original signal mask now child is safely
+ running */
+ if (pthread_sigmask(SIG_SETMASK, &oldmask, NULL) != 0) {
+ virReportSystemError(conn, errno,
+ "%s", _("cannot unblock signals"));
+ return -1;
+ }
+
+ *retpid = pid;
+ return 0;
+ }
+
+ /* child */
+
+ /* Don't want to report errors against this accidentally, so
+ just discard it */
+ conn = NULL;
+ /* Remove any error callback too, so errors in child now
+ get sent to stderr where they stand a fighting chance
+ of being seen / logged */
+ virSetErrorFunc(NULL, NULL);
+
+ /* Clear out all signal handlers from parent so nothing
+ unexpected can happen in our child once we unblock
+ signals */
+ sig_action.sa_handler = SIG_DFL;
+ sig_action.sa_flags = 0;
+ sigemptyset(&sig_action.sa_mask);
+
+ for (i = 1 ; i < NSIG ; i++)
+ /* Only possible errors are EFAULT or EINVAL
+ The former wont happen, the latter we
+ expect, so no need to check return value */
+ sigaction(i, &sig_action, NULL);
+
+ /* Unmask all signals in child, since we've no idea
+ what the caller's done with their signal mask
+ and don't want to propagate that to children */
+ sigemptyset(&newmask);
+ if (pthread_sigmask(SIG_SETMASK, &newmask, NULL) != 0) {
+ virReportSystemError(conn, errno,
+ "%s", _("cannot unblock signals"));
+ _exit(1);
+ }
+
+ openmax = sysconf (_SC_OPEN_MAX);
+ for (i = 3; i < openmax; i++)
+ if (i != infd &&
+ i != null &&
+ i != childout &&
+ i != childerr &&
+ (!keepfd ||
+ !FD_ISSET(i, keepfd)))
+ close(i);
+
+ if (dup2(infd >= 0 ? infd : null, STDIN_FILENO) < 0) {
+ virReportSystemError(conn, errno,
+ "%s", _("failed to setup stdin file handle"));
+ _exit(1);
+ }
+ if (childout > 0 &&
+ dup2(childout, STDOUT_FILENO) < 0) {
+ virReportSystemError(conn, errno,
+ "%s", _("failed to setup stdout file handle"));
+ _exit(1);
+ }
+ if (childerr > 0 &&
+ dup2(childerr, STDERR_FILENO) < 0) {
+ virReportSystemError(conn, errno,
+ "%s", _("failed to setup stderr file handle"));
+ _exit(1);
+ }
+
+ if (infd > 0)
+ close(infd);
+ close(null);
+ if (childout > 0)
+ close(childout);
+ if (childerr > 0 &&
+ childerr != childout)
+ close(childerr);
+
+ /* Daemonize as late as possible, so the parent process can detect
+ * the above errors with wait* */
+ if (flags & VIR_EXEC_DAEMON) {
+ if (setsid() < 0) {
+ virReportSystemError(conn, errno,
+ "%s", _("cannot become session leader"));
+ _exit(1);
+ }
+
+ if (chdir("/") < 0) {
+ virReportSystemError(conn, errno,
+ "%s", _("cannot change to root directory: %s"));
+ _exit(1);
+ }
+
+ pid = fork();
+ if (pid < 0) {
+ virReportSystemError(conn, errno,
+ "%s", _("cannot fork child process"));
+ _exit(1);
+ }
+
+ if (pid > 0) {
+ if (pidfile && virFileWritePidPath(pidfile,pid)) {
+ kill(pid, SIGTERM);
+ usleep(500*1000);
+ kill(pid, SIGTERM);
+ virReportSystemError(conn, errno,
+ _("could not write pidfile %s for %d"),
+ pidfile, pid);
+ _exit(1);
+ }
+ _exit(0);
+ }
+ }
+
+ if (hook)
+ if ((hook)(data) != 0)
+ _exit(1);
+
+ /* The steps above may need todo something privileged, so
+ * we delay clearing capabilities until the last minute */
+ if ((flags & VIR_EXEC_CLEAR_CAPS) &&
+ virClearCapabilities() < 0)
+ _exit(1);
+
+ if (envp)
+ execve(argv[0], (char **) argv, (char**)envp);
+ else
+ execvp(argv[0], (char **) argv);
+
+ virReportSystemError(conn, errno,
+ _("cannot execute binary %s"),
+ argv[0]);
+
+ _exit(1);
+
+ cleanup:
+ /* This is cleanup of parent process only - child
+ should never jump here on error */
+
+ /* NB we don't ReportError() on any failures here
+ because the code which jumped hre already raised
+ an error condition which we must not overwrite */
+ if (pipeerr[0] > 0)
+ close(pipeerr[0]);
+ if (pipeerr[1] > 0)
+ close(pipeerr[1]);
+ if (pipeout[0] > 0)
+ close(pipeout[0]);
+ if (pipeout[1] > 0)
+ close(pipeout[1]);
+ if (null > 0)
+ close(null);
+ return -1;
+}
+
+int
+virExecWithHook(virConnectPtr conn,
+ const char *const*argv,
+ const char *const*envp,
+ const fd_set *keepfd,
+ pid_t *retpid,
+ int infd, int *outfd, int *errfd,
+ int flags,
+ virExecHook hook,
+ void *data,
+ char *pidfile)
+{
+ char *argv_str;
+
+ if ((argv_str = virArgvToString(argv)) == NULL) {
+ virReportOOMError(conn);
+ return -1;
+ }
+ DEBUG0(argv_str);
+ VIR_FREE(argv_str);
+
+ return __virExec(conn, argv, envp, keepfd, retpid, infd, outfd, errfd,
+ flags, hook, data, pidfile);
+}
+
+/*
+ * See __virExec for explanation of the arguments.
+ *
+ * Wrapper function for __virExec, with a simpler set of parameters.
+ * Used to insulate the numerous callers from changes to __virExec argument
+ * list.
+ */
+int
+virExec(virConnectPtr conn,
+ const char *const*argv,
+ const char *const*envp,
+ const fd_set *keepfd,
+ pid_t *retpid,
+ int infd, int *outfd, int *errfd,
+ int flags)
+{
+ return virExecWithHook(conn, argv, envp, keepfd, retpid,
+ infd, outfd, errfd,
+ flags, NULL, NULL, NULL);
+}
+
+/*
+ * See __virExec for explanation of the arguments.
+ *
+ * This function will wait for the intermediate process (between the caller
+ * and the daemon) to exit. retpid will be the pid of the daemon, which can
+ * be checked for example to see if the daemon crashed immediately.
+ *
+ * Returns 0 on success
+ * -1 if initial fork failed (will have a reported error)
+ * -2 if intermediate process failed
+ * (won't have a reported error. pending on where the failure
+ * occured and when in the process occured, the error output
+ * could have gone to stderr or the passed errfd).
+ */
+int virExecDaemonize(virConnectPtr conn,
+ const char *const*argv,
+ const char *const*envp,
+ const fd_set *keepfd,
+ pid_t *retpid,
+ int infd, int *outfd, int *errfd,
+ int flags,
+ virExecHook hook,
+ void *data,
+ char *pidfile) {
+ int ret;
+ int childstat = 0;
+
+ ret = virExecWithHook(conn, argv, envp, keepfd, retpid,
+ infd, outfd, errfd,
+ flags | VIR_EXEC_DAEMON,
+ hook, data, pidfile);
+
+ /* __virExec should have set an error */
+ if (ret != 0)
+ return -1;
+
+ /* Wait for intermediate process to exit */
+ while (waitpid(*retpid, &childstat, 0) == -1 &&
+ errno == EINTR);
+
+ if (childstat != 0) {
+ ReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("Intermediate daemon process exited with status %d."),
+ WEXITSTATUS(childstat));
+ ret = -2;
+ }
+
+ return ret;
+}
+
+static int
+virPipeReadUntilEOF(virConnectPtr conn, int outfd, int errfd,
+ char **outbuf, char **errbuf) {
+
+ struct pollfd fds[2];
+ int i;
+ int finished[2];
+
+ fds[0].fd = outfd;
+ fds[0].events = POLLIN;
+ finished[0] = 0;
+ fds[1].fd = errfd;
+ fds[1].events = POLLIN;
+ finished[1] = 0;
+
+ while(!(finished[0] && finished[1])) {
+
+ if (poll(fds, ARRAY_CARDINALITY(fds), -1) < 0) {
+ if ((errno == EAGAIN) || (errno == EINTR))
+ continue;
+ goto pollerr;
+ }
+
+ for (i = 0; i < ARRAY_CARDINALITY(fds); ++i) {
+ char data[1024], **buf;
+ int got, size;
+
+ if (!(fds[i].revents))
+ continue;
+ else if (fds[i].revents & POLLHUP)
+ finished[i] = 1;
+
+ if (!(fds[i].revents & POLLIN)) {
+ if (fds[i].revents & POLLHUP)
+ continue;
+
+ ReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Unknown poll response."));
+ goto error;
+ }
+
+ got = read(fds[i].fd, data, sizeof(data));
+
+ if (got == 0) {
+ finished[i] = 1;
+ continue;
+ }
+ if (got < 0) {
+ if (errno == EINTR)
+ continue;
+ if (errno == EAGAIN)
+ break;
+ goto pollerr;
+ }
+
+ buf = ((fds[i].fd == outfd) ? outbuf : errbuf);
+ size = (*buf ? strlen(*buf) : 0);
+ if (VIR_REALLOC_N(*buf, size+got+1) < 0) {
+ virReportOOMError(conn);
+ goto error;
+ }
+ memmove(*buf+size, data, got);
+ (*buf)[size+got] = '\0';
+ }
+ continue;
+
+ pollerr:
+ virReportSystemError(conn, errno,
+ "%s", _("poll error"));
+ goto error;
+ }
+
+ return 0;
+
+error:
+ VIR_FREE(*outbuf);
+ VIR_FREE(*errbuf);
+ return -1;
+}
+
+/**
+ * @conn connection to report errors against
+ * @argv NULL terminated argv to run
+ * @status optional variable to return exit status in
+ *
+ * Run a command without using the shell.
+ *
+ * If status is NULL, then return 0 if the command run and
+ * exited with 0 status; Otherwise return -1
+ *
+ * If status is not-NULL, then return 0 if the command ran.
+ * The status variable is filled with the command exit status
+ * and should be checked by caller for success. Return -1
+ * only if the command could not be run.
+ */
+int
+virRun(virConnectPtr conn,
+ const char *const*argv,
+ int *status) {
+ pid_t childpid;
+ int exitstatus, execret, waitret;
+ int ret = -1;
+ int errfd = -1, outfd = -1;
+ char *outbuf = NULL;
+ char *errbuf = NULL;
+ char *argv_str = NULL;
+
+ if ((argv_str = virArgvToString(argv)) == NULL) {
+ virReportOOMError(conn);
+ goto error;
+ }
+ DEBUG0(argv_str);
+
+ if ((execret = __virExec(conn, argv, NULL, NULL,
+ &childpid, -1, &outfd, &errfd,
+ VIR_EXEC_NONE, NULL, NULL, NULL)) < 0) {
+ ret = execret;
+ goto error;
+ }
+
+ if (virPipeReadUntilEOF(conn, outfd, errfd, &outbuf, &errbuf) < 0) {
+ while (waitpid(childpid, &exitstatus, 0) == -1 && errno == EINTR)
+ ;
+ goto error;
+ }
+
+ if (outbuf)
+ DEBUG("Command stdout: %s", outbuf);
+ if (errbuf)
+ DEBUG("Command stderr: %s", errbuf);
+
+ while ((waitret = waitpid(childpid, &exitstatus, 0) == -1) &&
+ errno == EINTR);
+ if (waitret == -1) {
+ virReportSystemError(conn, errno,
+ _("cannot wait for '%s'"),
+ argv[0]);
+ goto error;
+ }
+
+ if (status == NULL) {
+ errno = EINVAL;
+ if (WIFEXITED(exitstatus) && WEXITSTATUS(exitstatus) != 0) {
+ ReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("'%s' exited with non-zero status %d and "
+ "signal %d: %s"), argv_str,
+ WIFEXITED(exitstatus) ? WEXITSTATUS(exitstatus) : 0,
+ WIFSIGNALED(exitstatus) ? WTERMSIG(exitstatus) : 0,
+ (errbuf ? errbuf : ""));
+ goto error;
+ }
+ } else {
+ *status = exitstatus;
+ }
+
+ ret = 0;
+
+ error:
+ VIR_FREE(outbuf);
+ VIR_FREE(errbuf);
+ VIR_FREE(argv_str);
+ if (outfd != -1)
+ close(outfd);
+ if (errfd != -1)
+ close(errfd);
+ return ret;
+}
+
+#else /* __MINGW32__ */
+
+int
+virRun(virConnectPtr conn,
+ const char *const *argv ATTRIBUTE_UNUSED,
+ int *status)
+{
+ if (status)
+ *status = ENOTSUP;
+ else
+ ReportError (conn, VIR_ERR_INTERNAL_ERROR, __FUNCTION__);
+ return -1;
+}
+
+int
+virExec(virConnectPtr conn,
+ const char *const*argv ATTRIBUTE_UNUSED,
+ const char *const*envp ATTRIBUTE_UNUSED,
+ const fd_set *keepfd ATTRIBUTE_UNUSED,
+ int *retpid ATTRIBUTE_UNUSED,
+ int infd ATTRIBUTE_UNUSED,
+ int *outfd ATTRIBUTE_UNUSED,
+ int *errfd ATTRIBUTE_UNUSED,
+ int flags ATTRIBUTE_UNUSED)
+{
+ ReportError (conn, VIR_ERR_INTERNAL_ERROR, __FUNCTION__);
+ return -1;
+}
+
+#endif /* __MINGW32__ */
+
+/* Like gnulib's fread_file, but read no more than the specified maximum
+ number of bytes. If the length of the input is <= max_len, and
+ upon error while reading that data, it works just like fread_file. */
+static char *
+fread_file_lim (FILE *stream, size_t max_len, size_t *length)
+{
+ char *buf = NULL;
+ size_t alloc = 0;
+ size_t size = 0;
+ int save_errno;
+
+ for (;;) {
+ size_t count;
+ size_t requested;
+
+ if (size + BUFSIZ + 1 > alloc) {
+ alloc += alloc / 2;
+ if (alloc < size + BUFSIZ + 1)
+ alloc = size + BUFSIZ + 1;
+
+ if (VIR_REALLOC_N(buf, alloc) < 0) {
+ save_errno = errno;
+ break;
+ }
+ }
+
+ /* Ensure that (size + requested <= max_len); */
+ requested = MIN (size < max_len ? max_len - size : 0,
+ alloc - size - 1);
+ count = fread (buf + size, 1, requested, stream);
+ size += count;
+
+ if (count != requested || requested == 0) {
+ save_errno = errno;
+ if (ferror (stream))
+ break;
+ buf[size] = '\0';
+ *length = size;
+ return buf;
+ }
+ }
+
+ free (buf);
+ errno = save_errno;
+ return NULL;
+}
+
+/* A wrapper around fread_file_lim that maps a failure due to
+ exceeding the maximum size limitation to EOVERFLOW. */
+static int virFileReadLimFP(FILE *fp, int maxlen, char **buf)
+{
+ size_t len;
+ char *s = fread_file_lim (fp, maxlen+1, &len);
+ if (s == NULL)
+ return -1;
+ if (len > maxlen || (int)len != len) {
+ VIR_FREE(s);
+ /* There was at least one byte more than MAXLEN.
+ Set errno accordingly. */
+ errno = EOVERFLOW;
+ return -1;
+ }
+ *buf = s;
+ return len;
+}
+
+/* Like virFileReadLimFP, but use a file descriptor rather than a FILE*. */
+int virFileReadLimFD(int fd_arg, int maxlen, char **buf)
+{
+ int fd = dup (fd_arg);
+ if (fd >= 0) {
+ FILE *fp = fdopen (fd, "r");
+ if (fp) {
+ int len = virFileReadLimFP (fp, maxlen, buf);
+ int saved_errno = errno;
+ fclose (fp);
+ errno = saved_errno;
+ return len;
+ } else {
+ int saved_errno = errno;
+ close (fd);
+ errno = saved_errno;
+ }
+ }
+ return -1;
+}
+
+int virFileReadAll(const char *path, int maxlen, char **buf)
+{
+ FILE *fh = fopen(path, "r");
+ if (fh == NULL) {
+ virReportSystemError(NULL, errno, _("Failed to open file '%s'"), path);
+ return -1;
+ }
+
+ int len = virFileReadLimFP (fh, maxlen, buf);
+ fclose(fh);
+ if (len < 0) {
+ virReportSystemError(NULL, errno, _("Failed to read file '%s'"), path);
+ return -1;
+ }
+
+ return len;
+}
+
+/* Truncate @path and write @str to it.
+ Return 0 for success, nonzero for failure.
+ Be careful to preserve any errno value upon failure. */
+int virFileWriteStr(const char *path, const char *str)
+{
+ int fd;
+
+ if ((fd = open(path, O_WRONLY|O_TRUNC)) == -1)
+ return -1;
+
+ if (safewrite(fd, str, strlen(str)) < 0) {
+ int saved_errno = errno;
+ close (fd);
+ errno = saved_errno;
+ return -1;
+ }
+
+ /* Use errno from failed close only if there was no write error. */
+ if (close (fd) != 0)
+ return -1;
+
+ return 0;
+}
+
+int virFileMatchesNameSuffix(const char *file,
+ const char *name,
+ const char *suffix)
+{
+ int filelen = strlen(file);
+ int namelen = strlen(name);
+ int suffixlen = strlen(suffix);
+
+ if (filelen == (namelen + suffixlen) &&
+ STREQLEN(file, name, namelen) &&
+ STREQLEN(file + namelen, suffix, suffixlen))
+ return 1;
+ else
+ return 0;
+}
+
+int virFileHasSuffix(const char *str,
+ const char *suffix)
+{
+ int len = strlen(str);
+ int suffixlen = strlen(suffix);
+
+ if (len < suffixlen)
+ return 0;
+
+ return STREQ(str + len - suffixlen, suffix);
+}
+
+#define SAME_INODE(Stat_buf_1, Stat_buf_2) \
+ ((Stat_buf_1).st_ino == (Stat_buf_2).st_ino \
+ && (Stat_buf_1).st_dev == (Stat_buf_2).st_dev)
+
+/* Return nonzero if checkLink and checkDest
+ refer to the same file. Otherwise, return 0. */
+int virFileLinkPointsTo(const char *checkLink,
+ const char *checkDest)
+{
+ struct stat src_sb;
+ struct stat dest_sb;
+
+ return (stat (checkLink, &src_sb) == 0
+ && stat (checkDest, &dest_sb) == 0
+ && SAME_INODE (src_sb, dest_sb));
+}
+
+
+
+/*
+ * Attempt to resolve a symbolic link, returning the
+ * real path
+ *
+ * Return 0 if path was not a symbolic, or the link was
+ * resolved. Return -1 upon error
+ */
+int virFileResolveLink(const char *linkpath,
+ char **resultpath)
+{
+#ifdef HAVE_READLINK
+ struct stat st;
+ char *buf;
+ int n;
+
+ *resultpath = NULL;
+
+ if (lstat(linkpath, &st) < 0)
+ return errno;
+
+ if (!S_ISLNK(st.st_mode)) {
+ if (!(*resultpath = strdup(linkpath)))
+ return -ENOMEM;
+ return 0;
+ }
+
+ /* Posix says that 'st_size' field from
+ * result of an lstat() call is filled with
+ * number of bytes in the destination
+ * filename.
+ */
+ if (VIR_ALLOC_N(buf, st.st_size + 1) < 0)
+ return -ENOMEM;
+
+ if ((n = readlink(linkpath, buf, st.st_size)) < 0) {
+ VIR_FREE(buf);
+ return -errno;
+ }
+
+ buf[n] = '\0';
+
+ *resultpath = buf;
+ return 0;
+#else
+ if (!(*resultpath = strdup(linkpath)))
+ return -ENOMEM;
+ return 0;
+#endif
+}
+
+/*
+ * Finds a requested file in the PATH env. e.g.:
+ * "kvm-img" will return "/usr/bin/kvm-img"
+ *
+ * You must free the result
+ */
+char *virFindFileInPath(const char *file)
+{
+ char pathenv[PATH_MAX];
+ char *penv = pathenv;
+ char *pathseg;
+ char fullpath[PATH_MAX];
+
+ /* copy PATH env so we can tweak it */
+ strncpy(pathenv, getenv("PATH"), PATH_MAX);
+ pathenv[PATH_MAX - 1] = '\0';
+
+
+ /* for each path segment, append the file to search for and test for
+ * it. return it if found.
+ */
+ while ((pathseg = strsep(&penv, ":")) != NULL) {
+ snprintf(fullpath, PATH_MAX, "%s/%s", pathseg, file);
+ if (virFileExists(fullpath))
+ return strdup(fullpath);
+ }
+
+ return NULL;
+}
+int virFileExists(const char *path)
+{
+ struct stat st;
+
+ if (stat(path, &st) >= 0)
+ return(1);
+ return(0);
+}
+
+int virFileMakePath(const char *path)
+{
+ struct stat st;
+ char parent[PATH_MAX];
+ char *p;
+ int err;
+
+ if (stat(path, &st) >= 0)
+ return 0;
+
+ strncpy(parent, path, PATH_MAX);
+ parent[PATH_MAX - 1] = '\0';
+
+ if (!(p = strrchr(parent, '/')))
+ return EINVAL;
+
+ if (p != parent) {
+ *p = '\0';
+ if ((err = virFileMakePath(parent)))
+ return err;
+ }
+
+ if (mkdir(path, 0777) < 0 && errno != EEXIST)
+ return errno;
+
+ return 0;
+}
+
+/* Build up a fully qualfiied path for a config file to be
+ * associated with a persistent guest or network */
+int virFileBuildPath(const char *dir,
+ const char *name,
+ const char *ext,
+ char *buf,
+ unsigned int buflen)
+{
+ if ((strlen(dir) + 1 + strlen(name) + (ext ? strlen(ext) : 0) + 1) >= (buflen-1))
+ return -1;
+
+ strcpy(buf, dir);
+ strcat(buf, "/");
+ strcat(buf, name);
+ if (ext)
+ strcat(buf, ext);
+ return 0;
+}
+
+
+int virFileOpenTty(int *ttymaster,
+ char **ttyName,
+ int rawmode)
+{
+ return virFileOpenTtyAt("/dev/ptmx",
+ ttymaster,
+ ttyName,
+ rawmode);
+}
+
+#ifdef __linux__
+int virFileOpenTtyAt(const char *ptmx,
+ int *ttymaster,
+ char **ttyName,
+ int rawmode)
+{
+ int rc = -1;
+
+ if ((*ttymaster = open(ptmx, O_RDWR|O_NOCTTY|O_NONBLOCK)) < 0)
+ goto cleanup;
+
+ if (unlockpt(*ttymaster) < 0)
+ goto cleanup;
+
+ if (grantpt(*ttymaster) < 0)
+ goto cleanup;
+
+ if (rawmode) {
+ struct termios ttyAttr;
+ if (tcgetattr(*ttymaster, &ttyAttr) < 0)
+ goto cleanup;
+
+ cfmakeraw(&ttyAttr);
+
+ if (tcsetattr(*ttymaster, TCSADRAIN, &ttyAttr) < 0)
+ goto cleanup;
+ }
+
+ if (ttyName) {
+ char tempTtyName[PATH_MAX];
+ if (ptsname_r(*ttymaster, tempTtyName, sizeof(tempTtyName)) < 0)
+ goto cleanup;
+
+ if ((*ttyName = strdup(tempTtyName)) == NULL) {
+ errno = ENOMEM;
+ goto cleanup;
+ }
+ }
+
+ rc = 0;
+
+cleanup:
+ if (rc != 0 &&
+ *ttymaster != -1) {
+ close(*ttymaster);
+ }
+
+ return rc;
+
+}
+#else
+int virFileOpenTtyAt(const char *ptmx ATTRIBUTE_UNUSED,
+ int *ttymaster ATTRIBUTE_UNUSED,
+ char **ttyName ATTRIBUTE_UNUSED,
+ int rawmode ATTRIBUTE_UNUSED)
+{
+ return -1;
+}
+#endif
+
+char* virFilePid(const char *dir, const char* name)
+{
+ char *pidfile;
+ virAsprintf(&pidfile, "%s/%s.pid", dir, name);
+ return pidfile;
+}
+
+int virFileWritePid(const char *dir,
+ const char *name,
+ pid_t pid)
+{
+ int rc;
+ char *pidfile = NULL;
+
+ if (name == NULL || dir == NULL) {
+ rc = EINVAL;
+ goto cleanup;
+ }
+
+ if ((rc = virFileMakePath(dir)))
+ goto cleanup;
+
+ if (!(pidfile = virFilePid(dir, name))) {
+ rc = ENOMEM;
+ goto cleanup;
+ }
+
+ rc = virFileWritePidPath(pidfile, pid);
+
+cleanup:
+ VIR_FREE(pidfile);
+ return rc;
+}
+
+int virFileWritePidPath(const char *pidfile,
+ pid_t pid)
+{
+ int rc;
+ int fd;
+ FILE *file = NULL;
+
+ if ((fd = open(pidfile,
+ O_WRONLY | O_CREAT | O_TRUNC,
+ S_IRUSR | S_IWUSR)) < 0) {
+ rc = errno;
+ goto cleanup;
+ }
+
+ if (!(file = fdopen(fd, "w"))) {
+ rc = errno;
+ close(fd);
+ goto cleanup;
+ }
+
+ if (fprintf(file, "%d", pid) < 0) {
+ rc = errno;
+ goto cleanup;
+ }
+
+ rc = 0;
+
+cleanup:
+ if (file &&
+ fclose(file) < 0) {
+ rc = errno;
+ }
+
+ return rc;
+}
+
+int virFileReadPid(const char *dir,
+ const char *name,
+ pid_t *pid)
+{
+ int rc;
+ FILE *file;
+ char *pidfile = NULL;
+ *pid = 0;
+
+ if (name == NULL || dir == NULL) {
+ rc = EINVAL;
+ goto cleanup;
+ }
+
+ if (!(pidfile = virFilePid(dir, name))) {
+ rc = ENOMEM;
+ goto cleanup;
+ }
+
+ if (!(file = fopen(pidfile, "r"))) {
+ rc = errno;
+ goto cleanup;
+ }
+
+ if (fscanf(file, "%d", pid) != 1) {
+ rc = EINVAL;
+ fclose(file);
+ goto cleanup;
+ }
+
+ if (fclose(file) < 0) {
+ rc = errno;
+ goto cleanup;
+ }
+
+ rc = 0;
+
+ cleanup:
+ VIR_FREE(pidfile);
+ return rc;
+}
+
+int virFileDeletePid(const char *dir,
+ const char *name)
+{
+ int rc = 0;
+ char *pidfile = NULL;
+
+ if (name == NULL || dir == NULL) {
+ rc = EINVAL;
+ goto cleanup;
+ }
+
+ if (!(pidfile = virFilePid(dir, name))) {
+ rc = ENOMEM;
+ goto cleanup;
+ }
+
+ if (unlink(pidfile) < 0 && errno != ENOENT)
+ rc = errno;
+
+cleanup:
+ VIR_FREE(pidfile);
+ return rc;
+}
+
+#endif /* PROXY */
+
+
+/* Like strtol, but produce an "int" result, and check more carefully.
+ Return 0 upon success; return -1 to indicate failure.
+ When END_PTR is NULL, the byte after the final valid digit must be NUL.
+ Otherwise, it's like strtol and lets the caller check any suffix for
+ validity. This function is careful to return -1 when the string S
+ represents a number that is not representable as an "int". */
+int
+virStrToLong_i(char const *s, char **end_ptr, int base, int *result)
+{
+ long int val;
+ char *p;
+ int err;
+
+ errno = 0;
+ val = strtol(s, &p, base);
+ err = (errno || (!end_ptr && *p) || p == s || (int) val != val);
+ if (end_ptr)
+ *end_ptr = p;
+ if (err)
+ return -1;
+ *result = val;
+ return 0;
+}
+
+/* Just like virStrToLong_i, above, but produce an "unsigned int" value. */
+int
+virStrToLong_ui(char const *s, char **end_ptr, int base, unsigned int *result)
+{
+ unsigned long int val;
+ char *p;
+ int err;
+
+ errno = 0;
+ val = strtoul(s, &p, base);
+ err = (errno || (!end_ptr && *p) || p == s || (unsigned int) val != val);
+ if (end_ptr)
+ *end_ptr = p;
+ if (err)
+ return -1;
+ *result = val;
+ return 0;
+}
+
+/* Just like virStrToLong_i, above, but produce an "long long" value. */
+int
+virStrToLong_ll(char const *s, char **end_ptr, int base, long long *result)
+{
+ long long val;
+ char *p;
+ int err;
+
+ errno = 0;
+ val = strtoll(s, &p, base);
+ err = (errno || (!end_ptr && *p) || p == s || (long long) val != val);
+ if (end_ptr)
+ *end_ptr = p;
+ if (err)
+ return -1;
+ *result = val;
+ return 0;
+}
+
+/* Just like virStrToLong_i, above, but produce an "unsigned long long" value. */
+int
+virStrToLong_ull(char const *s, char **end_ptr, int base, unsigned long long *result)
+{
+ unsigned long long val;
+ char *p;
+ int err;
+
+ errno = 0;
+ val = strtoull(s, &p, base);
+ err = (errno || (!end_ptr && *p) || p == s || (unsigned long long) val != val);
+ if (end_ptr)
+ *end_ptr = p;
+ if (err)
+ return -1;
+ *result = val;
+ return 0;
+}
+
+int
+virStrToDouble(char const *s,
+ char **end_ptr,
+ double *result)
+{
+ double val;
+ char *p;
+ int err;
+
+ errno = 0;
+ val = strtod(s, &p);
+ err = (errno || (!end_ptr && *p) || p == s);
+ if (end_ptr)
+ *end_ptr = p;
+ if (err)
+ return -1;
+ *result = val;
+ return 0;
+}
+
+/**
+ * virSkipSpaces:
+ * @str: pointer to the char pointer used
+ *
+ * Skip potential blanks, this includes space tabs, line feed,
+ * carriage returns and also '\\' which can be erronously emitted
+ * by xend
+ */
+void
+virSkipSpaces(const char **str)
+{
+ const char *cur = *str;
+
+ while ((*cur == ' ') || (*cur == '\t') || (*cur == '\n') ||
+ (*cur == '\r') || (*cur == '\\'))
+ cur++;
+ *str = cur;
+}
+
+/**
+ * virParseNumber:
+ * @str: pointer to the char pointer used
+ *
+ * Parse an unsigned number
+ *
+ * Returns the unsigned number or -1 in case of error. @str will be
+ * updated to skip the number.
+ */
+int
+virParseNumber(const char **str)
+{
+ int ret = 0;
+ const char *cur = *str;
+
+ if ((*cur < '0') || (*cur > '9'))
+ return (-1);
+
+ while (c_isdigit(*cur)) {
+ unsigned int c = *cur - '0';
+
+ if ((ret > INT_MAX / 10) ||
+ ((ret == INT_MAX / 10) && (c > INT_MAX % 10)))
+ return (-1);
+ ret = ret * 10 + c;
+ cur++;
+ }
+ *str = cur;
+ return (ret);
+}
+
+/**
+ * virAsprintf
+ *
+ * like glibc's_asprintf but makes sure *strp == NULL on failure
+ */
+int
+virAsprintf(char **strp, const char *fmt, ...)
+{
+ va_list ap;
+ int ret;
+
+ va_start(ap, fmt);
+
+ if ((ret = vasprintf(strp, fmt, ap)) == -1)
+ *strp = NULL;
+
+ va_end(ap);
+ return ret;
+}
+
+/* Compare two MAC addresses, ignoring differences in case,
+ * as well as leading zeros.
+ */
+int
+virMacAddrCompare (const char *p, const char *q)
+{
+ unsigned char c, d;
+ do {
+ while (*p == '0' && c_isxdigit (p[1]))
+ ++p;
+ while (*q == '0' && c_isxdigit (q[1]))
+ ++q;
+ c = c_tolower (*p);
+ d = c_tolower (*q);
+
+ if (c == 0 || d == 0)
+ break;
+
+ ++p;
+ ++q;
+ } while (c == d);
+
+ if (UCHAR_MAX <= INT_MAX)
+ return c - d;
+
+ /* On machines where 'char' and 'int' are types of the same size, the
+ difference of two 'unsigned char' values - including the sign bit -
+ doesn't fit in an 'int'. */
+ return (c > d ? 1 : c < d ? -1 : 0);
+}
+
+/**
+ * virParseMacAddr:
+ * @str: string representation of MAC address, e.g., "0:1E:FC:E:3a:CB"
+ * @addr: 6-byte MAC address
+ *
+ * Parse a MAC address
+ *
+ * Return 0 upon success, or -1 in case of error.
+ */
+int
+virParseMacAddr(const char* str, unsigned char *addr)
+{
+ int i;
+
+ errno = 0;
+ for (i = 0; i < VIR_MAC_BUFLEN; i++) {
+ char *end_ptr;
+ unsigned long result;
+
+ /* This is solely to avoid accepting the leading
+ * space or "+" that strtoul would otherwise accept.
+ */
+ if (!c_isxdigit(*str))
+ break;
+
+ result = strtoul(str, &end_ptr, 16);
+
+ if ((end_ptr - str) < 1 || 2 < (end_ptr - str) ||
+ (errno != 0) ||
+ (0xFF < result))
+ break;
+
+ addr[i] = (unsigned char) result;
+
+ if ((i == 5) && (*end_ptr == '\0'))
+ return 0;
+ if (*end_ptr != ':')
+ break;
+
+ str = end_ptr + 1;
+ }
+
+ return -1;
+}
+
+void virFormatMacAddr(const unsigned char *addr,
+ char *str)
+{
+ snprintf(str, VIR_MAC_STRING_BUFLEN,
+ "%02X:%02X:%02X:%02X:%02X:%02X",
+ addr[0], addr[1], addr[2],
+ addr[3], addr[4], addr[5]);
+ str[VIR_MAC_STRING_BUFLEN-1] = '\0';
+}
+
+void virGenerateMacAddr(const unsigned char *prefix,
+ unsigned char *addr)
+{
+ addr[0] = prefix[0];
+ addr[1] = prefix[1];
+ addr[2] = prefix[2];
+ addr[3] = virRandom(256);
+ addr[4] = virRandom(256);
+ addr[5] = virRandom(256);
+}
+
+
+int virEnumFromString(const char *const*types,
+ unsigned int ntypes,
+ const char *type)
+{
+ unsigned int i;
+ if (!type)
+ return -1;
+
+ for (i = 0 ; i < ntypes ; i++)
+ if (STREQ(types[i], type))
+ return i;
+
+ return -1;
+}
+
+const char *virEnumToString(const char *const*types,
+ unsigned int ntypes,
+ int type)
+{
+ if (type < 0 || type >= ntypes)
+ return NULL;
+
+ return types[type];
+}
+
+/* Translates a device name of the form (regex) "[fhv]d[a-z]+" into
+ * the corresponding index (e.g. sda => 0, hdz => 25, vdaa => 26)
+ * @param name The name of the device
+ * @return name's index, or -1 on failure
+ */
+int virDiskNameToIndex(const char *name) {
+ const char *ptr = NULL;
+ int idx = 0;
+ static char const* const drive_prefix[] = {"fd", "hd", "vd", "sd", "xvd"};
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_CARDINALITY(drive_prefix); i++) {
+ if (STRPREFIX(name, drive_prefix[i])) {
+ ptr = name + strlen(drive_prefix[i]);
+ break;
+ }
+ }
+
+ if (!ptr)
+ return -1;
+
+ for (i = 0; *ptr; i++) {
+ idx = (idx + i) * 26;
+
+ if (!c_islower(*ptr))
+ return -1;
+
+ idx += *ptr - 'a';
+ ptr++;
+ }
+
+ return idx;
+}
+
+#ifndef AI_CANONIDN
+#define AI_CANONIDN 0
+#endif
+
+char *virGetHostname(void)
+{
+ int r;
+ char hostname[HOST_NAME_MAX+1], *result;
+ struct addrinfo hints, *info;
+
+ r = gethostname (hostname, sizeof(hostname));
+ if (r == -1)
+ return NULL;
+ NUL_TERMINATE(hostname);
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_CANONNAME|AI_CANONIDN;
+ hints.ai_family = AF_UNSPEC;
+ r = getaddrinfo(hostname, NULL, &hints, &info);
+ if (r != 0)
+ return NULL;
+ if (info->ai_canonname == NULL) {
+ freeaddrinfo(info);
+ return NULL;
+ }
+
+ /* Caller frees this string. */
+ result = strdup (info->ai_canonname);
+ freeaddrinfo(info);
+ return result;
+}
+
+/* send signal to a single process */
+int virKillProcess(pid_t pid, int sig)
+{
+ if (pid <= 1) {
+ errno = ESRCH;
+ return -1;
+ }
+
+#ifdef WIN32
+ /* Mingw / Windows don't have many signals (AFAIK) */
+ switch (sig) {
+ case SIGINT:
+ /* This does a Ctrl+C equiv */
+ if (!GenerateConsoleCtrlEvent(CTRL_C_EVENT, pid)) {
+ errno = ESRCH;
+ return -1;
+ }
+ break;
+
+ case SIGTERM:
+ /* Since TerminateProcess is closer to SIG_KILL, we do
+ * a Ctrl+Break equiv which is more pleasant like the
+ * good old unix SIGTERM/HUP
+ */
+ if (!GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, pid)) {
+ errno = ESRCH;
+ return -1;
+ }
+ break;
+
+ default:
+ {
+ HANDLE proc;
+ proc = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
+ if (!proc) {
+ errno = ESRCH; /* Not entirely accurate, but close enough */
+ return -1;
+ }
+
+ /*
+ * TerminateProcess is more or less equiv to SIG_KILL, in that
+ * a process can't trap / block it
+ */
+ if (!TerminateProcess(proc, sig)) {
+ errno = ESRCH;
+ return -1;
+ }
+ CloseHandle(proc);
+ }
+ }
+ return 0;
+#else
+ return kill(pid, sig);
+#endif
+}
+
+
+static char randomState[128];
+static struct random_data randomData;
+static virMutex randomLock;
+
+int virRandomInitialize(unsigned int seed)
+{
+ if (virMutexInit(&randomLock) < 0)
+ return -1;
+
+ if (initstate_r(seed,
+ randomState,
+ sizeof(randomState),
+ &randomData) < 0)
+ return -1;
+
+ return 0;
+}
+
+int virRandom(int max)
+{
+ int32_t ret;
+
+ virMutexLock(&randomLock);
+ random_r(&randomData, &ret);
+ virMutexUnlock(&randomLock);
+
+ return (int) ((double)max * ((double)ret / (double)RAND_MAX));
+}
+
+
+#ifdef HAVE_GETPWUID_R
+enum {
+ VIR_USER_ENT_DIRECTORY,
+ VIR_USER_ENT_NAME,
+};
+
+static char *virGetUserEnt(virConnectPtr conn,
+ uid_t uid,
+ int field)
+{
+ char *strbuf;
+ char *ret;
+ struct passwd pwbuf;
+ struct passwd *pw = NULL;
+ size_t strbuflen = sysconf(_SC_GETPW_R_SIZE_MAX);
+
+ if (VIR_ALLOC_N(strbuf, strbuflen) < 0) {
+ virReportOOMError(conn);
+ return NULL;
+ }
+
+ /*
+ * From the manpage (terrifying but true):
+ *
+ * ERRORS
+ * 0 or ENOENT or ESRCH or EBADF or EPERM or ...
+ * The given name or uid was not found.
+ */
+ if (getpwuid_r(uid, &pwbuf, strbuf, strbuflen, &pw) != 0 || pw == NULL) {
+ virReportSystemError(conn, errno,
+ _("Failed to find user record for uid '%d'"),
+ uid);
+ VIR_FREE(strbuf);
+ return NULL;
+ }
+
+ if (field == VIR_USER_ENT_DIRECTORY)
+ ret = strdup(pw->pw_dir);
+ else
+ ret = strdup(pw->pw_name);
+
+ VIR_FREE(strbuf);
+ if (!ret)
+ virReportOOMError(conn);
+
+ return ret;
+}
+
+char *virGetUserDirectory(virConnectPtr conn,
+ uid_t uid)
+{
+ return virGetUserEnt(conn, uid, VIR_USER_ENT_DIRECTORY);
+}
+
+char *virGetUserName(virConnectPtr conn,
+ uid_t uid)
+{
+ return virGetUserEnt(conn, uid, VIR_USER_ENT_NAME);
+}
+
+
+int virGetUserID(virConnectPtr conn,
+ const char *name,
+ uid_t *uid)
+{
+ char *strbuf;
+ struct passwd pwbuf;
+ struct passwd *pw = NULL;
+ size_t strbuflen = sysconf(_SC_GETPW_R_SIZE_MAX);
+
+ if (VIR_ALLOC_N(strbuf, strbuflen) < 0) {
+ virReportOOMError(conn);
+ return -1;
+ }
+
+ /*
+ * From the manpage (terrifying but true):
+ *
+ * ERRORS
+ * 0 or ENOENT or ESRCH or EBADF or EPERM or ...
+ * The given name or uid was not found.
+ */
+ if (getpwnam_r(name, &pwbuf, strbuf, strbuflen, &pw) != 0 || pw == NULL) {
+ virReportSystemError(conn, errno,
+ _("Failed to find user record for name '%s'"),
+ name);
+ VIR_FREE(strbuf);
+ return -1;
+ }
+
+ *uid = pw->pw_uid;
+
+ VIR_FREE(strbuf);
+
+ return 0;
+}
+
+
+int virGetGroupID(virConnectPtr conn,
+ const char *name,
+ gid_t *gid)
+{
+ char *strbuf;
+ struct group grbuf;
+ struct group *gr = NULL;
+ size_t strbuflen = sysconf(_SC_GETGR_R_SIZE_MAX);
+
+ if (VIR_ALLOC_N(strbuf, strbuflen) < 0) {
+ virReportOOMError(conn);
+ return -1;
+ }
+
+ /*
+ * From the manpage (terrifying but true):
+ *
+ * ERRORS
+ * 0 or ENOENT or ESRCH or EBADF or EPERM or ...
+ * The given name or uid was not found.
+ */
+ if (getgrnam_r(name, &grbuf, strbuf, strbuflen, &gr) != 0 || gr == NULL) {
+ virReportSystemError(conn, errno,
+ _("Failed to find group record for name '%s'"),
+ name);
+ VIR_FREE(strbuf);
+ return -1;
+ }
+
+ *gid = gr->gr_gid;
+
+ VIR_FREE(strbuf);
+
+ return 0;
+}
+#endif
+
+
+#ifdef HAVE_MNTENT_H
+/* search /proc/mounts for mount point of *type; return pointer to
+ * malloc'ed string of the path if found, otherwise return NULL
+ * with errno set to an appropriate value.
+ */
+char *virFileFindMountPoint(const char *type)
+{
+ FILE *f;
+ struct mntent mb;
+ char mntbuf[1024];
+ char *ret = NULL;
+
+ f = setmntent("/proc/mounts", "r");
+ if (!f)
+ return NULL;
+
+ while (getmntent_r(f, &mb, mntbuf, sizeof(mntbuf))) {
+ if (STREQ(mb.mnt_type, type)) {
+ ret = strdup(mb.mnt_dir);
+ goto cleanup;
+ }
+ }
+
+ if (!ret)
+ errno = ENOENT;
+
+cleanup:
+ endmntent(f);
+
+ return ret;
+}
+#endif
+
+#ifndef PROXY
+#if defined(UDEVADM) || defined(UDEVSETTLE)
+void virFileWaitForDevices(virConnectPtr conn)
+{
+#ifdef UDEVADM
+ const char *const settleprog[] = { UDEVADM, "settle", NULL };
+#else
+ const char *const settleprog[] = { UDEVSETTLE, NULL };
+#endif
+ int exitstatus;
+
+ if (access(settleprog[0], X_OK) != 0)
+ return;
+
+ /*
+ * NOTE: we ignore errors here; this is just to make sure that any device
+ * nodes that are being created finish before we try to scan them.
+ * If this fails for any reason, we still have the backup of polling for
+ * 5 seconds for device nodes.
+ */
+ virRun(conn, settleprog, &exitstatus);
+}
+#else
+void virFileWaitForDevices(virConnectPtr conn ATTRIBUTE_UNUSED) {}
+#endif
+#endif
--- /dev/null
+
+/*
+ * utils.h: common, generic utility functions
+ *
+ * Copyright (C) 2006, 2007 Binary Karma
+ * Copyright (C) 2006 Shuveb Hussain
+ *
+ * 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
+ *
+ * File created Jul 18, 2007 - Shuveb Hussain <shuveb@binarykarma.com>
+ */
+
+#ifndef __VIR_UTIL_H__
+#define __VIR_UTIL_H__
+
+#include "verify.h"
+#include <sys/select.h>
+#include <sys/types.h>
+
+int saferead(int fd, void *buf, size_t count);
+ssize_t safewrite(int fd, const void *buf, size_t count);
+int safezero(int fd, int flags, off_t offset, off_t len);
+
+enum {
+ VIR_EXEC_NONE = 0,
+ VIR_EXEC_NONBLOCK = (1 << 0),
+ VIR_EXEC_DAEMON = (1 << 1),
+ VIR_EXEC_CLEAR_CAPS = (1 << 2),
+};
+
+int virSetNonBlock(int fd);
+int virSetCloseExec(int fd);
+
+/* This will execute in the context of the first child
+ * after fork() but before execve() */
+typedef int (*virExecHook)(void *data);
+
+int virExecDaemonize(virConnectPtr conn,
+ const char *const*argv,
+ const char *const*envp,
+ const fd_set *keepfd,
+ pid_t *retpid,
+ int infd, int *outfd, int *errfd,
+ int flags,
+ virExecHook hook,
+ void *data,
+ char *pidfile);
+int virExecWithHook(virConnectPtr conn,
+ const char *const*argv,
+ const char *const*envp,
+ const fd_set *keepfd,
+ int *retpid,
+ int infd,
+ int *outfd,
+ int *errfd,
+ int flags,
+ virExecHook hook,
+ void *data,
+ char *pidfile);
+int virExec(virConnectPtr conn,
+ const char *const*argv,
+ const char *const*envp,
+ const fd_set *keepfd,
+ pid_t *retpid,
+ int infd,
+ int *outfd,
+ int *errfd,
+ int flags);
+int virRun(virConnectPtr conn, const char *const*argv, int *status);
+
+int virFileReadLimFD(int fd, int maxlen, char **buf);
+
+int virFileReadAll(const char *path, int maxlen, char **buf);
+
+int virFileWriteStr(const char *path, const char *str);
+
+int virFileMatchesNameSuffix(const char *file,
+ const char *name,
+ const char *suffix);
+
+int virFileHasSuffix(const char *str,
+ const char *suffix);
+
+int virFileStripSuffix(char *str,
+ const char *suffix);
+
+int virFileLinkPointsTo(const char *checkLink,
+ const char *checkDest);
+
+int virFileResolveLink(const char *linkpath,
+ char **resultpath);
+
+char *virFindFileInPath(const char *file);
+
+int virFileExists(const char *path);
+
+int virFileMakePath(const char *path);
+
+int virFileBuildPath(const char *dir,
+ const char *name,
+ const char *ext,
+ char *buf,
+ unsigned int buflen);
+
+int virFileOpenTty(int *ttymaster,
+ char **ttyName,
+ int rawmode);
+int virFileOpenTtyAt(const char *ptmx,
+ int *ttymaster,
+ char **ttyName,
+ int rawmode);
+
+char* virFilePid(const char *dir,
+ const char *name);
+int virFileWritePidPath(const char *path,
+ pid_t pid);
+int virFileWritePid(const char *dir,
+ const char *name,
+ pid_t pid);
+int virFileReadPid(const char *dir,
+ const char *name,
+ pid_t *pid);
+int virFileDeletePid(const char *dir,
+ const char *name);
+
+char *virArgvToString(const char *const *argv);
+
+int virStrToLong_i(char const *s,
+ char **end_ptr,
+ int base,
+ int *result);
+
+int virStrToLong_ui(char const *s,
+ char **end_ptr,
+ int base,
+ unsigned int *result);
+int virStrToLong_ll(char const *s,
+ char **end_ptr,
+ int base,
+ long long *result);
+int virStrToLong_ull(char const *s,
+ char **end_ptr,
+ int base,
+ unsigned long long *result);
+int virStrToDouble(char const *s,
+ char **end_ptr,
+ double *result);
+
+int virMacAddrCompare (const char *mac1, const char *mac2);
+
+void virSkipSpaces(const char **str);
+int virParseNumber(const char **str);
+int virAsprintf(char **strp, const char *fmt, ...)
+ ATTRIBUTE_FMT_PRINTF(2, 3);
+
+#define VIR_MAC_BUFLEN 6
+#define VIR_MAC_PREFIX_BUFLEN 3
+#define VIR_MAC_STRING_BUFLEN VIR_MAC_BUFLEN * 3
+
+int virParseMacAddr(const char* str,
+ unsigned char *addr);
+void virFormatMacAddr(const unsigned char *addr,
+ char *str);
+void virGenerateMacAddr(const unsigned char *prefix,
+ unsigned char *addr);
+
+int virDiskNameToIndex(const char* str);
+
+
+int virEnumFromString(const char *const*types,
+ unsigned int ntypes,
+ const char *type);
+
+const char *virEnumToString(const char *const*types,
+ unsigned int ntypes,
+ int type);
+
+#define VIR_ENUM_IMPL(name, lastVal, ...) \
+ static const char *const name ## TypeList[] = { __VA_ARGS__ }; \
+ extern int (* name ## Verify (void)) [verify_true (ARRAY_CARDINALITY(name ## TypeList) == lastVal)]; \
+ const char *name ## TypeToString(int type) { \
+ return virEnumToString(name ## TypeList, \
+ ARRAY_CARDINALITY(name ## TypeList), \
+ type); \
+ } \
+ int name ## TypeFromString(const char *type) { \
+ return virEnumFromString(name ## TypeList, \
+ ARRAY_CARDINALITY(name ## TypeList), \
+ type); \
+ }
+
+#define VIR_ENUM_DECL(name) \
+ const char *name ## TypeToString(int type); \
+ int name ## TypeFromString(const char*type);
+
+#ifndef HAVE_GETUID
+static inline int getuid (void) { return 0; }
+#endif
+
+#ifndef HAVE_GETGID
+static inline int getgid (void) { return 0; }
+#endif
+
+char *virGetHostname(void);
+
+int virKillProcess(pid_t pid, int sig);
+
+#ifdef HAVE_GETPWUID_R
+char *virGetUserDirectory(virConnectPtr conn,
+ uid_t uid);
+char *virGetUserName(virConnectPtr conn,
+ uid_t uid);
+int virGetUserID(virConnectPtr conn,
+ const char *name,
+ uid_t *uid);
+int virGetGroupID(virConnectPtr conn,
+ const char *name,
+ gid_t *gid);
+#endif
+
+int virRandomInitialize(unsigned int seed);
+int virRandom(int max);
+
+#ifdef HAVE_MNTENT_H
+char *virFileFindMountPoint(const char *type);
+#endif
+
+void virFileWaitForDevices(virConnectPtr conn);
+
+#endif /* __VIR_UTIL_H__ */
--- /dev/null
+/*
+ * Copyright (C) 2007, 2008, 2009 Red Hat, Inc.
+ *
+ * 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
+ *
+ * Authors:
+ * Mark McLoughlin <markmc@redhat.com>
+ */
+
+#include <config.h>
+
+#include "uuid.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "c-ctype.h"
+#include "internal.h"
+#include "util.h"
+#include "virterror_internal.h"
+#include "logging.h"
+
+#ifndef ENODATA
+#define ENODATA EIO
+#endif
+
+static int
+virUUIDGenerateRandomBytes(unsigned char *buf,
+ int buflen)
+{
+ int fd;
+
+ if ((fd = open("/dev/urandom", O_RDONLY)) < 0)
+ return errno;
+
+ while (buflen > 0) {
+ int n;
+
+ if ((n = read(fd, buf, buflen)) <= 0) {
+ if (errno == EINTR)
+ continue;
+ close(fd);
+ return n < 0 ? errno : ENODATA;
+ }
+
+ buf += n;
+ buflen -= n;
+ }
+
+ close(fd);
+
+ return 0;
+}
+
+static int
+virUUIDGeneratePseudoRandomBytes(unsigned char *buf,
+ int buflen)
+{
+ while (buflen > 0) {
+ *buf = virRandom(256);
+ buflen--;
+ }
+
+ return 0;
+}
+
+/**
+ * virUUIDGenerate:
+ * @uuid: array of VIR_UUID_BUFLEN bytes to store the new UUID
+ *
+ * Generates a randomized unique identifier.
+ *
+ * Returns 0 in case of success and -1 in case of failure
+ */
+int
+virUUIDGenerate(unsigned char *uuid)
+{
+ int err;
+
+ if (uuid == NULL)
+ return(-1);
+
+ if ((err = virUUIDGenerateRandomBytes(uuid, VIR_UUID_BUFLEN))) {
+ char ebuf[1024];
+ VIR_WARN(_("Falling back to pseudorandom UUID,"
+ " failed to generate random bytes: %s"),
+ virStrerror(err, ebuf, sizeof ebuf));
+ }
+
+ return virUUIDGeneratePseudoRandomBytes(uuid, VIR_UUID_BUFLEN);
+}
+
+/* Convert C from hexadecimal character to integer. */
+static int
+hextobin (unsigned char c)
+{
+ switch (c)
+ {
+ default: return c - '0';
+ case 'a': case 'A': return 10;
+ case 'b': case 'B': return 11;
+ case 'c': case 'C': return 12;
+ case 'd': case 'D': return 13;
+ case 'e': case 'E': return 14;
+ case 'f': case 'F': return 15;
+ }
+}
+
+/**
+ * virUUIDParse:
+ * @uuidstr: zero terminated string representation of the UUID
+ * @uuid: array of VIR_UUID_BUFLEN bytes to store the raw UUID
+ *
+ * Parses the external string representation, allowing spaces and '-'
+ * character in the sequence, and storing the result as a raw UUID
+ *
+ * Returns 0 in case of success and -1 in case of error.
+ */
+int
+virUUIDParse(const char *uuidstr, unsigned char *uuid) {
+ const char *cur;
+ int i;
+
+ if ((uuidstr == NULL) || (uuid == NULL))
+ return(-1);
+
+ /*
+ * do a liberal scan allowing '-' and ' ' anywhere between character
+ * pairs as long as there is 32 of them in the end.
+ */
+ cur = uuidstr;
+ for (i = 0;i < VIR_UUID_BUFLEN;) {
+ uuid[i] = 0;
+ if (*cur == 0)
+ goto error;
+ if ((*cur == '-') || (*cur == ' ')) {
+ cur++;
+ continue;
+ }
+ if (!c_isxdigit(*cur))
+ goto error;
+ uuid[i] = hextobin(*cur);
+ uuid[i] *= 16;
+ cur++;
+ if (*cur == 0)
+ goto error;
+ if (!c_isxdigit(*cur))
+ goto error;
+ uuid[i] += hextobin(*cur);
+ i++;
+ cur++;
+ }
+
+ return 0;
+
+ error:
+ return -1;
+}
+
+/**
+ * virUUIDFormat:
+ * @uuid: array of VIR_UUID_RAW_LEN bytes to store the raw UUID
+ * @uuidstr: array of VIR_UUID_STRING_BUFLEN bytes to store the
+ * string representation of the UUID in. The resulting string
+ * will be NULL terminated.
+ *
+ * Converts the raw UUID into printable format, with embedded '-'
+ *
+ * Returns 0 in case of success and -1 in case of error.
+ */
+void virUUIDFormat(const unsigned char *uuid, char *uuidstr)
+{
+ snprintf(uuidstr, VIR_UUID_STRING_BUFLEN,
+ "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ uuid[0], uuid[1], uuid[2], uuid[3],
+ uuid[4], uuid[5], uuid[6], uuid[7],
+ uuid[8], uuid[9], uuid[10], uuid[11],
+ uuid[12], uuid[13], uuid[14], uuid[15]);
+ uuidstr[VIR_UUID_STRING_BUFLEN-1] = '\0';
+}
--- /dev/null
+/*
+ * Copyright (C) 2007 Red Hat, Inc.
+ *
+ * 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
+ *
+ * Authors:
+ * Mark McLoughlin <markmc@redhat.com>
+ */
+
+#ifndef __VIR_UUID_H__
+#define __VIR_UUID_H__
+
+int virUUIDGenerate(unsigned char *uuid);
+
+int virUUIDParse(const char *uuidstr,
+ unsigned char *uuid);
+
+void virUUIDFormat(const unsigned char *uuid,
+ char *uuidstr);
+
+#endif /* __VIR_UUID_H__ */
--- /dev/null
+/*
+ * virterror.c: implements error handling and reporting code for libvirt
+ *
+ * Copy: Copyright (C) 2006, 2008, 2009 Red Hat, Inc.
+ *
+ * See COPYING.LIB for the License of this software
+ *
+ * Author: Daniel Veillard <veillard@redhat.com>
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include "virterror_internal.h"
+#include "datatypes.h"
+#include "logging.h"
+#include "memory.h"
+#include "threads.h"
+#include "util.h"
+
+virThreadLocal virLastErr;
+
+virErrorFunc virErrorHandler = NULL; /* global error handler */
+void *virUserData = NULL; /* associated data */
+
+/*
+ * Macro used to format the message as a string in virRaiseError
+ * and borrowed from libxml2.
+ */
+#define VIR_GET_VAR_STR(msg, str) { \
+ int size, prev_size = -1; \
+ int chars; \
+ char *larger; \
+ va_list ap; \
+ \
+ str = (char *) malloc(150); \
+ if (str != NULL) { \
+ \
+ size = 150; \
+ \
+ while (1) { \
+ va_start(ap, msg); \
+ chars = vsnprintf(str, size, msg, ap); \
+ va_end(ap); \
+ if ((chars > -1) && (chars < size)) { \
+ if (prev_size == chars) { \
+ break; \
+ } else { \
+ prev_size = chars; \
+ } \
+ } \
+ if (chars > -1) \
+ size += chars + 1; \
+ else \
+ size += 100; \
+ if ((larger = (char *) realloc(str, size)) == NULL) { \
+ break; \
+ } \
+ str = larger; \
+ }} \
+}
+
+static virLogPriority virErrorLevelPriority(virErrorLevel level) {
+ switch (level) {
+ case VIR_ERR_NONE:
+ return(VIR_LOG_INFO);
+ case VIR_ERR_WARNING:
+ return(VIR_LOG_WARN);
+ case VIR_ERR_ERROR:
+ return(VIR_LOG_ERROR);
+ }
+ return(VIR_LOG_ERROR);
+}
+
+static const char *virErrorDomainName(virErrorDomain domain) {
+ const char *dom = "unknown";
+ switch (domain) {
+ case VIR_FROM_NONE:
+ dom = "";
+ break;
+ case VIR_FROM_XEN:
+ dom = "Xen ";
+ break;
+ case VIR_FROM_XML:
+ dom = "XML ";
+ break;
+ case VIR_FROM_XEND:
+ dom = "Xen Daemon ";
+ break;
+ case VIR_FROM_XENSTORE:
+ dom = "Xen Store ";
+ break;
+ case VIR_FROM_XEN_INOTIFY:
+ dom = "Xen Inotify ";
+ break;
+ case VIR_FROM_DOM:
+ dom = "Domain ";
+ break;
+ case VIR_FROM_RPC:
+ dom = "XML-RPC ";
+ break;
+ case VIR_FROM_QEMU:
+ dom = "QEMU ";
+ break;
+ case VIR_FROM_NET:
+ dom = "Network ";
+ break;
+ case VIR_FROM_TEST:
+ dom = "Test ";
+ break;
+ case VIR_FROM_REMOTE:
+ dom = "Remote ";
+ break;
+ case VIR_FROM_SEXPR:
+ dom = "S-Expr ";
+ break;
+ case VIR_FROM_PROXY:
+ dom = "PROXY ";
+ break;
+ case VIR_FROM_CONF:
+ dom = "Config ";
+ break;
+ case VIR_FROM_PHYP:
+ dom = "IBM power hypervisor ";
+ break;
+ case VIR_FROM_OPENVZ:
+ dom = "OpenVZ ";
+ break;
+ case VIR_FROM_XENXM:
+ dom = "Xen XM ";
+ break;
+ case VIR_FROM_STATS_LINUX:
+ dom = "Linux Stats ";
+ break;
+ case VIR_FROM_LXC:
+ dom = "Linux Container ";
+ break;
+ case VIR_FROM_STORAGE:
+ dom = "Storage ";
+ break;
+ case VIR_FROM_NETWORK:
+ dom = "Network Config ";
+ break;
+ case VIR_FROM_DOMAIN:
+ dom = "Domain Config ";
+ break;
+ case VIR_FROM_NODEDEV:
+ dom = "Node Device ";
+ break;
+ case VIR_FROM_UML:
+ dom = "UML ";
+ break;
+ case VIR_FROM_SECURITY:
+ dom = "Security Labeling ";
+ break;
+ case VIR_FROM_VBOX:
+ dom = "VBOX ";
+ break;
+ case VIR_FROM_INTERFACE:
+ dom = "Interface ";
+ break;
+ case VIR_FROM_ONE:
+ dom = "ONE ";
+ break;
+ case VIR_FROM_ESX:
+ dom = "ESX ";
+ break;
+ case VIR_FROM_SECRET:
+ dom = "Secret Storage ";
+ break;
+ }
+ return(dom);
+}
+
+
+/*
+ * Internal helper that is called when a thread exits, to
+ * release the error object stored in the thread local
+ */
+static void
+virLastErrFreeData(void *data)
+{
+ virErrorPtr err = data;
+ if (!err)
+ return;
+ virResetError(err);
+ VIR_FREE(err);
+}
+
+
+/**
+ * virErrorInitialize:
+ *
+ * Initialize the error data (per thread)
+ *
+ * Returns 0 in case of success, -1 in case of failure.
+ */
+int
+virErrorInitialize(void)
+{
+ return virThreadLocalInit(&virLastErr, virLastErrFreeData);
+}
+
+
+/*
+ * Internal helper to ensure a generic error code is stored
+ * in case where API returns failure, but forgot to set an
+ * error
+ */
+static void
+virErrorGenericFailure(virErrorPtr err)
+{
+ err->code = VIR_ERR_INTERNAL_ERROR;
+ err->domain = VIR_FROM_NONE;
+ err->level = VIR_ERR_ERROR;
+ err->message = strdup(_("Unknown failure"));
+}
+
+
+/*
+ * Internal helper to perform a deep copy of the an error
+ */
+static int
+virCopyError(virErrorPtr from,
+ virErrorPtr to)
+{
+ int ret = 0;
+ if (!to)
+ return 0;
+ virResetError(to);
+ if (!from)
+ return 0;
+ to->code = from->code;
+ to->domain = from->domain;
+ to->level = from->level;
+ if (from->message && !(to->message = strdup(from->message)))
+ ret = -1;
+ if (from->str1 && !(to->str1 = strdup(from->str1)))
+ ret = -1;
+ if (from->str2 && !(to->str2 = strdup(from->str2)))
+ ret = -1;
+ if (from->str3 && !(to->str3 = strdup(from->str3)))
+ ret = -1;
+ to->int1 = from->int1;
+ to->int2 = from->int2;
+ /*
+ * Delibrately not setting 'conn', 'dom', 'net' references
+ */
+ return ret;
+}
+
+static virErrorPtr
+virLastErrorObject(void)
+{
+ virErrorPtr err;
+ err = virThreadLocalGet(&virLastErr);
+ if (!err) {
+ if (VIR_ALLOC(err) < 0)
+ return NULL;
+ virThreadLocalSet(&virLastErr, err);
+ }
+ return err;
+}
+
+
+/**
+ * virGetLastError:
+ *
+ * Provide a pointer to the last error caught at the library level
+ *
+ * The error object is kept in thread local storage, so separate
+ * threads can safely access this concurrently.
+ *
+ * Returns a pointer to the last error or NULL if none occurred.
+ */
+virErrorPtr
+virGetLastError(void)
+{
+ virErrorPtr err = virLastErrorObject();
+ if (!err || err->code == VIR_ERR_OK)
+ return NULL;
+ return err;
+}
+
+/**
+ * virCopyLastError:
+ * @to: target to receive the copy
+ *
+ * Copy the content of the last error caught at the library level
+ *
+ * The error object is kept in thread local storage, so separate
+ * threads can safely access this concurrently.
+ *
+ * One will need to free the result with virResetError()
+ *
+ * Returns 0 if no error was found and the error code otherwise and -1 in case
+ * of parameter error.
+ */
+int
+virCopyLastError(virErrorPtr to)
+{
+ virErrorPtr err = virLastErrorObject();
+ /* We can't guarentee caller has initialized it to zero */
+ memset(to, 0, sizeof(*to));
+ if (err)
+ virCopyError(err, to);
+ else
+ virResetError(to);
+ return to->code;
+}
+
+/**
+ * virSaveLastError:
+ *
+ * Save the last error into a new error object.
+ *
+ * Returns a pointer to the copied error or NULL if allocation failed.
+ * It is the caller's responsibility to free the error with
+ * virFreeError().
+ */
+virErrorPtr
+virSaveLastError(void)
+{
+ virErrorPtr to;
+
+ if (VIR_ALLOC(to) < 0)
+ return NULL;
+
+ virCopyLastError(to);
+ return to;
+}
+
+/**
+ * virResetError:
+ * @err: pointer to the virError to clean up
+ *
+ * Reset the error being pointed to
+ */
+void
+virResetError(virErrorPtr err)
+{
+ if (err == NULL)
+ return;
+ free(err->message);
+ free(err->str1);
+ free(err->str2);
+ free(err->str3);
+ memset(err, 0, sizeof(virError));
+}
+
+/**
+ * virFreeError:
+ * @err: error to free
+ *
+ * Resets and frees the given error.
+ */
+void
+virFreeError(virErrorPtr err)
+{
+ virResetError(err);
+ VIR_FREE(err);
+}
+
+/**
+ * virResetLastError:
+ *
+ * Reset the last error caught at the library level.
+ *
+ * The error object is kept in thread local storage, so separate
+ * threads can safely access this concurrently, only resetting
+ * their own error object.
+ */
+void
+virResetLastError(void)
+{
+ virErrorPtr err = virLastErrorObject();
+ if (err)
+ virResetError(err);
+}
+
+/**
+ * virConnGetLastError:
+ * @conn: pointer to the hypervisor connection
+ *
+ * Provide a pointer to the last error caught on that connection
+ *
+ * This method is not protected against access from multiple
+ * threads. In a multi-threaded application, always use the
+ * global virGetLastError() API which is backed by thread
+ * local storage.
+ *
+ * If the connection object was discovered to be invalid by
+ * an API call, then the error will be reported against the
+ * global error object.
+ *
+ * Since 0.6.0, all errors reported in the per-connection object
+ * are also duplicated in the global error object. As such an
+ * application can always use virGetLastError(). This method
+ * remains for backwards compatability.
+ *
+ * Returns a pointer to the last error or NULL if none occurred.
+ */
+virErrorPtr
+virConnGetLastError(virConnectPtr conn)
+{
+ if (conn == NULL)
+ return NULL;
+ return &conn->err;
+}
+
+/**
+ * virConnCopyLastError:
+ * @conn: pointer to the hypervisor connection
+ * @to: target to receive the copy
+ *
+ * Copy the content of the last error caught on that connection
+ *
+ * This method is not protected against access from multiple
+ * threads. In a multi-threaded application, always use the
+ * global virGetLastError() API which is backed by thread
+ * local storage.
+ *
+ * If the connection object was discovered to be invalid by
+ * an API call, then the error will be reported against the
+ * global error object.
+ *
+ * Since 0.6.0, all errors reported in the per-connection object
+ * are also duplicated in the global error object. As such an
+ * application can always use virGetLastError(). This method
+ * remains for backwards compatability.
+ *
+ * One will need to free the result with virResetError()
+ *
+ * Returns 0 if no error was found and the error code otherwise and -1 in case
+ * of parameter error.
+ */
+int
+virConnCopyLastError(virConnectPtr conn, virErrorPtr to)
+{
+ /* We can't guarentee caller has initialized it to zero */
+ memset(to, 0, sizeof(*to));
+
+ if (conn == NULL)
+ return -1;
+ virMutexLock(&conn->lock);
+ if (conn->err.code == VIR_ERR_OK)
+ virResetError(to);
+ else
+ virCopyError(&conn->err, to);
+ virMutexUnlock(&conn->lock);
+ return to->code;
+}
+
+/**
+ * virConnResetLastError:
+ * @conn: pointer to the hypervisor connection
+ *
+ * The error object is kept in thread local storage, so separate
+ * threads can safely access this concurrently.
+ *
+ * Reset the last error caught on that connection
+ */
+void
+virConnResetLastError(virConnectPtr conn)
+{
+ if (conn == NULL)
+ return;
+ virMutexLock(&conn->lock);
+ virResetError(&conn->err);
+ virMutexUnlock(&conn->lock);
+}
+
+/**
+ * virSetErrorFunc:
+ * @userData: pointer to the user data provided in the handler callback
+ * @handler: the function to get called in case of error or NULL
+ *
+ * Set a library global error handling function, if @handler is NULL,
+ * it will reset to default printing on stderr. The error raised there
+ * are those for which no handler at the connection level could caught.
+ */
+void
+virSetErrorFunc(void *userData, virErrorFunc handler)
+{
+ virErrorHandler = handler;
+ virUserData = userData;
+}
+
+/**
+ * virConnSetErrorFunc:
+ * @conn: pointer to the hypervisor connection
+ * @userData: pointer to the user data provided in the handler callback
+ * @handler: the function to get called in case of error or NULL
+ *
+ * Set a connection error handling function, if @handler is NULL
+ * it will reset to default which is to pass error back to the global
+ * library handler.
+ */
+void
+virConnSetErrorFunc(virConnectPtr conn, void *userData,
+ virErrorFunc handler)
+{
+ if (conn == NULL)
+ return;
+ virMutexLock(&conn->lock);
+ conn->handler = handler;
+ conn->userData = userData;
+ virMutexUnlock(&conn->lock);
+}
+
+/**
+ * virDefaultErrorFunc:
+ * @err: pointer to the error.
+ *
+ * Default routine reporting an error to stderr.
+ */
+void
+virDefaultErrorFunc(virErrorPtr err)
+{
+ const char *lvl = "", *dom = "", *domain = "", *network = "";
+ int len;
+
+ if ((err == NULL) || (err->code == VIR_ERR_OK))
+ return;
+ switch (err->level) {
+ case VIR_ERR_NONE:
+ lvl = "";
+ break;
+ case VIR_ERR_WARNING:
+ lvl = _("warning");
+ break;
+ case VIR_ERR_ERROR:
+ lvl = _("error");
+ break;
+ }
+ dom = virErrorDomainName(err->domain);
+ if ((err->dom != NULL) && (err->code != VIR_ERR_INVALID_DOMAIN)) {
+ domain = err->dom->name;
+ } else if ((err->net != NULL) && (err->code != VIR_ERR_INVALID_NETWORK)) {
+ network = err->net->name;
+ }
+ len = strlen(err->message);
+ if ((err->domain == VIR_FROM_XML) && (err->code == VIR_ERR_XML_DETAIL) &&
+ (err->int1 != 0))
+ fprintf(stderr, "libvir: %s%s %s%s: line %d: %s",
+ dom, lvl, domain, network, err->int1, err->message);
+ else if ((len == 0) || (err->message[len - 1] != '\n'))
+ fprintf(stderr, "libvir: %s%s %s%s: %s\n",
+ dom, lvl, domain, network, err->message);
+ else
+ fprintf(stderr, "libvir: %s%s %s%s: %s",
+ dom, lvl, domain, network, err->message);
+}
+
+/**
+ * virSetGlobalError:
+ * Internal helper to ensure the global error object
+ * is initialized with a generic message if not already
+ * set.
+ */
+void
+virSetGlobalError(void)
+{
+ virErrorPtr err = virLastErrorObject();
+
+ if (err && err->code == VIR_ERR_OK)
+ virErrorGenericFailure(err);
+}
+
+/**
+ * virSetConnError:
+ * @conn: pointer to the hypervisor connection
+ *
+ * Internal helper to ensure the connection error object
+ * is initialized from the global object.
+ */
+void
+virSetConnError(virConnectPtr conn)
+{
+ virErrorPtr err = virLastErrorObject();
+
+ if (err && err->code == VIR_ERR_OK)
+ virErrorGenericFailure(err);
+
+ if (conn) {
+ virMutexLock(&conn->lock);
+ if (err)
+ virCopyError(err, &conn->err);
+ else
+ virErrorGenericFailure(&conn->err);
+ virMutexUnlock(&conn->lock);
+ }
+}
+
+
+
+/**
+ * virRaiseErrorFull:
+ * @conn: the connection to the hypervisor if available
+ * @filename: filename where error was raised
+ * @funcname: function name where error was raised
+ * @linenr: line number where error was raised
+ * @domain: the virErrorDomain indicating where it's coming from
+ * @code: the virErrorNumber code for the error
+ * @level: the virErrorLevel for the error
+ * @str1: extra string info
+ * @str2: extra string info
+ * @str3: extra string info
+ * @int1: extra int info
+ * @int2: extra int info
+ * @fmt: the message to display/transmit
+ * @...: extra parameters for the message display
+ *
+ * Internal routine called when an error is detected. It will raise it
+ * immediately if a callback is found and store it for later handling.
+ */
+void
+virRaiseErrorFull(virConnectPtr conn,
+ const char *filename ATTRIBUTE_UNUSED,
+ const char *funcname,
+ size_t linenr,
+ int domain,
+ int code,
+ virErrorLevel level,
+ const char *str1,
+ const char *str2,
+ const char *str3,
+ int int1,
+ int int2,
+ const char *fmt, ...)
+{
+ virErrorPtr to;
+ void *userData = virUserData;
+ virErrorFunc handler = virErrorHandler;
+ char *str;
+
+ /*
+ * All errors are recorded in thread local storage
+ * For compatability, public API calls will copy them
+ * to the per-connection error object when neccessary
+ */
+ to = virLastErrorObject();
+ if (!to)
+ return; /* Hit OOM allocating thread error object, sod all we can do now */
+
+ virResetError(to);
+
+ if (code == VIR_ERR_OK)
+ return;
+
+ /*
+ * try to find the best place to save and report the error
+ */
+ if (conn != NULL) {
+ virMutexLock(&conn->lock);
+ if (conn->handler != NULL) {
+ handler = conn->handler;
+ userData = conn->userData;
+ }
+ virMutexUnlock(&conn->lock);
+ }
+
+ /*
+ * formats the message
+ */
+ if (fmt == NULL) {
+ str = strdup(_("No error message provided"));
+ } else {
+ VIR_GET_VAR_STR(fmt, str);
+ }
+
+ /*
+ * Hook up the error or warning to the logging facility
+ * XXXX should we include filename as 'category' instead of domain name ?
+ */
+ virLogMessage(virErrorDomainName(domain), virErrorLevelPriority(level),
+ funcname, linenr, 1, "%s", str);
+
+ /*
+ * Save the information about the error
+ */
+ virResetError(to);
+ /*
+ * Delibrately not setting conn, dom & net fields since
+ * they're utterly unsafe
+ */
+ to->domain = domain;
+ to->code = code;
+ to->message = str;
+ to->level = level;
+ if (str1 != NULL)
+ to->str1 = strdup(str1);
+ if (str2 != NULL)
+ to->str2 = strdup(str2);
+ if (str3 != NULL)
+ to->str3 = strdup(str3);
+ to->int1 = int1;
+ to->int2 = int2;
+
+ /*
+ * now, report it
+ */
+ if (handler != NULL) {
+ handler(userData, to);
+ } else {
+ virDefaultErrorFunc(to);
+ }
+}
+
+/**
+ * virErrorMsg:
+ * @error: the virErrorNumber
+ * @info: usually the first parameter string
+ *
+ * Internal routine to get the message associated to an error raised
+ * from the library
+ *
+ * Returns the constant string associated to @error
+ */
+const char *
+virErrorMsg(virErrorNumber error, const char *info)
+{
+ const char *errmsg = NULL;
+
+ switch (error) {
+ case VIR_ERR_OK:
+ return (NULL);
+ case VIR_ERR_INTERNAL_ERROR:
+ if (info != NULL)
+ errmsg = _("internal error %s");
+ else
+ errmsg = _("internal error");
+ break;
+ case VIR_ERR_NO_MEMORY:
+ errmsg = _("out of memory");
+ break;
+ case VIR_ERR_NO_SUPPORT:
+ if (info == NULL)
+ errmsg = _("this function is not supported by the hypervisor");
+ else
+ errmsg = _("this function is not supported by the hypervisor: %s");
+ break;
+ case VIR_ERR_NO_CONNECT:
+ if (info == NULL)
+ errmsg = _("no hypervisor driver available");
+ else
+ errmsg = _("no hypervisor driver available for %s");
+ break;
+ case VIR_ERR_INVALID_CONN:
+ if (info == NULL)
+ errmsg = _("invalid connection pointer in");
+ else
+ errmsg = _("invalid connection pointer in %s");
+ break;
+ case VIR_ERR_INVALID_DOMAIN:
+ if (info == NULL)
+ errmsg = _("invalid domain pointer in");
+ else
+ errmsg = _("invalid domain pointer in %s");
+ break;
+ case VIR_ERR_INVALID_ARG:
+ if (info == NULL)
+ errmsg = _("invalid argument in");
+ else
+ errmsg = _("invalid argument in %s");
+ break;
+ case VIR_ERR_OPERATION_FAILED:
+ if (info != NULL)
+ errmsg = _("operation failed: %s");
+ else
+ errmsg = _("operation failed");
+ break;
+ case VIR_ERR_GET_FAILED:
+ if (info != NULL)
+ errmsg = _("GET operation failed: %s");
+ else
+ errmsg = _("GET operation failed");
+ break;
+ case VIR_ERR_POST_FAILED:
+ if (info != NULL)
+ errmsg = _("POST operation failed: %s");
+ else
+ errmsg = _("POST operation failed");
+ break;
+ case VIR_ERR_HTTP_ERROR:
+ errmsg = _("got unknown HTTP error code %d");
+ break;
+ case VIR_ERR_UNKNOWN_HOST:
+ if (info != NULL)
+ errmsg = _("unknown host %s");
+ else
+ errmsg = _("unknown host");
+ break;
+ case VIR_ERR_SEXPR_SERIAL:
+ if (info != NULL)
+ errmsg = _("failed to serialize S-Expr: %s");
+ else
+ errmsg = _("failed to serialize S-Expr");
+ break;
+ case VIR_ERR_NO_XEN:
+ if (info == NULL)
+ errmsg = _("could not use Xen hypervisor entry");
+ else
+ errmsg = _("could not use Xen hypervisor entry %s");
+ break;
+ case VIR_ERR_NO_XENSTORE:
+ if (info == NULL)
+ errmsg = _("could not connect to Xen Store");
+ else
+ errmsg = _("could not connect to Xen Store %s");
+ break;
+ case VIR_ERR_XEN_CALL:
+ errmsg = _("failed Xen syscall %s");
+ break;
+ case VIR_ERR_OS_TYPE:
+ if (info == NULL)
+ errmsg = _("unknown OS type");
+ else
+ errmsg = _("unknown OS type %s");
+ break;
+ case VIR_ERR_NO_KERNEL:
+ errmsg = _("missing kernel information");
+ break;
+ case VIR_ERR_NO_ROOT:
+ if (info == NULL)
+ errmsg = _("missing root device information");
+ else
+ errmsg = _("missing root device information in %s");
+ break;
+ case VIR_ERR_NO_SOURCE:
+ if (info == NULL)
+ errmsg = _("missing source information for device");
+ else
+ errmsg = _("missing source information for device %s");
+ break;
+ case VIR_ERR_NO_TARGET:
+ if (info == NULL)
+ errmsg = _("missing target information for device");
+ else
+ errmsg = _("missing target information for device %s");
+ break;
+ case VIR_ERR_NO_NAME:
+ if (info == NULL)
+ errmsg = _("missing domain name information");
+ else
+ errmsg = _("missing domain name information in %s");
+ break;
+ case VIR_ERR_NO_OS:
+ if (info == NULL)
+ errmsg = _("missing operating system information");
+ else
+ errmsg = _("missing operating system information for %s");
+ break;
+ case VIR_ERR_NO_DEVICE:
+ if (info == NULL)
+ errmsg = _("missing devices information");
+ else
+ errmsg = _("missing devices information for %s");
+ break;
+ case VIR_ERR_DRIVER_FULL:
+ if (info == NULL)
+ errmsg = _("too many drivers registered");
+ else
+ errmsg = _("too many drivers registered in %s");
+ break;
+ case VIR_ERR_CALL_FAILED: /* DEPRECATED, use VIR_ERR_NO_SUPPORT */
+ if (info == NULL)
+ errmsg = _("library call failed, possibly not supported");
+ else
+ errmsg = _("library call %s failed, possibly not supported");
+ break;
+ case VIR_ERR_XML_ERROR:
+ if (info == NULL)
+ errmsg = _("XML description not well formed or invalid");
+ else
+ errmsg = _("XML description for %s is not well formed or invalid");
+ break;
+ case VIR_ERR_DOM_EXIST:
+ if (info == NULL)
+ errmsg = _("this domain exists already");
+ else
+ errmsg = _("domain %s exists already");
+ break;
+ case VIR_ERR_OPERATION_DENIED:
+ if (info == NULL)
+ errmsg = _("operation forbidden for read only access");
+ else
+ errmsg = _("operation %s forbidden for read only access");
+ break;
+ case VIR_ERR_OPEN_FAILED:
+ if (info == NULL)
+ errmsg = _("failed to open configuration file for reading");
+ else
+ errmsg = _("failed to open %s for reading");
+ break;
+ case VIR_ERR_READ_FAILED:
+ if (info == NULL)
+ errmsg = _("failed to read configuration file");
+ else
+ errmsg = _("failed to read configuration file %s");
+ break;
+ case VIR_ERR_PARSE_FAILED:
+ if (info == NULL)
+ errmsg = _("failed to parse configuration file");
+ else
+ errmsg = _("failed to parse configuration file %s");
+ break;
+ case VIR_ERR_CONF_SYNTAX:
+ if (info == NULL)
+ errmsg = _("configuration file syntax error");
+ else
+ errmsg = _("configuration file syntax error: %s");
+ break;
+ case VIR_ERR_WRITE_FAILED:
+ if (info == NULL)
+ errmsg = _("failed to write configuration file");
+ else
+ errmsg = _("failed to write configuration file: %s");
+ break;
+ case VIR_ERR_XML_DETAIL:
+ if (info == NULL)
+ errmsg = _("parser error");
+ else
+ errmsg = "%s";
+ break;
+ case VIR_ERR_INVALID_NETWORK:
+ if (info == NULL)
+ errmsg = _("invalid network pointer in");
+ else
+ errmsg = _("invalid network pointer in %s");
+ break;
+ case VIR_ERR_NETWORK_EXIST:
+ if (info == NULL)
+ errmsg = _("this network exists already");
+ else
+ errmsg = _("network %s exists already");
+ break;
+ case VIR_ERR_SYSTEM_ERROR:
+ if (info == NULL)
+ errmsg = _("system call error");
+ else
+ errmsg = "%s";
+ break;
+ case VIR_ERR_RPC:
+ if (info == NULL)
+ errmsg = _("RPC error");
+ else
+ errmsg = "%s";
+ break;
+ case VIR_ERR_GNUTLS_ERROR:
+ if (info == NULL)
+ errmsg = _("GNUTLS call error");
+ else
+ errmsg = "%s";
+ break;
+ case VIR_WAR_NO_NETWORK:
+ if (info == NULL)
+ errmsg = _("Failed to find the network");
+ else
+ errmsg = _("Failed to find the network: %s");
+ break;
+ case VIR_ERR_NO_DOMAIN:
+ if (info == NULL)
+ errmsg = _("Domain not found");
+ else
+ errmsg = _("Domain not found: %s");
+ break;
+ case VIR_ERR_NO_NETWORK:
+ if (info == NULL)
+ errmsg = _("Network not found");
+ else
+ errmsg = _("Network not found: %s");
+ break;
+ case VIR_ERR_INVALID_MAC:
+ if (info == NULL)
+ errmsg = _("invalid MAC address");
+ else
+ errmsg = _("invalid MAC address: %s");
+ break;
+ case VIR_ERR_AUTH_FAILED:
+ if (info == NULL)
+ errmsg = _("authentication failed");
+ else
+ errmsg = _("authentication failed: %s");
+ break;
+ case VIR_ERR_NO_STORAGE_POOL:
+ if (info == NULL)
+ errmsg = _("Storage pool not found");
+ else
+ errmsg = _("Storage pool not found: %s");
+ break;
+ case VIR_ERR_NO_STORAGE_VOL:
+ if (info == NULL)
+ errmsg = _("Storage volume not found");
+ else
+ errmsg = _("Storage volume not found: %s");
+ break;
+ case VIR_ERR_INVALID_STORAGE_POOL:
+ if (info == NULL)
+ errmsg = _("invalid storage pool pointer in");
+ else
+ errmsg = _("invalid storage pool pointer in %s");
+ break;
+ case VIR_ERR_INVALID_STORAGE_VOL:
+ if (info == NULL)
+ errmsg = _("invalid storage volume pointer in");
+ else
+ errmsg = _("invalid storage volume pointer in %s");
+ break;
+ case VIR_WAR_NO_STORAGE:
+ if (info == NULL)
+ errmsg = _("Failed to find a storage driver");
+ else
+ errmsg = _("Failed to find a storage driver: %s");
+ break;
+ case VIR_WAR_NO_NODE:
+ if (info == NULL)
+ errmsg = _("Failed to find a node driver");
+ else
+ errmsg = _("Failed to find a node driver: %s");
+ break;
+ case VIR_ERR_INVALID_NODE_DEVICE:
+ if (info == NULL)
+ errmsg = _("invalid node device pointer");
+ else
+ errmsg = _("invalid node device pointer in %s");
+ break;
+ case VIR_ERR_NO_NODE_DEVICE:
+ if (info == NULL)
+ errmsg = _("Node device not found");
+ else
+ errmsg = _("Node device not found: %s");
+ break;
+ case VIR_ERR_NO_SECURITY_MODEL:
+ if (info == NULL)
+ errmsg = _("Security model not found");
+ else
+ errmsg = _("Security model not found: %s");
+ break;
+ case VIR_ERR_OPERATION_INVALID:
+ if (info == NULL)
+ errmsg = _("Requested operation is not valid");
+ else
+ errmsg = _("Requested operation is not valid: %s");
+ break;
+ case VIR_WAR_NO_INTERFACE:
+ if (info == NULL)
+ errmsg = _("Failed to find the interface");
+ else
+ errmsg = _("Failed to find the interface: %s");
+ break;
+ case VIR_ERR_NO_INTERFACE:
+ if (info == NULL)
+ errmsg = _("Interface not found");
+ else
+ errmsg = _("Interface not found: %s");
+ break;
+ case VIR_ERR_INVALID_INTERFACE:
+ if (info == NULL)
+ errmsg = _("invalid interface pointer in");
+ else
+ errmsg = _("invalid interface pointer in %s");
+ break;
+ case VIR_ERR_MULTIPLE_INTERFACES:
+ if (info == NULL)
+ errmsg = _("multiple matching interfaces found");
+ else
+ errmsg = _("multiple matching interfaces found: %s");
+ break;
+ case VIR_WAR_NO_SECRET:
+ if (info == NULL)
+ errmsg = _("Failed to find a secret storage driver");
+ else
+ errmsg = _("Failed to find a secret storage driver: %s");
+ break;
+ case VIR_ERR_INVALID_SECRET:
+ if (info == NULL)
+ errmsg = _("Invalid secret");
+ else
+ errmsg = _("Invalid secret: %s");
+ case VIR_ERR_NO_SECRET:
+ if (info == NULL)
+ errmsg = _("Secret not found");
+ else
+ errmsg = _("Secret not found: %s");
+ break;
+ }
+ return (errmsg);
+}
+
+/**
+ * virReportErrorHelper:
+ *
+ * @conn: the connection to the hypervisor if available
+ * @domcode: the virErrorDomain indicating where it's coming from
+ * @errcode: the virErrorNumber code for the error
+ * @filename: Source file error is dispatched from
+ * @funcname: Function error is dispatched from
+ * @linenr: Line number error is dispatched from
+ * @fmt: the format string
+ * @...: extra parameters for the message display
+ *
+ * Helper function to do most of the grunt work for individual driver
+ * ReportError
+ */
+void virReportErrorHelper(virConnectPtr conn,
+ int domcode,
+ int errcode,
+ const char *filename,
+ const char *funcname,
+ size_t linenr,
+ const char *fmt, ...)
+{
+ va_list args;
+ char errorMessage[1024];
+ const char *virerr;
+
+ if (fmt) {
+ va_start(args, fmt);
+ vsnprintf(errorMessage, sizeof(errorMessage)-1, fmt, args);
+ va_end(args);
+ } else {
+ errorMessage[0] = '\0';
+ }
+
+ virerr = virErrorMsg(errcode, (errorMessage[0] ? errorMessage : NULL));
+ virRaiseErrorFull(conn, filename, funcname, linenr,
+ domcode, errcode, VIR_ERR_ERROR,
+ virerr, errorMessage, NULL,
+ -1, -1, virerr, errorMessage);
+
+}
+
+/**
+ * virStrerror:
+ * @theerrno: the errno value
+ * @errBuf: the buffer to save the error to
+ * @errBufLen: the buffer length
+ *
+ * Generate an erro string for the given errno
+ *
+ * Returns a pointer to the error string, possibly indicating that the
+ * error is unknown
+ */
+const char *virStrerror(int theerrno, char *errBuf, size_t errBufLen)
+{
+#ifdef HAVE_STRERROR_R
+# ifdef __USE_GNU
+ /* Annoying linux specific API contract */
+ return strerror_r(theerrno, errBuf, errBufLen);
+# else
+ strerror_r(theerrno, errBuf, errBufLen);
+ return errBuf;
+# endif
+#else
+ /* Mingw lacks strerror_r() and its strerror() is definitely not
+ * threadsafe, so safest option is to just print the raw errno
+ * value - we can at least reliably & safely look it up in the
+ * header files for debug purposes
+ */
+ int n = snprintf(errBuf, errBufLen, "errno=%d", theerrno);
+ return (0 < n && n < errBufLen
+ ? errBuf : _("internal error: buffer too small"));
+#endif
+}
+
+/**
+ * virReportSystemErrorFull:
+ * @conn: the hyperisor connection
+ * @domcode: the virErrorDomain indicating where it's coming from
+ * @theerrno: an errno number
+ * @filename: filename where error was raised
+ * @funcname: function name where error was raised
+ * @linenr: line number where error was raised
+ * @fmt: the message to display/transmit
+ * @...: extra parameters for the message display
+ *
+ * Convenience internal routine called when a system error is detected.
+ */
+void virReportSystemErrorFull(virConnectPtr conn,
+ int domcode,
+ int theerrno,
+ const char *filename,
+ const char *funcname,
+ size_t linenr,
+ const char *fmt, ...)
+{
+ char strerror_buf[1024];
+ char msgDetailBuf[1024];
+
+ const char *errnoDetail = virStrerror(theerrno, strerror_buf,
+ sizeof(strerror_buf));
+ const char *msg = virErrorMsg(VIR_ERR_SYSTEM_ERROR, fmt);
+ const char *msgDetail = NULL;
+
+ if (fmt) {
+ va_list args;
+ int n;
+
+ va_start(args, fmt);
+ n = vsnprintf(msgDetailBuf, sizeof(msgDetailBuf), fmt, args);
+ va_end(args);
+
+ size_t len = strlen (msgDetailBuf);
+ if (0 <= n && n + 2 + len < sizeof (msgDetailBuf)) {
+ char *p = msgDetailBuf + n;
+ stpcpy (stpcpy (p, ": "), errnoDetail);
+ msgDetail = msgDetailBuf;
+ }
+ }
+
+ if (!msgDetail)
+ msgDetail = errnoDetail;
+
+ virRaiseErrorFull(conn, filename, funcname, linenr,
+ domcode, VIR_ERR_SYSTEM_ERROR, VIR_ERR_ERROR,
+ msg, msgDetail, NULL, -1, -1, msg, msgDetail);
+}
+
+/**
+ * virReportOOMErrorFull:
+ * @conn: the hyperisor connection
+ * @domcode: the virErrorDomain indicating where it's coming from
+ * @filename: filename where error was raised
+ * @funcname: function name where error was raised
+ * @linenr: line number where error was raised
+ *
+ * Convenience internal routine called when an out of memory error is
+ * detected
+ */
+void virReportOOMErrorFull(virConnectPtr conn,
+ int domcode,
+ const char *filename,
+ const char *funcname,
+ size_t linenr)
+{
+ const char *virerr;
+
+ virerr = virErrorMsg(VIR_ERR_NO_MEMORY, NULL);
+ virRaiseErrorFull(conn, filename, funcname, linenr,
+ domcode, VIR_ERR_NO_MEMORY, VIR_ERR_ERROR,
+ virerr, NULL, NULL, -1, -1, virerr, NULL);
+}
--- /dev/null
+/*
+ * virterror.h: internal error handling
+ *
+ * Copyright (C) 2006-2009 Red Hat, Inc.
+ *
+ * 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
+ *
+ */
+
+#ifndef __VIRT_ERROR_H_
+#define __VIRT_ERROR_H_
+
+#include "internal.h"
+
+extern virErrorFunc virErrorHandler;
+extern void *virUserData;
+
+/************************************************************************
+ * *
+ * API for error handling *
+ * *
+ ************************************************************************/
+int virErrorInitialize(void);
+void virRaiseErrorFull(virConnectPtr conn,
+ const char *filename,
+ const char *funcname,
+ size_t linenr,
+ int domain,
+ int code,
+ virErrorLevel level,
+ const char *str1,
+ const char *str2,
+ const char *str3,
+ int int1,
+ int int2,
+ const char *fmt, ...)
+ ATTRIBUTE_FMT_PRINTF(13, 14);
+
+/* Includes 'dom' and 'net' for compatbility, but they're ignored */
+#define virRaiseError(conn, dom, net, domain, code, level, \
+ str1, str2, str3, int1, int2, msg, ...) \
+ virRaiseErrorFull(conn, __FILE__, __FUNCTION__, __LINE__, \
+ domain, code, level, str1, str2, str3, int1, int2, \
+ msg, __VA_ARGS__)
+
+const char *virErrorMsg(virErrorNumber error, const char *info);
+void virReportErrorHelper(virConnectPtr conn, int domcode, int errcode,
+ const char *filename ATTRIBUTE_UNUSED,
+ const char *funcname ATTRIBUTE_UNUSED,
+ size_t linenr ATTRIBUTE_UNUSED,
+ const char *fmt, ...)
+ ATTRIBUTE_FMT_PRINTF(7, 8);
+
+void virReportSystemErrorFull(virConnectPtr conn,
+ int domcode,
+ int theerrno,
+ const char *filename,
+ const char *funcname,
+ size_t linenr,
+ const char *fmt, ...)
+ ATTRIBUTE_FMT_PRINTF(7, 8);
+
+#define virReportSystemError(conn, theerrno, fmt,...) \
+ virReportSystemErrorFull((conn), \
+ VIR_FROM_THIS, \
+ (theerrno), \
+ __FILE__, __FUNCTION__, __LINE__, \
+ (fmt), __VA_ARGS__)
+
+void virReportOOMErrorFull(virConnectPtr conn,
+ int domcode,
+ const char *filename,
+ const char *funcname,
+ size_t linenr);
+
+#define virReportOOMError(conn) \
+ virReportOOMErrorFull((conn), VIR_FROM_THIS, \
+ __FILE__, __FUNCTION__, __LINE__)
+
+
+void virSetGlobalError(void);
+void virSetConnError(virConnectPtr conn);
+const char *virStrerror(int theerrno, char *errBuf, size_t errBufLen);
+
+#endif
--- /dev/null
+/*
+ * xml.c: XML based interfaces for the libvir library
+ *
+ * Copyright (C) 2005, 2007-2009 Red Hat, Inc.
+ *
+ * See COPYING.LIB for the License of this software
+ *
+ * Daniel Veillard <veillard@redhat.com>
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <limits.h>
+#include <math.h> /* for isnan() */
+
+#include "virterror_internal.h"
+#include "xml.h"
+#include "buf.h"
+#include "util.h"
+#include "memory.h"
+
+#define VIR_FROM_THIS VIR_FROM_XML
+
+#define virXMLError(conn, code, fmt...) \
+ virReportErrorHelper(conn, VIR_FROM_XML, code, __FILE__, \
+ __FUNCTION__, __LINE__, fmt)
+
+
+/************************************************************************
+ * *
+ * Wrappers around libxml2 XPath specific functions *
+ * *
+ ************************************************************************/
+
+/**
+ * virXPathString:
+ * @xpath: the XPath string to evaluate
+ * @ctxt: an XPath context
+ *
+ * Convenience function to evaluate an XPath string
+ *
+ * Returns a new string which must be deallocated by the caller or NULL
+ * if the evaluation failed.
+ */
+char *
+virXPathString(virConnectPtr conn,
+ const char *xpath,
+ xmlXPathContextPtr ctxt)
+{
+ xmlXPathObjectPtr obj;
+ xmlNodePtr relnode;
+ char *ret;
+
+ if ((ctxt == NULL) || (xpath == NULL)) {
+ virXMLError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Invalid parameter to virXPathString()"));
+ return (NULL);
+ }
+ relnode = ctxt->node;
+ obj = xmlXPathEval(BAD_CAST xpath, ctxt);
+ if ((obj == NULL) || (obj->type != XPATH_STRING) ||
+ (obj->stringval == NULL) || (obj->stringval[0] == 0)) {
+ xmlXPathFreeObject(obj);
+ return (NULL);
+ }
+ ret = strdup((char *) obj->stringval);
+ xmlXPathFreeObject(obj);
+ if (ret == NULL) {
+ virReportOOMError(conn);
+ }
+ ctxt->node = relnode;
+ return (ret);
+}
+
+/**
+ * virXPathStringLimit:
+ * @xpath: the XPath string to evaluate
+ * @maxlen: maximum length permittred string
+ * @ctxt: an XPath context
+ *
+ * Wrapper for virXPathString, which validates the length of the returned
+ * string.
+ *
+ * Returns a new string which must be deallocated by the caller or NULL if
+ * the evaluation failed.
+ */
+char *
+virXPathStringLimit(virConnectPtr conn,
+ const char *xpath,
+ size_t maxlen,
+ xmlXPathContextPtr ctxt)
+{
+ char *tmp = virXPathString(conn, xpath, ctxt);
+
+ if (tmp != NULL && strlen(tmp) >= maxlen) {
+ virXMLError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("\'%s\' value longer than %Zd bytes in virXPathStringLimit()"),
+ xpath, maxlen);
+ return NULL;
+ }
+
+ return tmp;
+}
+
+/**
+ * virXPathNumber:
+ * @xpath: the XPath string to evaluate
+ * @ctxt: an XPath context
+ * @value: the returned double value
+ *
+ * Convenience function to evaluate an XPath number
+ *
+ * Returns 0 in case of success in which case @value is set,
+ * or -1 if the evaluation failed.
+ */
+int
+virXPathNumber(virConnectPtr conn,
+ const char *xpath,
+ xmlXPathContextPtr ctxt,
+ double *value)
+{
+ xmlXPathObjectPtr obj;
+ xmlNodePtr relnode;
+
+ if ((ctxt == NULL) || (xpath == NULL) || (value == NULL)) {
+ virXMLError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Invalid parameter to virXPathNumber()"));
+ return (-1);
+ }
+ relnode = ctxt->node;
+ obj = xmlXPathEval(BAD_CAST xpath, ctxt);
+ if ((obj == NULL) || (obj->type != XPATH_NUMBER) ||
+ (isnan(obj->floatval))) {
+ xmlXPathFreeObject(obj);
+ ctxt->node = relnode;
+ return (-1);
+ }
+
+ *value = obj->floatval;
+ xmlXPathFreeObject(obj);
+ ctxt->node = relnode;
+ return (0);
+}
+
+static int
+virXPathLongBase(virConnectPtr conn,
+ const char *xpath,
+ xmlXPathContextPtr ctxt,
+ int base,
+ long *value)
+{
+ xmlXPathObjectPtr obj;
+ xmlNodePtr relnode;
+ int ret = 0;
+
+ if ((ctxt == NULL) || (xpath == NULL) || (value == NULL)) {
+ virXMLError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Invalid parameter to virXPathLong()"));
+ return (-1);
+ }
+ relnode = ctxt->node;
+ obj = xmlXPathEval(BAD_CAST xpath, ctxt);
+ if ((obj != NULL) && (obj->type == XPATH_STRING) &&
+ (obj->stringval != NULL) && (obj->stringval[0] != 0)) {
+ char *conv = NULL;
+ long val;
+
+ val = strtol((const char *) obj->stringval, &conv, base);
+ if (conv == (const char *) obj->stringval) {
+ ret = -2;
+ } else {
+ *value = val;
+ }
+ } else if ((obj != NULL) && (obj->type == XPATH_NUMBER) &&
+ (!(isnan(obj->floatval)))) {
+ *value = (long) obj->floatval;
+ if (*value != obj->floatval) {
+ ret = -2;
+ }
+ } else {
+ ret = -1;
+ }
+
+ xmlXPathFreeObject(obj);
+ ctxt->node = relnode;
+ return (ret);
+}
+
+/**
+ * virXPathLong:
+ * @xpath: the XPath string to evaluate
+ * @ctxt: an XPath context
+ * @value: the returned long value
+ *
+ * Convenience function to evaluate an XPath number
+ *
+ * Returns 0 in case of success in which case @value is set,
+ * or -1 if the XPath evaluation failed or -2 if the
+ * value doesn't have a long format.
+ */
+int
+virXPathLong(virConnectPtr conn,
+ const char *xpath,
+ xmlXPathContextPtr ctxt,
+ long *value)
+{
+ return virXPathLongBase(conn, xpath, ctxt, 10, value);
+}
+
+/**
+ * virXPathLongHex:
+ * @xpath: the XPath string to evaluate
+ * @ctxt: an XPath context
+ * @value: the returned long value
+ *
+ * Convenience function to evaluate an XPath number
+ * according to a base of 16
+ *
+ * Returns 0 in case of success in which case @value is set,
+ * or -1 if the XPath evaluation failed or -2 if the
+ * value doesn't have a long format.
+ */
+int
+virXPathLongHex(virConnectPtr conn,
+ const char *xpath,
+ xmlXPathContextPtr ctxt,
+ long *value)
+{
+ return virXPathLongBase(conn, xpath, ctxt, 16, value);
+}
+
+static int
+virXPathULongBase(virConnectPtr conn,
+ const char *xpath,
+ xmlXPathContextPtr ctxt,
+ int base,
+ unsigned long *value)
+{
+ xmlXPathObjectPtr obj;
+ xmlNodePtr relnode;
+ int ret = 0;
+
+ if ((ctxt == NULL) || (xpath == NULL) || (value == NULL)) {
+ virXMLError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Invalid parameter to virXPathULong()"));
+ return (-1);
+ }
+ relnode = ctxt->node;
+ obj = xmlXPathEval(BAD_CAST xpath, ctxt);
+ if ((obj != NULL) && (obj->type == XPATH_STRING) &&
+ (obj->stringval != NULL) && (obj->stringval[0] != 0)) {
+ char *conv = NULL;
+ long val;
+
+ val = strtoul((const char *) obj->stringval, &conv, base);
+ if (conv == (const char *) obj->stringval) {
+ ret = -2;
+ } else {
+ *value = val;
+ }
+ } else if ((obj != NULL) && (obj->type == XPATH_NUMBER) &&
+ (!(isnan(obj->floatval)))) {
+ *value = (unsigned long) obj->floatval;
+ if (*value != obj->floatval) {
+ ret = -2;
+ }
+ } else {
+ ret = -1;
+ }
+
+ xmlXPathFreeObject(obj);
+ ctxt->node = relnode;
+ return (ret);
+}
+
+/**
+ * virXPathULong:
+ * @xpath: the XPath string to evaluate
+ * @ctxt: an XPath context
+ * @value: the returned long value
+ *
+ * Convenience function to evaluate an XPath number
+ *
+ * Returns 0 in case of success in which case @value is set,
+ * or -1 if the XPath evaluation failed or -2 if the
+ * value doesn't have a long format.
+ */
+int
+virXPathULong(virConnectPtr conn,
+ const char *xpath,
+ xmlXPathContextPtr ctxt,
+ unsigned long *value)
+{
+ return virXPathULongBase(conn, xpath, ctxt, 10, value);
+}
+
+/**
+ * virXPathUHex:
+ * @xpath: the XPath string to evaluate
+ * @ctxt: an XPath context
+ * @value: the returned long value
+ *
+ * Convenience function to evaluate an XPath number
+ * according to base of 16
+ *
+ * Returns 0 in case of success in which case @value is set,
+ * or -1 if the XPath evaluation failed or -2 if the
+ * value doesn't have a long format.
+ */
+int
+virXPathULongHex(virConnectPtr conn,
+ const char *xpath,
+ xmlXPathContextPtr ctxt,
+ unsigned long *value)
+{
+ return virXPathULongBase(conn, xpath, ctxt, 16, value);
+}
+
+/**
+ * virXPathULongLong:
+ * @xpath: the XPath string to evaluate
+ * @ctxt: an XPath context
+ * @value: the returned long long value
+ *
+ * Convenience function to evaluate an XPath number
+ *
+ * Returns 0 in case of success in which case @value is set,
+ * or -1 if the XPath evaluation failed or -2 if the
+ * value doesn't have a long format.
+ */
+int
+virXPathULongLong(virConnectPtr conn,
+ const char *xpath,
+ xmlXPathContextPtr ctxt,
+ unsigned long long *value)
+{
+ xmlXPathObjectPtr obj;
+ xmlNodePtr relnode;
+ int ret = 0;
+
+ if ((ctxt == NULL) || (xpath == NULL) || (value == NULL)) {
+ virXMLError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Invalid parameter to virXPathULong()"));
+ return (-1);
+ }
+ relnode = ctxt->node;
+ obj = xmlXPathEval(BAD_CAST xpath, ctxt);
+ if ((obj != NULL) && (obj->type == XPATH_STRING) &&
+ (obj->stringval != NULL) && (obj->stringval[0] != 0)) {
+ char *conv = NULL;
+ unsigned long long val;
+
+ val = strtoull((const char *) obj->stringval, &conv, 10);
+ if (conv == (const char *) obj->stringval) {
+ ret = -2;
+ } else {
+ *value = val;
+ }
+ } else if ((obj != NULL) && (obj->type == XPATH_NUMBER) &&
+ (!(isnan(obj->floatval)))) {
+ *value = (unsigned long long) obj->floatval;
+ if (*value != obj->floatval) {
+ ret = -2;
+ }
+ } else {
+ ret = -1;
+ }
+
+ xmlXPathFreeObject(obj);
+ ctxt->node = relnode;
+ return (ret);
+}
+
+char *
+virXMLPropString(xmlNodePtr node,
+ const char *name)
+{
+ return (char *)xmlGetProp(node, BAD_CAST name);
+}
+
+/**
+ * virXPathBoolean:
+ * @xpath: the XPath string to evaluate
+ * @ctxt: an XPath context
+ *
+ * Convenience function to evaluate an XPath boolean
+ *
+ * Returns 0 if false, 1 if true, or -1 if the evaluation failed.
+ */
+int
+virXPathBoolean(virConnectPtr conn,
+ const char *xpath,
+ xmlXPathContextPtr ctxt)
+{
+ xmlXPathObjectPtr obj;
+ xmlNodePtr relnode;
+ int ret;
+
+ if ((ctxt == NULL) || (xpath == NULL)) {
+ virXMLError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Invalid parameter to virXPathBoolean()"));
+ return (-1);
+ }
+ relnode = ctxt->node;
+ obj = xmlXPathEval(BAD_CAST xpath, ctxt);
+ if ((obj == NULL) || (obj->type != XPATH_BOOLEAN) ||
+ (obj->boolval < 0) || (obj->boolval > 1)) {
+ xmlXPathFreeObject(obj);
+ return (-1);
+ }
+ ret = obj->boolval;
+
+ xmlXPathFreeObject(obj);
+ ctxt->node = relnode;
+ return (ret);
+}
+
+/**
+ * virXPathNode:
+ * @xpath: the XPath string to evaluate
+ * @ctxt: an XPath context
+ *
+ * Convenience function to evaluate an XPath node set and returning
+ * only one node, the first one in the set if any
+ *
+ * Returns a pointer to the node or NULL if the evaluation failed.
+ */
+xmlNodePtr
+virXPathNode(virConnectPtr conn,
+ const char *xpath,
+ xmlXPathContextPtr ctxt)
+{
+ xmlXPathObjectPtr obj;
+ xmlNodePtr relnode;
+ xmlNodePtr ret;
+
+ if ((ctxt == NULL) || (xpath == NULL)) {
+ virXMLError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Invalid parameter to virXPathNode()"));
+ return (NULL);
+ }
+ relnode = ctxt->node;
+ obj = xmlXPathEval(BAD_CAST xpath, ctxt);
+ if ((obj == NULL) || (obj->type != XPATH_NODESET) ||
+ (obj->nodesetval == NULL) || (obj->nodesetval->nodeNr <= 0) ||
+ (obj->nodesetval->nodeTab == NULL)) {
+ xmlXPathFreeObject(obj);
+ ctxt->node = relnode;
+ return (NULL);
+ }
+
+ ret = obj->nodesetval->nodeTab[0];
+ xmlXPathFreeObject(obj);
+ ctxt->node = relnode;
+ return (ret);
+}
+
+/**
+ * virXPathNodeSet:
+ * @xpath: the XPath string to evaluate
+ * @ctxt: an XPath context
+ * @list: the returned list of nodes (or NULL if only count matters)
+ *
+ * Convenience function to evaluate an XPath node set
+ *
+ * Returns the number of nodes found in which case @list is set (and
+ * must be freed) or -1 if the evaluation failed.
+ */
+int
+virXPathNodeSet(virConnectPtr conn,
+ const char *xpath,
+ xmlXPathContextPtr ctxt,
+ xmlNodePtr **list)
+{
+ xmlXPathObjectPtr obj;
+ xmlNodePtr relnode;
+ int ret;
+
+ if ((ctxt == NULL) || (xpath == NULL)) {
+ virXMLError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Invalid parameter to virXPathNodeSet()"));
+ return (-1);
+ }
+
+ if (list != NULL)
+ *list = NULL;
+
+ relnode = ctxt->node;
+ obj = xmlXPathEval(BAD_CAST xpath, ctxt);
+ if ((obj == NULL) || (obj->type != XPATH_NODESET) ||
+ (obj->nodesetval == NULL) || (obj->nodesetval->nodeNr < 0)) {
+ xmlXPathFreeObject(obj);
+ ctxt->node = relnode;
+ return (-1);
+ }
+
+ ret = obj->nodesetval->nodeNr;
+ if (list != NULL && ret) {
+ if (VIR_ALLOC_N(*list, ret) < 0) {
+ virReportOOMError(conn);
+ ret = -1;
+ } else {
+ memcpy(*list, obj->nodesetval->nodeTab,
+ ret * sizeof(xmlNodePtr));
+ }
+ }
+ xmlXPathFreeObject(obj);
+ ctxt->node = relnode;
+ return (ret);
+}
--- /dev/null
+/*
+ * xml.h: internal definitions used for XML parsing routines.
+ */
+
+#ifndef __VIR_XML_H__
+#define __VIR_XML_H__
+
+#include "internal.h"
+
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/xpath.h>
+
+int virXPathBoolean (virConnectPtr conn,
+ const char *xpath,
+ xmlXPathContextPtr ctxt);
+char * virXPathString (virConnectPtr conn,
+ const char *xpath,
+ xmlXPathContextPtr ctxt);
+char * virXPathStringLimit(virConnectPtr conn,
+ const char *xpath,
+ size_t maxlen,
+ xmlXPathContextPtr ctxt);
+int virXPathNumber (virConnectPtr conn,
+ const char *xpath,
+ xmlXPathContextPtr ctxt,
+ double *value);
+int virXPathLong (virConnectPtr conn,
+ const char *xpath,
+ xmlXPathContextPtr ctxt,
+ long *value);
+int virXPathULong (virConnectPtr conn,
+ const char *xpath,
+ xmlXPathContextPtr ctxt,
+ unsigned long *value);
+int virXPathULongLong(virConnectPtr conn,
+ const char *xpath,
+ xmlXPathContextPtr ctxt,
+ unsigned long long *value);
+int virXPathLongHex (virConnectPtr conn,
+ const char *xpath,
+ xmlXPathContextPtr ctxt,
+ long *value);
+int virXPathULongHex(virConnectPtr conn,
+ const char *xpath,
+ xmlXPathContextPtr ctxt,
+ unsigned long *value);
+xmlNodePtr virXPathNode (virConnectPtr conn,
+ const char *xpath,
+ xmlXPathContextPtr ctxt);
+int virXPathNodeSet (virConnectPtr conn,
+ const char *xpath,
+ xmlXPathContextPtr ctxt,
+ xmlNodePtr **list);
+
+char * virXMLPropString(xmlNodePtr node,
+ const char *name);
+
+#endif /* __VIR_XML_H__ */
+++ /dev/null
-/*
- * Copyright (C) 2007, 2008, 2009 Red Hat, Inc.
- *
- * 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
- *
- * Authors:
- * Mark McLoughlin <markmc@redhat.com>
- */
-
-#include <config.h>
-
-#include "uuid.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <time.h>
-#include <unistd.h>
-
-#include "c-ctype.h"
-#include "internal.h"
-#include "util.h"
-#include "virterror_internal.h"
-#include "logging.h"
-
-#ifndef ENODATA
-#define ENODATA EIO
-#endif
-
-static int
-virUUIDGenerateRandomBytes(unsigned char *buf,
- int buflen)
-{
- int fd;
-
- if ((fd = open("/dev/urandom", O_RDONLY)) < 0)
- return errno;
-
- while (buflen > 0) {
- int n;
-
- if ((n = read(fd, buf, buflen)) <= 0) {
- if (errno == EINTR)
- continue;
- close(fd);
- return n < 0 ? errno : ENODATA;
- }
-
- buf += n;
- buflen -= n;
- }
-
- close(fd);
-
- return 0;
-}
-
-static int
-virUUIDGeneratePseudoRandomBytes(unsigned char *buf,
- int buflen)
-{
- while (buflen > 0) {
- *buf = virRandom(256);
- buflen--;
- }
-
- return 0;
-}
-
-/**
- * virUUIDGenerate:
- * @uuid: array of VIR_UUID_BUFLEN bytes to store the new UUID
- *
- * Generates a randomized unique identifier.
- *
- * Returns 0 in case of success and -1 in case of failure
- */
-int
-virUUIDGenerate(unsigned char *uuid)
-{
- int err;
-
- if (uuid == NULL)
- return(-1);
-
- if ((err = virUUIDGenerateRandomBytes(uuid, VIR_UUID_BUFLEN))) {
- char ebuf[1024];
- VIR_WARN(_("Falling back to pseudorandom UUID,"
- " failed to generate random bytes: %s"),
- virStrerror(err, ebuf, sizeof ebuf));
- }
-
- return virUUIDGeneratePseudoRandomBytes(uuid, VIR_UUID_BUFLEN);
-}
-
-/* Convert C from hexadecimal character to integer. */
-static int
-hextobin (unsigned char c)
-{
- switch (c)
- {
- default: return c - '0';
- case 'a': case 'A': return 10;
- case 'b': case 'B': return 11;
- case 'c': case 'C': return 12;
- case 'd': case 'D': return 13;
- case 'e': case 'E': return 14;
- case 'f': case 'F': return 15;
- }
-}
-
-/**
- * virUUIDParse:
- * @uuidstr: zero terminated string representation of the UUID
- * @uuid: array of VIR_UUID_BUFLEN bytes to store the raw UUID
- *
- * Parses the external string representation, allowing spaces and '-'
- * character in the sequence, and storing the result as a raw UUID
- *
- * Returns 0 in case of success and -1 in case of error.
- */
-int
-virUUIDParse(const char *uuidstr, unsigned char *uuid) {
- const char *cur;
- int i;
-
- if ((uuidstr == NULL) || (uuid == NULL))
- return(-1);
-
- /*
- * do a liberal scan allowing '-' and ' ' anywhere between character
- * pairs as long as there is 32 of them in the end.
- */
- cur = uuidstr;
- for (i = 0;i < VIR_UUID_BUFLEN;) {
- uuid[i] = 0;
- if (*cur == 0)
- goto error;
- if ((*cur == '-') || (*cur == ' ')) {
- cur++;
- continue;
- }
- if (!c_isxdigit(*cur))
- goto error;
- uuid[i] = hextobin(*cur);
- uuid[i] *= 16;
- cur++;
- if (*cur == 0)
- goto error;
- if (!c_isxdigit(*cur))
- goto error;
- uuid[i] += hextobin(*cur);
- i++;
- cur++;
- }
-
- return 0;
-
- error:
- return -1;
-}
-
-/**
- * virUUIDFormat:
- * @uuid: array of VIR_UUID_RAW_LEN bytes to store the raw UUID
- * @uuidstr: array of VIR_UUID_STRING_BUFLEN bytes to store the
- * string representation of the UUID in. The resulting string
- * will be NULL terminated.
- *
- * Converts the raw UUID into printable format, with embedded '-'
- *
- * Returns 0 in case of success and -1 in case of error.
- */
-void virUUIDFormat(const unsigned char *uuid, char *uuidstr)
-{
- snprintf(uuidstr, VIR_UUID_STRING_BUFLEN,
- "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
- uuid[0], uuid[1], uuid[2], uuid[3],
- uuid[4], uuid[5], uuid[6], uuid[7],
- uuid[8], uuid[9], uuid[10], uuid[11],
- uuid[12], uuid[13], uuid[14], uuid[15]);
- uuidstr[VIR_UUID_STRING_BUFLEN-1] = '\0';
-}
+++ /dev/null
-/*
- * Copyright (C) 2007 Red Hat, Inc.
- *
- * 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
- *
- * Authors:
- * Mark McLoughlin <markmc@redhat.com>
- */
-
-#ifndef __VIR_UUID_H__
-#define __VIR_UUID_H__
-
-int virUUIDGenerate(unsigned char *uuid);
-
-int virUUIDParse(const char *uuidstr,
- unsigned char *uuid);
-
-void virUUIDFormat(const unsigned char *uuid,
- char *uuidstr);
-
-#endif /* __VIR_UUID_H__ */
+++ /dev/null
-/*
- * virterror.c: implements error handling and reporting code for libvirt
- *
- * Copy: Copyright (C) 2006, 2008, 2009 Red Hat, Inc.
- *
- * See COPYING.LIB for the License of this software
- *
- * Author: Daniel Veillard <veillard@redhat.com>
- */
-
-#include <config.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdarg.h>
-
-#include "virterror_internal.h"
-#include "datatypes.h"
-#include "logging.h"
-#include "memory.h"
-#include "threads.h"
-#include "util.h"
-
-virThreadLocal virLastErr;
-
-virErrorFunc virErrorHandler = NULL; /* global error handler */
-void *virUserData = NULL; /* associated data */
-
-/*
- * Macro used to format the message as a string in virRaiseError
- * and borrowed from libxml2.
- */
-#define VIR_GET_VAR_STR(msg, str) { \
- int size, prev_size = -1; \
- int chars; \
- char *larger; \
- va_list ap; \
- \
- str = (char *) malloc(150); \
- if (str != NULL) { \
- \
- size = 150; \
- \
- while (1) { \
- va_start(ap, msg); \
- chars = vsnprintf(str, size, msg, ap); \
- va_end(ap); \
- if ((chars > -1) && (chars < size)) { \
- if (prev_size == chars) { \
- break; \
- } else { \
- prev_size = chars; \
- } \
- } \
- if (chars > -1) \
- size += chars + 1; \
- else \
- size += 100; \
- if ((larger = (char *) realloc(str, size)) == NULL) { \
- break; \
- } \
- str = larger; \
- }} \
-}
-
-static virLogPriority virErrorLevelPriority(virErrorLevel level) {
- switch (level) {
- case VIR_ERR_NONE:
- return(VIR_LOG_INFO);
- case VIR_ERR_WARNING:
- return(VIR_LOG_WARN);
- case VIR_ERR_ERROR:
- return(VIR_LOG_ERROR);
- }
- return(VIR_LOG_ERROR);
-}
-
-static const char *virErrorDomainName(virErrorDomain domain) {
- const char *dom = "unknown";
- switch (domain) {
- case VIR_FROM_NONE:
- dom = "";
- break;
- case VIR_FROM_XEN:
- dom = "Xen ";
- break;
- case VIR_FROM_XML:
- dom = "XML ";
- break;
- case VIR_FROM_XEND:
- dom = "Xen Daemon ";
- break;
- case VIR_FROM_XENSTORE:
- dom = "Xen Store ";
- break;
- case VIR_FROM_XEN_INOTIFY:
- dom = "Xen Inotify ";
- break;
- case VIR_FROM_DOM:
- dom = "Domain ";
- break;
- case VIR_FROM_RPC:
- dom = "XML-RPC ";
- break;
- case VIR_FROM_QEMU:
- dom = "QEMU ";
- break;
- case VIR_FROM_NET:
- dom = "Network ";
- break;
- case VIR_FROM_TEST:
- dom = "Test ";
- break;
- case VIR_FROM_REMOTE:
- dom = "Remote ";
- break;
- case VIR_FROM_SEXPR:
- dom = "S-Expr ";
- break;
- case VIR_FROM_PROXY:
- dom = "PROXY ";
- break;
- case VIR_FROM_CONF:
- dom = "Config ";
- break;
- case VIR_FROM_PHYP:
- dom = "IBM power hypervisor ";
- break;
- case VIR_FROM_OPENVZ:
- dom = "OpenVZ ";
- break;
- case VIR_FROM_XENXM:
- dom = "Xen XM ";
- break;
- case VIR_FROM_STATS_LINUX:
- dom = "Linux Stats ";
- break;
- case VIR_FROM_LXC:
- dom = "Linux Container ";
- break;
- case VIR_FROM_STORAGE:
- dom = "Storage ";
- break;
- case VIR_FROM_NETWORK:
- dom = "Network Config ";
- break;
- case VIR_FROM_DOMAIN:
- dom = "Domain Config ";
- break;
- case VIR_FROM_NODEDEV:
- dom = "Node Device ";
- break;
- case VIR_FROM_UML:
- dom = "UML ";
- break;
- case VIR_FROM_SECURITY:
- dom = "Security Labeling ";
- break;
- case VIR_FROM_VBOX:
- dom = "VBOX ";
- break;
- case VIR_FROM_INTERFACE:
- dom = "Interface ";
- break;
- case VIR_FROM_ONE:
- dom = "ONE ";
- break;
- case VIR_FROM_ESX:
- dom = "ESX ";
- break;
- case VIR_FROM_SECRET:
- dom = "Secret Storage ";
- break;
- }
- return(dom);
-}
-
-
-/*
- * Internal helper that is called when a thread exits, to
- * release the error object stored in the thread local
- */
-static void
-virLastErrFreeData(void *data)
-{
- virErrorPtr err = data;
- if (!err)
- return;
- virResetError(err);
- VIR_FREE(err);
-}
-
-
-/**
- * virErrorInitialize:
- *
- * Initialize the error data (per thread)
- *
- * Returns 0 in case of success, -1 in case of failure.
- */
-int
-virErrorInitialize(void)
-{
- return virThreadLocalInit(&virLastErr, virLastErrFreeData);
-}
-
-
-/*
- * Internal helper to ensure a generic error code is stored
- * in case where API returns failure, but forgot to set an
- * error
- */
-static void
-virErrorGenericFailure(virErrorPtr err)
-{
- err->code = VIR_ERR_INTERNAL_ERROR;
- err->domain = VIR_FROM_NONE;
- err->level = VIR_ERR_ERROR;
- err->message = strdup(_("Unknown failure"));
-}
-
-
-/*
- * Internal helper to perform a deep copy of the an error
- */
-static int
-virCopyError(virErrorPtr from,
- virErrorPtr to)
-{
- int ret = 0;
- if (!to)
- return 0;
- virResetError(to);
- if (!from)
- return 0;
- to->code = from->code;
- to->domain = from->domain;
- to->level = from->level;
- if (from->message && !(to->message = strdup(from->message)))
- ret = -1;
- if (from->str1 && !(to->str1 = strdup(from->str1)))
- ret = -1;
- if (from->str2 && !(to->str2 = strdup(from->str2)))
- ret = -1;
- if (from->str3 && !(to->str3 = strdup(from->str3)))
- ret = -1;
- to->int1 = from->int1;
- to->int2 = from->int2;
- /*
- * Delibrately not setting 'conn', 'dom', 'net' references
- */
- return ret;
-}
-
-static virErrorPtr
-virLastErrorObject(void)
-{
- virErrorPtr err;
- err = virThreadLocalGet(&virLastErr);
- if (!err) {
- if (VIR_ALLOC(err) < 0)
- return NULL;
- virThreadLocalSet(&virLastErr, err);
- }
- return err;
-}
-
-
-/**
- * virGetLastError:
- *
- * Provide a pointer to the last error caught at the library level
- *
- * The error object is kept in thread local storage, so separate
- * threads can safely access this concurrently.
- *
- * Returns a pointer to the last error or NULL if none occurred.
- */
-virErrorPtr
-virGetLastError(void)
-{
- virErrorPtr err = virLastErrorObject();
- if (!err || err->code == VIR_ERR_OK)
- return NULL;
- return err;
-}
-
-/**
- * virCopyLastError:
- * @to: target to receive the copy
- *
- * Copy the content of the last error caught at the library level
- *
- * The error object is kept in thread local storage, so separate
- * threads can safely access this concurrently.
- *
- * One will need to free the result with virResetError()
- *
- * Returns 0 if no error was found and the error code otherwise and -1 in case
- * of parameter error.
- */
-int
-virCopyLastError(virErrorPtr to)
-{
- virErrorPtr err = virLastErrorObject();
- /* We can't guarentee caller has initialized it to zero */
- memset(to, 0, sizeof(*to));
- if (err)
- virCopyError(err, to);
- else
- virResetError(to);
- return to->code;
-}
-
-/**
- * virSaveLastError:
- *
- * Save the last error into a new error object.
- *
- * Returns a pointer to the copied error or NULL if allocation failed.
- * It is the caller's responsibility to free the error with
- * virFreeError().
- */
-virErrorPtr
-virSaveLastError(void)
-{
- virErrorPtr to;
-
- if (VIR_ALLOC(to) < 0)
- return NULL;
-
- virCopyLastError(to);
- return to;
-}
-
-/**
- * virResetError:
- * @err: pointer to the virError to clean up
- *
- * Reset the error being pointed to
- */
-void
-virResetError(virErrorPtr err)
-{
- if (err == NULL)
- return;
- free(err->message);
- free(err->str1);
- free(err->str2);
- free(err->str3);
- memset(err, 0, sizeof(virError));
-}
-
-/**
- * virFreeError:
- * @err: error to free
- *
- * Resets and frees the given error.
- */
-void
-virFreeError(virErrorPtr err)
-{
- virResetError(err);
- VIR_FREE(err);
-}
-
-/**
- * virResetLastError:
- *
- * Reset the last error caught at the library level.
- *
- * The error object is kept in thread local storage, so separate
- * threads can safely access this concurrently, only resetting
- * their own error object.
- */
-void
-virResetLastError(void)
-{
- virErrorPtr err = virLastErrorObject();
- if (err)
- virResetError(err);
-}
-
-/**
- * virConnGetLastError:
- * @conn: pointer to the hypervisor connection
- *
- * Provide a pointer to the last error caught on that connection
- *
- * This method is not protected against access from multiple
- * threads. In a multi-threaded application, always use the
- * global virGetLastError() API which is backed by thread
- * local storage.
- *
- * If the connection object was discovered to be invalid by
- * an API call, then the error will be reported against the
- * global error object.
- *
- * Since 0.6.0, all errors reported in the per-connection object
- * are also duplicated in the global error object. As such an
- * application can always use virGetLastError(). This method
- * remains for backwards compatability.
- *
- * Returns a pointer to the last error or NULL if none occurred.
- */
-virErrorPtr
-virConnGetLastError(virConnectPtr conn)
-{
- if (conn == NULL)
- return NULL;
- return &conn->err;
-}
-
-/**
- * virConnCopyLastError:
- * @conn: pointer to the hypervisor connection
- * @to: target to receive the copy
- *
- * Copy the content of the last error caught on that connection
- *
- * This method is not protected against access from multiple
- * threads. In a multi-threaded application, always use the
- * global virGetLastError() API which is backed by thread
- * local storage.
- *
- * If the connection object was discovered to be invalid by
- * an API call, then the error will be reported against the
- * global error object.
- *
- * Since 0.6.0, all errors reported in the per-connection object
- * are also duplicated in the global error object. As such an
- * application can always use virGetLastError(). This method
- * remains for backwards compatability.
- *
- * One will need to free the result with virResetError()
- *
- * Returns 0 if no error was found and the error code otherwise and -1 in case
- * of parameter error.
- */
-int
-virConnCopyLastError(virConnectPtr conn, virErrorPtr to)
-{
- /* We can't guarentee caller has initialized it to zero */
- memset(to, 0, sizeof(*to));
-
- if (conn == NULL)
- return -1;
- virMutexLock(&conn->lock);
- if (conn->err.code == VIR_ERR_OK)
- virResetError(to);
- else
- virCopyError(&conn->err, to);
- virMutexUnlock(&conn->lock);
- return to->code;
-}
-
-/**
- * virConnResetLastError:
- * @conn: pointer to the hypervisor connection
- *
- * The error object is kept in thread local storage, so separate
- * threads can safely access this concurrently.
- *
- * Reset the last error caught on that connection
- */
-void
-virConnResetLastError(virConnectPtr conn)
-{
- if (conn == NULL)
- return;
- virMutexLock(&conn->lock);
- virResetError(&conn->err);
- virMutexUnlock(&conn->lock);
-}
-
-/**
- * virSetErrorFunc:
- * @userData: pointer to the user data provided in the handler callback
- * @handler: the function to get called in case of error or NULL
- *
- * Set a library global error handling function, if @handler is NULL,
- * it will reset to default printing on stderr. The error raised there
- * are those for which no handler at the connection level could caught.
- */
-void
-virSetErrorFunc(void *userData, virErrorFunc handler)
-{
- virErrorHandler = handler;
- virUserData = userData;
-}
-
-/**
- * virConnSetErrorFunc:
- * @conn: pointer to the hypervisor connection
- * @userData: pointer to the user data provided in the handler callback
- * @handler: the function to get called in case of error or NULL
- *
- * Set a connection error handling function, if @handler is NULL
- * it will reset to default which is to pass error back to the global
- * library handler.
- */
-void
-virConnSetErrorFunc(virConnectPtr conn, void *userData,
- virErrorFunc handler)
-{
- if (conn == NULL)
- return;
- virMutexLock(&conn->lock);
- conn->handler = handler;
- conn->userData = userData;
- virMutexUnlock(&conn->lock);
-}
-
-/**
- * virDefaultErrorFunc:
- * @err: pointer to the error.
- *
- * Default routine reporting an error to stderr.
- */
-void
-virDefaultErrorFunc(virErrorPtr err)
-{
- const char *lvl = "", *dom = "", *domain = "", *network = "";
- int len;
-
- if ((err == NULL) || (err->code == VIR_ERR_OK))
- return;
- switch (err->level) {
- case VIR_ERR_NONE:
- lvl = "";
- break;
- case VIR_ERR_WARNING:
- lvl = _("warning");
- break;
- case VIR_ERR_ERROR:
- lvl = _("error");
- break;
- }
- dom = virErrorDomainName(err->domain);
- if ((err->dom != NULL) && (err->code != VIR_ERR_INVALID_DOMAIN)) {
- domain = err->dom->name;
- } else if ((err->net != NULL) && (err->code != VIR_ERR_INVALID_NETWORK)) {
- network = err->net->name;
- }
- len = strlen(err->message);
- if ((err->domain == VIR_FROM_XML) && (err->code == VIR_ERR_XML_DETAIL) &&
- (err->int1 != 0))
- fprintf(stderr, "libvir: %s%s %s%s: line %d: %s",
- dom, lvl, domain, network, err->int1, err->message);
- else if ((len == 0) || (err->message[len - 1] != '\n'))
- fprintf(stderr, "libvir: %s%s %s%s: %s\n",
- dom, lvl, domain, network, err->message);
- else
- fprintf(stderr, "libvir: %s%s %s%s: %s",
- dom, lvl, domain, network, err->message);
-}
-
-/**
- * virSetGlobalError:
- * Internal helper to ensure the global error object
- * is initialized with a generic message if not already
- * set.
- */
-void
-virSetGlobalError(void)
-{
- virErrorPtr err = virLastErrorObject();
-
- if (err && err->code == VIR_ERR_OK)
- virErrorGenericFailure(err);
-}
-
-/**
- * virSetConnError:
- * @conn: pointer to the hypervisor connection
- *
- * Internal helper to ensure the connection error object
- * is initialized from the global object.
- */
-void
-virSetConnError(virConnectPtr conn)
-{
- virErrorPtr err = virLastErrorObject();
-
- if (err && err->code == VIR_ERR_OK)
- virErrorGenericFailure(err);
-
- if (conn) {
- virMutexLock(&conn->lock);
- if (err)
- virCopyError(err, &conn->err);
- else
- virErrorGenericFailure(&conn->err);
- virMutexUnlock(&conn->lock);
- }
-}
-
-
-
-/**
- * virRaiseErrorFull:
- * @conn: the connection to the hypervisor if available
- * @filename: filename where error was raised
- * @funcname: function name where error was raised
- * @linenr: line number where error was raised
- * @domain: the virErrorDomain indicating where it's coming from
- * @code: the virErrorNumber code for the error
- * @level: the virErrorLevel for the error
- * @str1: extra string info
- * @str2: extra string info
- * @str3: extra string info
- * @int1: extra int info
- * @int2: extra int info
- * @fmt: the message to display/transmit
- * @...: extra parameters for the message display
- *
- * Internal routine called when an error is detected. It will raise it
- * immediately if a callback is found and store it for later handling.
- */
-void
-virRaiseErrorFull(virConnectPtr conn,
- const char *filename ATTRIBUTE_UNUSED,
- const char *funcname,
- size_t linenr,
- int domain,
- int code,
- virErrorLevel level,
- const char *str1,
- const char *str2,
- const char *str3,
- int int1,
- int int2,
- const char *fmt, ...)
-{
- virErrorPtr to;
- void *userData = virUserData;
- virErrorFunc handler = virErrorHandler;
- char *str;
-
- /*
- * All errors are recorded in thread local storage
- * For compatability, public API calls will copy them
- * to the per-connection error object when neccessary
- */
- to = virLastErrorObject();
- if (!to)
- return; /* Hit OOM allocating thread error object, sod all we can do now */
-
- virResetError(to);
-
- if (code == VIR_ERR_OK)
- return;
-
- /*
- * try to find the best place to save and report the error
- */
- if (conn != NULL) {
- virMutexLock(&conn->lock);
- if (conn->handler != NULL) {
- handler = conn->handler;
- userData = conn->userData;
- }
- virMutexUnlock(&conn->lock);
- }
-
- /*
- * formats the message
- */
- if (fmt == NULL) {
- str = strdup(_("No error message provided"));
- } else {
- VIR_GET_VAR_STR(fmt, str);
- }
-
- /*
- * Hook up the error or warning to the logging facility
- * XXXX should we include filename as 'category' instead of domain name ?
- */
- virLogMessage(virErrorDomainName(domain), virErrorLevelPriority(level),
- funcname, linenr, 1, "%s", str);
-
- /*
- * Save the information about the error
- */
- virResetError(to);
- /*
- * Delibrately not setting conn, dom & net fields since
- * they're utterly unsafe
- */
- to->domain = domain;
- to->code = code;
- to->message = str;
- to->level = level;
- if (str1 != NULL)
- to->str1 = strdup(str1);
- if (str2 != NULL)
- to->str2 = strdup(str2);
- if (str3 != NULL)
- to->str3 = strdup(str3);
- to->int1 = int1;
- to->int2 = int2;
-
- /*
- * now, report it
- */
- if (handler != NULL) {
- handler(userData, to);
- } else {
- virDefaultErrorFunc(to);
- }
-}
-
-/**
- * virErrorMsg:
- * @error: the virErrorNumber
- * @info: usually the first parameter string
- *
- * Internal routine to get the message associated to an error raised
- * from the library
- *
- * Returns the constant string associated to @error
- */
-const char *
-virErrorMsg(virErrorNumber error, const char *info)
-{
- const char *errmsg = NULL;
-
- switch (error) {
- case VIR_ERR_OK:
- return (NULL);
- case VIR_ERR_INTERNAL_ERROR:
- if (info != NULL)
- errmsg = _("internal error %s");
- else
- errmsg = _("internal error");
- break;
- case VIR_ERR_NO_MEMORY:
- errmsg = _("out of memory");
- break;
- case VIR_ERR_NO_SUPPORT:
- if (info == NULL)
- errmsg = _("this function is not supported by the hypervisor");
- else
- errmsg = _("this function is not supported by the hypervisor: %s");
- break;
- case VIR_ERR_NO_CONNECT:
- if (info == NULL)
- errmsg = _("no hypervisor driver available");
- else
- errmsg = _("no hypervisor driver available for %s");
- break;
- case VIR_ERR_INVALID_CONN:
- if (info == NULL)
- errmsg = _("invalid connection pointer in");
- else
- errmsg = _("invalid connection pointer in %s");
- break;
- case VIR_ERR_INVALID_DOMAIN:
- if (info == NULL)
- errmsg = _("invalid domain pointer in");
- else
- errmsg = _("invalid domain pointer in %s");
- break;
- case VIR_ERR_INVALID_ARG:
- if (info == NULL)
- errmsg = _("invalid argument in");
- else
- errmsg = _("invalid argument in %s");
- break;
- case VIR_ERR_OPERATION_FAILED:
- if (info != NULL)
- errmsg = _("operation failed: %s");
- else
- errmsg = _("operation failed");
- break;
- case VIR_ERR_GET_FAILED:
- if (info != NULL)
- errmsg = _("GET operation failed: %s");
- else
- errmsg = _("GET operation failed");
- break;
- case VIR_ERR_POST_FAILED:
- if (info != NULL)
- errmsg = _("POST operation failed: %s");
- else
- errmsg = _("POST operation failed");
- break;
- case VIR_ERR_HTTP_ERROR:
- errmsg = _("got unknown HTTP error code %d");
- break;
- case VIR_ERR_UNKNOWN_HOST:
- if (info != NULL)
- errmsg = _("unknown host %s");
- else
- errmsg = _("unknown host");
- break;
- case VIR_ERR_SEXPR_SERIAL:
- if (info != NULL)
- errmsg = _("failed to serialize S-Expr: %s");
- else
- errmsg = _("failed to serialize S-Expr");
- break;
- case VIR_ERR_NO_XEN:
- if (info == NULL)
- errmsg = _("could not use Xen hypervisor entry");
- else
- errmsg = _("could not use Xen hypervisor entry %s");
- break;
- case VIR_ERR_NO_XENSTORE:
- if (info == NULL)
- errmsg = _("could not connect to Xen Store");
- else
- errmsg = _("could not connect to Xen Store %s");
- break;
- case VIR_ERR_XEN_CALL:
- errmsg = _("failed Xen syscall %s");
- break;
- case VIR_ERR_OS_TYPE:
- if (info == NULL)
- errmsg = _("unknown OS type");
- else
- errmsg = _("unknown OS type %s");
- break;
- case VIR_ERR_NO_KERNEL:
- errmsg = _("missing kernel information");
- break;
- case VIR_ERR_NO_ROOT:
- if (info == NULL)
- errmsg = _("missing root device information");
- else
- errmsg = _("missing root device information in %s");
- break;
- case VIR_ERR_NO_SOURCE:
- if (info == NULL)
- errmsg = _("missing source information for device");
- else
- errmsg = _("missing source information for device %s");
- break;
- case VIR_ERR_NO_TARGET:
- if (info == NULL)
- errmsg = _("missing target information for device");
- else
- errmsg = _("missing target information for device %s");
- break;
- case VIR_ERR_NO_NAME:
- if (info == NULL)
- errmsg = _("missing domain name information");
- else
- errmsg = _("missing domain name information in %s");
- break;
- case VIR_ERR_NO_OS:
- if (info == NULL)
- errmsg = _("missing operating system information");
- else
- errmsg = _("missing operating system information for %s");
- break;
- case VIR_ERR_NO_DEVICE:
- if (info == NULL)
- errmsg = _("missing devices information");
- else
- errmsg = _("missing devices information for %s");
- break;
- case VIR_ERR_DRIVER_FULL:
- if (info == NULL)
- errmsg = _("too many drivers registered");
- else
- errmsg = _("too many drivers registered in %s");
- break;
- case VIR_ERR_CALL_FAILED: /* DEPRECATED, use VIR_ERR_NO_SUPPORT */
- if (info == NULL)
- errmsg = _("library call failed, possibly not supported");
- else
- errmsg = _("library call %s failed, possibly not supported");
- break;
- case VIR_ERR_XML_ERROR:
- if (info == NULL)
- errmsg = _("XML description not well formed or invalid");
- else
- errmsg = _("XML description for %s is not well formed or invalid");
- break;
- case VIR_ERR_DOM_EXIST:
- if (info == NULL)
- errmsg = _("this domain exists already");
- else
- errmsg = _("domain %s exists already");
- break;
- case VIR_ERR_OPERATION_DENIED:
- if (info == NULL)
- errmsg = _("operation forbidden for read only access");
- else
- errmsg = _("operation %s forbidden for read only access");
- break;
- case VIR_ERR_OPEN_FAILED:
- if (info == NULL)
- errmsg = _("failed to open configuration file for reading");
- else
- errmsg = _("failed to open %s for reading");
- break;
- case VIR_ERR_READ_FAILED:
- if (info == NULL)
- errmsg = _("failed to read configuration file");
- else
- errmsg = _("failed to read configuration file %s");
- break;
- case VIR_ERR_PARSE_FAILED:
- if (info == NULL)
- errmsg = _("failed to parse configuration file");
- else
- errmsg = _("failed to parse configuration file %s");
- break;
- case VIR_ERR_CONF_SYNTAX:
- if (info == NULL)
- errmsg = _("configuration file syntax error");
- else
- errmsg = _("configuration file syntax error: %s");
- break;
- case VIR_ERR_WRITE_FAILED:
- if (info == NULL)
- errmsg = _("failed to write configuration file");
- else
- errmsg = _("failed to write configuration file: %s");
- break;
- case VIR_ERR_XML_DETAIL:
- if (info == NULL)
- errmsg = _("parser error");
- else
- errmsg = "%s";
- break;
- case VIR_ERR_INVALID_NETWORK:
- if (info == NULL)
- errmsg = _("invalid network pointer in");
- else
- errmsg = _("invalid network pointer in %s");
- break;
- case VIR_ERR_NETWORK_EXIST:
- if (info == NULL)
- errmsg = _("this network exists already");
- else
- errmsg = _("network %s exists already");
- break;
- case VIR_ERR_SYSTEM_ERROR:
- if (info == NULL)
- errmsg = _("system call error");
- else
- errmsg = "%s";
- break;
- case VIR_ERR_RPC:
- if (info == NULL)
- errmsg = _("RPC error");
- else
- errmsg = "%s";
- break;
- case VIR_ERR_GNUTLS_ERROR:
- if (info == NULL)
- errmsg = _("GNUTLS call error");
- else
- errmsg = "%s";
- break;
- case VIR_WAR_NO_NETWORK:
- if (info == NULL)
- errmsg = _("Failed to find the network");
- else
- errmsg = _("Failed to find the network: %s");
- break;
- case VIR_ERR_NO_DOMAIN:
- if (info == NULL)
- errmsg = _("Domain not found");
- else
- errmsg = _("Domain not found: %s");
- break;
- case VIR_ERR_NO_NETWORK:
- if (info == NULL)
- errmsg = _("Network not found");
- else
- errmsg = _("Network not found: %s");
- break;
- case VIR_ERR_INVALID_MAC:
- if (info == NULL)
- errmsg = _("invalid MAC address");
- else
- errmsg = _("invalid MAC address: %s");
- break;
- case VIR_ERR_AUTH_FAILED:
- if (info == NULL)
- errmsg = _("authentication failed");
- else
- errmsg = _("authentication failed: %s");
- break;
- case VIR_ERR_NO_STORAGE_POOL:
- if (info == NULL)
- errmsg = _("Storage pool not found");
- else
- errmsg = _("Storage pool not found: %s");
- break;
- case VIR_ERR_NO_STORAGE_VOL:
- if (info == NULL)
- errmsg = _("Storage volume not found");
- else
- errmsg = _("Storage volume not found: %s");
- break;
- case VIR_ERR_INVALID_STORAGE_POOL:
- if (info == NULL)
- errmsg = _("invalid storage pool pointer in");
- else
- errmsg = _("invalid storage pool pointer in %s");
- break;
- case VIR_ERR_INVALID_STORAGE_VOL:
- if (info == NULL)
- errmsg = _("invalid storage volume pointer in");
- else
- errmsg = _("invalid storage volume pointer in %s");
- break;
- case VIR_WAR_NO_STORAGE:
- if (info == NULL)
- errmsg = _("Failed to find a storage driver");
- else
- errmsg = _("Failed to find a storage driver: %s");
- break;
- case VIR_WAR_NO_NODE:
- if (info == NULL)
- errmsg = _("Failed to find a node driver");
- else
- errmsg = _("Failed to find a node driver: %s");
- break;
- case VIR_ERR_INVALID_NODE_DEVICE:
- if (info == NULL)
- errmsg = _("invalid node device pointer");
- else
- errmsg = _("invalid node device pointer in %s");
- break;
- case VIR_ERR_NO_NODE_DEVICE:
- if (info == NULL)
- errmsg = _("Node device not found");
- else
- errmsg = _("Node device not found: %s");
- break;
- case VIR_ERR_NO_SECURITY_MODEL:
- if (info == NULL)
- errmsg = _("Security model not found");
- else
- errmsg = _("Security model not found: %s");
- break;
- case VIR_ERR_OPERATION_INVALID:
- if (info == NULL)
- errmsg = _("Requested operation is not valid");
- else
- errmsg = _("Requested operation is not valid: %s");
- break;
- case VIR_WAR_NO_INTERFACE:
- if (info == NULL)
- errmsg = _("Failed to find the interface");
- else
- errmsg = _("Failed to find the interface: %s");
- break;
- case VIR_ERR_NO_INTERFACE:
- if (info == NULL)
- errmsg = _("Interface not found");
- else
- errmsg = _("Interface not found: %s");
- break;
- case VIR_ERR_INVALID_INTERFACE:
- if (info == NULL)
- errmsg = _("invalid interface pointer in");
- else
- errmsg = _("invalid interface pointer in %s");
- break;
- case VIR_ERR_MULTIPLE_INTERFACES:
- if (info == NULL)
- errmsg = _("multiple matching interfaces found");
- else
- errmsg = _("multiple matching interfaces found: %s");
- break;
- case VIR_WAR_NO_SECRET:
- if (info == NULL)
- errmsg = _("Failed to find a secret storage driver");
- else
- errmsg = _("Failed to find a secret storage driver: %s");
- break;
- case VIR_ERR_INVALID_SECRET:
- if (info == NULL)
- errmsg = _("Invalid secret");
- else
- errmsg = _("Invalid secret: %s");
- case VIR_ERR_NO_SECRET:
- if (info == NULL)
- errmsg = _("Secret not found");
- else
- errmsg = _("Secret not found: %s");
- break;
- }
- return (errmsg);
-}
-
-/**
- * virReportErrorHelper:
- *
- * @conn: the connection to the hypervisor if available
- * @domcode: the virErrorDomain indicating where it's coming from
- * @errcode: the virErrorNumber code for the error
- * @filename: Source file error is dispatched from
- * @funcname: Function error is dispatched from
- * @linenr: Line number error is dispatched from
- * @fmt: the format string
- * @...: extra parameters for the message display
- *
- * Helper function to do most of the grunt work for individual driver
- * ReportError
- */
-void virReportErrorHelper(virConnectPtr conn,
- int domcode,
- int errcode,
- const char *filename,
- const char *funcname,
- size_t linenr,
- const char *fmt, ...)
-{
- va_list args;
- char errorMessage[1024];
- const char *virerr;
-
- if (fmt) {
- va_start(args, fmt);
- vsnprintf(errorMessage, sizeof(errorMessage)-1, fmt, args);
- va_end(args);
- } else {
- errorMessage[0] = '\0';
- }
-
- virerr = virErrorMsg(errcode, (errorMessage[0] ? errorMessage : NULL));
- virRaiseErrorFull(conn, filename, funcname, linenr,
- domcode, errcode, VIR_ERR_ERROR,
- virerr, errorMessage, NULL,
- -1, -1, virerr, errorMessage);
-
-}
-
-/**
- * virStrerror:
- * @theerrno: the errno value
- * @errBuf: the buffer to save the error to
- * @errBufLen: the buffer length
- *
- * Generate an erro string for the given errno
- *
- * Returns a pointer to the error string, possibly indicating that the
- * error is unknown
- */
-const char *virStrerror(int theerrno, char *errBuf, size_t errBufLen)
-{
-#ifdef HAVE_STRERROR_R
-# ifdef __USE_GNU
- /* Annoying linux specific API contract */
- return strerror_r(theerrno, errBuf, errBufLen);
-# else
- strerror_r(theerrno, errBuf, errBufLen);
- return errBuf;
-# endif
-#else
- /* Mingw lacks strerror_r() and its strerror() is definitely not
- * threadsafe, so safest option is to just print the raw errno
- * value - we can at least reliably & safely look it up in the
- * header files for debug purposes
- */
- int n = snprintf(errBuf, errBufLen, "errno=%d", theerrno);
- return (0 < n && n < errBufLen
- ? errBuf : _("internal error: buffer too small"));
-#endif
-}
-
-/**
- * virReportSystemErrorFull:
- * @conn: the hyperisor connection
- * @domcode: the virErrorDomain indicating where it's coming from
- * @theerrno: an errno number
- * @filename: filename where error was raised
- * @funcname: function name where error was raised
- * @linenr: line number where error was raised
- * @fmt: the message to display/transmit
- * @...: extra parameters for the message display
- *
- * Convenience internal routine called when a system error is detected.
- */
-void virReportSystemErrorFull(virConnectPtr conn,
- int domcode,
- int theerrno,
- const char *filename,
- const char *funcname,
- size_t linenr,
- const char *fmt, ...)
-{
- char strerror_buf[1024];
- char msgDetailBuf[1024];
-
- const char *errnoDetail = virStrerror(theerrno, strerror_buf,
- sizeof(strerror_buf));
- const char *msg = virErrorMsg(VIR_ERR_SYSTEM_ERROR, fmt);
- const char *msgDetail = NULL;
-
- if (fmt) {
- va_list args;
- int n;
-
- va_start(args, fmt);
- n = vsnprintf(msgDetailBuf, sizeof(msgDetailBuf), fmt, args);
- va_end(args);
-
- size_t len = strlen (msgDetailBuf);
- if (0 <= n && n + 2 + len < sizeof (msgDetailBuf)) {
- char *p = msgDetailBuf + n;
- stpcpy (stpcpy (p, ": "), errnoDetail);
- msgDetail = msgDetailBuf;
- }
- }
-
- if (!msgDetail)
- msgDetail = errnoDetail;
-
- virRaiseErrorFull(conn, filename, funcname, linenr,
- domcode, VIR_ERR_SYSTEM_ERROR, VIR_ERR_ERROR,
- msg, msgDetail, NULL, -1, -1, msg, msgDetail);
-}
-
-/**
- * virReportOOMErrorFull:
- * @conn: the hyperisor connection
- * @domcode: the virErrorDomain indicating where it's coming from
- * @filename: filename where error was raised
- * @funcname: function name where error was raised
- * @linenr: line number where error was raised
- *
- * Convenience internal routine called when an out of memory error is
- * detected
- */
-void virReportOOMErrorFull(virConnectPtr conn,
- int domcode,
- const char *filename,
- const char *funcname,
- size_t linenr)
-{
- const char *virerr;
-
- virerr = virErrorMsg(VIR_ERR_NO_MEMORY, NULL);
- virRaiseErrorFull(conn, filename, funcname, linenr,
- domcode, VIR_ERR_NO_MEMORY, VIR_ERR_ERROR,
- virerr, NULL, NULL, -1, -1, virerr, NULL);
-}
+++ /dev/null
-/*
- * virterror.h: internal error handling
- *
- * Copyright (C) 2006-2009 Red Hat, Inc.
- *
- * 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
- *
- */
-
-#ifndef __VIRT_ERROR_H_
-#define __VIRT_ERROR_H_
-
-#include "internal.h"
-
-extern virErrorFunc virErrorHandler;
-extern void *virUserData;
-
-/************************************************************************
- * *
- * API for error handling *
- * *
- ************************************************************************/
-int virErrorInitialize(void);
-void virRaiseErrorFull(virConnectPtr conn,
- const char *filename,
- const char *funcname,
- size_t linenr,
- int domain,
- int code,
- virErrorLevel level,
- const char *str1,
- const char *str2,
- const char *str3,
- int int1,
- int int2,
- const char *fmt, ...)
- ATTRIBUTE_FMT_PRINTF(13, 14);
-
-/* Includes 'dom' and 'net' for compatbility, but they're ignored */
-#define virRaiseError(conn, dom, net, domain, code, level, \
- str1, str2, str3, int1, int2, msg, ...) \
- virRaiseErrorFull(conn, __FILE__, __FUNCTION__, __LINE__, \
- domain, code, level, str1, str2, str3, int1, int2, \
- msg, __VA_ARGS__)
-
-const char *virErrorMsg(virErrorNumber error, const char *info);
-void virReportErrorHelper(virConnectPtr conn, int domcode, int errcode,
- const char *filename ATTRIBUTE_UNUSED,
- const char *funcname ATTRIBUTE_UNUSED,
- size_t linenr ATTRIBUTE_UNUSED,
- const char *fmt, ...)
- ATTRIBUTE_FMT_PRINTF(7, 8);
-
-void virReportSystemErrorFull(virConnectPtr conn,
- int domcode,
- int theerrno,
- const char *filename,
- const char *funcname,
- size_t linenr,
- const char *fmt, ...)
- ATTRIBUTE_FMT_PRINTF(7, 8);
-
-#define virReportSystemError(conn, theerrno, fmt,...) \
- virReportSystemErrorFull((conn), \
- VIR_FROM_THIS, \
- (theerrno), \
- __FILE__, __FUNCTION__, __LINE__, \
- (fmt), __VA_ARGS__)
-
-void virReportOOMErrorFull(virConnectPtr conn,
- int domcode,
- const char *filename,
- const char *funcname,
- size_t linenr);
-
-#define virReportOOMError(conn) \
- virReportOOMErrorFull((conn), VIR_FROM_THIS, \
- __FILE__, __FUNCTION__, __LINE__)
-
-
-void virSetGlobalError(void);
-void virSetConnError(virConnectPtr conn);
-const char *virStrerror(int theerrno, char *errBuf, size_t errBufLen);
-
-#endif
if (priv->xshandle == NULL)
return(-1);
+#ifndef PROXY
if (priv->xsWatch != -1)
virEventRemoveHandle(priv->xsWatch);
+#endif
xs_daemon_close(priv->xshandle);
priv->xshandle = NULL;
+++ /dev/null
-/*
- * xml.c: XML based interfaces for the libvir library
- *
- * Copyright (C) 2005, 2007-2009 Red Hat, Inc.
- *
- * See COPYING.LIB for the License of this software
- *
- * Daniel Veillard <veillard@redhat.com>
- */
-
-#include <config.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdarg.h>
-#include <limits.h>
-#include <math.h> /* for isnan() */
-
-#include "virterror_internal.h"
-#include "xml.h"
-#include "buf.h"
-#include "util.h"
-#include "memory.h"
-
-#define VIR_FROM_THIS VIR_FROM_XML
-
-#define virXMLError(conn, code, fmt...) \
- virReportErrorHelper(conn, VIR_FROM_XML, code, __FILE__, \
- __FUNCTION__, __LINE__, fmt)
-
-
-/************************************************************************
- * *
- * Wrappers around libxml2 XPath specific functions *
- * *
- ************************************************************************/
-
-/**
- * virXPathString:
- * @xpath: the XPath string to evaluate
- * @ctxt: an XPath context
- *
- * Convenience function to evaluate an XPath string
- *
- * Returns a new string which must be deallocated by the caller or NULL
- * if the evaluation failed.
- */
-char *
-virXPathString(virConnectPtr conn,
- const char *xpath,
- xmlXPathContextPtr ctxt)
-{
- xmlXPathObjectPtr obj;
- xmlNodePtr relnode;
- char *ret;
-
- if ((ctxt == NULL) || (xpath == NULL)) {
- virXMLError(conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("Invalid parameter to virXPathString()"));
- return (NULL);
- }
- relnode = ctxt->node;
- obj = xmlXPathEval(BAD_CAST xpath, ctxt);
- if ((obj == NULL) || (obj->type != XPATH_STRING) ||
- (obj->stringval == NULL) || (obj->stringval[0] == 0)) {
- xmlXPathFreeObject(obj);
- return (NULL);
- }
- ret = strdup((char *) obj->stringval);
- xmlXPathFreeObject(obj);
- if (ret == NULL) {
- virReportOOMError(conn);
- }
- ctxt->node = relnode;
- return (ret);
-}
-
-/**
- * virXPathStringLimit:
- * @xpath: the XPath string to evaluate
- * @maxlen: maximum length permittred string
- * @ctxt: an XPath context
- *
- * Wrapper for virXPathString, which validates the length of the returned
- * string.
- *
- * Returns a new string which must be deallocated by the caller or NULL if
- * the evaluation failed.
- */
-char *
-virXPathStringLimit(virConnectPtr conn,
- const char *xpath,
- size_t maxlen,
- xmlXPathContextPtr ctxt)
-{
- char *tmp = virXPathString(conn, xpath, ctxt);
-
- if (tmp != NULL && strlen(tmp) >= maxlen) {
- virXMLError(conn, VIR_ERR_INTERNAL_ERROR,
- _("\'%s\' value longer than %Zd bytes in virXPathStringLimit()"),
- xpath, maxlen);
- return NULL;
- }
-
- return tmp;
-}
-
-/**
- * virXPathNumber:
- * @xpath: the XPath string to evaluate
- * @ctxt: an XPath context
- * @value: the returned double value
- *
- * Convenience function to evaluate an XPath number
- *
- * Returns 0 in case of success in which case @value is set,
- * or -1 if the evaluation failed.
- */
-int
-virXPathNumber(virConnectPtr conn,
- const char *xpath,
- xmlXPathContextPtr ctxt,
- double *value)
-{
- xmlXPathObjectPtr obj;
- xmlNodePtr relnode;
-
- if ((ctxt == NULL) || (xpath == NULL) || (value == NULL)) {
- virXMLError(conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("Invalid parameter to virXPathNumber()"));
- return (-1);
- }
- relnode = ctxt->node;
- obj = xmlXPathEval(BAD_CAST xpath, ctxt);
- if ((obj == NULL) || (obj->type != XPATH_NUMBER) ||
- (isnan(obj->floatval))) {
- xmlXPathFreeObject(obj);
- ctxt->node = relnode;
- return (-1);
- }
-
- *value = obj->floatval;
- xmlXPathFreeObject(obj);
- ctxt->node = relnode;
- return (0);
-}
-
-static int
-virXPathLongBase(virConnectPtr conn,
- const char *xpath,
- xmlXPathContextPtr ctxt,
- int base,
- long *value)
-{
- xmlXPathObjectPtr obj;
- xmlNodePtr relnode;
- int ret = 0;
-
- if ((ctxt == NULL) || (xpath == NULL) || (value == NULL)) {
- virXMLError(conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("Invalid parameter to virXPathLong()"));
- return (-1);
- }
- relnode = ctxt->node;
- obj = xmlXPathEval(BAD_CAST xpath, ctxt);
- if ((obj != NULL) && (obj->type == XPATH_STRING) &&
- (obj->stringval != NULL) && (obj->stringval[0] != 0)) {
- char *conv = NULL;
- long val;
-
- val = strtol((const char *) obj->stringval, &conv, base);
- if (conv == (const char *) obj->stringval) {
- ret = -2;
- } else {
- *value = val;
- }
- } else if ((obj != NULL) && (obj->type == XPATH_NUMBER) &&
- (!(isnan(obj->floatval)))) {
- *value = (long) obj->floatval;
- if (*value != obj->floatval) {
- ret = -2;
- }
- } else {
- ret = -1;
- }
-
- xmlXPathFreeObject(obj);
- ctxt->node = relnode;
- return (ret);
-}
-
-/**
- * virXPathLong:
- * @xpath: the XPath string to evaluate
- * @ctxt: an XPath context
- * @value: the returned long value
- *
- * Convenience function to evaluate an XPath number
- *
- * Returns 0 in case of success in which case @value is set,
- * or -1 if the XPath evaluation failed or -2 if the
- * value doesn't have a long format.
- */
-int
-virXPathLong(virConnectPtr conn,
- const char *xpath,
- xmlXPathContextPtr ctxt,
- long *value)
-{
- return virXPathLongBase(conn, xpath, ctxt, 10, value);
-}
-
-/**
- * virXPathLongHex:
- * @xpath: the XPath string to evaluate
- * @ctxt: an XPath context
- * @value: the returned long value
- *
- * Convenience function to evaluate an XPath number
- * according to a base of 16
- *
- * Returns 0 in case of success in which case @value is set,
- * or -1 if the XPath evaluation failed or -2 if the
- * value doesn't have a long format.
- */
-int
-virXPathLongHex(virConnectPtr conn,
- const char *xpath,
- xmlXPathContextPtr ctxt,
- long *value)
-{
- return virXPathLongBase(conn, xpath, ctxt, 16, value);
-}
-
-static int
-virXPathULongBase(virConnectPtr conn,
- const char *xpath,
- xmlXPathContextPtr ctxt,
- int base,
- unsigned long *value)
-{
- xmlXPathObjectPtr obj;
- xmlNodePtr relnode;
- int ret = 0;
-
- if ((ctxt == NULL) || (xpath == NULL) || (value == NULL)) {
- virXMLError(conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("Invalid parameter to virXPathULong()"));
- return (-1);
- }
- relnode = ctxt->node;
- obj = xmlXPathEval(BAD_CAST xpath, ctxt);
- if ((obj != NULL) && (obj->type == XPATH_STRING) &&
- (obj->stringval != NULL) && (obj->stringval[0] != 0)) {
- char *conv = NULL;
- long val;
-
- val = strtoul((const char *) obj->stringval, &conv, base);
- if (conv == (const char *) obj->stringval) {
- ret = -2;
- } else {
- *value = val;
- }
- } else if ((obj != NULL) && (obj->type == XPATH_NUMBER) &&
- (!(isnan(obj->floatval)))) {
- *value = (unsigned long) obj->floatval;
- if (*value != obj->floatval) {
- ret = -2;
- }
- } else {
- ret = -1;
- }
-
- xmlXPathFreeObject(obj);
- ctxt->node = relnode;
- return (ret);
-}
-
-/**
- * virXPathULong:
- * @xpath: the XPath string to evaluate
- * @ctxt: an XPath context
- * @value: the returned long value
- *
- * Convenience function to evaluate an XPath number
- *
- * Returns 0 in case of success in which case @value is set,
- * or -1 if the XPath evaluation failed or -2 if the
- * value doesn't have a long format.
- */
-int
-virXPathULong(virConnectPtr conn,
- const char *xpath,
- xmlXPathContextPtr ctxt,
- unsigned long *value)
-{
- return virXPathULongBase(conn, xpath, ctxt, 10, value);
-}
-
-/**
- * virXPathUHex:
- * @xpath: the XPath string to evaluate
- * @ctxt: an XPath context
- * @value: the returned long value
- *
- * Convenience function to evaluate an XPath number
- * according to base of 16
- *
- * Returns 0 in case of success in which case @value is set,
- * or -1 if the XPath evaluation failed or -2 if the
- * value doesn't have a long format.
- */
-int
-virXPathULongHex(virConnectPtr conn,
- const char *xpath,
- xmlXPathContextPtr ctxt,
- unsigned long *value)
-{
- return virXPathULongBase(conn, xpath, ctxt, 16, value);
-}
-
-/**
- * virXPathULongLong:
- * @xpath: the XPath string to evaluate
- * @ctxt: an XPath context
- * @value: the returned long long value
- *
- * Convenience function to evaluate an XPath number
- *
- * Returns 0 in case of success in which case @value is set,
- * or -1 if the XPath evaluation failed or -2 if the
- * value doesn't have a long format.
- */
-int
-virXPathULongLong(virConnectPtr conn,
- const char *xpath,
- xmlXPathContextPtr ctxt,
- unsigned long long *value)
-{
- xmlXPathObjectPtr obj;
- xmlNodePtr relnode;
- int ret = 0;
-
- if ((ctxt == NULL) || (xpath == NULL) || (value == NULL)) {
- virXMLError(conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("Invalid parameter to virXPathULong()"));
- return (-1);
- }
- relnode = ctxt->node;
- obj = xmlXPathEval(BAD_CAST xpath, ctxt);
- if ((obj != NULL) && (obj->type == XPATH_STRING) &&
- (obj->stringval != NULL) && (obj->stringval[0] != 0)) {
- char *conv = NULL;
- unsigned long long val;
-
- val = strtoull((const char *) obj->stringval, &conv, 10);
- if (conv == (const char *) obj->stringval) {
- ret = -2;
- } else {
- *value = val;
- }
- } else if ((obj != NULL) && (obj->type == XPATH_NUMBER) &&
- (!(isnan(obj->floatval)))) {
- *value = (unsigned long long) obj->floatval;
- if (*value != obj->floatval) {
- ret = -2;
- }
- } else {
- ret = -1;
- }
-
- xmlXPathFreeObject(obj);
- ctxt->node = relnode;
- return (ret);
-}
-
-char *
-virXMLPropString(xmlNodePtr node,
- const char *name)
-{
- return (char *)xmlGetProp(node, BAD_CAST name);
-}
-
-/**
- * virXPathBoolean:
- * @xpath: the XPath string to evaluate
- * @ctxt: an XPath context
- *
- * Convenience function to evaluate an XPath boolean
- *
- * Returns 0 if false, 1 if true, or -1 if the evaluation failed.
- */
-int
-virXPathBoolean(virConnectPtr conn,
- const char *xpath,
- xmlXPathContextPtr ctxt)
-{
- xmlXPathObjectPtr obj;
- xmlNodePtr relnode;
- int ret;
-
- if ((ctxt == NULL) || (xpath == NULL)) {
- virXMLError(conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("Invalid parameter to virXPathBoolean()"));
- return (-1);
- }
- relnode = ctxt->node;
- obj = xmlXPathEval(BAD_CAST xpath, ctxt);
- if ((obj == NULL) || (obj->type != XPATH_BOOLEAN) ||
- (obj->boolval < 0) || (obj->boolval > 1)) {
- xmlXPathFreeObject(obj);
- return (-1);
- }
- ret = obj->boolval;
-
- xmlXPathFreeObject(obj);
- ctxt->node = relnode;
- return (ret);
-}
-
-/**
- * virXPathNode:
- * @xpath: the XPath string to evaluate
- * @ctxt: an XPath context
- *
- * Convenience function to evaluate an XPath node set and returning
- * only one node, the first one in the set if any
- *
- * Returns a pointer to the node or NULL if the evaluation failed.
- */
-xmlNodePtr
-virXPathNode(virConnectPtr conn,
- const char *xpath,
- xmlXPathContextPtr ctxt)
-{
- xmlXPathObjectPtr obj;
- xmlNodePtr relnode;
- xmlNodePtr ret;
-
- if ((ctxt == NULL) || (xpath == NULL)) {
- virXMLError(conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("Invalid parameter to virXPathNode()"));
- return (NULL);
- }
- relnode = ctxt->node;
- obj = xmlXPathEval(BAD_CAST xpath, ctxt);
- if ((obj == NULL) || (obj->type != XPATH_NODESET) ||
- (obj->nodesetval == NULL) || (obj->nodesetval->nodeNr <= 0) ||
- (obj->nodesetval->nodeTab == NULL)) {
- xmlXPathFreeObject(obj);
- ctxt->node = relnode;
- return (NULL);
- }
-
- ret = obj->nodesetval->nodeTab[0];
- xmlXPathFreeObject(obj);
- ctxt->node = relnode;
- return (ret);
-}
-
-/**
- * virXPathNodeSet:
- * @xpath: the XPath string to evaluate
- * @ctxt: an XPath context
- * @list: the returned list of nodes (or NULL if only count matters)
- *
- * Convenience function to evaluate an XPath node set
- *
- * Returns the number of nodes found in which case @list is set (and
- * must be freed) or -1 if the evaluation failed.
- */
-int
-virXPathNodeSet(virConnectPtr conn,
- const char *xpath,
- xmlXPathContextPtr ctxt,
- xmlNodePtr **list)
-{
- xmlXPathObjectPtr obj;
- xmlNodePtr relnode;
- int ret;
-
- if ((ctxt == NULL) || (xpath == NULL)) {
- virXMLError(conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("Invalid parameter to virXPathNodeSet()"));
- return (-1);
- }
-
- if (list != NULL)
- *list = NULL;
-
- relnode = ctxt->node;
- obj = xmlXPathEval(BAD_CAST xpath, ctxt);
- if ((obj == NULL) || (obj->type != XPATH_NODESET) ||
- (obj->nodesetval == NULL) || (obj->nodesetval->nodeNr < 0)) {
- xmlXPathFreeObject(obj);
- ctxt->node = relnode;
- return (-1);
- }
-
- ret = obj->nodesetval->nodeNr;
- if (list != NULL && ret) {
- if (VIR_ALLOC_N(*list, ret) < 0) {
- virReportOOMError(conn);
- ret = -1;
- } else {
- memcpy(*list, obj->nodesetval->nodeTab,
- ret * sizeof(xmlNodePtr));
- }
- }
- xmlXPathFreeObject(obj);
- ctxt->node = relnode;
- return (ret);
-}
+++ /dev/null
-/*
- * xml.h: internal definitions used for XML parsing routines.
- */
-
-#ifndef __VIR_XML_H__
-#define __VIR_XML_H__
-
-#include "internal.h"
-
-#include <libxml/parser.h>
-#include <libxml/tree.h>
-#include <libxml/xpath.h>
-
-int virXPathBoolean (virConnectPtr conn,
- const char *xpath,
- xmlXPathContextPtr ctxt);
-char * virXPathString (virConnectPtr conn,
- const char *xpath,
- xmlXPathContextPtr ctxt);
-char * virXPathStringLimit(virConnectPtr conn,
- const char *xpath,
- size_t maxlen,
- xmlXPathContextPtr ctxt);
-int virXPathNumber (virConnectPtr conn,
- const char *xpath,
- xmlXPathContextPtr ctxt,
- double *value);
-int virXPathLong (virConnectPtr conn,
- const char *xpath,
- xmlXPathContextPtr ctxt,
- long *value);
-int virXPathULong (virConnectPtr conn,
- const char *xpath,
- xmlXPathContextPtr ctxt,
- unsigned long *value);
-int virXPathULongLong(virConnectPtr conn,
- const char *xpath,
- xmlXPathContextPtr ctxt,
- unsigned long long *value);
-int virXPathLongHex (virConnectPtr conn,
- const char *xpath,
- xmlXPathContextPtr ctxt,
- long *value);
-int virXPathULongHex(virConnectPtr conn,
- const char *xpath,
- xmlXPathContextPtr ctxt,
- unsigned long *value);
-xmlNodePtr virXPathNode (virConnectPtr conn,
- const char *xpath,
- xmlXPathContextPtr ctxt);
-int virXPathNodeSet (virConnectPtr conn,
- const char *xpath,
- xmlXPathContextPtr ctxt,
- xmlNodePtr **list);
-
-char * virXMLPropString(xmlNodePtr node,
- const char *name);
-
-#endif /* __VIR_XML_H__ */
-I$(top_builddir)/include \
-I$(top_srcdir)/include \
-I$(top_srcdir)/src \
+ -I$(top_srcdir)/src/util \
-I$(top_srcdir)/src/conf \
$(LIBXML_CFLAGS) \
$(GNUTLS_CFLAGS) \
virsh_CFLAGS = \
-I$(top_srcdir)/gnulib/lib -I../gnulib/lib \
-I../include \
- -I../src \
+ -I$(top_srcdir)/src \
+ -I$(top_srcdir)/src/util \
-DGETTEXT_PACKAGE=\"$(PACKAGE)\" \
-DLOCALEBASEDIR=\""$(datadir)/locale"\" \
$(COVERAGE_CFLAGS) \