]> xenbits.xensource.com Git - people/liuw/libxenctrl-split/libvirt.git/commitdiff
Move all shared utility files to src/util/
authorDaniel P. Berrange <berrange@redhat.com>
Wed, 16 Sep 2009 15:28:46 +0000 (16:28 +0100)
committerDaniel P. Berrange <berrange@redhat.com>
Mon, 21 Sep 2009 13:41:47 +0000 (14:41 +0100)
* src/bridge.c, src/bridge.h, src/buf.c, src/buf.h, src/cgroup.c,
  src/cgroup.h, src/conf.c, src/conf.h, src/event.c, src/event.h,
  src/hash.c, src/hash.h, src/hostusb.c, src/hostusb.h,
  src/iptables.c, src/iptables.h, src/logging.c, src/logging.h,
  src/memory.c, src/memory.h, src/pci.c, src/pci.h, src/qparams.c,
  src/qparams.h, src/stats_linux.c, src/stats_linux.h,
  src/threads-pthread.c, src/threads-pthread.h, src/threads-win32.c,
  src/threads-win32.h, src/threads.c, src/threads.h, src/util.c,
  src/util.h, src/uuid.c, src/uuid.h, src/virterror.c,
  src/virterror_internal.h, src/xml.c, src/xml.h: Move all files
  into src/util/
* daemon/Makefile.am: Add -Isrc/util/ to build flags
* src/Makefile.am: Add -Isrc/util/ to build flags and update for
  moved files
* src/libvirt_private.syms: Export cgroup APIs since they're now
  in util rather than linking directly to drivers
* src/xen/xs_internal.c: Disable bogus virEventRemoveHandle call
  when built under PROXY
* proxy/Makefile.am: Update for changed file locations. Remove
  bogus build of event.c
* tools/Makefile.am, tests/Makefile.am: Add -Isrc/util/ to build flags

89 files changed:
daemon/Makefile.am
docs/Makefile.am
docs/apibuild.py
proxy/Makefile.am
src/Makefile.am
src/bridge.c [deleted file]
src/bridge.h [deleted file]
src/buf.c [deleted file]
src/buf.h [deleted file]
src/cgroup.c [deleted file]
src/cgroup.h [deleted file]
src/conf.c [deleted file]
src/conf.h [deleted file]
src/event.c [deleted file]
src/event.h [deleted file]
src/hash.c [deleted file]
src/hash.h [deleted file]
src/hostusb.c [deleted file]
src/hostusb.h [deleted file]
src/iptables.c [deleted file]
src/iptables.h [deleted file]
src/libvirt_private.syms
src/logging.c [deleted file]
src/logging.h [deleted file]
src/memory.c [deleted file]
src/memory.h [deleted file]
src/pci.c [deleted file]
src/pci.h [deleted file]
src/qparams.c [deleted file]
src/qparams.h [deleted file]
src/stats_linux.c [deleted file]
src/stats_linux.h [deleted file]
src/threads-pthread.c [deleted file]
src/threads-pthread.h [deleted file]
src/threads-win32.c [deleted file]
src/threads-win32.h [deleted file]
src/threads.c [deleted file]
src/threads.h [deleted file]
src/util.c [deleted file]
src/util.h [deleted file]
src/util/bridge.c [new file with mode: 0644]
src/util/bridge.h [new file with mode: 0644]
src/util/buf.c [new file with mode: 0644]
src/util/buf.h [new file with mode: 0644]
src/util/cgroup.c [new file with mode: 0644]
src/util/cgroup.h [new file with mode: 0644]
src/util/conf.c [new file with mode: 0644]
src/util/conf.h [new file with mode: 0644]
src/util/event.c [new file with mode: 0644]
src/util/event.h [new file with mode: 0644]
src/util/hash.c [new file with mode: 0644]
src/util/hash.h [new file with mode: 0644]
src/util/hostusb.c [new file with mode: 0644]
src/util/hostusb.h [new file with mode: 0644]
src/util/iptables.c [new file with mode: 0644]
src/util/iptables.h [new file with mode: 0644]
src/util/logging.c [new file with mode: 0644]
src/util/logging.h [new file with mode: 0644]
src/util/memory.c [new file with mode: 0644]
src/util/memory.h [new file with mode: 0644]
src/util/pci.c [new file with mode: 0644]
src/util/pci.h [new file with mode: 0644]
src/util/qparams.c [new file with mode: 0644]
src/util/qparams.h [new file with mode: 0644]
src/util/stats_linux.c [new file with mode: 0644]
src/util/stats_linux.h [new file with mode: 0644]
src/util/threads-pthread.c [new file with mode: 0644]
src/util/threads-pthread.h [new file with mode: 0644]
src/util/threads-win32.c [new file with mode: 0644]
src/util/threads-win32.h [new file with mode: 0644]
src/util/threads.c [new file with mode: 0644]
src/util/threads.h [new file with mode: 0644]
src/util/util.c [new file with mode: 0644]
src/util/util.h [new file with mode: 0644]
src/util/uuid.c [new file with mode: 0644]
src/util/uuid.h [new file with mode: 0644]
src/util/virterror.c [new file with mode: 0644]
src/util/virterror_internal.h [new file with mode: 0644]
src/util/xml.c [new file with mode: 0644]
src/util/xml.h [new file with mode: 0644]
src/uuid.c [deleted file]
src/uuid.h [deleted file]
src/virterror.c [deleted file]
src/virterror_internal.h [deleted file]
src/xen/xs_internal.c
src/xml.c [deleted file]
src/xml.h [deleted file]
tests/Makefile.am
tools/Makefile.am

index 75f9c193a0e1974287aed17e75fe243b28819e26..2938e6c070b603c0ed6089d25e3f5c8c017ba01a 100644 (file)
@@ -84,6 +84,7 @@ libvirtd_CFLAGS = \
        -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) \
index 4cd11b005d37a916bb5545432896986991576566..40778239232f2e4599cd40d4312bd98bafe75e4c 100644 (file)
@@ -109,7 +109,7 @@ $(srcdir)/html/index.html: libvirt-api.xml newapi.xsl page.xsl sitemap.html.in
 
 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
index 84bc1ac3bfde3c4b13e5f7bfde88bfeca93d2e7c..855569b5b1beb55a5c13a0ce68d3f11f39a4e8ae 100755 (executable)
@@ -2089,11 +2089,11 @@ def rebuild():
     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"
index bd6a0c8b84bcfde030bc570cda4bb98eec5417f7..3e0050b7b077e1083f23efbe5561c40b74690697 100644 (file)
@@ -4,6 +4,7 @@ if WITH_PROXY
 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@ \
@@ -12,19 +13,21 @@ INCLUDES = -I$(top_srcdir)/gnulib/lib -I../gnulib/lib \
 
 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
index 113ffe317434a9c574560d8c0d8790b7a81b6671..f5534d7a479c96e02c0b3a2c11ee5e9dee6b90fe 100644 (file)
@@ -7,6 +7,7 @@ INCLUDES =                                                      \
                -I$(top_srcdir)/gnulib/lib                      \
                -I../gnulib/lib                                 \
                -I../include                                    \
+               -I@top_srcdir@/src/util                         \
                -I@top_srcdir@/include                          \
                $(DRIVER_MODULE_CFLAGS)                         \
                $(LIBXML_CFLAGS)                                \
@@ -35,26 +36,28 @@ mod_LTLIBRARIES =
 # 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
@@ -62,7 +65,6 @@ DRIVER_SOURCES =                                              \
                driver.c driver.h                               \
                internal.h                                      \
                datatypes.c datatypes.h                         \
-               stats_linux.c stats_linux.h                     \
                $(NODE_INFO_SOURCES)                            \
                libvirt.c libvirt_internal.h
 
@@ -140,15 +142,13 @@ LXC_DRIVER_SOURCES =                                              \
                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
@@ -166,9 +166,8 @@ VBOX_DRIVER_SOURCES =                                               \
 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                   \
@@ -533,6 +532,7 @@ endif
 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
@@ -542,7 +542,7 @@ noinst_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)
@@ -563,6 +563,7 @@ endif
 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
diff --git a/src/bridge.c b/src/bridge.c
deleted file mode 100644 (file)
index 414d87b..0000000
+++ /dev/null
@@ -1,867 +0,0 @@
-/*
- * 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 */
diff --git a/src/bridge.h b/src/bridge.h
deleted file mode 100644 (file)
index 2d9bec1..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * 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__ */
diff --git a/src/buf.c b/src/buf.c
deleted file mode 100644 (file)
index c802aa2..0000000
--- a/src/buf.c
+++ /dev/null
@@ -1,415 +0,0 @@
-/*
- * 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);
-}
diff --git a/src/buf.h b/src/buf.h
deleted file mode 100644 (file)
index 7d31cb2..0000000
--- a/src/buf.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 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__ */
diff --git a/src/cgroup.c b/src/cgroup.c
deleted file mode 100644 (file)
index 111601d..0000000
+++ /dev/null
@@ -1,898 +0,0 @@
-/*
- * 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);
-}
diff --git a/src/cgroup.h b/src/cgroup.h
deleted file mode 100644 (file)
index 6d43b14..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * 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 */
diff --git a/src/conf.c b/src/conf.c
deleted file mode 100644 (file)
index 2aa4a55..0000000
+++ /dev/null
@@ -1,988 +0,0 @@
-/**
- * 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;
-}
diff --git a/src/conf.h b/src/conf.h
deleted file mode 100644 (file)
index 40d9586..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-/**
- * 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__ */
diff --git a/src/event.c b/src/event.c
deleted file mode 100644 (file)
index 59b9ac6..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * 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;
-}
diff --git a/src/event.h b/src/event.h
deleted file mode 100644 (file)
index dc20622..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * 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__ */
diff --git a/src/hash.c b/src/hash.c
deleted file mode 100644 (file)
index 42a28d1..0000000
+++ /dev/null
@@ -1,589 +0,0 @@
-/*
- * 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);
-}
diff --git a/src/hash.h b/src/hash.h
deleted file mode 100644 (file)
index 7778909..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * 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__ */
diff --git a/src/hostusb.c b/src/hostusb.c
deleted file mode 100644 (file)
index 07e10b1..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * 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);
-}
diff --git a/src/hostusb.h b/src/hostusb.h
deleted file mode 100644 (file)
index 7f75c8b..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 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__ */
diff --git a/src/iptables.c b/src/iptables.c
deleted file mode 100644 (file)
index 4562800..0000000
+++ /dev/null
@@ -1,1122 +0,0 @@
-/*
- * 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);
-}
diff --git a/src/iptables.h b/src/iptables.h
deleted file mode 100644 (file)
index fbe9b5d..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * 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__ */
index 867678fa34a2d38ce5cf20dd919d2a494839094f..a2646a33d75382902fa14204c75aa9ead0611283 100644 (file)
@@ -47,6 +47,23 @@ virConfWriteFile;
 virConfWriteMem;
 
 
+# cgroup.h
+virCgroupForDomain;
+virCgroupForDriver;
+virCgroupRemove;
+virCgroupFree;
+virCgroupAddTask;
+virCgroupSetCpuShares;
+virCgroupGetCpuShares;
+virCgroupDenyDevicePath;
+virCgroupAllowDevicePath;
+virCgroupDenyAllDevices;
+virCgroupAllowDeviceMajor;
+virCgroupControllerTypeToString;
+virCgroupControllerTypeFromString;
+virCgroupGetCpuacctUsage;
+
+
 # datatypes.h
 virGetDomain;
 virGetInterface;
diff --git a/src/logging.c b/src/logging.c
deleted file mode 100644 (file)
index 07c2b0e..0000000
+++ /dev/null
@@ -1,881 +0,0 @@
-/*
- * 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));
-}
diff --git a/src/logging.h b/src/logging.h
deleted file mode 100644 (file)
index 8b2b84c..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * 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
diff --git a/src/memory.c b/src/memory.c
deleted file mode 100644 (file)
index b2ee376..0000000
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * 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;
-}
diff --git a/src/memory.h b/src/memory.h
deleted file mode 100644 (file)
index fc9e6c1..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * 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_ */
diff --git a/src/pci.c b/src/pci.c
deleted file mode 100644 (file)
index feaa6e8..0000000
--- a/src/pci.c
+++ /dev/null
@@ -1,1076 +0,0 @@
-/*
- * 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;
-}
diff --git a/src/pci.h b/src/pci.h
deleted file mode 100644 (file)
index 047955f..0000000
--- a/src/pci.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * 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__ */
diff --git a/src/qparams.c b/src/qparams.c
deleted file mode 100644 (file)
index d0a84b3..0000000
+++ /dev/null
@@ -1,261 +0,0 @@
-/* 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;
-}
diff --git a/src/qparams.h b/src/qparams.h
deleted file mode 100644 (file)
index 1a92048..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/* 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_ */
diff --git a/src/stats_linux.c b/src/stats_linux.c
deleted file mode 100644 (file)
index 7d8a5f9..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * 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__ */
diff --git a/src/stats_linux.h b/src/stats_linux.h
deleted file mode 100644 (file)
index 033a50b..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * 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__ */
diff --git a/src/threads-pthread.c b/src/threads-pthread.c
deleted file mode 100644 (file)
index 4e00bc5..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * 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);
-}
diff --git a/src/threads-pthread.h b/src/threads-pthread.h
deleted file mode 100644 (file)
index 6404d1d..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * 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;
-};
diff --git a/src/threads-win32.c b/src/threads-win32.c
deleted file mode 100644 (file)
index ef3f2ef..0000000
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * 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);
-}
diff --git a/src/threads-win32.h b/src/threads-win32.h
deleted file mode 100644 (file)
index 783d91d..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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;
-};
diff --git a/src/threads.c b/src/threads.c
deleted file mode 100644 (file)
index d61b743..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * 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
diff --git a/src/threads.h b/src/threads.h
deleted file mode 100644 (file)
index 62239b7..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * 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
diff --git a/src/util.c b/src/util.c
deleted file mode 100644 (file)
index 1878e33..0000000
+++ /dev/null
@@ -1,2048 +0,0 @@
-/*
- * 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
diff --git a/src/util.h b/src/util.h
deleted file mode 100644 (file)
index f9715ab..0000000
+++ /dev/null
@@ -1,242 +0,0 @@
-
-/*
- * 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__ */
diff --git a/src/util/bridge.c b/src/util/bridge.c
new file mode 100644 (file)
index 0000000..414d87b
--- /dev/null
@@ -0,0 +1,867 @@
+/*
+ * 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 */
diff --git a/src/util/bridge.h b/src/util/bridge.h
new file mode 100644 (file)
index 0000000..2d9bec1
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * 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__ */
diff --git a/src/util/buf.c b/src/util/buf.c
new file mode 100644 (file)
index 0000000..c802aa2
--- /dev/null
@@ -0,0 +1,415 @@
+/*
+ * 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);
+}
diff --git a/src/util/buf.h b/src/util/buf.h
new file mode 100644 (file)
index 0000000..7d31cb2
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * 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__ */
diff --git a/src/util/cgroup.c b/src/util/cgroup.c
new file mode 100644 (file)
index 0000000..111601d
--- /dev/null
@@ -0,0 +1,898 @@
+/*
+ * 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);
+}
diff --git a/src/util/cgroup.h b/src/util/cgroup.h
new file mode 100644 (file)
index 0000000..6d43b14
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * 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 */
diff --git a/src/util/conf.c b/src/util/conf.c
new file mode 100644 (file)
index 0000000..2aa4a55
--- /dev/null
@@ -0,0 +1,988 @@
+/**
+ * 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;
+}
diff --git a/src/util/conf.h b/src/util/conf.h
new file mode 100644 (file)
index 0000000..40d9586
--- /dev/null
@@ -0,0 +1,88 @@
+/**
+ * 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__ */
diff --git a/src/util/event.c b/src/util/event.c
new file mode 100644 (file)
index 0000000..59b9ac6
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * 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;
+}
diff --git a/src/util/event.h b/src/util/event.h
new file mode 100644 (file)
index 0000000..dc20622
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * 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__ */
diff --git a/src/util/hash.c b/src/util/hash.c
new file mode 100644 (file)
index 0000000..42a28d1
--- /dev/null
@@ -0,0 +1,589 @@
+/*
+ * 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);
+}
diff --git a/src/util/hash.h b/src/util/hash.h
new file mode 100644 (file)
index 0000000..7778909
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * 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__ */
diff --git a/src/util/hostusb.c b/src/util/hostusb.c
new file mode 100644 (file)
index 0000000..07e10b1
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * 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);
+}
diff --git a/src/util/hostusb.h b/src/util/hostusb.h
new file mode 100644 (file)
index 0000000..7f75c8b
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * 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__ */
diff --git a/src/util/iptables.c b/src/util/iptables.c
new file mode 100644 (file)
index 0000000..4562800
--- /dev/null
@@ -0,0 +1,1122 @@
+/*
+ * 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);
+}
diff --git a/src/util/iptables.h b/src/util/iptables.h
new file mode 100644 (file)
index 0000000..fbe9b5d
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * 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__ */
diff --git a/src/util/logging.c b/src/util/logging.c
new file mode 100644 (file)
index 0000000..07c2b0e
--- /dev/null
@@ -0,0 +1,881 @@
+/*
+ * 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));
+}
diff --git a/src/util/logging.h b/src/util/logging.h
new file mode 100644 (file)
index 0000000..8b2b84c
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * 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
diff --git a/src/util/memory.c b/src/util/memory.c
new file mode 100644 (file)
index 0000000..b2ee376
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * 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;
+}
diff --git a/src/util/memory.h b/src/util/memory.h
new file mode 100644 (file)
index 0000000..fc9e6c1
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * 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_ */
diff --git a/src/util/pci.c b/src/util/pci.c
new file mode 100644 (file)
index 0000000..feaa6e8
--- /dev/null
@@ -0,0 +1,1076 @@
+/*
+ * 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;
+}
diff --git a/src/util/pci.h b/src/util/pci.h
new file mode 100644 (file)
index 0000000..047955f
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * 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__ */
diff --git a/src/util/qparams.c b/src/util/qparams.c
new file mode 100644 (file)
index 0000000..d0a84b3
--- /dev/null
@@ -0,0 +1,261 @@
+/* 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;
+}
diff --git a/src/util/qparams.h b/src/util/qparams.h
new file mode 100644 (file)
index 0000000..1a92048
--- /dev/null
@@ -0,0 +1,56 @@
+/* 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_ */
diff --git a/src/util/stats_linux.c b/src/util/stats_linux.c
new file mode 100644 (file)
index 0000000..7d8a5f9
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * 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__ */
diff --git a/src/util/stats_linux.h b/src/util/stats_linux.h
new file mode 100644 (file)
index 0000000..033a50b
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * 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__ */
diff --git a/src/util/threads-pthread.c b/src/util/threads-pthread.c
new file mode 100644 (file)
index 0000000..4e00bc5
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * 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);
+}
diff --git a/src/util/threads-pthread.h b/src/util/threads-pthread.h
new file mode 100644 (file)
index 0000000..6404d1d
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * 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;
+};
diff --git a/src/util/threads-win32.c b/src/util/threads-win32.c
new file mode 100644 (file)
index 0000000..ef3f2ef
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * 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);
+}
diff --git a/src/util/threads-win32.h b/src/util/threads-win32.h
new file mode 100644 (file)
index 0000000..783d91d
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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;
+};
diff --git a/src/util/threads.c b/src/util/threads.c
new file mode 100644 (file)
index 0000000..d61b743
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * 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
diff --git a/src/util/threads.h b/src/util/threads.h
new file mode 100644 (file)
index 0000000..62239b7
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * 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
diff --git a/src/util/util.c b/src/util/util.c
new file mode 100644 (file)
index 0000000..1878e33
--- /dev/null
@@ -0,0 +1,2048 @@
+/*
+ * 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
diff --git a/src/util/util.h b/src/util/util.h
new file mode 100644 (file)
index 0000000..f9715ab
--- /dev/null
@@ -0,0 +1,242 @@
+
+/*
+ * 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__ */
diff --git a/src/util/uuid.c b/src/util/uuid.c
new file mode 100644 (file)
index 0000000..002a64d
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * 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';
+}
diff --git a/src/util/uuid.h b/src/util/uuid.h
new file mode 100644 (file)
index 0000000..c5230a8
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * 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__ */
diff --git a/src/util/virterror.c b/src/util/virterror.c
new file mode 100644 (file)
index 0000000..77b295c
--- /dev/null
@@ -0,0 +1,1247 @@
+/*
+ * 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);
+}
diff --git a/src/util/virterror_internal.h b/src/util/virterror_internal.h
new file mode 100644 (file)
index 0000000..da89de7
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * 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
diff --git a/src/util/xml.c b/src/util/xml.c
new file mode 100644 (file)
index 0000000..575d14e
--- /dev/null
@@ -0,0 +1,514 @@
+/*
+ * 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);
+}
diff --git a/src/util/xml.h b/src/util/xml.h
new file mode 100644 (file)
index 0000000..cddd42b
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * 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__ */
diff --git a/src/uuid.c b/src/uuid.c
deleted file mode 100644 (file)
index 002a64d..0000000
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * 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';
-}
diff --git a/src/uuid.h b/src/uuid.h
deleted file mode 100644 (file)
index c5230a8..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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__ */
diff --git a/src/virterror.c b/src/virterror.c
deleted file mode 100644 (file)
index 77b295c..0000000
+++ /dev/null
@@ -1,1247 +0,0 @@
-/*
- * 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);
-}
diff --git a/src/virterror_internal.h b/src/virterror_internal.h
deleted file mode 100644 (file)
index da89de7..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * 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
index 494728d6390d0637bc4c345b17dce060d65ac673..54f410f29c2c626af457886f8d684074441ea7e0 100644 (file)
@@ -388,8 +388,10 @@ xenStoreClose(virConnectPtr conn)
     if (priv->xshandle == NULL)
         return(-1);
 
+#ifndef PROXY
     if (priv->xsWatch != -1)
         virEventRemoveHandle(priv->xsWatch);
+#endif
     xs_daemon_close(priv->xshandle);
     priv->xshandle = NULL;
 
diff --git a/src/xml.c b/src/xml.c
deleted file mode 100644 (file)
index 575d14e..0000000
--- a/src/xml.c
+++ /dev/null
@@ -1,514 +0,0 @@
-/*
- * 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);
-}
diff --git a/src/xml.h b/src/xml.h
deleted file mode 100644 (file)
index cddd42b..0000000
--- a/src/xml.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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__ */
index 26b8c1f92d53518317c6e4353d204ec4bc78aba6..cc166717250391d7438c681cdc6835bdce106465 100644 (file)
@@ -10,6 +10,7 @@ INCLUDES = \
        -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) \
index 81698a4b30785a7a5887a4915f7cc953698f7ad6..c48b203e52c150b53c95c1a4f0ea70a6d8b27722 100644 (file)
@@ -44,7 +44,8 @@ virsh_LDADD =                                                 \
 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)                              \